Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make parts of the BlockNavigationList overridable using slots #21948

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