Skip to content

Commit

Permalink
Add reusable blocks tab to inserter.
Browse files Browse the repository at this point in the history
  • Loading branch information
ZebulanStanphill committed Jun 24, 2020
1 parent ea44697 commit a6a2134
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 60 deletions.
30 changes: 0 additions & 30 deletions packages/block-editor/src/components/inserter/block-types-tab.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';

Expand Down Expand Up @@ -60,12 +58,6 @@ export function BlockTypesTab( {
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 @@ -199,28 +191,6 @@ export function BlockTypesTab( {
);
} ) }

{ ! 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
48 changes: 34 additions & 14 deletions packages/block-editor/src/components/inserter/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import InserterSearchForm from './search-form';
import InserterPreviewPanel from './preview-panel';
import BlockTypesTab from './block-types-tab';
import BlockPatternsTabs from './block-patterns-tab';
import ReusableBlocksTab from './reusable-blocks-tab';
import useInsertionPoint from './hooks/use-insertion-point';
import InserterTabs from './tabs';

Expand All @@ -46,18 +47,21 @@ function InserterMenu( {
isAppender,
selectBlockOnInsert: __experimentalSelectBlockOnInsert,
} );
const { hasPatterns } = useSelect(
( select ) => {
const { getSettings } = select( 'core/block-editor' );
return {
hasPatterns: !! getSettings().__experimentalBlockPatterns
?.length,
};
},
[ isAppender, clientId, rootClientId ]
);
const { hasPatterns, hasReusableBlocks } = useSelect( ( select ) => {
const {
__experimentalBlockPatterns,
__experimentalFetchReusableBlocks,
} = select( 'core/block-editor' ).getSettings();

return {
hasPatterns: !! __experimentalBlockPatterns?.length,
hasReusableBlocks: !! __experimentalFetchReusableBlocks?.().length,
};
}, [] );

const showPatterns = ! destinationRootClientId && hasPatterns;
const showReusableBlocks = ! destinationRootClientId && hasReusableBlocks;

const onKeyDown = ( event ) => {
if (
includes(
Expand Down Expand Up @@ -106,6 +110,17 @@ function InserterMenu( {
<BlockPatternsTabs onInsert={ onInsert } filterValue={ filterValue } />
);

const reusableBlocksTab = (
<div className="block-editor-inserter__reusable-block-list">
<ReusableBlocksTab
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 All @@ -125,17 +140,22 @@ function InserterMenu( {
onChange={ setFilterValue }
value={ filterValue }
/>
{ showPatterns && (
<InserterTabs>
{ ( showPatterns || showReusableBlocks ) && (
<InserterTabs
showPatterns={ showPatterns }
showReusableBlocks={ showReusableBlocks }
>
{ ( tab ) => {
if ( tab.name === 'blocks' ) {
return blocksTab;
} else if ( tab.name === 'patterns' ) {
return patternsTab;
}
return patternsTab;
return reusableBlocksTab;
} }
</InserterTabs>
) }
{ ! showPatterns && blocksTab }
{ ! ( showPatterns || showReusableBlocks ) && blocksTab }
</div>
</div>
{ showInserterHelpPanel && hoveredItem && (
Expand Down
111 changes: 111 additions & 0 deletions packages/block-editor/src/components/inserter/reusable-blocks-tab.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 ReusableBlocksTab( {
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( ReusableBlocksTab );
47 changes: 31 additions & 16 deletions packages/block-editor/src/components/inserter/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,38 @@
import { TabPanel } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

function InserterTabs( { children } ) {
const blocksTab = {
name: 'blocks',
/* translators: Blocks tab title in the block inserter. */
title: __( 'Blocks' ),
};
const patternsTab = {
name: 'patterns',
/* translators: Patterns tab title in the block inserter. */
title: __( 'Patterns' ),
};
const reusableBlocksTab = {
name: 'reusable',
/* translators: Reusable blocks tab title in the block inserter. */
title: __( 'Reusable' ),
};

function InserterTabs( {
children,
showPatterns = false,
showReusableBlocks = false,
} ) {
const tabs = [ blocksTab ];

if ( showPatterns ) {
tabs.push( patternsTab );
}
if ( showReusableBlocks ) {
tabs.push( reusableBlocksTab );
}

return (
<TabPanel
className="block-editor-inserter__tabs"
tabs={ [
{
name: 'blocks',
/* translators: Blocks tab title in the block inserter. */
title: __( 'Blocks' ),
},
{
name: 'patterns',
/* translators: Patterns tab title in the block inserter. */
title: __( 'Patterns' ),
},
] }
>
<TabPanel className="block-editor-inserter__tabs" tabs={ tabs }>
{ children }
</TabPanel>
);
Expand Down

0 comments on commit a6a2134

Please sign in to comment.