Skip to content

Commit cf5d0b0

Browse files
adamsilversteinMamadukat-hamanojasmussenntsekouras
authored
Editor: Gather the View group of the Options menu into submenus (#82976)
Co-authored-by: adamsilverstein <adamsilverstein@git.wordpress.org> Co-authored-by: Mamaduka <mamaduka@git.wordpress.org> Co-authored-by: t-hamano <wildworks@git.wordpress.org> Co-authored-by: jasmussen <joen@git.wordpress.org> Co-authored-by: ntsekouras <ntsekouras@git.wordpress.org>
1 parent ee81f68 commit cf5d0b0

8 files changed

Lines changed: 191 additions & 118 deletions

File tree

‎packages/editor/src/components/more-menu/index.jsx‎

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { Menu } from '@wordpress/ui';
1010
import CopyContentMenuItem from './copy-content-menu-item';
1111
import MoreMenuItem from './more-menu-item';
1212
import ModeSwitcher from '../mode-switcher';
13-
import MoreMenuGroup from './more-menu-group';
1413
import MoreMenuPreferenceItem from './more-menu-preference-item';
14+
import MoreMenuSubmenu, { toMenuItems } from './more-menu-submenu';
1515
import ToolsMoreMenuGroup from './tools-more-menu-group';
1616
import ViewMoreMenuGroup from './view-more-menu-group';
1717
import { store as editorStore } from '../../store';
@@ -69,58 +69,64 @@ export default function MoreMenu( { isRevisionMode = false } ) {
6969
>
7070
<Menu.Group>
7171
<Menu.GroupLabel>{ _x( 'View', 'noun' ) }</Menu.GroupLabel>
72-
<MoreMenuPreferenceItem
73-
scope="core"
74-
name="fixedToolbar"
75-
onToggle={ turnOffDistractionFree }
76-
label={ __( 'Top toolbar' ) }
77-
info={ __(
78-
'Access all block and document tools in a single place'
79-
) }
80-
messageActivated={ __( 'Top toolbar activated.' ) }
81-
messageDeactivated={ __( 'Top toolbar deactivated.' ) }
82-
/>
83-
<MoreMenuPreferenceItem
84-
scope="core"
85-
name="distractionFree"
86-
label={ __( 'Distraction free' ) }
87-
info={ __( 'Write with calmness' ) }
88-
handleToggling={ false }
89-
onToggle={ () =>
90-
toggleDistractionFree( { createNotice: false } )
91-
}
92-
messageActivated={ __(
93-
'Distraction free mode activated.'
94-
) }
95-
messageDeactivated={ __(
96-
'Distraction free mode deactivated.'
97-
) }
98-
shortcut={ keyboardShortcut.primaryShift( '\\' ) }
99-
/>
100-
<MoreMenuPreferenceItem
101-
scope="core"
102-
name="focusMode"
103-
label={ __( 'Spotlight mode' ) }
104-
info={ __( 'Focus on one block at a time' ) }
105-
messageActivated={ __( 'Spotlight mode activated.' ) }
106-
messageDeactivated={ __(
107-
'Spotlight mode deactivated.'
72+
<MoreMenuSubmenu label={ __( 'Appearance' ) }>
73+
<MoreMenuPreferenceItem
74+
scope="core"
75+
name="fixedToolbar"
76+
onToggle={ turnOffDistractionFree }
77+
label={ __( 'Top toolbar' ) }
78+
info={ __(
79+
'Access all block and document tools in a single place'
80+
) }
81+
messageActivated={ __( 'Top toolbar activated.' ) }
82+
messageDeactivated={ __(
83+
'Top toolbar deactivated.'
84+
) }
85+
/>
86+
<MoreMenuPreferenceItem
87+
scope="core"
88+
name="distractionFree"
89+
label={ __( 'Distraction free' ) }
90+
info={ __( 'Write with calmness' ) }
91+
handleToggling={ false }
92+
onToggle={ () =>
93+
toggleDistractionFree( { createNotice: false } )
94+
}
95+
messageActivated={ __(
96+
'Distraction free mode activated.'
97+
) }
98+
messageDeactivated={ __(
99+
'Distraction free mode deactivated.'
100+
) }
101+
shortcut={ keyboardShortcut.primaryShift( '\\' ) }
102+
/>
103+
<MoreMenuPreferenceItem
104+
scope="core"
105+
name="focusMode"
106+
label={ __( 'Spotlight mode' ) }
107+
info={ __( 'Focus on one block at a time' ) }
108+
messageActivated={ __(
109+
'Spotlight mode activated.'
110+
) }
111+
messageDeactivated={ __(
112+
'Spotlight mode deactivated.'
113+
) }
114+
/>
115+
<ViewMoreMenuGroup.Slot />
116+
</MoreMenuSubmenu>
117+
<ActionItem.Slot
118+
name="core/plugin-more-menu"
119+
fillProps={ { as: MoreMenuItem } }
120+
>
121+
{ ( items ) => (
122+
<MoreMenuSubmenu label={ __( 'Panels' ) }>
123+
{ toMenuItems( items ) }
124+
</MoreMenuSubmenu>
108125
) }
109-
/>
110-
<ViewMoreMenuGroup.Slot />
126+
</ActionItem.Slot>
111127
</Menu.Group>
112128
<Menu.Separator />
113129
<ModeSwitcher />
114-
<ActionItem.Slot
115-
name="core/plugin-more-menu"
116-
fillProps={ { as: MoreMenuItem } }
117-
>
118-
{ ( items ) => (
119-
<MoreMenuGroup label={ __( 'Panels' ) }>
120-
{ items }
121-
</MoreMenuGroup>
122-
) }
123-
</ActionItem.Slot>
124130
<Menu.Separator />
125131
<Menu.Group>
126132
<Menu.GroupLabel>{ __( 'Tools' ) }</Menu.GroupLabel>

packages/editor/src/components/more-menu/more-menu-group.tsx renamed to packages/editor/src/components/more-menu/more-menu-submenu.tsx

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,18 @@ import { Menu } from '@wordpress/ui';
44
import type { ComponentProps, ReactNode } from 'react';
55
import MoreMenuItem from './more-menu-item';
66

7-
type MoreMenuGroupProps = {
7+
type MoreMenuSubmenuProps = {
88
/**
9-
* Label of the group. Omit it for a group that needs no heading.
9+
* Label of the item that opens the submenu.
1010
*/
11-
label?: string;
11+
label: string;
1212

1313
/**
14-
* Fills of the slot.
14+
* Items of the submenu.
1515
*/
1616
children: ReactNode;
1717
};
1818

19-
/**
20-
* Renders the fills of an action item slot as a group of a menu.
21-
*/
22-
export default function MoreMenuGroup( {
23-
label,
24-
children,
25-
}: MoreMenuGroupProps ) {
26-
return (
27-
<>
28-
<Menu.Separator />
29-
<Menu.Group>
30-
{ label && <Menu.GroupLabel>{ label }</Menu.GroupLabel> }
31-
{ toMenuItems( children ) }
32-
</Menu.Group>
33-
</>
34-
);
35-
}
36-
3719
/**
3820
* Renders the fills that bring a menu item of their own as menu items.
3921
*
@@ -46,7 +28,7 @@ export default function MoreMenuGroup( {
4628
*
4729
* @return The fills as menu items.
4830
*/
49-
function toMenuItems( fills: ReactNode ) {
31+
export function toMenuItems( fills: ReactNode ) {
5032
return Children.map( fills, ( fill ) => {
5133
if (
5234
! isValidElement< { href?: string } >( fill ) ||
@@ -72,3 +54,21 @@ function toMenuItems( fills: ReactNode ) {
7254
);
7355
} );
7456
}
57+
58+
/**
59+
* Renders a submenu of the editor's Options menu, opened from an item that
60+
* carries a label.
61+
*/
62+
export default function MoreMenuSubmenu( {
63+
label,
64+
children,
65+
}: MoreMenuSubmenuProps ) {
66+
return (
67+
<Menu.SubmenuRoot>
68+
<Menu.SubmenuTrigger>
69+
<Menu.ItemLabel>{ label }</Menu.ItemLabel>
70+
</Menu.SubmenuTrigger>
71+
<Menu.Popup>{ children }</Menu.Popup>
72+
</Menu.SubmenuRoot>
73+
);
74+
}

‎packages/editor/src/components/more-menu/style.scss‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
max-height: var(--available-height);
55
// Narrower than the default of the menu, closer to the previous menu,
66
// which sized itself to its longest label.
7-
max-width: var(--wpds-dimension-surface-width-sm);
7+
width: var(--wpds-dimension-surface-width-sm);
88
}

packages/editor/src/components/more-menu/test/more-menu-group.jsdom.test.tsx renamed to packages/editor/src/components/more-menu/test/more-menu-submenu.jsdom.test.tsx

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { forwardRef } from '@wordpress/element';
88
// eslint-disable-next-line @wordpress/use-recommended-components
99
import { Menu } from '@wordpress/ui';
1010
import MoreMenuItem from '../more-menu-item';
11-
import MoreMenuGroup from '../more-menu-group';
11+
import MoreMenuSubmenu, { toMenuItems } from '../more-menu-submenu';
1212

1313
// `MenuItem` renders a `Button`, which turns into a link given an address.
1414
// Neither of them declares `href` among its props.
@@ -20,9 +20,7 @@ function renderMenu( children: ReactNode ) {
2020
return render(
2121
<Menu.Root>
2222
<Menu.Trigger>Options</Menu.Trigger>
23-
<Menu.Popup>
24-
<MoreMenuGroup label="Panels">{ children }</MoreMenuGroup>
25-
</Menu.Popup>
23+
<Menu.Popup>{ children }</Menu.Popup>
2624
</Menu.Root>
2725
);
2826
}
@@ -32,12 +30,39 @@ async function openMenu( user: UserEvent ) {
3230
await screen.findByRole( 'menu' );
3331
}
3432

35-
describe( 'MoreMenuGroup', () => {
33+
describe( 'MoreMenuSubmenu', () => {
34+
it( 'opens its items from a labelled menu item', async () => {
35+
const user = userEvent.setup();
36+
37+
renderMenu(
38+
<MoreMenuSubmenu label="Panels">
39+
{ toMenuItems( <MenuItem>Legacy item</MenuItem> ) }
40+
</MoreMenuSubmenu>
41+
);
42+
await openMenu( user );
43+
44+
const trigger = screen.getByRole( 'menuitem', { name: 'Panels' } );
45+
expect( trigger ).toHaveAttribute( 'aria-haspopup', 'menu' );
46+
expect(
47+
screen.queryByRole( 'menuitem', { name: 'Legacy item' } )
48+
).not.toBeInTheDocument();
49+
50+
await user.click( trigger );
51+
52+
expect(
53+
await screen.findByRole( 'menuitem', { name: 'Legacy item' } )
54+
).toBeVisible();
55+
} );
56+
} );
57+
58+
describe( 'toMenuItems', () => {
3659
it( 'adopts legacy menu items as menu items', async () => {
3760
const user = userEvent.setup();
3861
const onClick = vi.fn();
3962

40-
renderMenu( <MenuItem onClick={ onClick }>Legacy item</MenuItem> );
63+
renderMenu(
64+
toMenuItems( <MenuItem onClick={ onClick }>Legacy item</MenuItem> )
65+
);
4166
await openMenu( user );
4267

4368
const item = screen.getByRole( 'menuitem', { name: 'Legacy item' } );
@@ -53,7 +78,9 @@ describe( 'MoreMenuGroup', () => {
5378
const user = userEvent.setup();
5479

5580
renderMenu(
56-
<MenuItem info="Legacy description">Legacy item</MenuItem>
81+
toMenuItems(
82+
<MenuItem info="Legacy description">Legacy item</MenuItem>
83+
)
5784
);
5885
await openMenu( user );
5986

@@ -68,9 +95,11 @@ describe( 'MoreMenuGroup', () => {
6895
const user = userEvent.setup();
6996

7097
renderMenu(
71-
<LinkMenuItem href="https://wordpress.org">
72-
Legacy link
73-
</LinkMenuItem>
98+
toMenuItems(
99+
<LinkMenuItem href="https://wordpress.org">
100+
Legacy link
101+
</LinkMenuItem>
102+
)
74103
);
75104
await openMenu( user );
76105

@@ -82,7 +111,9 @@ describe( 'MoreMenuGroup', () => {
82111
it( 'adopts a legacy link item of an empty address as a link item', async () => {
83112
const user = userEvent.setup();
84113

85-
renderMenu( <LinkMenuItem href="">Legacy link</LinkMenuItem> );
114+
renderMenu(
115+
toMenuItems( <LinkMenuItem href="">Legacy link</LinkMenuItem> )
116+
);
86117
await openMenu( user );
87118

88119
expect(
@@ -94,10 +125,12 @@ describe( 'MoreMenuGroup', () => {
94125
const user = userEvent.setup();
95126
const NothingMenuItem = forwardRef( () => null );
96127

97-
renderMenu( [
98-
<NothingMenuItem key="nothing" />,
99-
<MenuItem key="legacy">Legacy item</MenuItem>,
100-
] );
128+
renderMenu(
129+
toMenuItems( [
130+
<NothingMenuItem key="nothing" />,
131+
<MenuItem key="legacy">Legacy item</MenuItem>,
132+
] )
133+
);
101134
await openMenu( user );
102135

103136
await user.keyboard( '{ArrowDown}' );
@@ -109,7 +142,7 @@ describe( 'MoreMenuGroup', () => {
109142
it( 'leaves more menu items alone', async () => {
110143
const user = userEvent.setup();
111144

112-
renderMenu( <MoreMenuItem>Plugin item</MoreMenuItem> );
145+
renderMenu( toMenuItems( <MoreMenuItem>Plugin item</MoreMenuItem> ) );
113146
await openMenu( user );
114147

115148
expect( screen.getAllByRole( 'menuitem' ) ).toHaveLength( 1 );

‎packages/editor/src/components/preview-dropdown/index.jsx‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { privateApis as globalStylesEnginePrivateApis } from '@wordpress/global-
1212
// eslint-disable-next-line @wordpress/use-recommended-components
1313
import { Menu } from '@wordpress/ui';
1414
import { store as editorStore } from '../../store';
15-
import MoreMenuGroup from '../more-menu/more-menu-group';
1615
import MoreMenuItem from '../more-menu/more-menu-item';
16+
import { toMenuItems } from '../more-menu/more-menu-submenu';
1717
import { PostPreviewMenuItem } from '../post-preview-button';
1818
import { sidebars } from '../sidebar/constants';
1919
import { VIEWPORT_STATE_BY_DEVICE_TYPE } from '../../utils/device-type';
@@ -267,7 +267,12 @@ function PreviewMenu( { forceIsAutosaveable, disabled } ) {
267267
name="core/plugin-preview-menu"
268268
fillProps={ { as: MoreMenuItem } }
269269
>
270-
{ ( items ) => <MoreMenuGroup>{ items }</MoreMenuGroup> }
270+
{ ( items ) => (
271+
<>
272+
<Menu.Separator />
273+
<Menu.Group>{ toMenuItems( items ) }</Menu.Group>
274+
</>
275+
) }
271276
</ActionItem.Slot>
272277
</Menu.Popup>
273278
</Menu.Root>

0 commit comments

Comments
 (0)