options: once( function options() { return Promise.resolve( // Prioritize common category in block type options sortBy( getBlockTypes(), ( { category } ) => 'common' !== category ) ); } ),
afterEach( () => { getBlockTypes().forEach( ( block ) => { unregisterBlockType( block.name ); } ); } );
export function preferences( state = STORE_DEFAULTS.preferences, action ) { switch ( action.type ) { case 'TOGGLE_SIDEBAR': return { ...state, isSidebarOpened: ! state.isSidebarOpened, }; case 'TOGGLE_SIDEBAR_PANEL': return { ...state, panels: { ...state.panels, [ action.panel ]: ! get( state, [ 'panels', action.panel ], false ), }, }; case 'SWITCH_MODE': return { ...state, mode: action.mode, }; case 'INSERT_BLOCKS': // record the block usage and put the block in the recently used blocks let blockUsage = state.blockUsage; let recentlyUsedBlocks = [ ...state.recentlyUsedBlocks ]; action.blocks.forEach( ( block ) => { const uses = ( blockUsage[ block.name ] || 0 ) + 1; blockUsage = omit( blockUsage, block.name ); blockUsage[ block.name ] = uses; recentlyUsedBlocks = [ block.name, ...without( recentlyUsedBlocks, block.name ) ].slice( 0, MAX_RECENT_BLOCKS ); } ); return { ...state, blockUsage, recentlyUsedBlocks, }; case 'SETUP_EDITOR': const isBlockDefined = name => getBlockType( name ) !== undefined; const filterInvalidBlocksFromList = list => list.filter( isBlockDefined ); const filterInvalidBlocksFromObject = obj => pick( obj, keys( obj ).filter( isBlockDefined ) ); const commonBlocks = getBlockTypes() .filter( ( blockType ) => 'common' === blockType.category ) .map( ( blockType ) => blockType.name ); return { ...state, // recently used gets filled up to `MAX_RECENT_BLOCKS` with blocks from the common category recentlyUsedBlocks: filterInvalidBlocksFromList( [ ...state.recentlyUsedBlocks ] ) .concat( difference( commonBlocks, state.recentlyUsedBlocks ) ) .slice( 0, MAX_RECENT_BLOCKS ), blockUsage: filterInvalidBlocksFromObject( state.blockUsage ), }; case 'TOGGLE_FEATURE': return { ...state, features: { ...state.features, [ action.feature ]: ! state.features[ action.feature ], }, }; } return state; }
render() { const { instanceId } = this.props; const isSearching = this.state.filterValue; return ( <TabbableContainer className="editor-inserter__menu" deep onKeyDown={ this.interceptArrows } > <label htmlFor={ `editor-inserter__search-${ instanceId }` } className="screen-reader-text"> { __( 'Search for a block' ) } </label> <input id={ `editor-inserter__search-${ instanceId }` } type="search" placeholder={ __( 'Search for a block' ) } className="editor-inserter__search" onChange={ this.filter } ref={ this.bindReferenceNode( 'search' ) } /> { ! isSearching && <TabPanel className="editor-inserter__tabs" activeClass="is-active" onSelect={ this.switchTab } tabs={ [ { name: 'recent', title: __( 'Recent' ), className: 'editor-inserter__tab', }, { name: 'blocks', title: __( 'Blocks' ), className: 'editor-inserter__tab', }, { name: 'embeds', title: __( 'Embeds' ), className: 'editor-inserter__tab', }, ] } > { ( tabKey ) => { const blocksForTab = this.getBlocksForTab( tabKey ); const visibleBlocks = this.getVisibleBlocksByCategory( blocksForTab ); return ( <div ref={ ( ref ) => this.tabContainer = ref } className="editor-inserter__content"> { this.renderTabView( tabKey, visibleBlocks ) } </div> ); } } </TabPanel> } { isSearching && <div role="menu" className="editor-inserter__content"> { this.renderCategories( this.getVisibleBlocksByCategory( getBlockTypes() ) ) } </div> } </TabbableContainer> ); }
getBlockTypes() { // Block types that are marked as private should not appear in the inserter return getBlockTypes().filter( ( block ) => ! block.isPrivate ); }