Skip to content

Commit

Permalink
Add navigator for nav block (#17265)
Browse files Browse the repository at this point in the history
* Add icon for block navigator

* Extract block navigation list into its own file and export from block-editor package root

* Refactor navigator into own component and hook up to store

* Switch to using a hook to implement the block navigator toolbar

* Return elements from hook instead of components to avoid redeclaration of components
  • Loading branch information
talldan authored Sep 5, 2019
1 parent 5774046 commit 8dc1de9
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 53 deletions.
4 changes: 4 additions & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ Undocumented declaration.

Undocumented declaration.

<a name="BlockNavigationList" href="#BlockNavigationList">#</a> **BlockNavigationList**

Undocumented declaration.

<a name="BlockPreview" href="#BlockPreview">#</a> **BlockPreview**

BlockPreview renders a preview of a block or array of blocks.
Expand Down
55 changes: 3 additions & 52 deletions packages/block-editor/src/components/block-navigation/index.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,20 @@
/**
* External dependencies
*/
import { map, noop } from 'lodash';
import classnames from 'classnames';
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import { withSelect, withDispatch } from '@wordpress/data';
import { Button, NavigableMenu } from '@wordpress/components';
import { getBlockType } from '@wordpress/blocks';
import { NavigableMenu } from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import BlockIcon from '../block-icon';

function BlockNavigationList( {
blocks,
selectedBlockClientId,
selectBlock,
showNestedBlocks,
} ) {
return (
/*
* Disable reason: The `list` ARIA role is redundant but
* Safari+VoiceOver won't announce the list otherwise.
*/
/* eslint-disable jsx-a11y/no-redundant-roles */
<ul className="editor-block-navigation__list block-editor-block-navigation__list" role="list">
{ map( blocks, ( block ) => {
const blockType = getBlockType( block.name );
const isSelected = block.clientId === selectedBlockClientId;

return (
<li key={ block.clientId }>
<div className="editor-block-navigation__item block-editor-block-navigation__item">
<Button
className={ classnames( 'editor-block-navigation__item-button block-editor-block-navigation__item-button', {
'is-selected': isSelected,
} ) }
onClick={ () => selectBlock( block.clientId ) }
>
<BlockIcon icon={ blockType.icon } showColors />
{ blockType.title }
{ isSelected && <span className="screen-reader-text">{ __( '(selected block)' ) }</span> }
</Button>
</div>
{ showNestedBlocks && !! block.innerBlocks && !! block.innerBlocks.length && (
<BlockNavigationList
blocks={ block.innerBlocks }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
showNestedBlocks
/>
) }
</li>
);
} ) }
</ul>
/* eslint-enable jsx-a11y/no-redundant-roles */
);
}
import BlockNavigationList from './list';

function BlockNavigation( { rootBlock, rootBlocks, selectedBlockClientId, selectBlock } ) {
if ( ! rootBlocks || rootBlocks.length === 0 ) {
Expand Down
64 changes: 64 additions & 0 deletions packages/block-editor/src/components/block-navigation/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* External dependencies
*/
import { map } from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { Button } from '@wordpress/components';
import { getBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import BlockIcon from '../block-icon';

export default function BlockNavigationList( {
blocks,
selectedBlockClientId,
selectBlock,
showNestedBlocks,
} ) {
return (
/*
* Disable reason: The `list` ARIA role is redundant but
* Safari+VoiceOver won't announce the list otherwise.
*/
/* eslint-disable jsx-a11y/no-redundant-roles */
<ul className="editor-block-navigation__list block-editor-block-navigation__list" role="list">
{ map( blocks, ( block ) => {
const blockType = getBlockType( block.name );
const isSelected = block.clientId === selectedBlockClientId;

return (
<li key={ block.clientId }>
<div className="editor-block-navigation__item block-editor-block-navigation__item">
<Button
className={ classnames( 'editor-block-navigation__item-button block-editor-block-navigation__item-button', {
'is-selected': isSelected,
} ) }
onClick={ () => selectBlock( block.clientId ) }
>
<BlockIcon icon={ blockType.icon } showColors />
{ blockType.title }
{ isSelected && <span className="screen-reader-text">{ __( '(selected block)' ) }</span> }
</Button>
</div>
{ showNestedBlocks && !! block.innerBlocks && !! block.innerBlocks.length && (
<BlockNavigationList
blocks={ block.innerBlocks }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
showNestedBlocks
/>
) }
</li>
);
} ) }
</ul>
/* eslint-enable jsx-a11y/no-redundant-roles */
);
}
1 change: 1 addition & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { default as BlockEdit } from './block-edit';
export { default as BlockFormatControls } from './block-format-controls';
export { default as BlockIcon } from './block-icon';
export { default as BlockNavigationDropdown } from './block-navigation/dropdown';
export { default as BlockNavigationList } from './block-navigation/list';
export { default as BlockVerticalAlignmentToolbar } from './block-vertical-alignment-toolbar';
export { default as ButtonBlockerAppender } from './button-block-appender';
export { default as ColorPalette } from './color-palette';
Expand Down
14 changes: 13 additions & 1 deletion packages/block-library/src/navigation-menu/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,35 @@ import {
import {
InnerBlocks,
InspectorControls,
BlockControls,
} from '@wordpress/block-editor';
import {
CheckboxControl,
PanelBody,
Toolbar,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { __ } from '@wordpress/i18n';
import useBlockNavigator from './use-block-navigator';

function NavigationMenu( {
attributes,
setAttributes,
clientId,
} ) {
const { navigatorToolbarButton, navigatorModal } = useBlockNavigator( clientId );

return (
<Fragment>
<BlockControls>
<Toolbar>
{ navigatorToolbarButton }
</Toolbar>
</BlockControls>
{ navigatorModal }
<InspectorControls>
<PanelBody
title={ __( 'Menu Settings' ) }
Expand Down
80 changes: 80 additions & 0 deletions packages/block-library/src/navigation-menu/use-block-navigator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* WordPress dependencies
*/
import {
useState,
} from '@wordpress/element';
import {
useSelect,
useDispatch,
} from '@wordpress/data';
import {
BlockNavigationList,
} from '@wordpress/block-editor';
import {
IconButton,
SVG,
Path,
Modal,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';

const NavigatorIcon = (
<SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20">
<Path d="M5 5H3v2h2V5zm3 8h11v-2H8v2zm9-8H6v2h11V5zM7 11H5v2h2v-2zm0 8h2v-2H7v2zm3-2v2h11v-2H10z" />
</SVG>
);

export default function useBlockNavigator( clientId ) {
const [ isNavigationListOpen, setIsNavigationListOpen ] = useState( false );

const {
block,
selectedBlockClientId,
} = useSelect( ( select ) => {
const {
getSelectedBlockClientId,
getBlock,
} = select( 'core/block-editor' );

return {
block: getBlock( clientId ),
selectedBlockClientId: getSelectedBlockClientId(),
};
}, [ clientId ] );

const {
selectBlock,
} = useDispatch( 'core/block-editor' );

const navigatorToolbarButton = (
<IconButton
className="components-toolbar__control"
label={ __( 'Open block navigator' ) }
onClick={ () => setIsNavigationListOpen( true ) }
icon={ NavigatorIcon }
/>
);

const navigatorModal = isNavigationListOpen && (
<Modal
title={ __( 'Block Navigator' ) }
closeLabel={ __( 'Close' ) }
onRequestClose={ () => {
setIsNavigationListOpen( false );
} }
>
<BlockNavigationList
blocks={ [ block ] }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
showNestedBlocks
/>
</Modal>
);

return {
navigatorToolbarButton,
navigatorModal,
};
}

0 comments on commit 8dc1de9

Please sign in to comment.