diff --git a/packages/block-editor/src/components/block-navigation/block.js b/packages/block-editor/src/components/block-navigation/block.js index 7c0fca3f285344..50b8ad407c6b4a 100644 --- a/packages/block-editor/src/components/block-navigation/block.js +++ b/packages/block-editor/src/components/block-navigation/block.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; * WordPress dependencies */ import { __experimentalTreeGridCell as TreeGridCell } from '@wordpress/components'; - +import { moreVertical } from '@wordpress/icons'; import { useState } from '@wordpress/element'; /** @@ -20,6 +20,8 @@ import { } from '../block-mover/button'; import DescenderLines from './descender-lines'; import BlockNavigationBlockContents from './block-contents'; +import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown'; +import { useBlockNavigationContext } from './context'; export default function BlockNavigationBlock( { block, @@ -45,6 +47,14 @@ export default function BlockNavigationBlock( { 'block-editor-block-navigation-block__mover-cell', { 'is-visible': hasVisibleMovers } ); + const { + __experimentalWithEllipsisMenu: withEllipsisMenu, + __experimentalWithEllipsisMenuMinLevel: ellipsisMenuMinLevel, + } = useBlockNavigationContext(); + const ellipsisMenuClassName = classnames( + 'block-editor-block-navigation-block__menu-cell', + { 'is-visible': hasVisibleMovers } + ); return ( ) } + + { withEllipsisMenu && level >= ellipsisMenuMinLevel && ( + + { ( props ) => ( + + ) } + + ) } ); } diff --git a/packages/block-editor/src/components/block-navigation/context.js b/packages/block-editor/src/components/block-navigation/context.js index e21075d25d0f20..7d087b5f0e7490 100644 --- a/packages/block-editor/src/components/block-navigation/context.js +++ b/packages/block-editor/src/components/block-navigation/context.js @@ -5,6 +5,8 @@ import { createContext, useContext } from '@wordpress/element'; export const BlockNavigationContext = createContext( { __experimentalWithBlockNavigationSlots: false, + __experimentalWithEllipsisMenu: false, + __experimentalWithEllipsisMenuMinLevel: 0, } ); export const useBlockNavigationContext = () => diff --git a/packages/block-editor/src/components/block-navigation/dropdown.js b/packages/block-editor/src/components/block-navigation/dropdown.js index ba0e824c3667c0..287a0da8cfa78c 100644 --- a/packages/block-editor/src/components/block-navigation/dropdown.js +++ b/packages/block-editor/src/components/block-navigation/dropdown.js @@ -56,6 +56,7 @@ function BlockNavigationDropdownToggle( { isEnabled, onToggle, isOpen } ) { function BlockNavigationDropdown( { isDisabled, __experimentalWithBlockNavigationSlots, + __experimentalWithEllipsisMenu, } ) { const hasBlocks = useSelect( ( select ) => !! select( 'core/block-editor' ).getBlockCount(), @@ -79,6 +80,9 @@ function BlockNavigationDropdown( { __experimentalWithBlockNavigationSlots={ __experimentalWithBlockNavigationSlots } + __experimentalWithEllipsisMenu={ + __experimentalWithEllipsisMenu + } /> ) } /> diff --git a/packages/block-editor/src/components/block-navigation/index.js b/packages/block-editor/src/components/block-navigation/index.js index 9e6e99651a80c3..1f7a5b20e14c6a 100644 --- a/packages/block-editor/src/components/block-navigation/index.js +++ b/packages/block-editor/src/components/block-navigation/index.js @@ -21,6 +21,8 @@ function BlockNavigation( { selectedBlockClientId, selectBlock, __experimentalWithBlockNavigationSlots, + __experimentalWithEllipsisMenu, + __experimentalWithEllipsisMenuMinLevel, } ) { if ( ! rootBlocks || rootBlocks.length === 0 ) { return null; @@ -41,6 +43,12 @@ function BlockNavigation( { blocks={ [ rootBlock ] } selectedBlockClientId={ selectedBlockClientId } selectBlock={ selectBlock } + __experimentalWithEllipsisMenu={ + __experimentalWithEllipsisMenu + } + __experimentalWithEllipsisMenuMinLevel={ + __experimentalWithEllipsisMenuMinLevel + } __experimentalWithBlockNavigationSlots={ __experimentalWithBlockNavigationSlots } @@ -52,6 +60,12 @@ function BlockNavigation( { blocks={ rootBlocks } selectedBlockClientId={ selectedBlockClientId } selectBlock={ selectBlock } + __experimentalWithEllipsisMenu={ + __experimentalWithEllipsisMenu + } + __experimentalWithEllipsisMenuMinLevel={ + __experimentalWithEllipsisMenuMinLevel + } __experimentalWithBlockNavigationSlots={ __experimentalWithBlockNavigationSlots } diff --git a/packages/block-editor/src/components/block-navigation/style.scss b/packages/block-editor/src/components/block-navigation/style.scss index 82d766c6a27f6d..6aea8059c9d5e4 100644 --- a/packages/block-editor/src/components/block-navigation/style.scss +++ b/packages/block-editor/src/components/block-navigation/style.scss @@ -57,6 +57,7 @@ $tree-item-height: 36px; border-radius: $border-width; } + .block-editor-block-navigation-block__menu-cell, .block-editor-block-navigation-block__mover-cell { width: $button-size; opacity: 0; @@ -66,6 +67,13 @@ $tree-item-height: 36px; opacity: 1; @include edit-post__fade-in-animation; } + + &, + .components-button.has-icon { + width: 24px; + min-width: 24px; + padding: 0; + } } .block-editor-block-mover-button { diff --git a/packages/block-editor/src/components/block-navigation/tree.js b/packages/block-editor/src/components/block-navigation/tree.js index ee7d688565c016..096231e7159ecf 100644 --- a/packages/block-editor/src/components/block-navigation/tree.js +++ b/packages/block-editor/src/components/block-navigation/tree.js @@ -21,11 +21,24 @@ import { BlockNavigationContext } from './context'; */ export default function BlockNavigationTree( { __experimentalWithBlockNavigationSlots, + __experimentalWithEllipsisMenu, + __experimentalWithEllipsisMenuMinLevel, ...props } ) { const contextValue = useMemo( - () => ( { __experimentalWithBlockNavigationSlots } ), - [ __experimentalWithBlockNavigationSlots ] + () => ( { + __experimentalWithBlockNavigationSlots, + __experimentalWithEllipsisMenu, + __experimentalWithEllipsisMenuMinLevel: + typeof __experimentalWithEllipsisMenuMinLevel === 'number' + ? __experimentalWithEllipsisMenuMinLevel + : 0, + } ), + [ + __experimentalWithBlockNavigationSlots, + __experimentalWithEllipsisMenu, + __experimentalWithEllipsisMenuMinLevel, + ] ); return ( diff --git a/packages/block-editor/src/components/block-settings-menu-controls/index.js b/packages/block-editor/src/components/block-settings-menu-controls/index.js index 310d295b3dca52..fe64c785c0886f 100644 --- a/packages/block-editor/src/components/block-settings-menu-controls/index.js +++ b/packages/block-editor/src/components/block-settings-menu-controls/index.js @@ -13,14 +13,16 @@ const { Fill: BlockSettingsMenuControls, Slot } = createSlotFill( 'BlockSettingsMenuControls' ); -const BlockSettingsMenuControlsSlot = ( { fillProps } ) => { +const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => { const { selectedBlocks } = useSelect( ( select ) => { const { getBlocksByClientId, getSelectedBlockClientIds } = select( 'core/block-editor' ); + const ids = + clientIds !== null ? clientIds : getSelectedBlockClientIds(); return { selectedBlocks: map( - getBlocksByClientId( getSelectedBlockClientIds() ), + getBlocksByClientId( ids ), ( block ) => block.name ), }; diff --git a/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js new file mode 100644 index 00000000000000..e9e3ae9b235a9b --- /dev/null +++ b/packages/block-editor/src/components/block-settings-menu/block-settings-dropdown.js @@ -0,0 +1,174 @@ +/** + * External dependencies + */ +import { castArray, flow } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __, _n } from '@wordpress/i18n'; +import { + DropdownMenu, + MenuGroup, + MenuItem, + ClipboardButton, +} from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { moreHorizontal } from '@wordpress/icons'; +import { useState } from '@wordpress/element'; +import { serialize } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import BlockActions from '../block-actions'; +import BlockModeToggle from './block-mode-toggle'; +import BlockHTMLConvertButton from './block-html-convert-button'; +import BlockUnknownConvertButton from './block-unknown-convert-button'; +import __experimentalBlockSettingsMenuFirstItem from './block-settings-menu-first-item'; +import BlockSettingsMenuControls from '../block-settings-menu-controls'; + +const POPOVER_PROPS = { + className: 'block-editor-block-settings-menu__popover', + position: 'bottom right', + isAlternate: true, +}; + +export function BlockSettingsDropdown( { clientIds, ...props } ) { + const blockClientIds = castArray( clientIds ); + const count = blockClientIds.length; + const firstBlockClientId = blockClientIds[ 0 ]; + + const shortcuts = useSelect( ( select ) => { + const { getShortcutRepresentation } = select( + 'core/keyboard-shortcuts' + ); + return { + duplicate: getShortcutRepresentation( + 'core/block-editor/duplicate' + ), + remove: getShortcutRepresentation( 'core/block-editor/remove' ), + insertAfter: getShortcutRepresentation( + 'core/block-editor/insert-after' + ), + insertBefore: getShortcutRepresentation( + 'core/block-editor/insert-before' + ), + }; + }, [] ); + + const [ hasCopied, setHasCopied ] = useState(); + + return ( + + { ( { + canDuplicate, + canInsertDefaultBlock, + isLocked, + onDuplicate, + onInsertAfter, + onInsertBefore, + onRemove, + blocks, + } ) => ( + + { ( { onClose } ) => ( + <> + + <__experimentalBlockSettingsMenuFirstItem.Slot + fillProps={ { onClose } } + /> + { count === 1 && ( + + ) } + { count === 1 && ( + + ) } + serialize( blocks ) } + role="menuitem" + className="components-menu-item__button" + onCopy={ () => { + setHasCopied( true ); + } } + onFinishCopy={ () => setHasCopied( false ) } + > + { hasCopied + ? __( 'Copied!' ) + : __( 'Copy' ) } + + { canDuplicate && ( + + { __( 'Duplicate' ) } + + ) } + { canInsertDefaultBlock && ( + <> + + { __( 'Insert Before' ) } + + + { __( 'Insert After' ) } + + + ) } + { count === 1 && ( + + ) } + + + + { ! isLocked && ( + + { _n( + 'Remove Block', + 'Remove Blocks', + count + ) } + + ) } + + + ) } + + ) } + + ); +} + +export default BlockSettingsDropdown; diff --git a/packages/block-editor/src/components/block-settings-menu/index.js b/packages/block-editor/src/components/block-settings-menu/index.js index ef235038e6f16a..7014f29f0e3369 100644 --- a/packages/block-editor/src/components/block-settings-menu/index.js +++ b/packages/block-editor/src/components/block-settings-menu/index.js @@ -1,206 +1,29 @@ -/** - * External dependencies - */ -import { castArray, flow } from 'lodash'; - /** * WordPress dependencies */ -import { __, _n } from '@wordpress/i18n'; import { ToolbarGroup, __experimentalToolbarItem as ToolbarItem, - DropdownMenu, - MenuGroup, - MenuItem, - ClipboardButton, } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; -import { moreHorizontal } from '@wordpress/icons'; -import { useState } from '@wordpress/element'; -import { serialize } from '@wordpress/blocks'; /** * Internal dependencies */ -import BlockActions from '../block-actions'; -import BlockModeToggle from './block-mode-toggle'; -import BlockHTMLConvertButton from './block-html-convert-button'; -import BlockUnknownConvertButton from './block-unknown-convert-button'; -import __experimentalBlockSettingsMenuFirstItem from './block-settings-menu-first-item'; -import BlockSettingsMenuControls from '../block-settings-menu-controls'; - -const POPOVER_PROPS = { - className: 'block-editor-block-settings-menu__popover', - position: 'bottom right', - isAlternate: true, -}; - -export function BlockSettingsMenu( { clientIds } ) { - const blockClientIds = castArray( clientIds ); - const count = blockClientIds.length; - const firstBlockClientId = blockClientIds[ 0 ]; - - const shortcuts = useSelect( ( select ) => { - const { getShortcutRepresentation } = select( - 'core/keyboard-shortcuts' - ); - return { - duplicate: getShortcutRepresentation( - 'core/block-editor/duplicate' - ), - remove: getShortcutRepresentation( 'core/block-editor/remove' ), - insertAfter: getShortcutRepresentation( - 'core/block-editor/insert-after' - ), - insertBefore: getShortcutRepresentation( - 'core/block-editor/insert-before' - ), - }; - }, [] ); - - const [ hasCopied, setHasCopied ] = useState(); +import BlockSettingsDropdown from './block-settings-dropdown'; +export function BlockSettingsMenu( { clientIds, ...props } ) { return ( - - { ( { - canDuplicate, - canInsertDefaultBlock, - isLocked, - onDuplicate, - onInsertAfter, - onInsertBefore, - onRemove, - blocks, - } ) => ( - - - { ( toggleProps ) => ( - - { ( { onClose } ) => ( - <> - - <__experimentalBlockSettingsMenuFirstItem.Slot - fillProps={ { onClose } } - /> - { count === 1 && ( - - ) } - { count === 1 && ( - - ) } - - serialize( blocks ) - } - role="menuitem" - className="components-menu-item__button" - onCopy={ () => { - setHasCopied( true ); - } } - onFinishCopy={ () => - setHasCopied( false ) - } - > - { hasCopied - ? __( 'Copied!' ) - : __( 'Copy' ) } - - { canDuplicate && ( - - { __( 'Duplicate' ) } - - ) } - { canInsertDefaultBlock && ( - <> - - { __( - 'Insert Before' - ) } - - - { __( 'Insert After' ) } - - - ) } - { count === 1 && ( - - ) } - - - - { ! isLocked && ( - - { _n( - 'Remove Block', - 'Remove Blocks', - count - ) } - - ) } - - - ) } - - ) } - - - ) } - + + + { ( toggleProps ) => ( + + ) } + + ); } diff --git a/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js b/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js index c3410629834afe..2108f159e2bc5e 100644 --- a/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js +++ b/packages/edit-navigation/src/components/menu-editor/navigation-structure-panel.js @@ -25,7 +25,9 @@ export default function NavigationStructurePanel( { blocks, initialOpen } ) { blocks={ blocks } selectedBlockClientId={ selectedBlockClientIds[ 0 ] } selectBlock={ selectBlock } - __experimentalWithBlockNavigationSlots={ true } + __experimentalWithBlockNavigationSlots + __experimentalWithEllipsisMenu + __experimentalWithEllipsisMenuMinLevel={ 2 } showNestedBlocks showAppender showBlockMovers diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js index 4e386d22cc4f70..e6abef155e7163 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.js @@ -77,7 +77,10 @@ function HeaderToolbar( { onToggleInserter, isInserterOpen } ) { - + { displayBlockToolbar && (