Skip to content

Commit a428b15

Browse files
authored
Refactor DropdownMenu (#1108)
1 parent 606a933 commit a428b15

File tree

15 files changed

+11136
-13612
lines changed

15 files changed

+11136
-13612
lines changed
Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,31 @@
1-
import { DropdownMenu } from '@asyncapi/studio-ui'
1+
import React from 'react';
2+
import { Meta } from '@storybook/react';
3+
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, DropdownMenuItem, DropdownMenuSeparator } from '@asyncapi/studio-ui'
24

3-
export default {
5+
const meta: Meta = {
46
component: DropdownMenu,
57
parameters: {
68
layout: 'fullscreen',
79
backgrounds: {
810
default: 'dark'
911
}
10-
},
12+
}
1113
}
1214

13-
const items = [
14-
{
15-
title: 'Import from URL',
16-
onSelect: () => console.log('Import from URL')
17-
},
18-
{
19-
title: 'Import from file',
20-
onSelect: () => console.log('Import from file')
21-
},
22-
{
23-
title: 'Import from Base64',
24-
onSelect: () => console.log('Import from Base64')
25-
},
26-
{
27-
type: 'separator'
28-
},
29-
{
30-
title: 'Generate code/docs',
31-
onSelect: () => console.log('Generate code/docs')
32-
},
33-
]
15+
export default meta
16+
3417

3518
export const Default = {
36-
args: {
37-
trigger: <button className="text-black bg-white rounded mx-3 my-3 px-3">Click me!</button>,
38-
items,
39-
side: 'bottom',
40-
align: 'start'
41-
}
19+
render: () => (<DropdownMenu>
20+
<DropdownMenuTrigger asChild>
21+
<button className="text-black bg-white rounded mx-3 my-3 px-3">Click me!</button>
22+
</DropdownMenuTrigger>
23+
<DropdownMenuContent>
24+
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Import from URL</DropdownMenuItem>
25+
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Import from file</DropdownMenuItem>
26+
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Import from Base64</DropdownMenuItem>
27+
<DropdownMenuSeparator />
28+
<DropdownMenuItem onSelect={(e) => console.log(e.target)}>Generate code/docs</DropdownMenuItem>
29+
</DropdownMenuContent>
30+
</DropdownMenu>)
4231
}

apps/design-system/src/styles/tailwind.output.css

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com
2+
! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
33
*/
44

55
/*
@@ -32,9 +32,11 @@
3232
4. Use the user's configured `sans` font-family by default.
3333
5. Use the user's configured `sans` font-feature-settings by default.
3434
6. Use the user's configured `sans` font-variation-settings by default.
35+
7. Disable tap highlights on iOS
3536
*/
3637

37-
html {
38+
html,
39+
:host {
3840
line-height: 1.5;
3941
/* 1 */
4042
-webkit-text-size-adjust: 100%;
@@ -48,6 +50,8 @@ html {
4850
/* 5 */
4951
font-variation-settings: normal;
5052
/* 6 */
53+
-webkit-tap-highlight-color: transparent;
54+
/* 7 */
5155
}
5256

5357
/*
@@ -119,8 +123,10 @@ strong {
119123
}
120124

121125
/*
122-
1. Use the user's configured `mono` font family by default.
123-
2. Correct the odd `em` font sizing in all browsers.
126+
1. Use the user's configured `mono` font-family by default.
127+
2. Use the user's configured `mono` font-feature-settings by default.
128+
3. Use the user's configured `mono` font-variation-settings by default.
129+
4. Correct the odd `em` font sizing in all browsers.
124130
*/
125131

126132
code,
@@ -129,8 +135,12 @@ samp,
129135
pre {
130136
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
131137
/* 1 */
132-
font-size: 1em;
138+
font-feature-settings: normal;
133139
/* 2 */
140+
font-variation-settings: normal;
141+
/* 3 */
142+
font-size: 1em;
143+
/* 4 */
134144
}
135145

136146
/*
@@ -199,6 +209,8 @@ textarea {
199209
/* 1 */
200210
line-height: inherit;
201211
/* 1 */
212+
letter-spacing: inherit;
213+
/* 1 */
202214
color: inherit;
203215
/* 1 */
204216
margin: 0;
@@ -222,9 +234,9 @@ select {
222234
*/
223235

224236
button,
225-
[type='button'],
226-
[type='reset'],
227-
[type='submit'] {
237+
input:where([type='button']),
238+
input:where([type='reset']),
239+
input:where([type='submit']) {
228240
-webkit-appearance: button;
229241
/* 1 */
230242
background-color: transparent;
@@ -473,6 +485,10 @@ video {
473485
--tw-backdrop-opacity: ;
474486
--tw-backdrop-saturate: ;
475487
--tw-backdrop-sepia: ;
488+
--tw-contain-size: ;
489+
--tw-contain-layout: ;
490+
--tw-contain-paint: ;
491+
--tw-contain-style: ;
476492
}
477493

478494
::backdrop {
@@ -523,6 +539,10 @@ video {
523539
--tw-backdrop-opacity: ;
524540
--tw-backdrop-saturate: ;
525541
--tw-backdrop-sepia: ;
542+
--tw-contain-size: ;
543+
--tw-contain-layout: ;
544+
--tw-contain-paint: ;
545+
--tw-contain-style: ;
526546
}
527547

528548
.m-3 {
Lines changed: 72 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,80 @@
1-
import type { FunctionComponent, ReactNode } from 'react'
2-
import * as RadixDropdownMenu from '@radix-ui/react-dropdown-menu'
1+
"use client"
32

4-
interface DropdownMenuRegularItem {
5-
type?: 'regular'
6-
title: string
7-
onSelect: () => void
8-
}
3+
import * as React from "react"
4+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
95

10-
interface DropdownMenuSeparatorItem {
11-
type: 'separator'
12-
}
6+
import { cn } from "@asyncapi/studio-utils"
137

14-
export type DropdownMenuItem = DropdownMenuRegularItem | DropdownMenuSeparatorItem
8+
const DropdownMenu = DropdownMenuPrimitive.Root
159

16-
interface DropdownMenuProps {
17-
trigger: ReactNode
18-
items: DropdownMenuItem[]
19-
side?: 'top' | 'right' | 'bottom' | 'left'
20-
align?: 'start' | 'center' | 'end'
21-
onSelect?: (options: string[]) => void
22-
}
10+
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
2311

24-
interface DropdownMenuItemComponentProps {
25-
item: DropdownMenuItem
26-
}
12+
const DropdownMenuGroup = DropdownMenuPrimitive.Group
13+
14+
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
15+
16+
const DropdownMenuSub = DropdownMenuPrimitive.Sub
17+
18+
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
19+
20+
21+
const DropdownMenuContent = React.forwardRef<
22+
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
23+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
24+
>(({ className, sideOffset = 5, ...props }, ref) => (
25+
<DropdownMenuPrimitive.Portal>
26+
<DropdownMenuPrimitive.Content
27+
ref={ref}
28+
sideOffset={sideOffset}
29+
className={cn(
30+
"min-w-[220px] bg-gray-950 rounded-md p-2.5 shadow",
31+
className
32+
)}
33+
{...props}
34+
/>
35+
</DropdownMenuPrimitive.Portal>
36+
))
37+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
38+
39+
const DropdownMenuItem = React.forwardRef<
40+
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
41+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
42+
inset?: boolean
43+
}
44+
>(({ className, ...props }, ref) => (
45+
<DropdownMenuPrimitive.Item
46+
ref={ref}
47+
className={cn(
48+
"text-gray-200 text-sm leading-7 px-2.5 cursor-pointer rounded outline-none select-none hover:bg-gray-700 focus:bg-gray-700",
49+
className
50+
)}
51+
{...props}
52+
/>
53+
))
54+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
55+
56+
57+
const DropdownMenuSeparator = React.forwardRef<
58+
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
59+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
60+
>(({ className, ...props }, ref) => (
61+
<DropdownMenuPrimitive.Separator
62+
ref={ref}
63+
className={cn("w-full h-px bg-gray-700 my-2", className)}
64+
{...props}
65+
/>
66+
))
67+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
2768

28-
const DropdownMenuItemComponent: FunctionComponent<DropdownMenuItemComponentProps> = ({ item }) => {
29-
return (
30-
item.type === 'separator' ? (
31-
<RadixDropdownMenu.Separator className="w-full h-px bg-gray-700 my-2" />
32-
) : (
33-
<RadixDropdownMenu.Item
34-
className="text-gray-200 text-sm leading-7 px-2.5 cursor-pointer rounded outline-none select-none hover:bg-gray-700 focus:bg-gray-700"
35-
onSelect={item.onSelect}
36-
>
37-
{item.title}
38-
</RadixDropdownMenu.Item>
39-
)
40-
)
41-
}
4269

43-
export const DropdownMenu: FunctionComponent<DropdownMenuProps> = ({
44-
trigger,
45-
items,
46-
side,
47-
align,
48-
onSelect
49-
}) => {
50-
return (
51-
<RadixDropdownMenu.Root>
52-
<RadixDropdownMenu.Trigger aria-label='Select an Option.' asChild>
53-
{trigger}
54-
</RadixDropdownMenu.Trigger>
55-
<RadixDropdownMenu.Portal>
56-
<RadixDropdownMenu.Content className="min-w-[220px] bg-gray-950 rounded-md p-2.5 shadow" sideOffset={5} side={side} align={align}>
57-
{
58-
items.map((item, index) => (
59-
<DropdownMenuItemComponent key={index} item={item} />
60-
))
61-
}
62-
<RadixDropdownMenu.Arrow className="fill-gray-950" />
63-
</RadixDropdownMenu.Content>
64-
</RadixDropdownMenu.Portal>
65-
</RadixDropdownMenu.Root>
66-
)
70+
export {
71+
DropdownMenu,
72+
DropdownMenuTrigger,
73+
DropdownMenuContent,
74+
DropdownMenuItem,
75+
DropdownMenuSeparator,
76+
DropdownMenuGroup,
77+
DropdownMenuPortal,
78+
DropdownMenuSub,
79+
DropdownMenuRadioGroup,
6780
}

packages/ui/components/Toolbar.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Tooltip from './Tooltip'
22
import * as RadixToolbar from '@radix-ui/react-toolbar'
33
import { FunctionComponent } from 'react'
4-
import { DropdownMenu, DropdownMenuItem } from './DropdownMenu'
4+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from './DropdownMenu'
55

66
interface ToolbarToggleItem {
77
type: 'toggle'
@@ -31,10 +31,21 @@ interface ToolbarSeparatorItem {
3131
type: 'separator'
3232
}
3333

34+
interface DropdownMenuRegularItem {
35+
type?: 'regular'
36+
title: string
37+
onSelect: () => void
38+
}
39+
40+
interface DropdownMenuSeparatorItem {
41+
type: 'separator'
42+
}
43+
44+
type DropdownMenuItemInterface = DropdownMenuRegularItem | DropdownMenuSeparatorItem
3445
interface ToolbarDropdownMenuItem {
3546
type: 'dropdownMenu',
3647
icon: FunctionComponent<any>
37-
items: DropdownMenuItem[]
48+
items: DropdownMenuItemInterface[]
3849
}
3950

4051
type ToolbarItem = ToolbarToggleItem | ToolbarToggleGroupSingleItem | ToolbarToggleGroupMultipleItem | ToolbarSeparatorItem | ToolbarDropdownMenuItem
@@ -117,17 +128,19 @@ const ToolbarItem: FunctionComponent<ToolbarItemProps> = ({ item }) => {
117128
)
118129
} else if (type === 'dropdownMenu') {
119130
return (
120-
<DropdownMenu
121-
trigger={
131+
<DropdownMenu>
132+
<DropdownMenuTrigger asChild>
122133
<button className="flex text-sm focus:outline-none border-box py-2 my-3.5 text-gray-500 hover:text-white focus:text-white rounded">
123134
<item.icon className="w-6 h-6"/>
124135
</button>
125-
}
126-
items={item.items}
127-
side="bottom"
128-
align="end"
129-
/>
130-
136+
</DropdownMenuTrigger>
137+
<DropdownMenuContent>
138+
{item.items.map((menuItem) => (
139+
menuItem.type === 'separator' ? <DropdownMenuSeparator key={menuItem.type} /> :
140+
<DropdownMenuItem key={menuItem.title} onSelect={menuItem.onSelect}>{menuItem.title}</DropdownMenuItem>
141+
))}
142+
</DropdownMenuContent>
143+
</DropdownMenu>
131144
)
132145
}
133146
throw new Error(`Unsupported type of Toolbar item: ${type}`)

0 commit comments

Comments
 (0)