diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index ffdba40b5f1625..5dad36577e3611 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -384,7 +384,7 @@ A collection of blocks that allow visitors to get around your site. ([Source](ht - **Name:** core/navigation - **Category:** theme - **Supports:** align (full, wide), anchor, inserter, spacing (blockGap, units), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, hasIcon, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, textColor +- **Attributes:** __unstableLocation, backgroundColor, customBackgroundColor, customOverlayBackgroundColor, customOverlayTextColor, customTextColor, hasIcon, maxNestingLevel, openSubmenusOnClick, overlayBackgroundColor, overlayMenu, overlayTextColor, ref, rgbBackgroundColor, rgbTextColor, showSubmenuIcon, textColor ## Navigation Area diff --git a/packages/block-library/src/navigation-link/block.json b/packages/block-library/src/navigation-link/block.json index fd1f0524432f1a..5ce15a970d8c2a 100644 --- a/packages/block-library/src/navigation-link/block.json +++ b/packages/block-library/src/navigation-link/block.json @@ -52,6 +52,7 @@ "fontSize", "customFontSize", "showSubmenuIcon", + "maxNestingLevel", "style" ], "supports": { diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index 43cab0244b9406..889e125781c673 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -49,8 +49,6 @@ import { store as coreStore } from '@wordpress/core-data'; */ import { name } from './block.json'; -const MAX_NESTING = 5; - /** * A React hook to determine if it's dragging within the target element. * @@ -400,6 +398,7 @@ export default function NavigationLinkEdit( { } = attributes; const [ isInvalid, isDraft ] = useIsInvalidLink( kind, type, id ); + const { maxNestingLevel } = context; const link = { url, @@ -452,7 +451,7 @@ export default function NavigationLinkEdit( { getBlockParentsByBlockName( clientId, [ name, 'core/navigation-submenu', - ] ).length >= MAX_NESTING, + ] ).length >= maxNestingLevel, isTopLevelLink: getBlockName( getBlockRootClientId( clientId ) ) === 'core/navigation', diff --git a/packages/block-library/src/navigation-submenu/block.json b/packages/block-library/src/navigation-submenu/block.json index 97bd455a468e36..f311a9f36e41a7 100644 --- a/packages/block-library/src/navigation-submenu/block.json +++ b/packages/block-library/src/navigation-submenu/block.json @@ -52,6 +52,7 @@ "fontSize", "customFontSize", "showSubmenuIcon", + "maxNestingLevel", "openSubmenusOnClick", "style" ], diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index 998dc33c261d58..abbea4c63d8b4c 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -2,7 +2,7 @@ * External dependencies */ import classnames from 'classnames'; -import { escape, pull } from 'lodash'; +import { escape, without } from 'lodash'; /** * WordPress dependencies @@ -55,8 +55,6 @@ const DEFAULT_BLOCK = { name: 'core/navigation-link', }; -const MAX_NESTING = 5; - /** * A React hook to determine if it's dragging within the target element. * @@ -293,7 +291,7 @@ export default function NavigationSubmenuEdit( { url, opensInNewTab, }; - const { showSubmenuIcon, openSubmenusOnClick } = context; + const { showSubmenuIcon, maxNestingLevel, openSubmenusOnClick } = context; const { saveEntityRecord } = useDispatch( coreStore ); const { @@ -351,7 +349,7 @@ export default function NavigationSubmenuEdit( { return { isAtMaxNesting: getBlockParentsByBlockName( clientId, name ).length >= - MAX_NESTING, + maxNestingLevel, isTopLevelItem: getBlockParentsByBlockName( clientId, name ).length === 0, isParentOfSelectedBlock: hasSelectedInnerBlock( @@ -503,9 +501,9 @@ export default function NavigationSubmenuEdit( { // Always use overlay colors for submenus. const innerBlocksColors = getColors( context, true ); - if ( isAtMaxNesting ) { - pull( ALLOWED_BLOCKS, 'core/navigation-submenu' ); - } + const allowedBlocks = isAtMaxNesting + ? without( ALLOWED_BLOCKS, 'core/navigation-submenu' ) + : ALLOWED_BLOCKS; const innerBlocksProps = useInnerBlocksProps( { @@ -528,7 +526,7 @@ export default function NavigationSubmenuEdit( { }, }, { - allowedBlocks: ALLOWED_BLOCKS, + allowedBlocks, __experimentalDefaultBlock: DEFAULT_BLOCK, __experimentalDirectInsert: true, diff --git a/packages/block-library/src/navigation/block.json b/packages/block-library/src/navigation/block.json index 254e85903c9c94..dc904dc25eee1e 100644 --- a/packages/block-library/src/navigation/block.json +++ b/packages/block-library/src/navigation/block.json @@ -59,6 +59,10 @@ }, "customOverlayTextColor": { "type": "string" + }, + "maxNestingLevel": { + "type": "number", + "default": 5 } }, "usesContext": [ "navigationArea" ], @@ -76,7 +80,8 @@ "showSubmenuIcon": "showSubmenuIcon", "openSubmenusOnClick": "openSubmenusOnClick", "style": "style", - "orientation": "orientation" + "orientation": "orientation", + "maxNestingLevel": "maxNestingLevel" }, "supports": { "align": [ "wide", "full" ], diff --git a/packages/e2e-tests/specs/editor/blocks/navigation.test.js b/packages/e2e-tests/specs/editor/blocks/navigation.test.js index 41352a8b192553..16d8fbeb87eb55 100644 --- a/packages/e2e-tests/specs/editor/blocks/navigation.test.js +++ b/packages/e2e-tests/specs/editor/blocks/navigation.test.js @@ -884,6 +884,46 @@ describe( 'Navigation', () => { newMenuButton.click(); } + it( 'respects the nesting level', async () => { + await createNewPost(); + + await insertBlock( 'Navigation' ); + + const navBlock = await waitForBlock( 'Navigation' ); + + // Create empty Navigation block with no items + const startEmptyButton = await page.waitForXPath( + START_EMPTY_XPATH + ); + await startEmptyButton.click(); + + await populateNavWithOneItem(); + + await clickOnMoreMenuItem( 'Code editor' ); + const codeEditorInput = await page.waitForSelector( + '.editor-post-text-editor' + ); + + let code = await codeEditorInput.evaluate( ( el ) => el.value ); + code = code.replace( '} /-->', ',"maxNestingLevel":0} /-->' ); + await codeEditorInput.evaluate( + ( el, newCode ) => ( el.value = newCode ), + code + ); + await clickButton( 'Exit code editor' ); + + const blockAppender = navBlock.$( '.block-list-appender' ); + + expect( blockAppender ).not.toBeNull(); + + // Check the Submenu block is no longer present. + const navSubmenuSelector = + '[aria-label="Editor content"][role="region"] [aria-label="Block: Submenu"]'; + const submenuBlock = await page.$( navSubmenuSelector ); + + expect( submenuBlock ).toBeFalsy(); + } ); + it( 'does not retain uncontrolled inner blocks when creating a new entity', async () => { await createNewPost(); await clickOnMoreMenuItem( 'Code editor' ); diff --git a/test/integration/fixtures/blocks/core__navigation.json b/test/integration/fixtures/blocks/core__navigation.json index 08489c00195264..f1f5d211efd3ab 100644 --- a/test/integration/fixtures/blocks/core__navigation.json +++ b/test/integration/fixtures/blocks/core__navigation.json @@ -6,7 +6,8 @@ "showSubmenuIcon": true, "openSubmenusOnClick": false, "overlayMenu": "mobile", - "hasIcon": true + "hasIcon": true, + "maxNestingLevel": 5 }, "innerBlocks": [] }