@wordpress/block-library
Version:
Block library for the WordPress editor.
170 lines (154 loc) • 4.2 kB
JavaScript
/**
* WordPress dependencies
*/
import { createBlock } from '@wordpress/blocks';
import {
addSubmenu,
chevronUp,
chevronDown,
moreVertical,
} from '@wordpress/icons';
import { DropdownMenu, MenuItem, MenuGroup } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
import { BlockTitle, store as blockEditorStore } from '@wordpress/block-editor';
const POPOVER_PROPS = {
className: 'block-editor-block-settings-menu__popover',
placement: 'bottom-start',
};
const BLOCKS_THAT_CAN_BE_CONVERTED_TO_SUBMENU = [
'core/navigation-link',
'core/navigation-submenu',
];
function AddSubmenuItem( {
block,
onClose,
expandedState,
expand,
setInsertedBlock,
} ) {
const { insertBlock, replaceBlock, replaceInnerBlocks } =
useDispatch( blockEditorStore );
const clientId = block.clientId;
const isDisabled = ! BLOCKS_THAT_CAN_BE_CONVERTED_TO_SUBMENU.includes(
block.name
);
return (
<MenuItem
icon={ addSubmenu }
disabled={ isDisabled }
onClick={ () => {
const updateSelectionOnInsert = false;
const newLink = createBlock( 'core/navigation-link' );
if ( block.name === 'core/navigation-submenu' ) {
insertBlock(
newLink,
block.innerBlocks.length,
clientId,
updateSelectionOnInsert
);
} else {
// Convert to a submenu if the block currently isn't one.
const newSubmenu = createBlock(
'core/navigation-submenu',
block.attributes,
block.innerBlocks
);
// The following must happen as two independent actions.
// Why? Because the offcanvas editor relies on the getLastInsertedBlocksClientIds
// selector to determine which block is "active". As the UX needs the newLink to be
// the "active" block it must be the last block to be inserted.
// Therefore the Submenu is first created and **then** the newLink is inserted
// thus ensuring it is the last inserted block.
replaceBlock( clientId, newSubmenu );
replaceInnerBlocks(
newSubmenu.clientId,
[ newLink ],
updateSelectionOnInsert
);
}
// This call sets the local List View state for the "last inserted block".
// This is required for the Nav Block to determine whether or not to display
// the Link UI for this new block.
setInsertedBlock( newLink );
if ( ! expandedState[ block.clientId ] ) {
expand( block.clientId );
}
onClose();
} }
>
{ __( 'Add submenu link' ) }
</MenuItem>
);
}
export default function LeafMoreMenu( props ) {
const { block } = props;
const { clientId } = block;
const { moveBlocksDown, moveBlocksUp, removeBlocks } =
useDispatch( blockEditorStore );
const removeLabel = sprintf(
/* translators: %s: block name */
__( 'Remove %s' ),
BlockTitle( { clientId, maximumLength: 25 } )
);
const rootClientId = useSelect(
( select ) => {
const { getBlockRootClientId } = select( blockEditorStore );
return getBlockRootClientId( clientId );
},
[ clientId ]
);
return (
<DropdownMenu
icon={ moreVertical }
label={ __( 'Options' ) }
className="block-editor-block-settings-menu"
popoverProps={ POPOVER_PROPS }
noIcons
{ ...props }
>
{ ( { onClose } ) => (
<>
<MenuGroup>
<MenuItem
icon={ chevronUp }
onClick={ () => {
moveBlocksUp( [ clientId ], rootClientId );
onClose();
} }
>
{ __( 'Move up' ) }
</MenuItem>
<MenuItem
icon={ chevronDown }
onClick={ () => {
moveBlocksDown( [ clientId ], rootClientId );
onClose();
} }
>
{ __( 'Move down' ) }
</MenuItem>
<AddSubmenuItem
block={ block }
onClose={ onClose }
expanded
expandedState={ props.expandedState }
expand={ props.expand }
setInsertedBlock={ props.setInsertedBlock }
/>
</MenuGroup>
<MenuGroup>
<MenuItem
onClick={ () => {
removeBlocks( [ clientId ], false );
onClose();
} }
>
{ removeLabel }
</MenuItem>
</MenuGroup>
</>
) }
</DropdownMenu>
);
}