Skip to content

Commit

Permalink
Navigation: Improve flow when creating from menu (#23187)
Browse files Browse the repository at this point in the history
* Navigation: Improve flow when creating from menu

When the user opts to create a Navigation block from an existing menu,
let them click on the Create button immediately while we fetch the menu
items in the background. This way we avoid disabling the Create button
which is a confusing UX.

* Navigation: Create empty block if empty menu selected
  • Loading branch information
noisysocks committed Jun 16, 2020
1 parent 02490a4 commit 7f858e0
Showing 1 changed file with 63 additions and 68 deletions.
131 changes: 63 additions & 68 deletions packages/block-library/src/navigation/placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ import {
Placeholder,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { forwardRef, useCallback, useMemo, useState } from '@wordpress/element';
import {
forwardRef,
useCallback,
useMemo,
useState,
useEffect,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { navigation as icon } from '@wordpress/icons';

Expand Down Expand Up @@ -137,51 +143,11 @@ function convertPagesToBlocks( pages ) {
);
}

/**
* Returns a value that indicates whether the create button should be disabled.
*
* @param {Object} selectedCreateOption An object containing details of
* the selected create option.
* @param {boolean} hasResolvedPages Indicates whether pages have loaded.
* @param {boolean} hasResolvedMenuItems Indicates whether menu items have loaded.
*
* @return {boolean} A value that indicates whether the create button is disabled.
*/
function getIsCreateButtonDisabled(
selectedCreateOption,
hasResolvedPages,
hasResolvedMenuItems
) {
// If there is no key at all then disable.
if ( ! selectedCreateOption ) {
return true;
}

const optionKey = selectedCreateOption?.key;

// Always disable if the default "placeholder" option is selected.
if ( optionKey === CREATE_PLACEHOLDER_VALUE ) {
return true;
}

// Always enable if Create Empty is selected.
if ( optionKey === CREATE_EMPTY_OPTION_VALUE ) {
return false;
}

// Enable if Pages option selected and we have Pages available.
if ( optionKey === CREATE_FROM_PAGES_OPTION_VALUE && hasResolvedPages ) {
return false;
}

// Enable if a menu is selected and menu items have loaded.
const selectedMenu = getSelectedMenu( selectedCreateOption );
return selectedMenu === undefined || ! hasResolvedMenuItems;
}

function NavigationPlaceholder( { onCreate }, ref ) {
const [ selectedCreateOption, setSelectedCreateOption ] = useState();

const [ isCreatingFromMenu, setIsCreatingFromMenu ] = useState( false );

const {
pages,
isResolvingPages,
Expand Down Expand Up @@ -279,38 +245,65 @@ function NavigationPlaceholder( { onCreate }, ref ) {
[ menus, hasMenus, hasPages ]
);

const createFromMenu = useCallback( () => {
// If an empty menu was selected, create an empty block.
if ( ! menuItems.length ) {
const blocks = [ createBlock( 'core/navigation-link' ) ];
onCreate( blocks );
return;
}

const blocks = convertMenuItemsToBlocks( menuItems );
const selectNavigationBlock = true;
onCreate( blocks, selectNavigationBlock );
} );

const onCreateButtonClick = useCallback( () => {
if ( ! selectedCreateOption ) {
return;
}

const { key } = selectedCreateOption;
switch ( key ) {
case CREATE_PLACEHOLDER_VALUE:
// Do nothing.
return;

case CREATE_EMPTY_OPTION_VALUE: {
const blocks = [ createBlock( 'core/navigation-link' ) ];
onCreate( blocks );
return;
}

if ( key === CREATE_FROM_PAGES_OPTION_VALUE && hasPages ) {
const blocks = convertPagesToBlocks( pages );
const selectNavigationBlock = true;
onCreate( blocks, selectNavigationBlock );
return;
}
case CREATE_FROM_PAGES_OPTION_VALUE: {
const blocks = convertPagesToBlocks( pages );
const selectNavigationBlock = true;
onCreate( blocks, selectNavigationBlock );
return;
}

if ( key === CREATE_EMPTY_OPTION_VALUE || ! menuItems?.length ) {
const blocks = [ createBlock( 'core/navigation-link' ) ];
onCreate( blocks );
}
// The default case indicates that a menu was selected.
default:
// If we have menu items, create the block right away.
if ( hasResolvedMenuItems ) {
createFromMenu();
return;
}

// Infer that the user selected a menu to create from.
// If either there's no selected menu or menu items are undefined
// this is undefined behavior, do nothing.
const selectedMenu = getSelectedMenu( selectedCreateOption );
if ( selectedMenu === undefined || menuItems === undefined ) {
return;
// Otherwise, create the block when resolution finishes.
setIsCreatingFromMenu( true );
}

const blocks = convertMenuItemsToBlocks( menuItems );
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 ] );

return (
<Placeholder
className="wp-block-navigation-placeholder"
Expand Down Expand Up @@ -349,6 +342,7 @@ function NavigationPlaceholder( { onCreate }, ref ) {
return;
}
setSelectedCreateOption( selectedItem );
setIsCreatingFromMenu( false );
} }
options={ createOptions.map( ( option ) => {
return {
Expand All @@ -360,12 +354,13 @@ function NavigationPlaceholder( { onCreate }, ref ) {
<Button
isSecondary
className="wp-block-navigation-placeholder__button"
disabled={
! selectedCreateOption ||
selectedCreateOption.key ===
CREATE_PLACEHOLDER_VALUE
}
isBusy={ isCreatingFromMenu }
onClick={ onCreateButtonClick }
disabled={ getIsCreateButtonDisabled(
selectedCreateOption,
hasResolvedPages,
hasResolvedMenuItems
) }
>
{ __( 'Create' ) }
</Button>
Expand Down

0 comments on commit 7f858e0

Please sign in to comment.