Skip to content

Commit

Permalink
Components: Refactor DropdownMenu to stop using unstable props (#15968)
Browse files Browse the repository at this point in the history
* Remove __unstableLabelPosition by reusing position provided for the dropdown menu

* Replaces unstable class names with the documented contentClassName prop

* Refactor DropdownMenu component to allow passing props to nested components

* Add CHANGELOG entries and deprecations messages for update props

* Swap params for mergeProps helper
  • Loading branch information
gziolo authored Aug 12, 2019
1 parent 87e2c15 commit e2c01f7
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import BlockUnknownConvertButton from './block-unknown-convert-button';
import __experimentalBlockSettingsMenuFirstItem from './block-settings-menu-first-item';
import __experimentalBlockSettingsMenuPluginsExtension from './block-settings-menu-plugins-extension';

const POPOVER_PROPS = {
className: 'block-editor-block-settings-menu__popover editor-block-settings-menu__popover',
position: 'bottom right',
};

export function BlockSettingsMenu( { clientIds } ) {
const blockClientIds = castArray( clientIds );
const count = blockClientIds.length;
Expand All @@ -45,11 +50,8 @@ export function BlockSettingsMenu( { clientIds } ) {
<DropdownMenu
icon="ellipsis"
label={ __( 'More options' ) }
position="bottom right"
className="block-editor-block-settings-menu"
__unstableToggleClassName="block-editor-block-settings-menu__toggle editor-block-settings-menu__toggle"
__unstableMenuClassName="block-editor-block-settings-menu__content editor-block-settings-menu__content"
__unstablePopoverClassName="block-editor-block-settings-menu__popover editor-block-settings-menu__popover"
popoverProps={ POPOVER_PROPS }
>
{ ( { onClose } ) => (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.block-editor-block-settings-menu__content {
padding: 0;
.block-editor-block-settings-menu .components-dropdown-menu__toggle .dashicon {
transform: rotate(90deg);
}

.block-editor-block-settings-menu__toggle .dashicon {
transform: rotate(90deg);
.block-editor-block-settings-menu__popover .components-dropdown-menu__menu {
padding: 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import { orderBy } from 'lodash';
import { __ } from '@wordpress/i18n';
import { Toolbar, Slot, DropdownMenu } from '@wordpress/components';

const POPOVER_PROPS = {
position: 'bottom left',
};

const FormatToolbar = () => {
return (
<div className="editor-format-toolbar block-editor-format-toolbar">
Expand All @@ -22,9 +26,9 @@ const FormatToolbar = () => {
{ ( fills ) => fills.length !== 0 &&
<DropdownMenu
icon={ false }
position="bottom left"
label={ __( 'More Rich Text Controls' ) }
controls={ orderBy( fills.map( ( [ { props } ] ) => props ), 'title' ) }
popoverProps={ POPOVER_PROPS }
/>
}
</Slot>
Expand Down
10 changes: 9 additions & 1 deletion packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

### New Features

- Added a new `popoverProps` prop to the `Dropdown` component which allows users of the `Dropdown` component to pass props directly to the `PopOver` component.
- Added a new `popoverProps` prop to the `Dropdown` component which allows users of the `Dropdown` component to pass props directly to the `Popover` component.
- Added and documented `hideLabelFromVision` prop to `BaseControl` used by `SelectControl`, `TextControl`, and `TextareaControl`.
- Added a new `popoverProps` prop to the `DropdownMenu` component which allows to pass props directly to the nested `Popover` component.
- Added a new `toggleProps` prop to the `DropdownMenu` component which allows to pass props directly to the nested `IconButton` component.
- Added a new `menuProps` prop to the `DropdownMenu` component which allows to pass props directly to the nested `NavigableMenu` component.

### Deprecations

- `menuLabel` prop in `DropdownComponent` has been deprecated. Consider using `menuProps` object and its `aria-label` property instead.
- `position` prop in `DropdownComponent` has been deprecated. Consider using `popoverProps` object and its `position` property instead.

### Bug Fixes

Expand Down
41 changes: 25 additions & 16 deletions packages/components/src/dropdown-menu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,21 +163,6 @@ 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.
Expand All @@ -202,7 +187,31 @@ See also: [https://developer.wordpress.org/resource/dashicons/](https://develope

#### className

A class name to apply to the dropdown wrapper element.
A class name to apply to the dropdown menu's toggle element wrapper.

- Type: `String`
- Required: No

#### popoverProps

Properties of `popoverProps` object will be passed as props to the nested `Popover` component.
Use this object to modify props available for the `Popover` component that are not already exposed in the `DropdownMenu` component, e.g.: the direction in which the popover should open relative to its parent node set with `position` prop.

- Type: `Object`
- Required: No

#### toggleProps

Properties of `toggleProps` object will be passed as props to the nested `IconButton` component in the `renderToggle` implementation of the `Dropdown` component used internally.
Use this object to modify props available for the `IconButton` component that are not already exposed in the `DropdownMenu` component, e.g.: the tooltip text displayed on hover set with `tooltip` prop.

- Type: `Object`
- Required: No

#### menuProps

Properties of `menuProps` object will be passed as props to the nested `NavigableMenu` component in the `renderContent` implementation of the `Dropdown` component used internally.
Use this object to modify props available for the `NavigableMenu` component that are not already exposed in the `DropdownMenu` component, e.g.: the orientation of the menu set with `orientation` prop.

- Type: `Object`
- Required: No
63 changes: 50 additions & 13 deletions packages/components/src/dropdown-menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { flatMap, isEmpty, isFunction } from 'lodash';
* WordPress dependencies
*/
import { DOWN } from '@wordpress/keycodes';
import deprecated from '@wordpress/deprecated';

/**
* Internal dependencies
Expand All @@ -16,20 +17,47 @@ import IconButton from '../icon-button';
import Dropdown from '../dropdown';
import { NavigableMenu } from '../navigable-container';

function mergeProps( defaultProps = {}, props = {} ) {
const mergedProps = {
...defaultProps,
...props,
};

if ( props.className && defaultProps.className ) {
mergedProps.className = classnames( props.className, defaultProps.className );
}

return mergedProps;
}

function DropdownMenu( {
children,
className,
controls,
hasArrowIndicator = false,
icon = 'menu',
label,
popoverProps,
toggleProps,
menuProps,
// The following props exist for backward compatibility.
menuLabel,
position,
__unstableLabelPosition,
__unstableMenuClassName,
__unstablePopoverClassName,
__unstableToggleClassName,
} ) {
if ( menuLabel ) {
deprecated( '`menuLabel` prop in `DropdownComponent`', {
alternative: '`menuProps` object and its `aria-label` property',
plugin: 'Gutenberg',
} );
}

if ( position ) {
deprecated( '`position` prop in `DropdownComponent`', {
alternative: '`popoverProps` object and its `position` property',
plugin: 'Gutenberg',
} );
}

if ( isEmpty( controls ) && ! isFunction( children ) ) {
return null;
}
Expand All @@ -42,12 +70,15 @@ function DropdownMenu( {
controlSets = [ controlSets ];
}
}
const mergedPopoverProps = mergeProps( {
className: 'components-dropdown-menu__popover',
position,
}, popoverProps );

return (
<Dropdown
className={ classnames( 'components-dropdown-menu', className ) }
contentClassName={ classnames( 'components-dropdown-menu__popover', __unstablePopoverClassName ) }
position={ position }
popoverProps={ mergedPopoverProps }
renderToggle={ ( { isOpen, onToggle } ) => {
const openOnArrowDown = ( event ) => {
if ( ! isOpen && event.keyCode === DOWN ) {
Expand All @@ -56,31 +87,37 @@ function DropdownMenu( {
onToggle();
}
};
const mergedToggleProps = mergeProps( {
className: classnames( 'components-dropdown-menu__toggle', {
'is-opened': isOpen,
} ),
tooltip: label,
}, toggleProps );

return (
<IconButton
className={ classnames( 'components-dropdown-menu__toggle', __unstableToggleClassName, {
'is-opened': isOpen,
} ) }
{ ...mergedToggleProps }
icon={ icon }
onClick={ onToggle }
onKeyDown={ openOnArrowDown }
aria-haspopup="true"
aria-expanded={ isOpen }
label={ label }
labelPosition={ __unstableLabelPosition }
tooltip={ label }
>
{ ( ! icon || hasArrowIndicator ) && <span className="components-dropdown-menu__indicator" /> }
</IconButton>
);
} }
renderContent={ ( props ) => {
const mergedMenuProps = mergeProps( {
'aria-label': menuLabel || label,
className: 'components-dropdown-menu__menu',
}, menuProps );

return (
<NavigableMenu
className={ classnames( 'components-dropdown-menu__menu', __unstableMenuClassName ) }
{ ...mergedMenuProps }
role="menu"
aria-label={ menuLabel || label }
>
{
isFunction( children ) ?
Expand Down
2 changes: 1 addition & 1 deletion packages/e2e-tests/specs/block-grouping.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ describe( 'Block Grouping', () => {
it( 'does not show group option in the options toolbar if Grouping block is disabled ', async () => {
await clickBlockToolbarButton( 'More options' );

const blockOptionsDropdownHTML = await page.evaluate( () => document.querySelector( '.block-editor-block-settings-menu__content' ).innerHTML );
const blockOptionsDropdownHTML = await page.evaluate( () => document.querySelector( '.block-editor-block-settings-menu__popover' ).innerHTML );

expect( blockOptionsDropdownHTML ).not.toContain( 'Group' );
} );
Expand Down
13 changes: 10 additions & 3 deletions packages/edit-post/src/components/header/more-menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ import ToolsMoreMenuGroup from '../tools-more-menu-group';
import OptionsMenuItem from '../options-menu-item';
import WritingMenu from '../writing-menu';

const POPOVER_PROPS = {
className: 'edit-post-more-menu__content',
position: 'bottom left',
};
const TOGGLE_PROPS = {
labelPosition: 'bottom',
};

const MoreMenu = () => (
<DropdownMenu
className="edit-post-more-menu"
position="bottom left"
icon="ellipsis"
label={ __( 'More tools & options' ) }
__unstableLabelPosition="bottom"
__unstablePopoverClassName="edit-post-more-menu__content"
popoverProps={ POPOVER_PROPS }
toggleProps={ TOGGLE_PROPS }
>
{ ( { onClose } ) => (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,29 @@
exports[`MoreMenu should match snapshot 1`] = `
<MoreMenu>
<DropdownMenu
__unstableLabelPosition="bottom"
__unstablePopoverClassName="edit-post-more-menu__content"
className="edit-post-more-menu"
icon="ellipsis"
label="More tools & options"
position="bottom left"
popoverProps={
Object {
"className": "edit-post-more-menu__content",
"position": "bottom left",
}
}
toggleProps={
Object {
"labelPosition": "bottom",
}
}
>
<Dropdown
className="components-dropdown-menu edit-post-more-menu"
contentClassName="components-dropdown-menu__popover edit-post-more-menu__content"
position="bottom left"
popoverProps={
Object {
"className": "edit-post-more-menu__content components-dropdown-menu__popover",
"position": "bottom left",
}
}
renderContent={[Function]}
renderToggle={[Function]}
>
Expand Down

0 comments on commit e2c01f7

Please sign in to comment.