Skip to content

Commit

Permalink
Make parts of the BlockNavigationList overridable using slots (#21948)
Browse files Browse the repository at this point in the history
* First stab at editable menu items in navigator

Use Slot/Fill instead of hardcoded components

Disable slots/fills in global editor block navigator

Grab clientId from context instead of requiring a prop

Improve readability of block-navigation/list.js

Use context to determine whether or not given BlockNavigation may be customized with slots

Restore default value for selectBlock in navigation-structure-panel.js

Remove obsolete onChange passed to NavigationStructurePanel

Use constant value for BlockNavigationContext

Use memo() in BlockStyles

Remove performance changes from BlockStyles

Generalize BlockNavigationListItem and remove the BlockNavigationListItemFill for now

Rename useBlockNavigationSlots to withBlockNavigationSlots

Restore RichText in the navigator

Sort out BlockNavigationListItem and BlockNavigationListItemWrapper

Rename BlockNavigationListItemWrapper to BlockNavigationBranch

* Move BlockNavigationBranch to a different file

* Refactor BlockNavigationContext to be an internal detail

* Lint

* Rename all occurences of withBlockNavigationSlots to __experimentalWithBlockNavigationSlots

* Remove export of BlockNavigationContext

* Adjust class names

* Remove the fill from edit.js for now

* Update class name in e2e tests

* Link
  • Loading branch information
adamziel authored May 8, 2020
1 parent fca4e02 commit 655db77
Show file tree
Hide file tree
Showing 14 changed files with 202 additions and 48 deletions.
59 changes: 59 additions & 0 deletions packages/block-editor/src/components/block-navigation/branch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* WordPress dependencies
*/
import { Children, cloneElement, useContext } from '@wordpress/element';
import { Fill, Slot } from '@wordpress/components';

/**
* Internal dependencies
*/
import BlockNavigationListItem from './list-item';
import { BlockNavigationContext } from './list';
import { BlockListBlockContext } from '../block-list/block';

const BlockNavigationBranch = ( { children, ...props } ) => {
const { __experimentalWithBlockNavigationSlots } = useContext(
BlockNavigationContext
);
if ( ! __experimentalWithBlockNavigationSlots ) {
return (
<li>
<BlockNavigationListItem { ...props } />
{ children }
</li>
);
}

return (
<li>
<BlockNavigationListItemSlot blockId={ props.block.clientId }>
{ ( fills ) => {
if ( ! fills.length ) {
return <BlockNavigationListItem { ...props } />;
}

return Children.map( fills, ( fill ) =>
cloneElement( fill, {
...props,
...fill.props,
} )
);
} }
</BlockNavigationListItemSlot>
{ children }
</li>
);
};

export default BlockNavigationBranch;

const listItemSlotName = ( blockId ) => `BlockNavigationList-item-${ blockId }`;

export const BlockNavigationListItemSlot = ( { blockId, ...props } ) => (
<Slot { ...props } name={ listItemSlotName( blockId ) } />
);

export const BlockNavigationListItemFill = ( props ) => {
const { clientId } = useContext( BlockListBlockContext );
return <Fill { ...props } name={ listItemSlotName( clientId ) } />;
};
12 changes: 10 additions & 2 deletions packages/block-editor/src/components/block-navigation/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ function BlockNavigationDropdownToggle( { isEnabled, onToggle, isOpen } ) {
);
}

function BlockNavigationDropdown( { isDisabled } ) {
function BlockNavigationDropdown( {
isDisabled,
__experimentalWithBlockNavigationSlots,
} ) {
const hasBlocks = useSelect(
( select ) => !! select( 'core/block-editor' ).getBlockCount(),
[]
Expand All @@ -71,7 +74,12 @@ function BlockNavigationDropdown( { isDisabled } ) {
/>
) }
renderContent={ ( { onClose } ) => (
<BlockNavigation onSelect={ onClose } />
<BlockNavigation
onSelect={ onClose }
__experimentalWithBlockNavigationSlots={
__experimentalWithBlockNavigationSlots
}
/>
) }
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function BlockNavigation( {
rootBlocks,
selectedBlockClientId,
selectBlock,
__experimentalWithBlockNavigationSlots,
} ) {
if ( ! rootBlocks || rootBlocks.length === 0 ) {
return null;
Expand All @@ -44,6 +45,9 @@ function BlockNavigation( {
blocks={ [ rootBlock ] }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
__experimentalWithBlockNavigationSlots={
__experimentalWithBlockNavigationSlots
}
showNestedBlocks
/>
) }
Expand All @@ -52,6 +56,9 @@ function BlockNavigation( {
blocks={ rootBlocks }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
__experimentalWithBlockNavigationSlots={
__experimentalWithBlockNavigationSlots
}
/>
) }
</NavigableMenu>
Expand Down
58 changes: 58 additions & 0 deletions packages/block-editor/src/components/block-navigation/list-item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { Button, VisuallyHidden } from '@wordpress/components';
import {
__experimentalGetBlockLabel as getBlockLabel,
getBlockType,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

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

export default function BlockNavigationListItem( {
block,
onClick,
isSelected,
wrapperComponent: WrapperComponent,
children,
} ) {
const blockType = getBlockType( block.name );

return (
<div className="block-editor-block-navigation__list-item">
<WrapperComponent
className={ classnames(
'block-editor-block-navigation__list-item-button',
{
'is-selected': isSelected,
}
) }
onClick={ onClick }
>
<BlockIcon icon={ blockType.icon } showColors />
{ children
? children
: getBlockLabel( blockType, block.attributes ) }
{ isSelected && (
<VisuallyHidden as="span">
{ __( '(selected block)' ) }
</VisuallyHidden>
) }
</WrapperComponent>
</div>
);
}

BlockNavigationListItem.defaultProps = {
onClick: () => {},
wrapperComponent: ( props ) => <Button { ...props } />,
};
65 changes: 33 additions & 32 deletions packages/block-editor/src/components/block-navigation/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,23 @@
* External dependencies
*/
import { isNil, map, omitBy } from 'lodash';
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { Button, VisuallyHidden } from '@wordpress/components';
import {
__experimentalGetBlockLabel as getBlockLabel,
getBlockType,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { useMemo, createContext } from '@wordpress/element';

/**
* Internal dependencies
*/
import BlockIcon from '../block-icon';
import ButtonBlockAppender from '../button-block-appender';
import BlockNavigationBranch from './branch';

export default function BlockNavigationList( {
export const BlockNavigationContext = createContext( {
__experimentalWithBlockNavigationSlots: false,
} );

function BlockNavigationList( {
blocks,
selectedBlockClientId,
selectBlock,
Expand All @@ -40,30 +38,14 @@ export default function BlockNavigationList( {
/* eslint-disable jsx-a11y/no-redundant-roles */
<ul className="block-editor-block-navigation__list" role="list">
{ map( omitBy( blocks, isNil ), ( block ) => {
const blockType = getBlockType( block.name );
const isSelected = block.clientId === selectedBlockClientId;

return (
<li key={ block.clientId }>
<div className="block-editor-block-navigation__item">
<Button
className={ classnames(
'block-editor-block-navigation__item-button',
{
'is-selected': isSelected,
}
) }
onClick={ () => selectBlock( block.clientId ) }
>
<BlockIcon icon={ blockType.icon } showColors />
{ getBlockLabel( blockType, block.attributes ) }
{ isSelected && (
<VisuallyHidden as="span">
{ __( '(selected block)' ) }
</VisuallyHidden>
) }
</Button>
</div>
<BlockNavigationBranch
block={ block }
key={ block.clientId }
isSelected={ isSelected }
onClick={ () => selectBlock( block.clientId ) }
>
{ showNestedBlocks &&
!! block.innerBlocks &&
!! block.innerBlocks.length && (
Expand All @@ -78,7 +60,7 @@ export default function BlockNavigationList( {
showNestedBlocks
/>
) }
</li>
</BlockNavigationBranch>
);
} ) }
{ shouldShowAppender && (
Expand All @@ -95,3 +77,22 @@ export default function BlockNavigationList( {
/* eslint-enable jsx-a11y/no-redundant-roles */
);
}

BlockNavigationList.defaultProps = {
selectBlock: () => {},
};

export default function BlockNavigationListWrapper( {
__experimentalWithBlockNavigationSlots,
...props
} ) {
const blockNavigationContext = useMemo(
() => ( { __experimentalWithBlockNavigationSlots } ),
[ __experimentalWithBlockNavigationSlots ]
);
return (
<BlockNavigationContext.Provider value={ blockNavigationContext }>
<BlockNavigationList { ...props } />
</BlockNavigationContext.Provider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ $tree-item-height: 36px;
margin-left: 1.5em;
}

.block-editor-block-navigation__item {
.block-editor-block-navigation__list-item {
position: relative;

&::before {
Expand All @@ -48,7 +48,7 @@ $tree-item-height: 36px;
}
}

.block-editor-block-navigation__item-button {
.block-editor-block-navigation__list-item-button {
margin-left: 0.8em;
width: calc(100% - 0.8em);
height: auto;
Expand All @@ -68,7 +68,7 @@ $tree-item-height: 36px;
}
}

.block-editor-block-navigation__item-button {
.block-editor-block-navigation__list-item-button {
display: flex;
align-items: center;
width: 100%;
Expand Down
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ 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 __experimentalBlockNavigationList } from './block-navigation/list';
export { BlockNavigationListItemFill as __experimentalBlockNavigationListItemFill } from './block-navigation/branch';
export { default as __experimentalBlockNavigationListItem } from './block-navigation/list-item';
export { default as __experimentalBlockVariationPicker } from './block-variation-picker';
export { default as BlockVerticalAlignmentToolbar } from './block-vertical-alignment-toolbar';
export { default as ButtonBlockerAppender } from './button-block-appender';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import { __experimentalBlockNavigationList } from '@wordpress/block-editor';
import { useSelect, useDispatch } from '@wordpress/data';

export default function BlockNavigationList( { clientId } ) {
export default function BlockNavigationList( {
clientId,
__experimentalWithBlockNavigationSlots,
} ) {
const { block, selectedBlockClientId } = useSelect(
( select ) => {
const { getSelectedBlockClientId, getBlock } = select(
Expand All @@ -26,6 +29,9 @@ export default function BlockNavigationList( { clientId } ) {
blocks={ [ block ] }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
__experimentalWithBlockNavigationSlots={
__experimentalWithBlockNavigationSlots
}
showNestedBlocks
showAppender
/>
Expand Down
8 changes: 6 additions & 2 deletions packages/block-library/src/navigation/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ function Navigation( {
);

const { navigatorToolbarButton, navigatorModal } = useBlockNavigator(
clientId
clientId,
true
);

// Builds navigation links from default Pages.
Expand Down Expand Up @@ -229,7 +230,10 @@ function Navigation( {
{ navigatorModal }
<InspectorControls>
<PanelBody title={ __( 'Navigation Structure' ) }>
<BlockNavigationList clientId={ clientId } />
<BlockNavigationList
clientId={ clientId }
__experimentalWithBlockNavigationSlots
/>
</PanelBody>
<PanelBody title={ __( 'Text settings' ) }>
<FontSizePicker
Expand Down
12 changes: 10 additions & 2 deletions packages/block-library/src/navigation/use-block-navigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ const NavigatorIcon = (
</SVG>
);

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

const navigatorToolbarButton = (
Expand All @@ -41,7 +44,12 @@ export default function useBlockNavigator( clientId ) {
setIsNavigationListOpen( false );
} }
>
<BlockNavigationList clientId={ clientId } />
<BlockNavigationList
clientId={ clientId }
__experimentalWithBlockNavigationSlots={
__experimentalWithBlockNavigationSlots
}
/>
</Modal>
);

Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-tests/specs/editor/blocks/columns.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe( 'Columns', () => {
await page.click( '[aria-label="Block navigation"]' );
const columnBlockMenuItem = (
await page.$x(
'//button[contains(concat(" ", @class, " "), " block-editor-block-navigation__item-button ")][text()="Column"]'
'//button[contains(concat(" ", @class, " "), " block-editor-block-navigation__list-item-button ")][text()="Column"]'
)
)[ 0 ];
await columnBlockMenuItem.click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async function getFirstInserterIcon() {
async function selectFirstBlock() {
await pressKeyWithModifier( 'access', 'o' );
const navButtons = await page.$$(
'.block-editor-block-navigation__item-button'
'.block-editor-block-navigation__list-item-button'
);
await navButtons[ 0 ].click();
}
Expand Down
Loading

0 comments on commit 655db77

Please sign in to comment.