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 && (
+
+ ) }
+ { canInsertDefaultBlock && (
+ <>
+
+
+ >
+ ) }
+ { count === 1 && (
+
+ ) }
+
+
+
+ { ! isLocked && (
+
+ ) }
+
+ >
+ ) }
+
+ ) }
+
+ );
+}
+
+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 && (
-
- ) }
- { canInsertDefaultBlock && (
- <>
-
-
- >
- ) }
- { count === 1 && (
-
- ) }
-
-
-
- { ! isLocked && (
-
- ) }
-
- >
- ) }
-
- ) }
-
-
- ) }
-
+
+
+ { ( 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 && (