Skip to content

Commit

Permalink
Add reusable block tab to inserter.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZebulanStanphill committed Jun 23, 2020
1 parent 7532a48 commit af3e07d
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 31 deletions.
30 changes: 0 additions & 30 deletions packages/block-editor/src/components/inserter/block-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { map, findIndex, flow, sortBy, groupBy, isEmpty } from 'lodash';
*/
import { __, _x, _n, sprintf } from '@wordpress/i18n';
import { withSpokenMessages } from '@wordpress/components';
import { addQueryArgs } from '@wordpress/url';
import { controlsRepeat } from '@wordpress/icons';
import { useMemo, useEffect } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
Expand Down Expand Up @@ -61,12 +59,6 @@ export function InserterBlockList( {
return items.slice( 0, MAX_SUGGESTED_ITEMS );
}, [ items ] );

const reusableItems = useMemo( () => {
return filteredItems.filter(
( { category } ) => category === 'reusable'
);
}, [ filteredItems ] );

const uncategorizedItems = useMemo( () => {
return filteredItems.filter( ( item ) => ! item.category );
}, [ filteredItems ] );
Expand Down Expand Up @@ -200,28 +192,6 @@ export function InserterBlockList( {
);
} ) }

{ ! hasChildItems && !! reusableItems.length && (
<InserterPanel
className="block-editor-inserter__reusable-blocks-panel"
title={ __( 'Reusable' ) }
icon={ controlsRepeat }
>
<BlockTypesList
items={ reusableItems }
onSelect={ onSelectItem }
onHover={ onHover }
/>
<a
className="block-editor-inserter__manage-reusable-blocks"
href={ addQueryArgs( 'edit.php', {
post_type: 'wp_block',
} ) }
>
{ __( 'Manage all reusable blocks' ) }
</a>
</InserterPanel>
) }

<__experimentalInserterMenuExtension.Slot
fillProps={ {
onSelect: onSelectItem,
Expand Down
21 changes: 20 additions & 1 deletion packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import InserterPreviewPanel from './preview-panel';
import InserterBlockList from './block-list';
import BlockPatterns from './block-patterns';
import useInsertionPoint from './hooks/use-insertion-point';
import InserterReusableBlockList from './reusable-block-list';

const stopKeyPropagation = ( event ) => event.stopPropagation();

Expand Down Expand Up @@ -105,6 +106,17 @@ function InserterMenu( {
<BlockPatterns onInsert={ onInsert } filterValue={ filterValue } />
);

const reusableBlocksTab = (
<div className="block-editor-inserter__reusable-block-list">
<InserterReusableBlockList
rootClientId={ destinationRootClientId }
onInsert={ onInsert }
onHover={ onHover }
filterValue={ filterValue }
/>
</div>
);

// Disable reason (no-autofocus): The inserter menu is a modal display, not one which
// is always visible, and one which already incurs this behavior of autoFocus via
// Popover's focusOnMount.
Expand Down Expand Up @@ -133,13 +145,20 @@ function InserterMenu( {
/* translators: Patterns tab title in the block inserter. */
title: __( 'Patterns' ),
},
{
name: 'reusable',
/* translators: Reusable blocks tab title in the block inserter. */
title: __( 'Reusable' ),
},
] }
>
{ ( tab ) => {
if ( tab.name === 'blocks' ) {
return blocksTab;
} else if ( tab.name === 'patterns' ) {
return patternsTab;
}
return patternsTab;
return reusableBlocksTab;
} }
</TabPanel>
) }
Expand Down
111 changes: 111 additions & 0 deletions packages/block-editor/src/components/inserter/reusable-block-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* External dependencies
*/
import { isEmpty } from 'lodash';

/**
* WordPress dependencies
*/
import { withSpokenMessages } from '@wordpress/components';
import { useMemo, useEffect } from '@wordpress/element';
import { __, _n, sprintf } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';

/**
* Internal dependencies
*/
import BlockTypesList from '../block-types-list';
import __experimentalInserterMenuExtension from '../inserter-menu-extension';
import { searchBlockItems } from './search-items';
import InserterPanel from './panel';
import InserterNoResults from './no-results';
import useBlockTypesState from './hooks/use-block-types-state';

/**
* List of reusable blocks shown in the "Reusable" tab of the inserter.
*
* @param {Object} props Component props.
* @param {?string} props.rootClientId Client id of block to insert into.
* @param {Function} props.onInsert Callback to run when item is inserted.
* @param {Function} props.onHover Callback to run when item is hovered.
* @param {?string} props.filterValue Search term.
* @param {Function} props.debouncedSpeak Debounced speak function.
*
* @return {WPComponent} The component.
*/
export function InserterReusableBlockList( {
rootClientId,
onInsert,
onHover,
filterValue,
debouncedSpeak,
} ) {
const [ items, categories, collections, onSelectItem ] = useBlockTypesState(
rootClientId,
onInsert
);

const filteredItems = useMemo( () => {
return searchBlockItems(
items,
categories,
collections,
filterValue
).filter( ( { category } ) => category === 'reusable' );
}, [ filterValue, items, categories, collections ] );

// Announce search results on change.
useEffect( () => {
const resultsFoundMessage = sprintf(
/* translators: %d: number of results. */
_n( '%d result found.', '%d results found.', filteredItems.length ),
filteredItems.length
);
debouncedSpeak( resultsFoundMessage );
}, [ filterValue, debouncedSpeak ] );

const hasItems = ! isEmpty( filteredItems );

return (
<div>
{ filteredItems.length > 0 && (
<InserterPanel className="block-editor-inserter__reusable-blocks-panel">
<BlockTypesList
items={ filteredItems }
onSelect={ onSelectItem }
onHover={ onHover }
/>
<a
className="block-editor-inserter__manage-reusable-blocks"
href={ addQueryArgs( 'edit.php', {
post_type: 'wp_block',
} ) }
>
{ __( 'Manage all reusable blocks' ) }
</a>
</InserterPanel>
) }

<__experimentalInserterMenuExtension.Slot
fillProps={ {
onSelect: onSelectItem,
onHover,
filterValue,
hasItems,
} }
>
{ ( fills ) => {
if ( fills.length ) {
return fills;
}
if ( ! hasItems ) {
return <InserterNoResults />;
}
return null;
} }
</__experimentalInserterMenuExtension.Slot>
</div>
);
}

export default withSpokenMessages( InserterReusableBlockList );

0 comments on commit af3e07d

Please sign in to comment.