diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/navigation-menu-content.js b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/navigation-menu-content.js index d5ef5984e9fb1..2981c57c19fd1 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/navigation-menu-content.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menus/navigation-menu-content.js @@ -10,9 +10,10 @@ import { } from '@wordpress/block-editor'; import { useDispatch, useSelect } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; -import { useCallback, useState } from '@wordpress/element'; import { Popover } from '@wordpress/components'; import { __unstableStripHTML as stripHTML } from '@wordpress/dom'; +import { useCallback, useEffect, useState } from '@wordpress/element'; +import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies @@ -47,18 +48,53 @@ function CustomLinkAdditionalBlockUI( { block, onClose } ) { ); } +// Needs to be kept in sync with the query used at packages/block-library/src/page-list/edit.js. +const MAX_PAGE_COUNT = 100; +const PAGES_QUERY = [ + 'postType', + 'page', + { + per_page: MAX_PAGE_COUNT, + _fields: [ 'id', 'link', 'menu_order', 'parent', 'title', 'type' ], + // TODO: When https://core.trac.wordpress.org/ticket/39037 REST API support for multiple orderby + // values is resolved, update 'orderby' to [ 'menu_order', 'post_title' ] to provide a consistent + // sort. + orderby: 'menu_order', + order: 'asc', + }, +]; export default function NavigationMenuContent( { rootClientId, onSelect } ) { - const { clientIdsTree, isLoading } = useSelect( + const [ isLoading, setIsLoading ] = useState( true ); + const { clientIdsTree, shouldKeepLoading, isSinglePageList } = useSelect( ( select ) => { - const { __unstableGetClientIdsTree, areInnerBlocksControlled } = - select( blockEditorStore ); - return { - clientIdsTree: __unstableGetClientIdsTree( rootClientId ), + const { + __unstableGetClientIdsTree, + areInnerBlocksControlled, + getBlockName, + } = select( blockEditorStore ); + const { isResolving } = select( coreStore ); + const _clientIdsTree = __unstableGetClientIdsTree( rootClientId ); + const hasOnlyPageListBlock = + _clientIdsTree.length === 1 && + getBlockName( _clientIdsTree[ 0 ].clientId ) === + 'core/page-list'; + const isLoadingPages = isResolving( + 'getEntityRecords', + PAGES_QUERY + ); + return { + clientIdsTree: _clientIdsTree, // This is a small hack to wait for the navigation block // to actually load its inner blocks. - isLoading: ! areInnerBlocksControlled( rootClientId ), + shouldKeepLoading: + ! areInnerBlocksControlled( rootClientId ) || + isLoadingPages, + isSinglePageList: + hasOnlyPageListBlock && + ! isLoadingPages && + _clientIdsTree[ 0 ].innerBlocks.length > 0, }; }, [ rootClientId ] @@ -89,6 +125,25 @@ export default function NavigationMenuContent( { rootClientId, onSelect } ) { [ customLinkEditPopoverOpenId, setIsCustomLinkEditPopoverOpenId ] ); + // Delay loading stop by 50ms to avoid flickering. + useEffect( () => { + let timeoutId; + if ( shouldKeepLoading && ! isLoading ) { + setIsLoading( true ); + } + if ( ! shouldKeepLoading && isLoading ) { + timeoutId = setTimeout( () => { + setIsLoading( false ); + timeoutId = undefined; + }, 50 ); + } + return () => { + if ( timeoutId ) { + clearTimeout( timeoutId ); + } + }; + }, [ shouldKeepLoading, clientIdsTree, isLoading ] ); + const { OffCanvasEditor, LeafMoreMenu } = unlock( blockEditorPrivateApis ); const offCanvasOnselect = useCallback( @@ -127,7 +182,11 @@ export default function NavigationMenuContent( { rootClientId, onSelect } ) { { isLoading && } { ! isLoading && (