Skip to content

Commit

Permalink
DropdownMenuV2: add GroupLabel subcomponent (WordPress#64854)
Browse files Browse the repository at this point in the history
* DropdownMenuV2: add GroupLabel subcomponent

* Use in Storybook examples

* Use Text component

* Use the first-party group label in the block bindings dropdown menu

* Apply design feedback

* Remove unneeded block-editor-bindings__popover classname

* Add dedicated DropdownMenuGroupLabelProps type

* Fix README

* CHANGELOG

---

Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Co-authored-by: jameskoster <jameskoster@git.wordpress.org>
Co-authored-by: cbravobernal <cbravobernal@git.wordpress.org>
  • Loading branch information
5 people authored and bph committed Aug 31, 2024
1 parent 4f96f2e commit 1ddeda8
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 30 deletions.
10 changes: 2 additions & 8 deletions packages/block-editor/src/hooks/block-bindings.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,9 @@ function BlockBindingsPanelDropdown( { fieldsList, attribute, binding } ) {
<Fragment key={ name }>
<DropdownMenuV2.Group>
{ Object.keys( fieldsList ).length > 1 && (
<Text
className="block-editor-bindings__source-label"
upperCase
variant="muted"
aria-hidden
>
<DropdownMenuV2.GroupLabel>
{ registeredSources[ name ].label }
</Text>
</DropdownMenuV2.GroupLabel>
) }
{ Object.entries( fields ).map( ( [ key, value ] ) => (
<DropdownMenuV2.RadioItem
Expand Down Expand Up @@ -160,7 +155,6 @@ function EditableBlockBindingsPanelItems( {
isMobile ? 'bottom-start' : 'left-start'
}
gutter={ isMobile ? 8 : 36 }
className="block-editor-bindings__popover"
trigger={
<Item>
<BlockBindingsAttribute
Expand Down
8 changes: 0 additions & 8 deletions packages/block-editor/src/hooks/block-bindings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,3 @@ div.block-editor-bindings__panel {
color: inherit;
}
}

.block-editor-bindings__popover {
// This won't be needed if `DropdownMenuGroup` component handles the label.
.block-editor-bindings__source-label {
grid-column: 2;
margin: $grid-unit-10 0;
}
}
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@

- `DropdownMenu` v2: fix flashing menu item styles when using keyboard ([#64873](https://github.com/WordPress/gutenberg/pull/64873)).
- `DropdownMenu` v2: refactor to overloaded naming convention ([#64654](https://github.com/WordPress/gutenberg/pull/64654)).
- `DropdownMenu` v2: add `GroupLabel` subcomponent ([#64854](https://github.com/WordPress/gutenberg/pull/64854)).
- `Composite` V2: fix Storybook docgen ([#64682](https://github.com/WordPress/gutenberg/pull/64682)).

## 28.6.0 (2024-08-21)
Expand Down
18 changes: 16 additions & 2 deletions packages/components/src/dropdown-menu-v2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ The help text contents.

- Required: yes

### `DropdownMenuGroup`
### `DropdownMenuV2.Group`

Used to group menu items.

Expand All @@ -325,6 +325,20 @@ The contents of the group.

- Required: yes

### `DropdownMenuSeparatorProps`
### `DropdownMenuV2.GroupLabel`

Used to render a group label. The label text should be kept as short as possible.

#### Props

The component accepts the following props:

##### `children`: `React.ReactNode`

The contents of the group label.

- Required: yes

### `DropdownMenuV2.Separator`

Used to render a visual separator.
37 changes: 37 additions & 0 deletions packages/components/src/dropdown-menu-v2/group-label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* WordPress dependencies
*/
import { forwardRef, useContext } from '@wordpress/element';

/**
* Internal dependencies
*/
import type { WordPressComponentProps } from '../context';
import { DropdownMenuContext } from './context';
import { Text } from '../text';
import type { DropdownMenuGroupLabelProps } from './types';
import * as Styled from './styles';

export const DropdownMenuGroupLabel = forwardRef<
HTMLDivElement,
WordPressComponentProps< DropdownMenuGroupLabelProps, 'div', false >
>( function DropdownMenuGroup( props, ref ) {
const dropdownMenuContext = useContext( DropdownMenuContext );
return (
<Styled.DropdownMenuGroupLabel
ref={ ref }
render={
// @ts-expect-error The `children` prop is passed
<Text
upperCase
variant="muted"
size="11px"
weight={ 500 }
lineHeight="16px"
/>
}
{ ...props }
store={ dropdownMenuContext?.store }
/>
);
} );
4 changes: 4 additions & 0 deletions packages/components/src/dropdown-menu-v2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { DropdownMenuItem } from './item';
import { DropdownMenuCheckboxItem } from './checkbox-item';
import { DropdownMenuRadioItem } from './radio-item';
import { DropdownMenuGroup } from './group';
import { DropdownMenuGroupLabel } from './group-label';
import { DropdownMenuSeparator } from './separator';
import { DropdownMenuItemLabel } from './item-label';
import { DropdownMenuItemHelpText } from './item-help-text';
Expand Down Expand Up @@ -215,6 +216,9 @@ export const DropdownMenuV2 = Object.assign(
Group: Object.assign( DropdownMenuGroup, {
displayName: 'DropdownMenuV2.Group',
} ),
GroupLabel: Object.assign( DropdownMenuGroupLabel, {
displayName: 'DropdownMenuV2.GroupLabel',
} ),
Separator: Object.assign( DropdownMenuSeparator, {
displayName: 'DropdownMenuV2.Separator',
} ),
Expand Down
45 changes: 33 additions & 12 deletions packages/components/src/dropdown-menu-v2/stories/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const meta: Meta< typeof DropdownMenuV2 > = {
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
Group: DropdownMenuV2.Group,
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
GroupLabel: DropdownMenuV2.GroupLabel,
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
Separator: DropdownMenuV2.Separator,
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
Context: DropdownMenuV2.Context,
Expand Down Expand Up @@ -83,6 +85,7 @@ export const Default: StoryFn< typeof DropdownMenuV2 > = ( props ) => (
<DropdownMenuV2.Item disabled>Disabled item</DropdownMenuV2.Item>
<DropdownMenuV2.Separator />
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>Group label</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.Item
prefix={ <Icon icon={ customLink } size={ 24 } /> }
>
Expand Down Expand Up @@ -182,6 +185,9 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
return (
<DropdownMenuV2 { ...props }>
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>
Single selection, uncontrolled
</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.CheckboxItem
name="checkbox-individual-uncontrolled-a"
value="a"
Expand All @@ -191,7 +197,7 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item A
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Uncontrolled
Initially unchecked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
<DropdownMenuV2.CheckboxItem
Expand All @@ -203,12 +209,15 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item B
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Uncontrolled, initially checked
Initially checked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
</DropdownMenuV2.Group>
<DropdownMenuV2.Separator />
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>
Single selection, controlled
</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.CheckboxItem
name="checkbox-individual-controlled-a"
value="a"
Expand All @@ -219,7 +228,7 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item A
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Controlled
Initially unchecked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
<DropdownMenuV2.CheckboxItem
Expand All @@ -232,12 +241,15 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item B
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Controlled, initially checked
Initially checked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
</DropdownMenuV2.Group>
<DropdownMenuV2.Separator />
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>
Multiple selection, uncontrolled
</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.CheckboxItem
name="checkbox-multiple-uncontrolled"
value="a"
Expand All @@ -246,7 +258,7 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item A
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Uncontrolled, multiple selection
Initially unchecked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
<DropdownMenuV2.CheckboxItem
Expand All @@ -258,12 +270,15 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item B
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Uncontrolled, multiple selection, initially checked
Initially checked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
</DropdownMenuV2.Group>
<DropdownMenuV2.Separator />
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>
Multiple selection, controlled
</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.CheckboxItem
name="checkbox-multiple-controlled"
value="a"
Expand All @@ -274,7 +289,7 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item A
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Controlled, multiple selection
Initially unchecked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
<DropdownMenuV2.CheckboxItem
Expand All @@ -287,7 +302,7 @@ export const WithCheckboxes: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Checkbox item B
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Controlled, multiple selection, initially checked
Initially checked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.CheckboxItem>
</DropdownMenuV2.Group>
Expand All @@ -307,12 +322,15 @@ export const WithRadios: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
return (
<DropdownMenuV2 { ...props }>
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>
Uncontrolled
</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.RadioItem name="radio-uncontrolled" value="one">
<DropdownMenuV2.ItemLabel>
Radio item 1
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Uncontrolled
Initially unchecked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.RadioItem>
<DropdownMenuV2.RadioItem
Expand All @@ -324,12 +342,15 @@ export const WithRadios: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Radio item 2
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Uncontrolled, initially checked
Initially checked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.RadioItem>
</DropdownMenuV2.Group>
<DropdownMenuV2.Separator />
<DropdownMenuV2.Group>
<DropdownMenuV2.GroupLabel>
Controlled
</DropdownMenuV2.GroupLabel>
<DropdownMenuV2.RadioItem
name="radio-controlled"
value="one"
Expand All @@ -340,7 +361,7 @@ export const WithRadios: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Radio item 1
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Controlled
Initially unchecked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.RadioItem>
<DropdownMenuV2.RadioItem
Expand All @@ -353,7 +374,7 @@ export const WithRadios: StoryFn< typeof DropdownMenuV2 > = ( props ) => {
Radio item 2
</DropdownMenuV2.ItemLabel>
<DropdownMenuV2.ItemHelpText>
Controlled, initially checked
Initially checked
</DropdownMenuV2.ItemHelpText>
</DropdownMenuV2.RadioItem>
</DropdownMenuV2.Group>
Expand Down
9 changes: 9 additions & 0 deletions packages/components/src/dropdown-menu-v2/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,15 @@ export const DropdownMenuGroup = styled( Ariakit.MenuGroup )`
display: contents;
`;

export const DropdownMenuGroupLabel = styled( Ariakit.MenuGroupLabel )`
/* Occupy the width of all grid columns (ie. full width) */
grid-column: 1 / -1;
padding-block-start: ${ space( 3 ) };
padding-block-end: ${ space( 2 ) };
padding-inline: ${ ITEM_PADDING_INLINE };
`;

export const DropdownMenuSeparator = styled( Ariakit.MenuSeparator )<
Pick< DropdownMenuContext, 'variant' >
>`
Expand Down
7 changes: 7 additions & 0 deletions packages/components/src/dropdown-menu-v2/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ export interface DropdownMenuGroupProps {
children: React.ReactNode;
}

export interface DropdownMenuGroupLabelProps {
/**
* The contents of the dropdown menu group.
*/
children: React.ReactNode;
}

export interface DropdownMenuItemProps {
/**
* The contents of the menu item.
Expand Down

0 comments on commit 1ddeda8

Please sign in to comment.