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 && ( - - { __( 'Duplicate' ) } - - ) } - { ! isLocked && ( - <> - - { __( 'Insert Before' ) } - - - { __( 'Insert After' ) } - - - ) } - { count === 1 && ( - - ) } - <__experimentalBlockSettingsMenuPluginsExtension.Slot fillProps={ { clientIds, onClose } } /> -
- { ! isLocked && ( - - { __( 'Remove Block' ) } - - ) } - - ) } - /> + + + { ( { onClose } ) => ( + <> + + <__experimentalBlockSettingsMenuFirstItem.Slot + fillProps={ { onClose } } + /> + { count === 1 && ( + + ) } + { count === 1 && ( + + ) } + { ! isLocked && canDuplicate && ( + + { __( 'Duplicate' ) } + + ) } + { ! isLocked && ( + <> + + { __( 'Insert Before' ) } + + + { __( 'Insert After' ) } + + + ) } + { count === 1 && ( + + ) } + <__experimentalBlockSettingsMenuPluginsExtension.Slot + fillProps={ { clientIds, onClose } } + /> + + + { ! isLocked && ( + + { __( 'Remove Block' ) } + + ) } + + + ) } + + ) } ); } -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 } ) => ( + + + + Move Up + + + Move Down + + + + + Remove + + + + ) } + +); +``` + ### 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 }
+ } - +
{ 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" >