From 7fde4bf3362ccc04d02897fde30bb5d8f0daa689 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Mon, 6 Sep 2021 15:34:20 +0800 Subject: [PATCH 01/10] Implement placeholder --- packages/block-library/src/navigation/edit.js | 9 +- .../src/components/block-placeholder/index.js | 185 ++++++++++++++++ .../block-placeholder/menu-items-to-blocks.js | 198 ++++++++++++++++++ .../components/block-placeholder/style.scss | 42 ++++ .../use-navigation-entities.js | 142 +++++++++++++ .../add-navigation-editor-placeholder.js | 28 +++ packages/edit-navigation/src/filters/index.js | 2 + packages/edit-navigation/src/style.scss | 1 + 8 files changed, 605 insertions(+), 2 deletions(-) create mode 100644 packages/edit-navigation/src/components/block-placeholder/index.js create mode 100644 packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js create mode 100644 packages/edit-navigation/src/components/block-placeholder/style.scss create mode 100644 packages/edit-navigation/src/components/block-placeholder/use-navigation-entities.js create mode 100644 packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index 79e06d370460a2..f5d7a1c44f6563 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -103,6 +103,7 @@ function Navigation( { hasSubmenuIndicatorSetting = true, hasItemJustificationControls = true, hasColorSettings = true, + customPlaceholder: CustomPlaceholder = null, } ) { const [ isPlaceholderShown, setIsPlaceholderShown ] = useState( ! hasExistingNavItems @@ -163,7 +164,7 @@ function Navigation( { // inherit templateLock={ 'all' }. templateLock: false, __experimentalLayout: LAYOUT, - placeholder, + placeholder: ! CustomPlaceholder ? placeholder : undefined, } ); @@ -200,9 +201,13 @@ function Navigation( { } ); if ( isPlaceholderShown ) { + const PlaceholderComponent = CustomPlaceholder + ? CustomPlaceholder + : NavigationPlaceholder; + return (
- { setIsPlaceholderShown( false ); updateInnerBlocks( blocks ); diff --git a/packages/edit-navigation/src/components/block-placeholder/index.js b/packages/edit-navigation/src/components/block-placeholder/index.js new file mode 100644 index 00000000000000..0414c3c32ad59d --- /dev/null +++ b/packages/edit-navigation/src/components/block-placeholder/index.js @@ -0,0 +1,185 @@ +/** + * WordPress dependencies + */ +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; +import { + Placeholder, + Button, + DropdownMenu, + MenuGroup, + MenuItem, + Spinner, +} from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { + forwardRef, + useCallback, + useState, + useEffect, +} from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { chevronDown } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { store as navigationStore } from '../../store'; +import { useMenuEntityProp } from '../../hooks'; +import useNavigationEntities from './use-navigation-entities'; +import menuItemsToBlocks from './menu-items-to-blocks'; + +/** + * Convert pages to blocks. + * + * @param {Object[]} pages An array of pages. + * + * @return {WPBlock[]} An array of blocks. + */ +function convertPagesToBlocks( pages ) { + if ( ! pages?.length ) { + return null; + } + + return pages.map( ( { title, type, link: url, id } ) => + createBlock( 'core/navigation-link', { + type, + id, + url, + label: ! title.rendered ? __( '(no title)' ) : title.rendered, + opensInNewTab: false, + } ) + ); +} + +function BlockPlaceholder( { onCreate }, ref ) { + const [ selectedMenu, setSelectedMenu ] = useState(); + const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false ); + + const selectedMenuId = useSelect( ( select ) => + select( navigationStore ).getSelectedMenuId() + ); + const [ menuName ] = useMenuEntityProp( 'name', selectedMenuId ); + + const { + isResolvingPages, + menus, + isResolvingMenus, + menuItems, + hasResolvedMenuItems, + pages, + hasPages, + hasMenus, + } = useNavigationEntities( selectedMenu ); + + const isLoading = isResolvingPages || isResolvingMenus; + + const createFromMenu = useCallback( () => { + const { innerBlocks: blocks } = menuItemsToBlocks( menuItems ); + const selectNavigationBlock = true; + onCreate( blocks, selectNavigationBlock ); + } ); + + 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 = () => { + onCreate( [] ); + }; + + const onCreateAllPages = () => { + const blocks = convertPagesToBlocks( pages ); + const selectNavigationBlock = true; + onCreate( blocks, selectNavigationBlock ); + }; + + 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: 'tertiary', + }; + + return ( + +
+ { isLoading && ( +
+ +
+ ) } + { ! isLoading && ( +
+ + { hasPages ? ( + + ) : undefined } + { hasMenus ? ( + + { ( { onClose } ) => ( + + { menus.map( ( menu ) => { + return ( + { + setSelectedMenu( + menu.id + ); + onCreateFromMenu(); + } } + onClose={ onClose } + key={ menu.id } + > + { menu.name } + + ); + } ) } + + ) } + + ) : undefined } +
+ ) } +
+
+ ); +} + +export default forwardRef( BlockPlaceholder ); diff --git a/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js b/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js new file mode 100644 index 00000000000000..6e2c90f5d26687 --- /dev/null +++ b/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js @@ -0,0 +1,198 @@ +/** + * External dependencies + */ +import { sortBy } from 'lodash'; + +/** + * WordPress dependencies + */ +/** + * WordPress dependencies + */ +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; + +/** + * Convert a flat menu item structure to a nested blocks structure. + * + * @param {Object[]} menuItems An array of menu items. + * + * @return {WPBlock[]} An array of blocks. + */ +export default function menuItemsToBlocks( menuItems ) { + if ( ! menuItems ) { + return null; + } + + const menuTree = createDataTree( menuItems ); + return mapMenuItemsToBlocks( menuTree ); +} + +/** + * A recursive function that maps menu item nodes to blocks. + * + * @param {WPNavMenuItem[]} menuItems An array of WPNavMenuItem items. + * @return {Object} Object containing innerBlocks and mapping. + */ +function mapMenuItemsToBlocks( menuItems ) { + let mapping = {}; + + // The menuItem should be in menu_order sort order. + const sortedItems = sortBy( menuItems, 'menu_order' ); + + const innerBlocks = sortedItems.map( ( menuItem ) => { + const attributes = menuItemToBlockAttributes( menuItem ); + + // If there are children recurse to build those nested blocks. + const { + innerBlocks: nestedBlocks = [], // alias to avoid shadowing + mapping: nestedMapping = {}, // alias to avoid shadowing + } = menuItem.children?.length + ? mapMenuItemsToBlocks( menuItem.children ) + : {}; + + // Update parent mapping with nested mapping. + mapping = { + ...mapping, + ...nestedMapping, + }; + + // Create block with nested "innerBlocks". + const block = createBlock( + 'core/navigation-link', + attributes, + nestedBlocks + ); + + // Create mapping for menuItem -> block + mapping[ menuItem.id ] = block.clientId; + + return block; + } ); + + return { + innerBlocks, + mapping, + }; +} + +/** + * A WP nav_menu_item object. + * For more documentation on the individual fields present on a menu item please see: + * https://core.trac.wordpress.org/browser/tags/5.7.1/src/wp-includes/nav-menu.php#L789 + * + * Changes made here should also be mirrored in packages/edit-navigation/src/store/utils.js. + * + * @typedef WPNavMenuItem + * + * @property {Object} title stores the raw and rendered versions of the title/label for this menu item. + * @property {Array} xfn the XFN relationships expressed in the link of this menu item. + * @property {Array} classes the HTML class attributes for this menu item. + * @property {string} attr_title the HTML title attribute for this menu item. + * @property {string} object The type of object originally represented, such as 'category', 'post', or 'attachment'. + * @property {string} object_id The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. + * @property {string} description The description of this menu item. + * @property {string} url The URL to which this menu item points. + * @property {string} type The family of objects originally represented, such as 'post_type' or 'taxonomy'. + * @property {string} target The target attribute of the link element for this menu item. + */ + +/** + * Convert block attributes to menu item. + * + * @param {WPNavMenuItem} menuItem the menu item to be converted to block attributes. + * @return {Object} the block attributes converted from the WPNavMenuItem item. + */ +function menuItemToBlockAttributes( { + title: menuItemTitleField, + xfn, + classes, + // eslint-disable-next-line camelcase + attr_title, + object, + // eslint-disable-next-line camelcase + object_id, + description, + url, + type: menuItemTypeField, + target, +} ) { + // For historical reasons, the `core/navigation-link` variation type is `tag` + // whereas WP Core expects `post_tag` as the `object` type. + // To avoid writing a block migration we perform a conversion here. + // See also inverse equivalent in `blockAttributesToMenuItem`. + if ( object && object === 'post_tag' ) { + object = 'tag'; + } + + return { + label: menuItemTitleField?.rendered || '', + ...( object?.length && { + type: object, + } ), + kind: menuItemTypeField?.replace( '_', '-' ) || 'custom', + url: url || '', + ...( xfn?.length && + xfn.join( ' ' ).trim() && { + rel: xfn.join( ' ' ).trim(), + } ), + ...( classes?.length && + classes.join( ' ' ).trim() && { + className: classes.join( ' ' ).trim(), + } ), + ...( attr_title?.length && { + title: attr_title, + } ), + // eslint-disable-next-line camelcase + ...( object_id && + 'custom' !== object && { + id: object_id, + } ), + ...( description?.length && { + description, + } ), + ...( target === '_blank' && { + opensInNewTab: true, + } ), + }; +} + +/** + * Creates a nested, hierarchical tree representation from unstructured data that + * has an inherent relationship defined between individual items. + * + * For example, by default, each element in the dataset should have an `id` and + * `parent` property where the `parent` property indicates a relationship between + * the current item and another item with a matching `id` properties. + * + * This is useful for building linked lists of data from flat data structures. + * + * @param {Array} dataset linked data to be rearranged into a hierarchical tree based on relational fields. + * @param {string} id the property which uniquely identifies each entry within the array. + * @param {*} relation the property which identifies how the current item is related to other items in the data (if at all). + * @return {Array} a nested array of parent/child relationships + */ +function createDataTree( dataset, id = 'id', relation = 'parent' ) { + const hashTable = Object.create( null ); + const dataTree = []; + + for ( const data of dataset ) { + hashTable[ data[ id ] ] = { + ...data, + children: [], + }; + } + for ( const data of dataset ) { + if ( data[ relation ] ) { + hashTable[ data[ relation ] ].children.push( + hashTable[ data[ id ] ] + ); + } else { + dataTree.push( hashTable[ data[ id ] ] ); + } + } + + return dataTree; +} diff --git a/packages/edit-navigation/src/components/block-placeholder/style.scss b/packages/edit-navigation/src/components/block-placeholder/style.scss new file mode 100644 index 00000000000000..af9e392326de60 --- /dev/null +++ b/packages/edit-navigation/src/components/block-placeholder/style.scss @@ -0,0 +1,42 @@ +.wp-block-placeholder { + // The navigation editor already has a border around content. + // Hide the placeholder's border. Requires extra specificity. + &.wp-block-placeholder { + box-shadow: none; + } + + // Show placeholder instructions when it's a medium size. + &.is-medium .components-placeholder__instructions { + display: block; + } + + // Display buttons in a column when placeholder is small. + .wp-block-placeholder__actions { + display: flex; + flex-direction: column; + + .components-button { + margin-bottom: $grid-unit-15; + margin-right: 0; + + // Avoid bottom margin on the dropdown since it makes the + // menu anchor itself too far away from the button. + &.components-dropdown-menu__toggle { + margin-bottom: 0; + } + } + } + + @include break-medium() { + .wp-block-placeholder__actions { + flex-direction: row; + } + + // Change the default button margin. Again use extra specificity. + &.wp-block-placeholder.is-medium .components-button { + margin-bottom: 0; + margin-right: $grid-unit-15; + } + } + +} diff --git a/packages/edit-navigation/src/components/block-placeholder/use-navigation-entities.js b/packages/edit-navigation/src/components/block-placeholder/use-navigation-entities.js new file mode 100644 index 00000000000000..17806deadd9a81 --- /dev/null +++ b/packages/edit-navigation/src/components/block-placeholder/use-navigation-entities.js @@ -0,0 +1,142 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * @typedef {Object} NavigationEntitiesData + * @property {Array|undefined} pages - a collection of WP Post entity objects of post type "Page". + * @property {boolean} isResolvingPages - indicates whether the request to fetch pages is currently resolving. + * @property {boolean} hasResolvedPages - indicates whether the request to fetch pages has finished resolving. + * @property {Array|undefined} menus - a collection of Menu entity objects. + * @property {boolean} isResolvingMenus - indicates whether the request to fetch menus is currently resolving. + * @property {boolean} hasResolvedMenus - indicates whether the request to fetch menus has finished resolving. + * @property {Array|undefined} menusItems - a collection of Menu Item entity objects for the current menuId. + * @property {boolean} hasResolvedMenuItems - indicates whether the request to fetch menuItems has finished resolving. + * @property {boolean} hasPages - indicates whether there is currently any data for pages. + * @property {boolean} hasMenus - indicates whether there is currently any data for menus. + */ + +/** + * Manages fetching and resolution state for all entities required + * for the Navigation block. + * + * @param {number} menuId the menu for which to retrieve menuItem data. + * @return { NavigationEntitiesData } the entity data. + */ +export default function useNavigationEntities( menuId ) { + return { + ...usePageEntities(), + ...useMenuEntities(), + ...useMenuItemEntities( menuId ), + }; +} + +function useMenuEntities() { + const { menus, isResolvingMenus, hasResolvedMenus } = useSelect( + ( select ) => { + const { getMenus, isResolving, hasFinishedResolution } = select( + coreStore + ); + + const menusParameters = [ { per_page: -1 } ]; + + return { + menus: getMenus( ...menusParameters ), + isResolvingMenus: isResolving( 'getMenus', menusParameters ), + hasResolvedMenus: hasFinishedResolution( + 'getMenus', + menusParameters + ), + }; + }, + [] + ); + + return { + menus, + isResolvingMenus, + hasResolvedMenus, + hasMenus: !! ( hasResolvedMenus && menus?.length ), + }; +} + +function useMenuItemEntities( menuId ) { + const { menuItems, hasResolvedMenuItems } = useSelect( + ( select ) => { + const { getMenuItems, hasFinishedResolution } = select( coreStore ); + + const hasSelectedMenu = menuId !== undefined; + const menuItemsParameters = hasSelectedMenu + ? [ + { + menus: menuId, + per_page: -1, + }, + ] + : undefined; + + return { + menuItems: hasSelectedMenu + ? getMenuItems( ...menuItemsParameters ) + : undefined, + hasResolvedMenuItems: hasSelectedMenu + ? hasFinishedResolution( + 'getMenuItems', + menuItemsParameters + ) + : false, + }; + }, + [ menuId ] + ); + + return { + menuItems, + hasResolvedMenuItems, + }; +} + +function usePageEntities() { + const { pages, isResolvingPages, hasResolvedPages } = useSelect( + ( select ) => { + const { + getEntityRecords, + isResolving, + hasFinishedResolution, + } = select( coreStore ); + + const pagesParameters = [ + 'postType', + 'page', + { + parent: 0, + order: 'asc', + orderby: 'id', + per_page: -1, + }, + ]; + + return { + pages: getEntityRecords( ...pagesParameters ) || null, + isResolvingPages: isResolving( + 'getEntityRecords', + pagesParameters + ), + hasResolvedPages: hasFinishedResolution( + 'getEntityRecords', + pagesParameters + ), + }; + }, + [] + ); + + return { + pages, + isResolvingPages, + hasResolvedPages, + hasPages: !! ( hasResolvedPages && pages?.length ), + }; +} diff --git a/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js b/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js new file mode 100644 index 00000000000000..263658d0ffc646 --- /dev/null +++ b/packages/edit-navigation/src/filters/add-navigation-editor-placeholder.js @@ -0,0 +1,28 @@ +/** + * WordPress dependencies + */ +/** + * Internal dependencies + */ +import { addFilter } from '@wordpress/hooks'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import BlockPlaceholder from '../components/block-placeholder'; + +const addNavigationEditorPlaceholder = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + if ( props.name !== 'core/navigation' ) { + return ; + } + return ( + + ); + }, + 'withNavigationEditorPlaceholder' +); + +export default () => + addFilter( + 'editor.BlockEdit', + 'core/edit-navigation/with-navigation-editor-placeholder', + addNavigationEditorPlaceholder + ); diff --git a/packages/edit-navigation/src/filters/index.js b/packages/edit-navigation/src/filters/index.js index 96315b46b7eb8d..08ab87f0fe4b5d 100644 --- a/packages/edit-navigation/src/filters/index.js +++ b/packages/edit-navigation/src/filters/index.js @@ -1,6 +1,7 @@ /** * Internal dependencies */ +import addNavigationEditorPlaceholder from './add-navigation-editor-placeholder'; import addMenuNameEditor from './add-menu-name-editor'; import disableInsertingNonNavigationBlocks from './disable-inserting-non-navigation-blocks'; import removeEditUnsupportedFeatures from './remove-edit-unsupported-features'; @@ -9,6 +10,7 @@ import removeSettingsUnsupportedFeatures from './remove-settings-unsupported-fea export const addFilters = ( shouldAddDisableInsertingNonNavigationBlocksFilter ) => { + addNavigationEditorPlaceholder(); addMenuNameEditor(); if ( shouldAddDisableInsertingNonNavigationBlocksFilter ) { disableInsertingNonNavigationBlocks(); diff --git a/packages/edit-navigation/src/style.scss b/packages/edit-navigation/src/style.scss index d3865a1dfff8ea..ef8c1bdea66467 100644 --- a/packages/edit-navigation/src/style.scss +++ b/packages/edit-navigation/src/style.scss @@ -8,6 +8,7 @@ $navigation-editor-spacing-top: $grid-unit-50 * 2; } @import "./components/add-menu/style.scss"; +@import "./components/block-placeholder/style.scss"; @import "../../interface/src/style.scss"; @import "./components/editor/style.scss"; @import "./components/error-boundary/style.scss"; From 2eea26c173f50183b6b707ced1b367f7b2045ae2 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Mon, 6 Sep 2021 15:37:54 +0800 Subject: [PATCH 02/10] Filter out selected menu --- .../src/components/block-placeholder/index.js | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/edit-navigation/src/components/block-placeholder/index.js b/packages/edit-navigation/src/components/block-placeholder/index.js index 0414c3c32ad59d..cf2cac7c50f6b6 100644 --- a/packages/edit-navigation/src/components/block-placeholder/index.js +++ b/packages/edit-navigation/src/components/block-placeholder/index.js @@ -155,22 +155,27 @@ function BlockPlaceholder( { onCreate }, ref ) { > { ( { onClose } ) => ( - { menus.map( ( menu ) => { - return ( - { - setSelectedMenu( - menu.id - ); - onCreateFromMenu(); - } } - onClose={ onClose } - key={ menu.id } - > - { menu.name } - - ); - } ) } + { menus + .filter( + ( menu ) => + menu.id !== selectedMenuId + ) + .map( ( menu ) => { + return ( + { + setSelectedMenu( + menu.id + ); + onCreateFromMenu(); + } } + onClose={ onClose } + key={ menu.id } + > + { menu.name } + + ); + } ) } ) } From 95e4c0d4b4a50920ba26751b63e84ad4eca214d2 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Mon, 6 Sep 2021 15:57:47 +0800 Subject: [PATCH 03/10] Update tests --- .../__snapshots__/navigation-editor.test.js.snap | 2 +- .../specs/experiments/navigation-editor.test.js | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/e2e-tests/specs/experiments/__snapshots__/navigation-editor.test.js.snap b/packages/e2e-tests/specs/experiments/__snapshots__/navigation-editor.test.js.snap index 89f22e7ad5236c..82c208896c7dca 100644 --- a/packages/e2e-tests/specs/experiments/__snapshots__/navigation-editor.test.js.snap +++ b/packages/e2e-tests/specs/experiments/__snapshots__/navigation-editor.test.js.snap @@ -4,7 +4,7 @@ exports[`Navigation editor allows creation of a menu when there are existing men exports[`Navigation editor allows creation of a menu when there are no current menu items 1`] = ` " - + " `; diff --git a/packages/e2e-tests/specs/experiments/navigation-editor.test.js b/packages/e2e-tests/specs/experiments/navigation-editor.test.js index fa8bdf21d852ac..972ba27eb834b3 100644 --- a/packages/e2e-tests/specs/experiments/navigation-editor.test.js +++ b/packages/e2e-tests/specs/experiments/navigation-editor.test.js @@ -193,7 +193,18 @@ describe( 'Navigation editor', () => { POST: menuPostResponse, } ), ...getMenuItemMocks( { GET: [] } ), - ...getPagesMocks( { GET: [ {} ] } ), // mock a single page + ...getPagesMocks( { + GET: [ + { + type: 'page', + id: 1, + link: 'https://example.com/1', + title: { + rendered: 'My page', + }, + }, + ], + } ), ] ); await page.keyboard.type( 'Main Menu' ); @@ -354,7 +365,7 @@ describe( 'Navigation editor', () => { ); await navBlock.click(); const startEmptyButton = await page.waitForXPath( - '//button[.="Start empty"]' + '//button[.="Start blank"]' ); await startEmptyButton.click(); From 6ff4831e948fe289a8def8f85b554b52c4134485 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Mon, 6 Sep 2021 16:05:02 +0800 Subject: [PATCH 04/10] Fix empty dropdown when there are no other menus --- .../src/components/block-placeholder/index.js | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/edit-navigation/src/components/block-placeholder/index.js b/packages/edit-navigation/src/components/block-placeholder/index.js index cf2cac7c50f6b6..38f367cf4b0800 100644 --- a/packages/edit-navigation/src/components/block-placeholder/index.js +++ b/packages/edit-navigation/src/components/block-placeholder/index.js @@ -116,6 +116,12 @@ function BlockPlaceholder( { onCreate }, ref ) { variant: 'tertiary', }; + const selectableMenus = menus?.filter( + ( menu ) => menu.id !== selectedMenuId + ); + + const hasSelectableMenus = !! selectableMenus?.length; + return ( ) : undefined } - { hasMenus ? ( + { hasSelectableMenus ? ( { ( { onClose } ) => ( - { menus - .filter( - ( menu ) => - menu.id !== selectedMenuId - ) - .map( ( menu ) => { - return ( - { - setSelectedMenu( - menu.id - ); - onCreateFromMenu(); - } } - onClose={ onClose } - key={ menu.id } - > - { menu.name } - - ); - } ) } + { selectableMenus.map( ( menu ) => { + return ( + { + setSelectedMenu( + menu.id + ); + onCreateFromMenu(); + } } + onClose={ onClose } + key={ menu.id } + > + { menu.name } + + ); + } ) } ) } From 6c25d1bc6924c993d0398d23d9d3544c130bbc11 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Tue, 7 Sep 2021 11:35:36 +0800 Subject: [PATCH 05/10] Use useSelectedMenuId hook Co-authored-by: George Mamadashvili --- .../src/components/block-placeholder/index.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/edit-navigation/src/components/block-placeholder/index.js b/packages/edit-navigation/src/components/block-placeholder/index.js index 38f367cf4b0800..98de7b668b1c63 100644 --- a/packages/edit-navigation/src/components/block-placeholder/index.js +++ b/packages/edit-navigation/src/components/block-placeholder/index.js @@ -13,7 +13,6 @@ import { MenuItem, Spinner, } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; import { forwardRef, useCallback, @@ -26,8 +25,7 @@ import { chevronDown } from '@wordpress/icons'; /** * Internal dependencies */ -import { store as navigationStore } from '../../store'; -import { useMenuEntityProp } from '../../hooks'; +import { useMenuEntityProp, useSelectedMenuId } from '../../hooks'; import useNavigationEntities from './use-navigation-entities'; import menuItemsToBlocks from './menu-items-to-blocks'; @@ -58,9 +56,7 @@ function BlockPlaceholder( { onCreate }, ref ) { const [ selectedMenu, setSelectedMenu ] = useState(); const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false ); - const selectedMenuId = useSelect( ( select ) => - select( navigationStore ).getSelectedMenuId() - ); + const [ selectedMenuId ] = useSelectedMenuId(); const [ menuName ] = useMenuEntityProp( 'name', selectedMenuId ); const { From cb65b92d4101d1af5e24e57d9af6fc0baafbfb92 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Tue, 7 Sep 2021 11:36:54 +0800 Subject: [PATCH 06/10] Remove duplicate import comments --- .../components/block-placeholder/menu-items-to-blocks.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js b/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js index 6e2c90f5d26687..47010b42e42035 100644 --- a/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js +++ b/packages/edit-navigation/src/components/block-placeholder/menu-items-to-blocks.js @@ -3,12 +3,6 @@ */ import { sortBy } from 'lodash'; -/** - * WordPress dependencies - */ -/** - * WordPress dependencies - */ /** * WordPress dependencies */ From b386aba523647fc6f7fb929f80853afc963ef094 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Tue, 7 Sep 2021 12:01:35 +0800 Subject: [PATCH 07/10] Styling adjustments --- .../src/components/block-placeholder/index.js | 19 ++++++++------- .../components/block-placeholder/style.scss | 24 ++++++++++++++----- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/packages/edit-navigation/src/components/block-placeholder/index.js b/packages/edit-navigation/src/components/block-placeholder/index.js index 98de7b668b1c63..7b4312080f85ea 100644 --- a/packages/edit-navigation/src/components/block-placeholder/index.js +++ b/packages/edit-navigation/src/components/block-placeholder/index.js @@ -52,6 +52,9 @@ function convertPagesToBlocks( pages ) { ); } +const TOGGLE_PROPS = { variant: 'tertiary' }; +const POPOVER_PROPS = { position: 'bottom center' }; + function BlockPlaceholder( { onCreate }, ref ) { const [ selectedMenu, setSelectedMenu ] = useState(); const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false ); @@ -108,10 +111,6 @@ function BlockPlaceholder( { onCreate }, ref ) { } }, [ isCreatingFromMenu, hasResolvedMenuItems ] ); - const toggleProps = { - variant: 'tertiary', - }; - const selectableMenus = menus?.filter( ( menu ) => menu.id !== selectedMenuId ); @@ -120,21 +119,24 @@ function BlockPlaceholder( { onCreate }, ref ) { return ( -
+
{ isLoading && (
) } { ! isLoading && ( -
+