Skip to content

Commit 244c2e5

Browse files
authored
DropdownMenu v2: Render in the default Popover.Slot (#51046)
* Add new slotName prop * Add storybook example * Use context to use same slot for submenu portal * Use default popover slot instead of exposing a slotName prop, update Storybook * CHANGELOG
1 parent c3ce573 commit 244c2e5

File tree

4 files changed

+31
-6
lines changed

4 files changed

+31
-6
lines changed

packages/components/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
### Experimental
1818

1919
- `DropdownMenu` v2: Tweak styles ([#50967](https://github.com/WordPress/gutenberg/pull/50967)).
20+
- `DropdownMenu` v2: Render in the default `Popover.Slot` ([#51046](https://github.com/WordPress/gutenberg/pull/51046)).
2021

2122
## 25.0.0 (2023-05-24)
2223

packages/components/src/dropdown-menu-v2/index.tsx

+22-4
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
66
/**
77
* WordPress dependencies
88
*/
9-
import { forwardRef } from '@wordpress/element';
9+
import { forwardRef, createContext, useContext } from '@wordpress/element';
1010
import { isRTL } from '@wordpress/i18n';
1111
import { check, chevronRightSmall, lineSolid } from '@wordpress/icons';
1212
import { SVG, Circle } from '@wordpress/primitives';
1313

1414
/**
1515
* Internal dependencies
1616
*/
17+
import { useSlot } from '../slot-fill';
1718
import Icon from '../icon';
19+
import { SLOT_NAME as POPOVER_DEFAULT_SLOT_NAME } from '../popover';
1820
import * as DropdownMenuStyled from './styles';
1921
import type {
2022
DropdownMenuProps,
@@ -34,6 +36,12 @@ const SUB_MENU_OFFSET_SIDE = 12;
3436
// Opposite amount of the top padding of the menu item
3537
const SUB_MENU_OFFSET_ALIGN = -8;
3638

39+
const DropdownMenuPrivateContext = createContext< {
40+
portalContainer: HTMLElement | null;
41+
} >( {
42+
portalContainer: null,
43+
} );
44+
3745
/**
3846
* `DropdownMenu` displays a menu to the user (such as a set of actions
3947
* or functions) triggered by a button.
@@ -53,6 +61,10 @@ export const DropdownMenu = ( {
5361
children,
5462
trigger,
5563
}: DropdownMenuProps ) => {
64+
// Render the portal in the default slot used by the legacy Popover component.
65+
const slot = useSlot( POPOVER_DEFAULT_SLOT_NAME );
66+
const portalContainer = slot.ref?.current;
67+
5668
return (
5769
<DropdownMenuPrimitive.Root
5870
defaultOpen={ defaultOpen }
@@ -64,15 +76,19 @@ export const DropdownMenu = ( {
6476
<DropdownMenuPrimitive.Trigger asChild>
6577
{ trigger }
6678
</DropdownMenuPrimitive.Trigger>
67-
<DropdownMenuPrimitive.Portal>
79+
<DropdownMenuPrimitive.Portal container={ portalContainer }>
6880
<DropdownMenuStyled.Content
6981
side={ side }
7082
align={ align }
7183
sideOffset={ sideOffset }
7284
alignOffset={ alignOffset }
7385
loop={ true }
7486
>
75-
{ children }
87+
<DropdownMenuPrivateContext.Provider
88+
value={ { portalContainer } }
89+
>
90+
{ children }
91+
</DropdownMenuPrivateContext.Provider>
7692
</DropdownMenuStyled.Content>
7793
</DropdownMenuPrimitive.Portal>
7894
</DropdownMenuPrimitive.Root>
@@ -118,6 +134,8 @@ export const DropdownSubMenu = ( {
118134
children,
119135
trigger,
120136
}: DropdownSubMenuProps ) => {
137+
const { portalContainer } = useContext( DropdownMenuPrivateContext );
138+
121139
return (
122140
<DropdownMenuPrimitive.Sub
123141
defaultOpen={ defaultOpen }
@@ -130,7 +148,7 @@ export const DropdownSubMenu = ( {
130148
>
131149
{ trigger }
132150
</DropdownMenuStyled.SubTrigger>
133-
<DropdownMenuPrimitive.Portal>
151+
<DropdownMenuPrimitive.Portal container={ portalContainer }>
134152
<DropdownMenuStyled.SubContent
135153
loop
136154
sideOffset={ SUB_MENU_OFFSET_SIDE }

packages/components/src/dropdown-menu-v2/stories/index.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {
2020
DropdownSubMenuTrigger,
2121
} from '..';
2222
import Button from '../../button';
23+
import Popover from '../../popover';
24+
import { Provider as SlotFillProvider } from '../../slot-fill';
2325

2426
/**
2527
* WordPress dependencies
@@ -127,7 +129,11 @@ const RadioItemsGroup = () => {
127129
};
128130

129131
const Template: ComponentStory< typeof DropdownMenu > = ( props ) => (
130-
<DropdownMenu { ...props } />
132+
<SlotFillProvider>
133+
<DropdownMenu { ...props } />
134+
{ /* @ts-expect-error Slot is not currently typed on Popover */ }
135+
<Popover.Slot />
136+
</SlotFillProvider>
131137
);
132138
export const Default = Template.bind( {} );
133139
Default.args = {

packages/components/src/popover/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ import { overlayMiddlewares } from './overlay-middlewares';
7474
*
7575
* @type {string}
7676
*/
77-
const SLOT_NAME = 'Popover';
77+
export const SLOT_NAME = 'Popover';
7878

7979
// An SVG displaying a triangle facing down, filled with a solid
8080
// color and bordered in such a way to create an arrow-like effect.

0 commit comments

Comments
 (0)