diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index ea8b7f7dd84775..d347e2711b413a 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -415,23 +415,27 @@ function Navigation( { } /> ) } - - { isEntityAvailable && ( - - ) } - + { ! isPlaceholderShown && ( + + { isEntityAvailable && ( + + ) } + + ) } diff --git a/packages/block-library/src/navigation/edit/placeholder/create-inner-blocks-step.js b/packages/block-library/src/navigation/edit/placeholder/create-inner-blocks-step.js deleted file mode 100644 index 33f36c8ecd2a99..00000000000000 --- a/packages/block-library/src/navigation/edit/placeholder/create-inner-blocks-step.js +++ /dev/null @@ -1,152 +0,0 @@ -/** - * WordPress dependencies - */ -import { createBlock } from '@wordpress/blocks'; -import { - Placeholder, - Button, - DropdownMenu, - MenuGroup, - MenuItem, - Spinner, -} from '@wordpress/components'; - -import { - forwardRef, - useCallback, - useState, - useEffect, -} from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { navigation, chevronDown, Icon } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import useNavigationEntities from '../../use-navigation-entities'; -import PlaceholderPreview from './placeholder-preview'; -import menuItemsToBlocks from '../../menu-items-to-blocks'; - -function CreateInnerBlocksStep( { onFinish }, ref ) { - const [ selectedMenu, setSelectedMenu ] = useState(); - - const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false ); - - const { - isResolvingPages, - menus, - isResolvingMenus, - menuItems, - hasResolvedMenuItems, - hasPages, - hasMenus, - } = useNavigationEntities( selectedMenu ); - - const isLoading = isResolvingPages || isResolvingMenus; - - const createFromMenu = useCallback( () => { - const { innerBlocks: blocks } = menuItemsToBlocks( menuItems ); - onFinish( blocks ); - }, [ menuItems, menuItemsToBlocks, onFinish ] ); - - const onCreateFromMenu = () => { - // If we have menu items, create the block right away. - if ( hasResolvedMenuItems ) { - createFromMenu(); - return; - } - - // Otherwise, create the block when resolution finishes. - setIsCreatingFromMenu( true ); - }; - - const onCreateEmptyMenu = () => { - onFinish( [] ); - }; - - const onCreateAllPages = () => { - const block = [ createBlock( 'core/page-list' ) ]; - onFinish( block ); - }; - - useEffect( () => { - // If the user selected a menu but we had to wait for menu items to - // finish resolving, then create the block once resolution finishes. - if ( isCreatingFromMenu && hasResolvedMenuItems ) { - createFromMenu(); - setIsCreatingFromMenu( false ); - } - }, [ isCreatingFromMenu, hasResolvedMenuItems ] ); - - const toggleProps = { - variant: 'primary', - className: 'wp-block-navigation-placeholder__actions__dropdown', - }; - return ( - - - -
- { isLoading && ( -
- -
- ) } - { ! isLoading && ( -
-
- { __( 'Navigation' ) } -
- { hasMenus ? ( - - { ( { onClose } ) => ( - - { menus.map( ( menu ) => { - return ( - { - setSelectedMenu( - menu.id - ); - onCreateFromMenu(); - } } - onClose={ onClose } - key={ menu.id } - > - { menu.name } - - ); - } ) } - - ) } - - ) : undefined } - { hasPages ? ( - - ) : undefined } - -
- ) } -
-
- ); -} - -export default forwardRef( CreateInnerBlocksStep ); diff --git a/packages/block-library/src/navigation/edit/placeholder/index.js b/packages/block-library/src/navigation/edit/placeholder/index.js index 1306f24ad812e2..9c19c88e309a16 100644 --- a/packages/block-library/src/navigation/edit/placeholder/index.js +++ b/packages/block-library/src/navigation/edit/placeholder/index.js @@ -1,32 +1,107 @@ /** * WordPress dependencies */ -import { serialize } from '@wordpress/blocks'; +import { serialize, createBlock } from '@wordpress/blocks'; +import { + Placeholder, + Button, + DropdownMenu, + MenuGroup, + MenuItem, +} from '@wordpress/components'; import { store as coreStore } from '@wordpress/core-data'; import { useDispatch } from '@wordpress/data'; -import { useCallback, useState } from '@wordpress/element'; +import { useCallback, useState, useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; - -const PLACEHOLDER_STEPS = { - selectNavigationPost: 1, - createInnerBlocks: 2, -}; +import { navigation, chevronDown, Icon } from '@wordpress/icons'; /** * Internal dependencies */ -import SelectNavigationMenuStep from './select-navigation-menu-step'; -import CreateInnerBlocksStep from './create-inner-blocks-step'; -export default function Placeholder( { +import useNavigationEntities from '../../use-navigation-entities'; +import PlaceholderPreview from './placeholder-preview'; +import menuItemsToBlocks from '../../menu-items-to-blocks'; +import NavigationMenuNameModal from '../navigation-menu-name-modal'; +import useNavigationMenu from '../../use-navigation-menu'; + +const ExistingMenusDropdown = ( { + canSwitchNavigationMenu, + navigationMenus, + setSelectedMenu, + onFinish, + menus, + onCreateFromMenu, +} ) => { + const toggleProps = { + variant: 'primary', + className: 'wp-block-navigation-placeholder__actions__dropdown', + }; + return ( + + { ( { onClose } ) => ( + <> + + { canSwitchNavigationMenu && + navigationMenus.map( ( menu ) => { + return ( + { + setSelectedMenu( menu.id ); + onFinish( menu ); + } } + onClose={ onClose } + key={ menu.id } + > + { menu.title.rendered } + + ); + } ) } + + + { menus.map( ( menu ) => { + return ( + { + setSelectedMenu( menu.id ); + onCreateFromMenu( menu.name ); + } } + onClose={ onClose } + key={ menu.id } + > + { menu.name } + + ); + } ) } + + + ) } + + ); +}; + +export default function NavigationPlaceholder( { onFinish, canSwitchNavigationMenu, hasResolvedNavigationMenu, } ) { - const [ step, setStep ] = useState( - PLACEHOLDER_STEPS.selectNavigationPost + const [ selectedMenu, setSelectedMenu ] = useState(); + + const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false ); + + const [ menuName, setMenuName ] = useState( '' ); + + const [ isNewMenuModalVisible, setIsNewMenuModalVisible ] = useState( + false ); - const [ navigationMenuTitle, setNavigationMenuTitle ] = useState( '' ); + + const [ createEmpty, setCreateEmpty ] = useState( false ); + const { saveEntityRecord } = useDispatch( coreStore ); // This callback uses data from the two placeholder steps and only creates @@ -50,30 +125,131 @@ export default function Placeholder( { [ serialize, saveEntityRecord ] ); + const onFinishMenuCreation = async ( navigationMenuTitle, blocks ) => { + const navigationMenu = await createNavigationMenu( + navigationMenuTitle, + blocks + ); + onFinish( navigationMenu ); + }; + + const { + isResolvingPages, + menus, + isResolvingMenus, + menuItems, + hasResolvedMenuItems, + hasPages, + hasMenus, + } = useNavigationEntities( selectedMenu ); + + const isStillLoading = isResolvingPages || isResolvingMenus; + + const createFromMenu = useCallback( + ( name ) => { + const { innerBlocks: blocks } = menuItemsToBlocks( menuItems ); + onFinishMenuCreation( name, blocks ); + }, + [ menuItems, menuItemsToBlocks, onFinish ] + ); + + const onCreateFromMenu = ( name ) => { + // If we have menu items, create the block right away. + if ( hasResolvedMenuItems ) { + createFromMenu( name ); + return; + } + + // Otherwise, create the block when resolution finishes. + setIsCreatingFromMenu( true ); + // Store the name to use later. + setMenuName( name ); + }; + + const onCreateEmptyMenu = ( name ) => { + onFinishMenuCreation( name, [] ); + }; + + const onCreateAllPages = ( name ) => { + const block = [ createBlock( 'core/page-list' ) ]; + onFinishMenuCreation( name, block ); + setIsNewMenuModalVisible( true ); + }; + + useEffect( () => { + // If the user selected a menu but we had to wait for menu items to + // finish resolving, then create the block once resolution finishes. + if ( isCreatingFromMenu && hasResolvedMenuItems ) { + createFromMenu( menuName ); + setIsCreatingFromMenu( false ); + } + }, [ isCreatingFromMenu, hasResolvedMenuItems, menuName ] ); + + const { navigationMenus } = useNavigationMenu(); + return ( <> - { step === PLACEHOLDER_STEPS.selectNavigationPost && ( - { - setNavigationMenuTitle( newTitle ); - setStep( PLACEHOLDER_STEPS.createInnerBlocks ); - } } - onSelectExisting={ ( navigationMenu ) => { - onFinish( navigationMenu ); - } } - canSwitchNavigationMenu={ canSwitchNavigationMenu } - hasResolvedNavigationMenu={ hasResolvedNavigationMenu } - /> + { ( ! hasResolvedNavigationMenu || isStillLoading ) && ( + + ) } + { hasResolvedNavigationMenu && ! isStillLoading && ( + + +
+
+
+ { ' ' } + { __( 'Navigation' ) } +
+ { hasMenus || navigationMenus.length ? ( + + ) : undefined } + { hasPages ? ( + + ) : undefined } + +
+
+
) } - { step === PLACEHOLDER_STEPS.createInnerBlocks && ( - { - const navigationMenu = await createNavigationMenu( - navigationMenuTitle, - blocks - ); - onFinish( navigationMenu ); + { isNewMenuModalVisible && ( + { + setIsNewMenuModalVisible( false ); } } + onFinish={ + createEmpty ? onCreateEmptyMenu : onCreateAllPages + } /> ) } diff --git a/packages/block-library/src/navigation/edit/placeholder/select-navigation-menu-step.js b/packages/block-library/src/navigation/edit/placeholder/select-navigation-menu-step.js deleted file mode 100644 index 1d8c468577c4ac..00000000000000 --- a/packages/block-library/src/navigation/edit/placeholder/select-navigation-menu-step.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { useState } from '@wordpress/element'; -import { Button, Dropdown, Placeholder } from '@wordpress/components'; -import { navigation as navigationIcon } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import PlaceholderPreview from './placeholder-preview'; -import NavigationMenuSelector from '../navigation-menu-selector'; -import NavigationMenuNameModal from '../navigation-menu-name-modal'; - -export default function SelectNavigationMenuStep( { - canSwitchNavigationMenu, - hasResolvedNavigationMenu, - onCreateNew, - onSelectExisting, -} ) { - const [ isNewMenuModalVisible, setIsNewMenuModalVisible ] = useState( - false - ); - - return ( - <> - { ! hasResolvedNavigationMenu && } - { hasResolvedNavigationMenu && ( - - { canSwitchNavigationMenu && ( - ( - - ) } - renderContent={ ( { onClose } ) => ( - - ) } - /> - ) } - - - ) } - { isNewMenuModalVisible && ( - { - setIsNewMenuModalVisible( false ); - } } - onFinish={ onCreateNew } - /> - ) } - - ); -}