Skip to content

Commit 609fdb4

Browse files
authored
chore: Add portal to the DropdownMenuContent by default (#4828)
## Description We should never use those menus without a portal, enforcing it by default now: - added portal to DropdownMenuContent - removed usages of the portal in consumers ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
1 parent 196a3d3 commit 609fdb4

File tree

11 files changed

+454
-485
lines changed

11 files changed

+454
-485
lines changed

apps/builder/app/builder/features/settings-panel/variables-section.tsx

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
DropdownMenu,
1010
DropdownMenuContent,
1111
DropdownMenuItem,
12-
DropdownMenuPortal,
1312
DropdownMenuTrigger,
1413
Flex,
1514
Label,
@@ -257,25 +256,23 @@ const VariablesItem = ({
257256
onClick={() => {}}
258257
/>
259258
</DropdownMenuTrigger>
260-
<DropdownMenuPortal>
261-
<DropdownMenuContent
262-
css={{ width: theme.spacing[28] }}
263-
onCloseAutoFocus={(event) => event.preventDefault()}
264-
>
265-
<DropdownMenuItem onSelect={() => setInspectDialogOpen(true)}>
266-
Inspect
259+
<DropdownMenuContent
260+
css={{ width: theme.spacing[28] }}
261+
onCloseAutoFocus={(event) => event.preventDefault()}
262+
>
263+
<DropdownMenuItem onSelect={() => setInspectDialogOpen(true)}>
264+
Inspect
265+
</DropdownMenuItem>
266+
{source === "local" && (
267+
<DropdownMenuItem
268+
// allow to delete only unused variables
269+
disabled={variable.type === "parameter" || usageCount > 0}
270+
onSelect={() => deleteVariable(variable.id)}
271+
>
272+
Delete {usageCount > 0 && `(${usageCount} bindings)`}
267273
</DropdownMenuItem>
268-
{source === "local" && (
269-
<DropdownMenuItem
270-
// allow to delete only unused variables
271-
disabled={variable.type === "parameter" || usageCount > 0}
272-
onSelect={() => deleteVariable(variable.id)}
273-
>
274-
Delete {usageCount > 0 && `(${usageCount} bindings)`}
275-
</DropdownMenuItem>
276-
)}
277-
</DropdownMenuContent>
278-
</DropdownMenuPortal>
274+
)}
275+
</DropdownMenuContent>
279276
</DropdownMenu>
280277
</>
281278
}

apps/builder/app/builder/features/style-panel/controls/menu/menu-control.tsx

Lines changed: 48 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
DropdownMenu,
77
DropdownMenuContent,
88
DropdownMenuItem,
9-
DropdownMenuPortal,
109
DropdownMenuRadioGroup,
1110
DropdownMenuRadioItem,
1211
DropdownMenuSeparator,
@@ -74,57 +73,55 @@ export const MenuControl = ({
7473
</IconButton>
7574
</DropdownMenuTrigger>
7675
</PropertyValueTooltip>
77-
<DropdownMenuPortal>
78-
<DropdownMenuContent sideOffset={4} collisionPadding={16} side="bottom">
79-
<DropdownMenuRadioGroup
80-
value={currentValue}
81-
onValueChange={(value) => setValue({ type: "keyword", value })}
82-
>
83-
{items.map(({ name, label, icon: Icon }) => {
84-
return (
85-
<DropdownMenuRadioItem
86-
text="sentence"
87-
key={name}
88-
value={name}
89-
icon={<MenuCheckedIcon />}
90-
onFocus={() => {
91-
setValue(
92-
{ type: "keyword", value: name },
93-
{ isEphemeral: true }
94-
);
95-
setDescriptionValue(name);
96-
}}
97-
onBlur={() => {
98-
setValue(
99-
{ type: "keyword", value: currentValue },
100-
{ isEphemeral: true }
101-
);
102-
setDescriptionValue(undefined);
103-
}}
104-
>
105-
<Flex gap="1">
106-
<Flex
107-
css={{
108-
width: theme.spacing[9],
109-
height: theme.spacing[9],
110-
}}
111-
align="center"
112-
justify="center"
113-
>
114-
<Icon />
115-
</Flex>
116-
{label}
76+
<DropdownMenuContent sideOffset={4} collisionPadding={16} side="bottom">
77+
<DropdownMenuRadioGroup
78+
value={currentValue}
79+
onValueChange={(value) => setValue({ type: "keyword", value })}
80+
>
81+
{items.map(({ name, label, icon: Icon }) => {
82+
return (
83+
<DropdownMenuRadioItem
84+
text="sentence"
85+
key={name}
86+
value={name}
87+
icon={<MenuCheckedIcon />}
88+
onFocus={() => {
89+
setValue(
90+
{ type: "keyword", value: name },
91+
{ isEphemeral: true }
92+
);
93+
setDescriptionValue(name);
94+
}}
95+
onBlur={() => {
96+
setValue(
97+
{ type: "keyword", value: currentValue },
98+
{ isEphemeral: true }
99+
);
100+
setDescriptionValue(undefined);
101+
}}
102+
>
103+
<Flex gap="1">
104+
<Flex
105+
css={{
106+
width: theme.spacing[9],
107+
height: theme.spacing[9],
108+
}}
109+
align="center"
110+
justify="center"
111+
>
112+
<Icon />
117113
</Flex>
118-
</DropdownMenuRadioItem>
119-
);
120-
})}
121-
</DropdownMenuRadioGroup>
122-
<DropdownMenuSeparator />
123-
<DropdownMenuItem hint>
124-
<Box css={{ width: theme.spacing[25] }}>{description}</Box>
125-
</DropdownMenuItem>
126-
</DropdownMenuContent>
127-
</DropdownMenuPortal>
114+
{label}
115+
</Flex>
116+
</DropdownMenuRadioItem>
117+
);
118+
})}
119+
</DropdownMenuRadioGroup>
120+
<DropdownMenuSeparator />
121+
<DropdownMenuItem hint>
122+
<Box css={{ width: theme.spacing[25] }}>{description}</Box>
123+
</DropdownMenuItem>
124+
</DropdownMenuContent>
128125
</DropdownMenu>
129126
);
130127
};

apps/builder/app/builder/features/style-panel/sections/transforms/transforms.tsx

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
DropdownMenu,
1313
DropdownMenuContent,
1414
DropdownMenuItem,
15-
DropdownMenuPortal,
1615
DropdownMenuTrigger,
1716
Flex,
1817
Grid,
@@ -170,31 +169,29 @@ export const Section = () => {
170169
prefix={<PlusIcon />}
171170
></SectionTitleButton>
172171
</DropdownMenuTrigger>
173-
<DropdownMenuPortal>
174-
<DropdownMenuContent
175-
collisionPadding={16}
176-
css={{ width: theme.spacing[24] }}
177-
>
178-
{transformPanels.map((panel) => (
179-
<DropdownMenuItem
180-
disabled={isTransformPanelPropertyUsed({
172+
<DropdownMenuContent
173+
collisionPadding={16}
174+
css={{ width: theme.spacing[24] }}
175+
>
176+
{transformPanels.map((panel) => (
177+
<DropdownMenuItem
178+
disabled={isTransformPanelPropertyUsed({
179+
panel,
180+
styles,
181+
})}
182+
key={panel}
183+
onSelect={() => {
184+
addDefaultsForTransormSection({
181185
panel,
182186
styles,
183-
})}
184-
key={panel}
185-
onSelect={() => {
186-
addDefaultsForTransormSection({
187-
panel,
188-
styles,
189-
});
190-
setIsOpen(true);
191-
}}
192-
>
193-
{humanizeString(panel)}
194-
</DropdownMenuItem>
195-
))}
196-
</DropdownMenuContent>
197-
</DropdownMenuPortal>
187+
});
188+
setIsOpen(true);
189+
}}
190+
>
191+
{humanizeString(panel)}
192+
</DropdownMenuItem>
193+
))}
194+
</DropdownMenuContent>
198195
</DropdownMenu>
199196
</Flex>
200197
}

apps/builder/app/builder/features/style-panel/style-source/style-source-control.tsx

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
DropdownMenu,
33
DropdownMenuContent,
4-
DropdownMenuPortal,
54
DropdownMenuTrigger,
65
Text,
76
styled,
@@ -97,14 +96,12 @@ const Menu = (props: MenuProps) => {
9796
<ChevronDownIcon style={{ position: "relative" }} />
9897
</MenuTrigger>
9998
</DropdownMenuTrigger>
100-
<DropdownMenuPortal>
101-
<DropdownMenuContent
102-
onCloseAutoFocus={(event) => event.preventDefault()}
103-
css={{ maxWidth: theme.spacing[24] }}
104-
>
105-
{props.children}
106-
</DropdownMenuContent>
107-
</DropdownMenuPortal>
99+
<DropdownMenuContent
100+
onCloseAutoFocus={(event) => event.preventDefault()}
101+
css={{ maxWidth: theme.spacing[24] }}
102+
>
103+
{props.children}
104+
</DropdownMenuContent>
108105
</DropdownMenu>
109106
);
110107
};

apps/builder/app/builder/features/topbar/builder-mode.tsx

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@ import {
2020
ToolbarToggleItem,
2121
Tooltip,
2222
Text,
23-
} from "@webstudio-is/design-system";
24-
import {
2523
DropdownMenu,
2624
DropdownMenuContent,
27-
DropdownMenuPortal,
2825
DropdownMenuTrigger,
2926
} from "@webstudio-is/design-system";
3027
import {
@@ -107,53 +104,51 @@ export const BuilderModeDropDown = () => {
107104
</ToolbarToggleItem>
108105
</DropdownMenuTrigger>
109106
</Tooltip>
110-
<DropdownMenuPortal>
111-
<DropdownMenuContent
112-
sideOffset={4}
113-
collisionPadding={16}
114-
side="bottom"
115-
loop
107+
<DropdownMenuContent
108+
sideOffset={4}
109+
collisionPadding={16}
110+
side="bottom"
111+
loop
112+
>
113+
<DropdownMenuRadioGroup
114+
value={builderMode}
115+
onValueChange={(value) => {
116+
if (isBuilderMode(value)) {
117+
setBuilderMode(value);
118+
}
119+
}}
116120
>
117-
<DropdownMenuRadioGroup
118-
value={builderMode}
119-
onValueChange={(value) => {
120-
if (isBuilderMode(value)) {
121-
setBuilderMode(value);
122-
}
123-
}}
124-
>
125-
{Object.entries(menuItems)
126-
.filter(([_, { enabled }]) => enabled)
127-
.map(([mode, { icon, title, shortcut }]) => (
128-
<DropdownMenuRadioItem
129-
key={mode}
130-
value={mode}
131-
onFocus={handleFocus(mode as keyof typeof menuItems)}
132-
onBlur={handleBlur}
133-
icon={<MenuCheckedIcon />}
134-
>
135-
<Flex css={{ px: theme.spacing[3] }} gap={2}>
136-
{icon}
137-
<Box>{title}</Box>
138-
</Flex>
139-
<DropdownMenuItemRightSlot>
140-
<Kbd value={shortcut} />
141-
</DropdownMenuItemRightSlot>
142-
&nbsp;
143-
</DropdownMenuRadioItem>
144-
))}
145-
</DropdownMenuRadioGroup>
146-
<DropdownMenuSeparator />
121+
{Object.entries(menuItems)
122+
.filter(([_, { enabled }]) => enabled)
123+
.map(([mode, { icon, title, shortcut }]) => (
124+
<DropdownMenuRadioItem
125+
key={mode}
126+
value={mode}
127+
onFocus={handleFocus(mode as keyof typeof menuItems)}
128+
onBlur={handleBlur}
129+
icon={<MenuCheckedIcon />}
130+
>
131+
<Flex css={{ px: theme.spacing[3] }} gap={2}>
132+
{icon}
133+
<Box>{title}</Box>
134+
</Flex>
135+
<DropdownMenuItemRightSlot>
136+
<Kbd value={shortcut} />
137+
</DropdownMenuItemRightSlot>
138+
&nbsp;
139+
</DropdownMenuRadioItem>
140+
))}
141+
</DropdownMenuRadioGroup>
142+
<DropdownMenuSeparator />
147143

148-
<div className={menuItemCss({ hint: true })}>
149-
<Box css={{ width: theme.spacing[25] }}>
150-
{activeMode
151-
? menuItems[activeMode].description
152-
: "Select Design or Content mode"}
153-
</Box>
154-
</div>
155-
</DropdownMenuContent>
156-
</DropdownMenuPortal>
144+
<div className={menuItemCss({ hint: true })}>
145+
<Box css={{ width: theme.spacing[25] }}>
146+
{activeMode
147+
? menuItems[activeMode].description
148+
: "Select Design or Content mode"}
149+
</Box>
150+
</div>
151+
</DropdownMenuContent>
157152
</DropdownMenu>
158153
</Flex>
159154
);

0 commit comments

Comments
 (0)