Skip to content

Commit

Permalink
Move data logic out of the inserter
Browse files Browse the repository at this point in the history
Moves the logic that determines which items should appear in the
inserter into dedicated selector functions. This way, the logic is
easier to test and can be re-used.
  • Loading branch information
noisysocks committed Jan 16, 2018
1 parent af74fa6 commit cd1f9be
Show file tree
Hide file tree
Showing 6 changed files with 504 additions and 298 deletions.
73 changes: 47 additions & 26 deletions editor/components/inserter/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,71 +10,92 @@ import { Component } from '@wordpress/element';
import { NavigableMenu } from '@wordpress/components';
import { BlockIcon } from '@wordpress/blocks';

function deriveActiveBlocks( blocks ) {
return blocks.filter( ( block ) => ! block.disabled );
/**
* Determines which items can be selected. These are the items that are not
* disabled.
*
* @param {Editor.InserterItem[]} items Items to filter.
* @returns {Editor.InserterItem[]} Items that can be selected.
*/
function deriveActiveItems( items ) {
return items.filter( ( item ) => ! item.isDisabled );
}

export default class InserterGroup extends Component {
/**
* @inheritdoc
*/
constructor() {
super( ...arguments );

this.onNavigate = this.onNavigate.bind( this );

this.activeBlocks = deriveActiveBlocks( this.props.blockTypes );
this.activeItems = deriveActiveItems( this.props.items );
this.state = {
current: this.activeBlocks.length > 0 ? this.activeBlocks[ 0 ].name : null,
current: this.activeItems.length > 0 ? this.activeItems[ 0 ] : null,
};
}

/**
* @inheritdoc
*/
componentWillReceiveProps( nextProps ) {
if ( ! isEqual( this.props.blockTypes, nextProps.blockTypes ) ) {
this.activeBlocks = deriveActiveBlocks( nextProps.blockTypes );
if ( ! isEqual( this.props.items, nextProps.items ) ) {
this.activeItems = deriveActiveItems( nextProps.items );
// Try and preserve any still valid selected state.
const current = find( this.activeBlocks, { name: this.state.current } );
const current = find( this.activeItems, ( item ) => isEqual( item, this.state.current ) );
if ( ! current ) {
this.setState( {
current: this.activeBlocks.length > 0 ? this.activeBlocks[ 0 ].name : null,
current: this.activeItems.length > 0 ? this.activeItems[ 0 ] : null,
} );
}
}
}

renderItem( block ) {
/**
* Renders a single item.
*
* @param {Editor.InserterItem} item Item to render.
* @param {number} index Index of the item.
* @returns {JSX.Element} Rendered button.
*/
renderItem( item, index ) {
const { current } = this.state;
const { selectBlock, bindReferenceNode } = this.props;
const { disabled } = block;
const { onSelectItem } = this.props;

return (
<button
role="menuitem"
key={ block.name === 'core/block' && block.initialAttributes ?
block.name + block.initialAttributes.ref :
block.name
}
key={ index }
className="editor-inserter__block"
onClick={ selectBlock( block ) }
ref={ bindReferenceNode( block.name ) }
tabIndex={ current === block.name || disabled ? null : '-1' }
disabled={ disabled }
onClick={ () => onSelectItem( item ) }
tabIndex={ isEqual( current, item ) || item.isDisabled ? null : '-1' }
disabled={ item.isDisabled }
>
<BlockIcon icon={ block.icon } />
{ block.title }
<BlockIcon icon={ item.icon } />
{ item.title }
</button>
);
}

/**
* Updates the currently selected item in response to a user navigating the
* menu with their keyboard.
*
* @param {number} index Index of the newly selected item.
*/
onNavigate( index ) {
const { activeBlocks } = this;
const dest = activeBlocks[ index ];
const { activeItems } = this;
const dest = activeItems[ index ];
if ( dest ) {
this.setState( {
current: dest.name,
current: dest,
} );
}
}

render() {
const { labelledBy, blockTypes } = this.props;
const { labelledBy, items } = this.props;

return (
<NavigableMenu
Expand All @@ -83,7 +104,7 @@ export default class InserterGroup extends Component {
aria-labelledby={ labelledBy }
cycle={ false }
onNavigate={ this.onNavigate }>
{ blockTypes.map( this.renderItem, this ) }
{ items.map( this.renderItem, this ) }
</NavigableMenu>
);
}
Expand Down
15 changes: 5 additions & 10 deletions editor/components/inserter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,12 @@ class Inserter extends Component {
</IconButton>
) }
renderContent={ ( { onClose } ) => {
const onInsert = ( name, initialAttributes ) => {
onInsertBlock(
name,
initialAttributes,
insertionPoint
);

const onSelect = ( item ) => {
onInsertBlock( item, insertionPoint );
onClose();
};

return <InserterMenu onSelect={ onInsert } />;
return <InserterMenu onSelect={ onSelect } />;
} }
/>
);
Expand All @@ -108,9 +103,9 @@ export default compose( [
};
},
( dispatch ) => ( {
onInsertBlock( name, initialAttributes, position ) {
onInsertBlock( item, position ) {
dispatch( insertBlock(
createBlock( name, initialAttributes ),
createBlock( item.name, item.initialAttributes ),
position
) );
},
Expand Down
Loading

0 comments on commit cd1f9be

Please sign in to comment.