diff --git a/packages/block-editor/src/components/inner-blocks/button-block-appender.js b/packages/block-editor/src/components/inner-blocks/button-block-appender.js index 88bd12bd46b771..5319b5d4d3c368 100644 --- a/packages/block-editor/src/components/inner-blocks/button-block-appender.js +++ b/packages/block-editor/src/components/inner-blocks/button-block-appender.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * Internal dependencies */ @@ -9,9 +14,13 @@ export const ButtonBlockAppender = ( { showSeparator, isFloating, onAddBlock, + isToggle, } ) => { return ( , [] ); + // When the block is selected itself or has a top level item selected that + // doesn't itself have children, show the standard appender. Else show no + // appender. + const appender = + isSelected || + ( isImmediateParentOfSelectedBlock && ! selectedBlockHasDescendants ) + ? undefined + : false; + const innerBlocksProps = useInnerBlocksProps( { className: 'wp-block-navigation__container', @@ -152,12 +164,8 @@ function Navigation( { { allowedBlocks: ALLOWED_BLOCKS, orientation: attributes.orientation, - renderAppender: - ( isImmediateParentOfSelectedBlock && - ! selectedBlockHasDescendants ) || - isSelected - ? InnerBlocks.DefaultAppender - : false, + renderAppender: CustomAppender || appender, + // Ensure block toolbar is not too far removed from item // being edited when in vertical mode. // see: https://github.com/WordPress/gutenberg/pull/34615. diff --git a/packages/e2e-tests/specs/experiments/navigation-editor.test.js b/packages/e2e-tests/specs/experiments/navigation-editor.test.js index 972ba27eb834b3..16d343c6f91edb 100644 --- a/packages/e2e-tests/specs/experiments/navigation-editor.test.js +++ b/packages/e2e-tests/specs/experiments/navigation-editor.test.js @@ -315,6 +315,22 @@ describe( 'Navigation editor', () => { expect( await getSerializedBlocks() ).toMatchSnapshot(); } ); + it( 'shows the trailing block appender within the navigation block when no blocks are selected', async () => { + await setUpResponseMocking( [ + ...getMenuMocks( { GET: assignMockMenuIds( menusFixture ) } ), + ...getMenuItemMocks( { GET: menuItemsFixture } ), + ] ); + await visitNavigationEditor(); + + const selectedBlocks = await page.$$( '.wp-block.is-selected' ); + expect( selectedBlocks.length ).toBe( 0 ); + + const blockListAppender = await page.$( + '.block-list-appender button[aria-label="Add block"]' + ); + expect( blockListAppender ).toBeTruthy(); + } ); + it( 'shows a submenu when a link is selected and hides it when clicking the editor to deselect it', async () => { await setUpResponseMocking( [ ...getMenuMocks( { GET: assignMockMenuIds( menusFixture ) } ), diff --git a/packages/edit-navigation/src/components/editor/style.scss b/packages/edit-navigation/src/components/editor/style.scss index 5c5d813b02d38b..d48af467b1ab39 100644 --- a/packages/edit-navigation/src/components/editor/style.scss +++ b/packages/edit-navigation/src/components/editor/style.scss @@ -164,4 +164,12 @@ padding: 0; } } + + // Override behavior that hides the navigation block's appender when it's deselected. + .block-editor-block-list__block:not(.is-selected):not(.has-child-selected):not(.block-editor-block-list__layout) { + .block-editor-block-list__layout > .block-list-appender .block-list-appender__toggle { + opacity: unset; + transform: unset; + } + } } diff --git a/packages/edit-navigation/src/filters/add-navigation-editor-custom-appender.js b/packages/edit-navigation/src/filters/add-navigation-editor-custom-appender.js new file mode 100644 index 00000000000000..6a3b5f64e94dce --- /dev/null +++ b/packages/edit-navigation/src/filters/add-navigation-editor-custom-appender.js @@ -0,0 +1,76 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { addFilter } from '@wordpress/hooks'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { + InnerBlocks, + store as blockEditorStore, +} from '@wordpress/block-editor'; + +function CustomAppender() { + return ; +} + +function EnhancedNavigationBlock( { blockEdit: BlockEdit, ...props } ) { + const clientId = props.clientId; + const { + noBlockSelected, + isSelected, + isImmediateParentOfSelectedBlock, + selectedBlockHasDescendants, + } = useSelect( + ( select ) => { + const { + getClientIdsOfDescendants, + hasSelectedInnerBlock, + getSelectedBlockClientId, + } = select( blockEditorStore ); + const _isImmediateParentOfSelectedBlock = hasSelectedInnerBlock( + clientId, + false + ); + const selectedBlockId = getSelectedBlockClientId(); + const _selectedBlockHasDescendants = !! getClientIdsOfDescendants( [ + selectedBlockId, + ] )?.length; + + return { + isSelected: selectedBlockId === clientId, + noBlockSelected: ! selectedBlockId, + isImmediateParentOfSelectedBlock: _isImmediateParentOfSelectedBlock, + selectedBlockHasDescendants: _selectedBlockHasDescendants, + }; + }, + [ clientId ] + ); + + const customAppender = + noBlockSelected || + isSelected || + ( isImmediateParentOfSelectedBlock && ! selectedBlockHasDescendants ) + ? CustomAppender + : false; + + return ; +} + +const addNavigationEditorCustomAppender = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + if ( props.name !== 'core/navigation' ) { + return ; + } + + // Use a separate component so that `useSelect` only run on the navigation block. + return ; + }, + 'withNavigationEditorCustomAppender' +); + +export default () => + addFilter( + 'editor.BlockEdit', + 'core/edit-navigation/with-navigation-editor-custom-appender', + addNavigationEditorCustomAppender + ); diff --git a/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js b/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js index 263658d0ffc646..94b62fea180572 100644 --- a/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js +++ b/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js @@ -1,11 +1,12 @@ /** * WordPress dependencies */ +import { addFilter } from '@wordpress/hooks'; +import { createHigherOrderComponent } from '@wordpress/compose'; + /** * Internal dependencies */ -import { addFilter } from '@wordpress/hooks'; -import { createHigherOrderComponent } from '@wordpress/compose'; import BlockPlaceholder from '../components/block-placeholder'; const addNavigationEditorPlaceholder = createHigherOrderComponent( diff --git a/packages/edit-navigation/src/filters/index.js b/packages/edit-navigation/src/filters/index.js index 08ab87f0fe4b5d..17074eb87c6603 100644 --- a/packages/edit-navigation/src/filters/index.js +++ b/packages/edit-navigation/src/filters/index.js @@ -1,6 +1,7 @@ /** * Internal dependencies */ +import addNavigationEditorCustomAppender from './add-navigation-editor-custom-appender'; import addNavigationEditorPlaceholder from './add-navigation-editor-placeholder'; import addMenuNameEditor from './add-menu-name-editor'; import disableInsertingNonNavigationBlocks from './disable-inserting-non-navigation-blocks'; @@ -10,6 +11,7 @@ import removeSettingsUnsupportedFeatures from './remove-settings-unsupported-fea export const addFilters = ( shouldAddDisableInsertingNonNavigationBlocksFilter ) => { + addNavigationEditorCustomAppender(); addNavigationEditorPlaceholder(); addMenuNameEditor(); if ( shouldAddDisableInsertingNonNavigationBlocksFilter ) {