diff --git a/packages/block-editor/src/components/block-navigation/branch.js b/packages/block-editor/src/components/block-navigation/branch.js new file mode 100644 index 0000000000000..3b3b5839772d1 --- /dev/null +++ b/packages/block-editor/src/components/block-navigation/branch.js @@ -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 ( +
  • + + { children } +
  • + ); + } + + return ( +
  • + + { ( fills ) => { + if ( ! fills.length ) { + return ; + } + + return Children.map( fills, ( fill ) => + cloneElement( fill, { + ...props, + ...fill.props, + } ) + ); + } } + + { children } +
  • + ); +}; + +export default BlockNavigationBranch; + +const listItemSlotName = ( blockId ) => `BlockNavigationList-item-${ blockId }`; + +export const BlockNavigationListItemSlot = ( { blockId, ...props } ) => ( + +); + +export const BlockNavigationListItemFill = ( props ) => { + const { clientId } = useContext( BlockListBlockContext ); + return ; +}; diff --git a/packages/block-editor/src/components/block-navigation/dropdown.js b/packages/block-editor/src/components/block-navigation/dropdown.js index b230aac4236ad..ba0e824c3667c 100644 --- a/packages/block-editor/src/components/block-navigation/dropdown.js +++ b/packages/block-editor/src/components/block-navigation/dropdown.js @@ -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(), [] @@ -71,7 +74,12 @@ function BlockNavigationDropdown( { isDisabled } ) { /> ) } renderContent={ ( { onClose } ) => ( - + ) } /> ); diff --git a/packages/block-editor/src/components/block-navigation/index.js b/packages/block-editor/src/components/block-navigation/index.js index 4d25ffda1bb01..cd00328440c6e 100644 --- a/packages/block-editor/src/components/block-navigation/index.js +++ b/packages/block-editor/src/components/block-navigation/index.js @@ -21,6 +21,7 @@ function BlockNavigation( { rootBlocks, selectedBlockClientId, selectBlock, + __experimentalWithBlockNavigationSlots, } ) { if ( ! rootBlocks || rootBlocks.length === 0 ) { return null; @@ -44,6 +45,9 @@ function BlockNavigation( { blocks={ [ rootBlock ] } selectedBlockClientId={ selectedBlockClientId } selectBlock={ selectBlock } + __experimentalWithBlockNavigationSlots={ + __experimentalWithBlockNavigationSlots + } showNestedBlocks /> ) } @@ -52,6 +56,9 @@ function BlockNavigation( { blocks={ rootBlocks } selectedBlockClientId={ selectedBlockClientId } selectBlock={ selectBlock } + __experimentalWithBlockNavigationSlots={ + __experimentalWithBlockNavigationSlots + } /> ) } diff --git a/packages/block-editor/src/components/block-navigation/list-item.js b/packages/block-editor/src/components/block-navigation/list-item.js new file mode 100644 index 0000000000000..965f2d648e8b0 --- /dev/null +++ b/packages/block-editor/src/components/block-navigation/list-item.js @@ -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 ( +
    + + + { children + ? children + : getBlockLabel( blockType, block.attributes ) } + { isSelected && ( + + { __( '(selected block)' ) } + + ) } + +
    + ); +} + +BlockNavigationListItem.defaultProps = { + onClick: () => {}, + wrapperComponent: ( props ) => - + selectBlock( block.clientId ) } + > { showNestedBlocks && !! block.innerBlocks && !! block.innerBlocks.length && ( @@ -78,7 +60,7 @@ export default function BlockNavigationList( { showNestedBlocks /> ) } - + ); } ) } { shouldShowAppender && ( @@ -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 ( + + + + ); +} diff --git a/packages/block-editor/src/components/block-navigation/style.scss b/packages/block-editor/src/components/block-navigation/style.scss index abc9ad802ed08..c9576d7024a35 100644 --- a/packages/block-editor/src/components/block-navigation/style.scss +++ b/packages/block-editor/src/components/block-navigation/style.scss @@ -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 { @@ -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; @@ -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%; diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 2e9230b150f70..ebc42de4eece2 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -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'; diff --git a/packages/block-library/src/navigation/block-navigation-list.js b/packages/block-library/src/navigation/block-navigation-list.js index 43bc0793e057e..30edddba26abf 100644 --- a/packages/block-library/src/navigation/block-navigation-list.js +++ b/packages/block-library/src/navigation/block-navigation-list.js @@ -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( @@ -26,6 +29,9 @@ export default function BlockNavigationList( { clientId } ) { blocks={ [ block ] } selectedBlockClientId={ selectedBlockClientId } selectBlock={ selectBlock } + __experimentalWithBlockNavigationSlots={ + __experimentalWithBlockNavigationSlots + } showNestedBlocks showAppender /> diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index 9e3013682fb1c..4f9c708d20592 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -82,7 +82,8 @@ function Navigation( { ); const { navigatorToolbarButton, navigatorModal } = useBlockNavigator( - clientId + clientId, + true ); // Builds navigation links from default Pages. @@ -229,7 +230,10 @@ function Navigation( { { navigatorModal } - + ); -export default function useBlockNavigator( clientId ) { +export default function useBlockNavigator( + clientId, + __experimentalWithBlockNavigationSlots +) { const [ isNavigationListOpen, setIsNavigationListOpen ] = useState( false ); const navigatorToolbarButton = ( @@ -41,7 +44,12 @@ export default function useBlockNavigator( clientId ) { setIsNavigationListOpen( false ); } } > - + ); diff --git a/packages/e2e-tests/specs/editor/blocks/columns.test.js b/packages/e2e-tests/specs/editor/blocks/columns.test.js index b92e763d9bf04..c4ce364df6f24 100644 --- a/packages/e2e-tests/specs/editor/blocks/columns.test.js +++ b/packages/e2e-tests/specs/editor/blocks/columns.test.js @@ -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(); diff --git a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js index fd506d98fb3f7..56d93927d30d0 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js @@ -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(); } diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js index 63ae6d57ecd1f..e4ce4f002cd1e 100644 --- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js +++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js @@ -13,7 +13,7 @@ import { async function openBlockNavigator() { await pressKeyWithModifier( 'access', 'o' ); await page.waitForSelector( - '.block-editor-block-navigation__item-button.is-selected' + '.block-editor-block-navigation__list-item-button.is-selected' ); } @@ -38,7 +38,7 @@ describe( 'Navigating the block hierarchy', () => { await page.click( '[aria-label="Block navigation"]' ); const columnsBlockMenuItem = ( await page.$x( - "//button[contains(@class,'block-editor-block-navigation__item') and contains(text(), 'Columns')]" + "//button[contains(@class,'block-editor-block-navigation__list-item') and contains(text(), 'Columns')]" ) )[ 0 ]; await columnsBlockMenuItem.click(); @@ -57,7 +57,7 @@ describe( 'Navigating the block hierarchy', () => { await page.click( '[aria-label="Block navigation"]' ); const lastColumnsBlockMenuItem = ( await page.$x( - "//button[contains(@class,'block-editor-block-navigation__item') and contains(text(), 'Column')]" + "//button[contains(@class,'block-editor-block-navigation__list-item') and contains(text(), 'Column')]" ) )[ 3 ]; await lastColumnsBlockMenuItem.click(); @@ -163,7 +163,7 @@ describe( 'Navigating the block hierarchy', () => { await page.click( '[aria-label="Block navigation"]' ); const groupMenuItem = ( await page.$x( - "//button[contains(@class,'block-editor-block-navigation__item') and contains(text(), 'Group')]" + "//button[contains(@class,'block-editor-block-navigation__list-item') and contains(text(), 'Group')]" ) )[ 0 ]; await groupMenuItem.click(); diff --git a/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js b/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js index 085260b41863d..353d7b04a2a19 100644 --- a/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js +++ b/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js @@ -24,6 +24,7 @@ export default function NavigationStructurePanel( { blocks, initialOpen } ) { blocks={ blocks } selectedBlockClientId={ selectedBlockClientIds[ 0 ] } selectBlock={ selectBlock } + __experimentalWithBlockNavigationSlots={ true } showNestedBlocks showAppender />