diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md
index ac9a9f9f9ebafe..f8f88cb313e74b 100644
--- a/packages/block-editor/CHANGELOG.md
+++ b/packages/block-editor/CHANGELOG.md
@@ -1,3 +1,9 @@
+## Master
+
+### Internal
+
+- Refactored `BlockSettingsMenu` to use `DropdownMenu` from `@wordpress/components`.
+
## 2.0.0 (2019-04-16)
### New Features
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 21899126bae2fa..005be38e380b43 100644
--- a/packages/block-editor/src/components/block-settings-menu/index.js
+++ b/packages/block-editor/src/components/block-settings-menu/index.js
@@ -1,15 +1,18 @@
/**
* External dependencies
*/
-import classnames from 'classnames';
import { castArray, flow } from 'lodash';
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { Toolbar, Dropdown, NavigableMenu, MenuItem } from '@wordpress/components';
-import { withDispatch } from '@wordpress/data';
+import {
+ Toolbar,
+ DropdownMenu,
+ MenuGroup,
+ MenuItem,
+} from '@wordpress/components';
/**
* Internal dependencies
@@ -22,7 +25,7 @@ import BlockUnknownConvertButton from './block-unknown-convert-button';
import __experimentalBlockSettingsMenuFirstItem from './block-settings-menu-first-item';
import __experimentalBlockSettingsMenuPluginsExtension from './block-settings-menu-plugins-extension';
-export function BlockSettingsMenu( { clientIds, onSelect } ) {
+export function BlockSettingsMenu( { clientIds } ) {
const blockClientIds = castArray( clientIds );
const count = blockClientIds.length;
const firstBlockClientId = blockClientIds[ 0 ];
@@ -30,105 +33,91 @@ export function BlockSettingsMenu( { clientIds, onSelect } ) {
return (
{ ( { onDuplicate, onRemove, onInsertAfter, onInsertBefore, canDuplicate, isLocked } ) => (
- {
- const toggleClassname = classnames( 'editor-block-settings-menu__toggle block-editor-block-settings-menu__toggle', {
- 'is-opened': isOpen,
- } );
- const label = isOpen ? __( 'Hide options' ) : __( 'More options' );
-
- return (
- {
- if ( count === 1 ) {
- onSelect( firstBlockClientId );
- }
- onToggle();
- },
- className: toggleClassname,
- extraProps: { 'aria-expanded': isOpen },
- } ] } />
- );
- } }
- renderContent={ ( { onClose } ) => (
-
- <__experimentalBlockSettingsMenuFirstItem.Slot fillProps={ { onClose } } />
- { count === 1 && (
-
- ) }
- { count === 1 && (
-
- ) }
- { ! isLocked && canDuplicate && (
-
- ) }
- { ! isLocked && (
- <>
-
-
- >
- ) }
- { count === 1 && (
-
- ) }
- <__experimentalBlockSettingsMenuPluginsExtension.Slot fillProps={ { clientIds, onClose } } />
-
- { ! isLocked && (
-
- ) }
-
- ) }
- />
+
+
+ { ( { onClose } ) => (
+ <>
+
+ <__experimentalBlockSettingsMenuFirstItem.Slot
+ fillProps={ { onClose } }
+ />
+ { count === 1 && (
+
+ ) }
+ { count === 1 && (
+
+ ) }
+ { ! isLocked && canDuplicate && (
+
+ ) }
+ { ! isLocked && (
+ <>
+
+
+ >
+ ) }
+ { count === 1 && (
+
+ ) }
+ <__experimentalBlockSettingsMenuPluginsExtension.Slot
+ fillProps={ { clientIds, onClose } }
+ />
+
+
+ { ! isLocked && (
+
+ ) }
+
+ >
+ ) }
+
+
) }
);
}
-export default withDispatch( ( dispatch ) => {
- const { selectBlock } = dispatch( 'core/block-editor' );
-
- return {
- onSelect( clientId ) {
- selectBlock( clientId );
- },
- };
-} )( BlockSettingsMenu );
+export default BlockSettingsMenu;
diff --git a/packages/block-editor/src/components/block-settings-menu/style.scss b/packages/block-editor/src/components/block-settings-menu/style.scss
index 197303805352e6..0b690745012edd 100644
--- a/packages/block-editor/src/components/block-settings-menu/style.scss
+++ b/packages/block-editor/src/components/block-settings-menu/style.scss
@@ -1,59 +1,7 @@
-.block-editor-block-settings-menu__toggle .dashicon {
- transform: rotate(90deg);
+.block-editor-block-settings-menu__content {
+ padding: 0;
}
-// Popout menu
-.block-editor-block-settings-menu__popover {
- &::before,
- &::after {
- margin-left: 2px;
- }
-
- .block-editor-block-settings-menu__content {
- padding: ($grid-size - $border-width) 0;
- }
-
- .block-editor-block-settings-menu__separator {
- margin-top: $grid-size;
- margin-bottom: $grid-size;
- margin-left: 0;
- margin-right: 0;
- border-top: $border-width solid $light-gray-500;
-
- // Check if the separator is the last child in the node and if so, hide itself
- &:last-child {
- display: none;
- }
- }
-
- .block-editor-block-settings-menu__title {
- display: block;
- padding: 6px;
- color: $dark-gray-300;
- }
-
- // Menu items
- .block-editor-block-settings-menu__control {
- width: 100%;
- justify-content: flex-start;
- background: none;
- outline: none;
- border-radius: 0;
- text-align: left;
- cursor: pointer;
- color: $dark-gray-600;
- @include menu-style__neutral;
-
- &:hover:not(:disabled):not([aria-disabled="true"]) {
- @include menu-style__hover;
- }
-
- &:focus:not(:disabled):not([aria-disabled="true"]) {
- @include menu-style__focus;
- }
-
- .dashicon {
- margin-right: 5px;
- }
- }
+.block-editor-block-settings-menu__toggle .dashicon {
+ transform: rotate(90deg);
}
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index e6c72c7dbb190d..e6db0bcd0c8ff4 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -3,6 +3,16 @@
### New Feature
- Add new `BlockQuotation` block to the primitives folder to support blockquote in a multiplatform way. [#15482](https://github.com/WordPress/gutenberg/pull/15482).
+- `DropdownMenu` now supports passing a [render prop](https://reactjs.org/docs/render-props.html#using-props-other-than-render) as children for more advanced customization.
+
+### Internal
+
+- `MenuGroup` no longer uses `NavigableMenu` internally. It needs to be explicitly wrapped with `NavigableMenu` to bring back the same behavior.
+
+### Documentation
+
+- Added missing documentation for `DropdownMenu` props `menuLabel`, `position`, `className`.
+
## 7.4.0 (2019-05-21)
diff --git a/packages/components/src/dropdown-menu/README.md b/packages/components/src/dropdown-menu/README.md
index 9346140bb27ef0..4e2243c653b2f4 100644
--- a/packages/components/src/dropdown-menu/README.md
+++ b/packages/components/src/dropdown-menu/README.md
@@ -91,6 +91,47 @@ const MyDropdownMenu = () => (
);
```
+Alternatively, specify a `children` function which returns elements valid for use in a DropdownMenu: `MenuItem`, `MenuItemsChoice`, or `MenuGroup`.
+
+```jsx
+import { Fragment } from '@wordpress/element';
+import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
+
+const MyDropdownMenu = () => (
+
+ { ( { onClose } ) => (
+
+
+
+
+
+
+
+
+
+ ) }
+
+);
+```
+
### Props
The component accepts the following props:
@@ -112,13 +153,46 @@ A human-readable label to present as accessibility text on the focused collapsed
- Type: `String`
- Required: Yes
+#### menuLabel
+
+A human-readable label to present as accessibility text on the expanded menu container.
+
+- Type: `String`
+- Required: No
+
+#### position
+
+The direction in which the menu should open. Specify y- and x-axis as a space-separated string. Supports `"top"`, `"middle"`, `"bottom"` y axis, and `"left"`, `"center"`, `"right"` x axis.
+
+- Type: `String`
+- Required: No
+- Default: `"top center"`
+
#### controls
An array of objects describing the options to be shown in the expanded menu.
Each object should include an `icon` [Dashicon](https://developer.wordpress.org/resource/dashicons/) slug string, a human-readable `title` string, `isDisabled` boolean flag and an `onClick` function callback to invoke when the option is selected.
+A valid DropdownMenu must specify one or the other of a `controls` or `children` prop.
+
- Type: `Array`
-- Required: Yes
+- Required: No
+
+#### children
+
+A [function render prop](https://reactjs.org/docs/render-props.html#using-props-other-than-render) which should return an element or elements valid for use in a DropdownMenu: `MenuItem`, `MenuItemsChoice`, or `MenuGroup`. Its first argument is a props object including the same values as given to a [`Dropdown`'s `renderContent`](/packages/components/src/dropdown#rendercontent) (`isOpen`, `onToggle`, `onClose`).
+
+A valid DropdownMenu must specify one or the other of a `controls` or `children` prop.
+
+- Type: `Function`
+- Required: No
See also: [https://developer.wordpress.org/resource/dashicons/](https://developer.wordpress.org/resource/dashicons/)
+
+#### className
+
+A class name to apply to the dropdown wrapper element.
+
+- Type: `String`
+- Required: No
diff --git a/packages/components/src/dropdown-menu/index.js b/packages/components/src/dropdown-menu/index.js
index e301935a0ac60d..8195a309ec0241 100644
--- a/packages/components/src/dropdown-menu/index.js
+++ b/packages/components/src/dropdown-menu/index.js
@@ -2,7 +2,7 @@
* External dependencies
*/
import classnames from 'classnames';
-import { flatMap } from 'lodash';
+import { flatMap, isEmpty, isFunction } from 'lodash';
/**
* WordPress dependencies
@@ -17,27 +17,35 @@ import Dropdown from '../dropdown';
import { NavigableMenu } from '../navigable-container';
function DropdownMenu( {
+ children,
+ className,
+ controls,
icon = 'menu',
label,
menuLabel,
- controls,
- className,
position,
+ __unstableLabelPosition,
+ __unstableMenuClassName,
+ __unstablePopoverClassName,
+ __unstableToggleClassName,
} ) {
- if ( ! controls || ! controls.length ) {
+ if ( isEmpty( controls ) && ! isFunction( children ) ) {
return null;
}
// Normalize controls to nested array of objects (sets of controls)
- let controlSets = controls;
- if ( ! Array.isArray( controlSets[ 0 ] ) ) {
- controlSets = [ controlSets ];
+ let controlSets;
+ if ( ! isEmpty( controls ) ) {
+ controlSets = controls;
+ if ( ! Array.isArray( controlSets[ 0 ] ) ) {
+ controlSets = [ controlSets ];
+ }
}
return (
{
const openOnArrowDown = ( event ) => {
@@ -47,35 +55,44 @@ function DropdownMenu( {
onToggle();
}
};
+
return (
-
+ { ! icon && }
);
} }
- renderContent={ ( { onClose } ) => {
+ renderContent={ ( props ) => {
return (
+ {
+ isFunction( children ) ?
+ children( props ) :
+ null
+ }
{ flatMap( controlSets, ( controlSet, indexOfSet ) => (
controlSet.map( ( control, indexOfControl ) => (
{
event.stopPropagation();
- onClose();
+ props.onClose();
if ( control.onClick ) {
control.onClick();
}
diff --git a/packages/components/src/dropdown-menu/style.scss b/packages/components/src/dropdown-menu/style.scss
index 3a1ac01f332e6c..34f58970bf9f40 100644
--- a/packages/components/src/dropdown-menu/style.scss
+++ b/packages/components/src/dropdown-menu/style.scss
@@ -36,18 +36,20 @@
}
}
}
+
.components-dropdown-menu__popover .components-popover__content {
width: 200px;
}
.components-dropdown-menu__menu {
width: 100%;
- padding: 9px;
+ padding: ($grid-size - $border-width) 0;
font-family: $default-font;
font-size: $default-font-size;
line-height: $default-line-height;
- .components-dropdown-menu__menu-item {
+ .components-dropdown-menu__menu-item,
+ .components-menu-item {
width: 100%;
padding: 6px;
outline: none;
@@ -92,4 +94,16 @@
@include formatting-button-style__active();
}
}
+
+ .components-menu-group:not(:last-child) {
+ border-bottom: $border-width solid $light-gray-500;
+ }
+
+ .components-menu-item__button {
+ padding-left: 2rem;
+
+ &.has-icon {
+ padding-left: 0.5rem;
+ }
+ }
}
diff --git a/packages/components/src/dropdown-menu/test/index.js b/packages/components/src/dropdown-menu/test/index.js
index ef8e900de24f9f..74e0089eed68bb 100644
--- a/packages/components/src/dropdown-menu/test/index.js
+++ b/packages/components/src/dropdown-menu/test/index.js
@@ -1,21 +1,22 @@
/**
* External dependencies
*/
-import { shallow } from 'enzyme';
-import TestUtils from 'react-dom/test-utils';
+import { shallow, mount } from 'enzyme';
/**
* WordPress dependencies
*/
import { DOWN } from '@wordpress/keycodes';
-import { Component } from '@wordpress/element';
/**
* Internal dependencies
*/
import DropdownMenu from '../';
+import { IconButton, MenuItem, NavigableMenu } from '../../';
describe( 'DropdownMenu', () => {
+ const children = ( { onClose } ) => ;
+
let controls;
beforeEach( () => {
controls = [
@@ -43,42 +44,48 @@ describe( 'DropdownMenu', () => {
} );
describe( 'basic rendering', () => {
- it( 'should render a null element when controls are not assigned', () => {
+ it( 'should render a null element when neither controls nor children are assigned', () => {
const wrapper = shallow( );
expect( wrapper.type() ).toBeNull();
} );
- it( 'should render a null element when controls are empty', () => {
+ it( 'should render a null element when controls are empty and children is not specified', () => {
const wrapper = shallow( );
expect( wrapper.type() ).toBeNull();
} );
- it( 'should open menu on arrow down', () => {
- // needed because TestUtils.renderIntoDocument returns null for stateless
- // components
- class Menu extends Component {
- render() {
- return ;
- }
- }
- const wrapper = TestUtils.renderIntoDocument( );
- const buttonElement = TestUtils.findRenderedDOMComponentWithClass(
- wrapper,
- 'components-dropdown-menu__toggle'
- );
- // Close menu by keyup
- TestUtils.Simulate.keyDown(
- buttonElement,
- {
- stopPropagation: () => {},
- preventDefault: () => {},
- keyCode: DOWN,
- }
- );
-
- expect( TestUtils.scryRenderedDOMComponentsWithClass( wrapper, 'components-popover' ) ).toHaveLength( 1 );
+ it( 'should open menu on arrow down (controls)', () => {
+ const wrapper = mount( );
+ const button = wrapper.find( IconButton ).filter( '.components-dropdown-menu__toggle' );
+
+ button.simulate( 'keydown', {
+ stopPropagation: () => {},
+ preventDefault: () => {},
+ keyCode: DOWN,
+ } );
+
+ expect( wrapper.find( NavigableMenu ) ).toHaveLength( 1 );
+ expect( wrapper.find( IconButton ).filter( '.components-dropdown-menu__menu-item' ) ).toHaveLength( controls.length );
+ } );
+
+ it( 'should open menu on arrow down (children)', () => {
+ const wrapper = mount( );
+ const button = wrapper.find( IconButton ).filter( '.components-dropdown-menu__toggle' );
+
+ button.simulate( 'keydown', {
+ stopPropagation: () => {},
+ preventDefault: () => {},
+ keyCode: DOWN,
+ } );
+
+ expect( wrapper.find( NavigableMenu ) ).toHaveLength( 1 );
+
+ wrapper.find( MenuItem ).props().onClick();
+ wrapper.update();
+
+ expect( wrapper.find( NavigableMenu ) ).toHaveLength( 0 );
} );
} );
} );
diff --git a/packages/components/src/menu-group/index.js b/packages/components/src/menu-group/index.js
index f5b2aff60337ed..ba98c5fea4fd22 100644
--- a/packages/components/src/menu-group/index.js
+++ b/packages/components/src/menu-group/index.js
@@ -9,11 +9,6 @@ import classnames from 'classnames';
import { Children } from '@wordpress/element';
import { withInstanceId } from '@wordpress/compose';
-/**
- * Internal dependencies
- */
-import { NavigableMenu } from '../navigable-container';
-
export function MenuGroup( {
children,
className = '',
@@ -33,11 +28,17 @@ export function MenuGroup( {
return (
{ label &&
-
{ label }
+
+ { label }
+
}
-
+
{ children }
-
+
);
}
diff --git a/packages/components/src/menu-group/test/__snapshots__/index.js.snap b/packages/components/src/menu-group/test/__snapshots__/index.js.snap
index c33b2fcad917cd..4a0c0e751a2667 100644
--- a/packages/components/src/menu-group/test/__snapshots__/index.js.snap
+++ b/packages/components/src/menu-group/test/__snapshots__/index.js.snap
@@ -5,18 +5,19 @@ exports[`MenuGroup should match snapshot 1`] = `
className="components-menu-group"
>
-
My item
-
+
`;
diff --git a/packages/components/src/menu-item/style.scss b/packages/components/src/menu-item/style.scss
index 7ef38dfc8c3036..8424da18a6f02d 100644
--- a/packages/components/src/menu-item/style.scss
+++ b/packages/components/src/menu-item/style.scss
@@ -10,7 +10,7 @@
.dashicon,
.components-menu-items__item-icon,
> span > svg {
- margin-right: 4px;
+ margin-right: 5px;
}
.components-menu-items__item-icon {
diff --git a/packages/e2e-test-utils/src/click-on-more-menu-item.js b/packages/e2e-test-utils/src/click-on-more-menu-item.js
index 0465441ec64965..2e9ef6c946499b 100644
--- a/packages/e2e-test-utils/src/click-on-more-menu-item.js
+++ b/packages/e2e-test-utils/src/click-on-more-menu-item.js
@@ -10,7 +10,7 @@ import { first } from 'lodash';
*/
export async function clickOnMoreMenuItem( buttonLabel ) {
await expect( page ).toClick(
- '.edit-post-more-menu [aria-label="Show more tools & options"]'
+ '.edit-post-more-menu [aria-label="More tools & options"]'
);
const moreMenuContainerSelector =
'//*[contains(concat(" ", @class, " "), " edit-post-more-menu__content ")]';
diff --git a/packages/e2e-test-utils/src/switch-editor-mode-to.js b/packages/e2e-test-utils/src/switch-editor-mode-to.js
index 6978b2ee812472..c0ddfa274c9c2b 100644
--- a/packages/e2e-test-utils/src/switch-editor-mode-to.js
+++ b/packages/e2e-test-utils/src/switch-editor-mode-to.js
@@ -5,7 +5,7 @@
*/
export async function switchEditorModeTo( mode ) {
await page.click(
- '.edit-post-more-menu [aria-label="Show more tools & options"]'
+ '.edit-post-more-menu [aria-label="More tools & options"]'
);
const [ button ] = await page.$x(
`//button[contains(text(), '${ mode } Editor')]`
diff --git a/packages/e2e-tests/specs/adding-blocks.test.js b/packages/e2e-tests/specs/adding-blocks.test.js
index aeafc65cd8cc39..332dab5083f3ba 100644
--- a/packages/e2e-tests/specs/adding-blocks.test.js
+++ b/packages/e2e-tests/specs/adding-blocks.test.js
@@ -97,7 +97,7 @@ describe( 'adding blocks', () => {
await page.keyboard.type( 'Second paragraph' );
// Switch to Text Mode to check HTML Output
- await page.click( '.edit-post-more-menu [aria-label="Show more tools & options"]' );
+ await page.click( '.edit-post-more-menu [aria-label="More tools & options"]' );
const codeEditorButton = ( await page.$x( "//button[contains(text(), 'Code Editor')]" ) )[ 0 ];
await codeEditorButton.click( 'button' );
diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js
index 6adcb01681bb2a..194ff847328c18 100644
--- a/packages/e2e-tests/specs/block-deletion.test.js
+++ b/packages/e2e-tests/specs/block-deletion.test.js
@@ -3,6 +3,7 @@
*/
import {
clickBlockAppender,
+ clickBlockToolbarButton,
getEditedPostContent,
createNewPost,
isInDefaultBlock,
@@ -22,7 +23,7 @@ const addThreeParagraphsToNewPost = async () => {
};
const clickOnBlockSettingsMenuItem = async ( buttonLabel ) => {
- await expect( page ).toClick( '.block-editor-block-settings-menu__toggle' );
+ await clickBlockToolbarButton( 'More options' );
const itemButton = ( await page.$x( `//*[contains(@class, "block-editor-block-settings-menu__popover")]//button[contains(text(), '${ buttonLabel }')]` ) )[ 0 ];
await itemButton.click();
};
diff --git a/packages/e2e-tests/specs/blocks/preformatted.test.js b/packages/e2e-tests/specs/blocks/preformatted.test.js
index a5f9965af3c519..ea6575785613cf 100644
--- a/packages/e2e-tests/specs/blocks/preformatted.test.js
+++ b/packages/e2e-tests/specs/blocks/preformatted.test.js
@@ -2,6 +2,7 @@
* WordPress dependencies
*/
import {
+ clickBlockToolbarButton,
getEditedPostContent,
createNewPost,
insertBlock,
@@ -21,16 +22,12 @@ describe( 'Preformatted', () => {
expect( await getEditedPostContent() ).toMatchSnapshot();
- await page.keyboard.press( 'Escape' );
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
await clickButton( 'Convert to Blocks' );
// Once it's edited, it should be saved as BR tags.
await page.keyboard.type( '0' );
await page.keyboard.press( 'Enter' );
- await page.keyboard.press( 'Escape' );
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
await clickButton( 'Edit as HTML' );
expect( await getEditedPostContent() ).toMatchSnapshot();
diff --git a/packages/e2e-tests/specs/editor-modes.test.js b/packages/e2e-tests/specs/editor-modes.test.js
index 1bb525123e197d..eda64312514c98 100644
--- a/packages/e2e-tests/specs/editor-modes.test.js
+++ b/packages/e2e-tests/specs/editor-modes.test.js
@@ -3,6 +3,7 @@
*/
import {
clickBlockAppender,
+ clickBlockToolbarButton,
createNewPost,
switchEditorModeTo,
} from '@wordpress/e2e-test-utils';
@@ -23,8 +24,7 @@ describe( 'Editing modes (visual/HTML)', () => {
await page.keyboard.press( 'Escape' );
// Change editing mode from "Visual" to "HTML".
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
let changeModeButton = await page.waitForXPath( '//button[text()="Edit as HTML"]' );
await changeModeButton.click();
@@ -36,8 +36,7 @@ describe( 'Editing modes (visual/HTML)', () => {
await page.keyboard.press( 'Escape' );
// Change editing mode from "HTML" back to "Visual".
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
changeModeButton = await page.waitForXPath( '//button[text()="Edit visually"]' );
await changeModeButton.click();
@@ -51,8 +50,7 @@ describe( 'Editing modes (visual/HTML)', () => {
await page.keyboard.press( 'Escape' );
// Change editing mode from "Visual" to "HTML".
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
const changeModeButton = await page.waitForXPath( '//button[text()="Edit as HTML"]' );
await changeModeButton.click();
@@ -67,8 +65,7 @@ describe( 'Editing modes (visual/HTML)', () => {
await page.keyboard.press( 'Escape' );
// Change editing mode from "Visual" to "HTML".
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
const changeModeButton = await page.waitForXPath( '//button[text()="Edit as HTML"]' );
await changeModeButton.click();
@@ -101,7 +98,7 @@ describe( 'Editing modes (visual/HTML)', () => {
// Switch to Code Editor and hide More Menu
await switchEditorModeTo( 'Code' );
await page.click(
- '.edit-post-more-menu [aria-label="Hide more tools & options"]'
+ '.edit-post-more-menu [aria-label="More tools & options"]'
);
// The Block inspector should not be active anymore
diff --git a/packages/e2e-tests/specs/keyboard-navigable-blocks.test.js b/packages/e2e-tests/specs/keyboard-navigable-blocks.test.js
index 5253528a615cd0..64d1afcda1a61e 100644
--- a/packages/e2e-tests/specs/keyboard-navigable-blocks.test.js
+++ b/packages/e2e-tests/specs/keyboard-navigable-blocks.test.js
@@ -100,9 +100,7 @@ const tabThroughBlockToolbar = async () => {
// Tab to focus on the 'More formatting' dropdown toggle
await page.keyboard.press( 'Tab' );
const isFocusedBlockSettingsDropdown = await page.evaluate( () =>
- document.activeElement.classList.contains(
- 'block-editor-block-settings-menu__toggle'
- )
+ document.activeElement.classList.contains( 'components-dropdown-menu__toggle' )
);
await expect( isFocusedBlockSettingsDropdown ).toBe( true );
};
diff --git a/packages/e2e-tests/specs/nux.test.js b/packages/e2e-tests/specs/nux.test.js
index d8a64be089ecaf..40c980fac079cc 100644
--- a/packages/e2e-tests/specs/nux.test.js
+++ b/packages/e2e-tests/specs/nux.test.js
@@ -117,7 +117,7 @@ describe( 'New User Experience (NUX)', () => {
await clickAllTips( page );
// Open the "More" menu to check the "Show Tips" element.
- await page.click( '.edit-post-more-menu [aria-label="Show more tools & options"]' );
+ await page.click( '.edit-post-more-menu [aria-label="More tools & options"]' );
const showTipsButton = await page.$x( '//button[contains(text(), "Show Tips")][@aria-pressed="false"]' );
expect( showTipsButton ).toHaveLength( 1 );
@@ -132,7 +132,7 @@ describe( 'New User Experience (NUX)', () => {
await clickOnMoreMenuItem( 'Show Tips' );
// Open the "More" menu to check the "Show Tips" element.
- await page.click( '.edit-post-more-menu [aria-label="Show more tools & options"]' );
+ await page.click( '.edit-post-more-menu [aria-label="More tools & options"]' );
const showTipsButton = await page.$x( '//button[contains(text(), "Show Tips")][@aria-pressed="true"]' );
expect( showTipsButton ).toHaveLength( 1 );
diff --git a/packages/e2e-tests/specs/plugins/annotations.test.js b/packages/e2e-tests/specs/plugins/annotations.test.js
index 65474777d3db1d..5bab673a41d806 100644
--- a/packages/e2e-tests/specs/plugins/annotations.test.js
+++ b/packages/e2e-tests/specs/plugins/annotations.test.js
@@ -3,13 +3,14 @@
*/
import {
activatePlugin,
+ clickBlockToolbarButton,
clickOnMoreMenuItem,
createNewPost,
deactivatePlugin,
} from '@wordpress/e2e-test-utils';
const clickOnBlockSettingsMenuItem = async ( buttonLabel ) => {
- await expect( page ).toClick( '.block-editor-block-settings-menu__toggle' );
+ await clickBlockToolbarButton( 'More options' );
const itemButton = ( await page.$x( `//*[contains(@class, "block-editor-block-settings-menu__popover")]//button[contains(text(), '${ buttonLabel }')]` ) )[ 0 ];
await itemButton.click();
};
diff --git a/packages/e2e-tests/specs/reusable-blocks.test.js b/packages/e2e-tests/specs/reusable-blocks.test.js
index a8ab98c2dd3181..7a9174f5b6246a 100644
--- a/packages/e2e-tests/specs/reusable-blocks.test.js
+++ b/packages/e2e-tests/specs/reusable-blocks.test.js
@@ -155,7 +155,7 @@ describe( 'Reusable Blocks', () => {
await insertBlock( 'Surprised greeting block' );
// Convert block to a regular block
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
const convertButton = await page.waitForXPath(
'//button[text()="Convert to Regular Block"]'
);
@@ -178,7 +178,7 @@ describe( 'Reusable Blocks', () => {
await insertBlock( 'Surprised greeting block' );
// Delete the block and accept the confirmation dialog
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
const deleteButton = await page.waitForXPath( '//button[text()="Remove from Reusable Blocks"]' );
await Promise.all( [ waitForAndAcceptDialog(), deleteButton.click() ] );
@@ -214,8 +214,7 @@ describe( 'Reusable Blocks', () => {
await pressKeyWithModifier( 'primary', 'a' );
// Convert block to a reusable block
- await page.waitForSelector( 'button[aria-label="More options"]' );
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
const convertButton = await page.waitForXPath( '//button[text()="Add to Reusable Blocks"]' );
await convertButton.click();
@@ -256,7 +255,7 @@ describe( 'Reusable Blocks', () => {
await insertBlock( 'Multi-selection reusable block' );
// Convert block to a regular block
- await page.click( 'button[aria-label="More options"]' );
+ await clickBlockToolbarButton( 'More options' );
const convertButton = await page.waitForXPath(
'//button[text()="Convert to Regular Block"]'
);
diff --git a/packages/edit-post/src/components/header/more-menu/index.js b/packages/edit-post/src/components/header/more-menu/index.js
index 9458a73c66b5e3..16d9b16afb77a1 100644
--- a/packages/edit-post/src/components/header/more-menu/index.js
+++ b/packages/edit-post/src/components/header/more-menu/index.js
@@ -2,7 +2,7 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { IconButton, Dropdown, MenuGroup } from '@wordpress/components';
+import { DropdownMenu, MenuGroup } from '@wordpress/components';
/**
* Internal dependencies
@@ -13,24 +13,16 @@ import ToolsMoreMenuGroup from '../tools-more-menu-group';
import OptionsMenuItem from '../options-menu-item';
import WritingMenu from '../writing-menu';
-const ariaClosed = __( 'Show more tools & options' );
-const ariaOpen = __( 'Hide more tools & options' );
-
const MoreMenu = () => (
- (
-
- ) }
- renderContent={ ( { onClose } ) => (
+ icon="ellipsis"
+ label={ __( 'More tools & options' ) }
+ __unstableLabelPosition="bottom"
+ __unstablePopoverClassName="edit-post-more-menu__content"
+ >
+ { ( { onClose } ) => (
<>
@@ -41,7 +33,7 @@ const MoreMenu = () => (
>
) }
- />
+
);
export default MoreMenu;
diff --git a/packages/edit-post/src/components/header/more-menu/style.scss b/packages/edit-post/src/components/header/more-menu/style.scss
index 011e4eeb91337b..a6e9a1cdc68ae3 100644
--- a/packages/edit-post/src/components/header/more-menu/style.scss
+++ b/packages/edit-post/src/components/header/more-menu/style.scss
@@ -29,16 +29,7 @@
max-width: $break-mobile;
}
- .components-menu-group:not(:last-child),
- > div:not(:last-child) .components-menu-group {
- border-bottom: $border-width solid $light-gray-500;
- }
-
- .components-menu-item__button {
- padding-left: 2rem;
-
- &.has-icon {
- padding-left: 0.5rem;
- }
+ .components-dropdown-menu__menu {
+ padding: 0;
}
}
diff --git a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
index 78f197fda6035d..cc17255097c02d 100644
--- a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
+++ b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
@@ -2,64 +2,70 @@
exports[`MoreMenu should match snapshot 1`] = `
-
-
-
-
-
-
-
-
-
-
-
+ >
+
+
+
+
+
+
+
+
+
+
+
+
`;
diff --git a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap
index 6e395b2e7ebae9..0a2564900eda2e 100644
--- a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap
+++ b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap
@@ -5,6 +5,7 @@ exports[`PluginMoreMenuItem renders menu item as button properly 1`] = `
className="components-menu-group"
>