@rovula/ui 0.1.21 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/cjs/bundle.css +175 -26
  2. package/dist/cjs/bundle.js +675 -675
  3. package/dist/cjs/bundle.js.map +1 -1
  4. package/dist/cjs/types/components/Badge/Badge.d.ts +40 -0
  5. package/dist/cjs/types/components/Badge/Badge.stories.d.ts +295 -0
  6. package/dist/cjs/types/components/Badge/Badge.styles.d.ts +7 -0
  7. package/dist/cjs/types/components/Badge/index.d.ts +2 -0
  8. package/dist/cjs/types/components/Dropdown/Dropdown.d.ts +4 -8
  9. package/dist/cjs/types/components/Dropdown/Dropdown.stories.d.ts +1 -6
  10. package/dist/cjs/types/components/DropdownMenu/DropdownMenu.d.ts +5 -1
  11. package/dist/cjs/types/components/DropdownMenu/DropdownMenu.stories.d.ts +16 -0
  12. package/dist/cjs/types/index.d.ts +3 -1
  13. package/dist/cjs/types/patterns/menu/Menu.d.ts +70 -0
  14. package/dist/cjs/types/{components/Menu → patterns/menu}/Menu.stories.d.ts +17 -10
  15. package/dist/cjs/types/utils/mergeRefs.d.ts +20 -0
  16. package/dist/components/Avatar/Avatar.styles.js +2 -2
  17. package/dist/components/Badge/Badge.js +36 -0
  18. package/dist/components/Badge/Badge.stories.js +51 -0
  19. package/dist/components/Badge/Badge.styles.js +62 -0
  20. package/dist/components/Badge/index.js +2 -0
  21. package/dist/components/Dropdown/Dropdown.js +54 -163
  22. package/dist/components/Dropdown/Dropdown.stories.js +29 -0
  23. package/dist/components/DropdownMenu/DropdownMenu.js +22 -9
  24. package/dist/components/DropdownMenu/DropdownMenu.stories.js +54 -10
  25. package/dist/components/TextInput/TextInput.js +6 -3
  26. package/dist/esm/bundle.css +175 -26
  27. package/dist/esm/bundle.js +1545 -1545
  28. package/dist/esm/bundle.js.map +1 -1
  29. package/dist/esm/types/components/Badge/Badge.d.ts +40 -0
  30. package/dist/esm/types/components/Badge/Badge.stories.d.ts +295 -0
  31. package/dist/esm/types/components/Badge/Badge.styles.d.ts +7 -0
  32. package/dist/esm/types/components/Badge/index.d.ts +2 -0
  33. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +4 -8
  34. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +1 -6
  35. package/dist/esm/types/components/DropdownMenu/DropdownMenu.d.ts +5 -1
  36. package/dist/esm/types/components/DropdownMenu/DropdownMenu.stories.d.ts +16 -0
  37. package/dist/esm/types/index.d.ts +3 -1
  38. package/dist/esm/types/patterns/menu/Menu.d.ts +70 -0
  39. package/dist/esm/types/{components/Menu → patterns/menu}/Menu.stories.d.ts +17 -10
  40. package/dist/esm/types/utils/mergeRefs.d.ts +20 -0
  41. package/dist/index.d.ts +116 -73
  42. package/dist/index.js +2 -1
  43. package/dist/patterns/menu/Menu.js +95 -0
  44. package/dist/patterns/menu/Menu.stories.js +611 -0
  45. package/dist/src/theme/global.css +289 -37
  46. package/dist/utils/mergeRefs.js +42 -0
  47. package/package.json +1 -1
  48. package/src/components/Avatar/Avatar.styles.ts +2 -2
  49. package/src/components/Badge/Badge.stories.tsx +128 -0
  50. package/src/components/Badge/Badge.styles.ts +70 -0
  51. package/src/components/Badge/Badge.tsx +103 -0
  52. package/src/components/Badge/index.ts +3 -0
  53. package/src/components/Dropdown/Dropdown.stories.tsx +170 -1
  54. package/src/components/Dropdown/Dropdown.tsx +186 -276
  55. package/src/components/DropdownMenu/DropdownMenu.stories.tsx +1050 -113
  56. package/src/components/DropdownMenu/DropdownMenu.tsx +116 -52
  57. package/src/components/TextInput/TextInput.tsx +6 -3
  58. package/src/index.ts +3 -1
  59. package/src/patterns/menu/Menu.stories.tsx +1100 -0
  60. package/src/patterns/menu/Menu.tsx +282 -0
  61. package/src/theme/themes/xspector/baseline.css +0 -1
  62. package/src/theme/tokens/baseline.css +2 -1
  63. package/src/theme/tokens/components/badge.css +54 -0
  64. package/src/theme/tokens/components/dropdown-menu.css +15 -4
  65. package/src/utils/mergeRefs.ts +46 -0
  66. package/dist/cjs/types/components/Menu/Menu.d.ts +0 -65
  67. package/dist/cjs/types/components/Menu/helpers.d.ts +0 -19
  68. package/dist/cjs/types/components/Menu/index.d.ts +0 -4
  69. package/dist/components/Menu/Menu.js +0 -64
  70. package/dist/components/Menu/Menu.stories.js +0 -406
  71. package/dist/components/Menu/helpers.js +0 -28
  72. package/dist/components/Menu/index.js +0 -3
  73. package/dist/esm/types/components/Menu/Menu.d.ts +0 -65
  74. package/dist/esm/types/components/Menu/helpers.d.ts +0 -19
  75. package/dist/esm/types/components/Menu/index.d.ts +0 -4
  76. package/src/components/Menu/Menu.stories.tsx +0 -586
  77. package/src/components/Menu/Menu.tsx +0 -235
  78. package/src/components/Menu/helpers.ts +0 -45
  79. package/src/components/Menu/index.ts +0 -7
  80. package/src/theme/themes/xspector/components/dropdown-menu.css +0 -28
@@ -8,7 +8,10 @@ import {
8
8
  DropdownMenuItem,
9
9
  DropdownMenuLabel,
10
10
  DropdownMenuPortal,
11
+ DropdownMenuRadioGroup,
12
+ DropdownMenuRadioItem,
11
13
  DropdownMenuSeparator,
14
+ DropdownMenuShortcut,
12
15
  DropdownMenuSub,
13
16
  DropdownMenuSubContent,
14
17
  DropdownMenuSubTrigger,
@@ -38,34 +41,45 @@ export default meta;
38
41
 
39
42
  // ---------------------------------------------------------------------------
40
43
  // Figma: Normal dropdown / action menu
41
- // Shows all item states: Default, Hover (focus), Selected, Disabled, Selected+Disabled
44
+ // Shows all item states: Default, Hover, Selected, Disabled, Selected+Disabled
42
45
  // ---------------------------------------------------------------------------
43
46
  export const AllStates = {
44
47
  name: "All States (Normal)",
45
48
  render: () => (
46
49
  <div className="flex gap-8 items-start flex-wrap">
47
- {/* Default open — all states visible */}
50
+ {/* Static — all states visible */}
48
51
  <div>
49
- <p className="typography-small4 text-text-g-contrast-medium mb-2">All States</p>
50
- <DropdownMenu open>
52
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
53
+ All States
54
+ </p>
55
+ <DropdownMenu>
51
56
  <DropdownMenuTrigger asChild>
52
57
  <ActionButton variant="icon">
53
58
  <Icon type="heroicons" name="ellipsis-vertical" />
54
59
  </ActionButton>
55
60
  </DropdownMenuTrigger>
56
- <DropdownMenuContent className="relative" style={{ position: "static", transform: "none" }}>
61
+ <DropdownMenuContent
62
+ className="relative"
63
+ style={{ position: "static", transform: "none" }}
64
+ >
57
65
  <DropdownMenuItem>Option Description</DropdownMenuItem>
58
- <DropdownMenuItem className="!bg-[var(--dropdown-menu-hover-bg)]">Option Description (Hover)</DropdownMenuItem>
59
- <DropdownMenuCheckboxItem checked>Option Description</DropdownMenuCheckboxItem>
66
+ <DropdownMenuItem className="!bg-[var(--dropdown-menu-hover-bg)]">
67
+ Option Description (Hover)
68
+ </DropdownMenuItem>
69
+ <DropdownMenuItem selected>Option Description</DropdownMenuItem>
60
70
  <DropdownMenuItem disabled>Option Description</DropdownMenuItem>
61
- <DropdownMenuCheckboxItem checked disabled>Option Description</DropdownMenuCheckboxItem>
71
+ <DropdownMenuItem selected disabled>
72
+ Option Description
73
+ </DropdownMenuItem>
62
74
  </DropdownMenuContent>
63
75
  </DropdownMenu>
64
76
  </div>
65
77
 
66
78
  {/* Interactive version */}
67
79
  <div>
68
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
80
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
81
+ Interactive
82
+ </p>
69
83
  <DropdownMenu>
70
84
  <DropdownMenuTrigger asChild>
71
85
  <Button variant="outline">Open Menu</Button>
@@ -73,9 +87,11 @@ export const AllStates = {
73
87
  <DropdownMenuContent>
74
88
  <DropdownMenuItem>Option Description</DropdownMenuItem>
75
89
  <DropdownMenuItem>Option Description</DropdownMenuItem>
76
- <DropdownMenuCheckboxItem checked>Option Description</DropdownMenuCheckboxItem>
90
+ <DropdownMenuItem selected>Option Description</DropdownMenuItem>
77
91
  <DropdownMenuItem disabled>Option Description</DropdownMenuItem>
78
- <DropdownMenuCheckboxItem checked disabled>Option Description</DropdownMenuCheckboxItem>
92
+ <DropdownMenuItem selected disabled>
93
+ Option Description
94
+ </DropdownMenuItem>
79
95
  </DropdownMenuContent>
80
96
  </DropdownMenu>
81
97
  </div>
@@ -92,60 +108,136 @@ export const WithIcon = {
92
108
  render: () => (
93
109
  <div className="flex gap-8 items-start flex-wrap">
94
110
  <div>
95
- <p className="typography-small4 text-text-g-contrast-medium mb-2">All States — With Icon</p>
96
- <DropdownMenu open>
111
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
112
+ All States — With Icon
113
+ </p>
114
+ <DropdownMenu>
97
115
  <DropdownMenuTrigger asChild>
98
116
  <ActionButton variant="icon">
99
117
  <Icon type="heroicons" name="ellipsis-vertical" />
100
118
  </ActionButton>
101
119
  </DropdownMenuTrigger>
102
- <DropdownMenuContent className="relative" style={{ position: "static", transform: "none" }}>
103
- <DropdownMenuItem>
104
- <Icon type="heroicons" name="rocket-launch" className="size-4 shrink-0" />
120
+ <DropdownMenuContent
121
+ className="relative"
122
+ style={{ position: "static", transform: "none" }}
123
+ >
124
+ <DropdownMenuItem
125
+ icon={
126
+ <Icon
127
+ type="heroicons"
128
+ name="rocket-launch"
129
+ className="size-4 shrink-0"
130
+ />
131
+ }
132
+ >
105
133
  Option Description
106
134
  </DropdownMenuItem>
107
- <DropdownMenuItem className="!bg-[var(--dropdown-menu-hover-bg)]">
108
- <Icon type="heroicons" name="rocket-launch" className="size-4 shrink-0" />
135
+ <DropdownMenuItem
136
+ className="!bg-[var(--dropdown-menu-hover-bg)]"
137
+ icon={
138
+ <Icon
139
+ type="heroicons"
140
+ name="rocket-launch"
141
+ className="size-4 shrink-0"
142
+ />
143
+ }
144
+ >
109
145
  Option Description (Hover)
110
146
  </DropdownMenuItem>
111
- <DropdownMenuCheckboxItem checked>
112
- <Icon type="heroicons" name="rocket-launch" className="size-4 shrink-0" />
113
- Option Description
114
- </DropdownMenuCheckboxItem>
115
- <DropdownMenuItem disabled>
116
- <Icon type="heroicons" name="rocket-launch" className="size-4 shrink-0" />
117
- Option Description
147
+ <DropdownMenuItem
148
+ selected
149
+ icon={
150
+ <Icon
151
+ type="heroicons"
152
+ name="rocket-launch"
153
+ className="size-4 shrink-0"
154
+ />
155
+ }
156
+ >
157
+ Option Description (Selected)
158
+ </DropdownMenuItem>
159
+ <DropdownMenuItem
160
+ disabled
161
+ icon={
162
+ <Icon
163
+ type="heroicons"
164
+ name="rocket-launch"
165
+ className="size-4 shrink-0"
166
+ />
167
+ }
168
+ >
169
+ Option Description (Disabled)
170
+ </DropdownMenuItem>
171
+ <DropdownMenuItem
172
+ selected
173
+ disabled
174
+ icon={
175
+ <Icon
176
+ type="heroicons"
177
+ name="rocket-launch"
178
+ className="size-4 shrink-0"
179
+ />
180
+ }
181
+ >
182
+ Option Description (Selected + Disabled)
118
183
  </DropdownMenuItem>
119
- <DropdownMenuCheckboxItem checked disabled>
120
- <Icon type="heroicons" name="rocket-launch" className="size-4 shrink-0" />
121
- Option Description
122
- </DropdownMenuCheckboxItem>
123
184
  </DropdownMenuContent>
124
185
  </DropdownMenu>
125
186
  </div>
126
187
 
127
188
  <div>
128
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
189
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
190
+ Interactive
191
+ </p>
129
192
  <DropdownMenu>
130
193
  <DropdownMenuTrigger asChild>
131
194
  <Button variant="outline">Open Menu</Button>
132
195
  </DropdownMenuTrigger>
133
196
  <DropdownMenuContent>
134
- <DropdownMenuItem>
135
- <Icon type="heroicons" name="rocket-launch" className="size-4 shrink-0" />
136
- Option Description
197
+ <DropdownMenuItem
198
+ icon={
199
+ <Icon
200
+ type="heroicons"
201
+ name="rocket-launch"
202
+ className="size-4 shrink-0"
203
+ />
204
+ }
205
+ >
206
+ Launch
137
207
  </DropdownMenuItem>
138
- <DropdownMenuItem>
139
- <Icon type="heroicons" name="pencil" className="size-4 shrink-0" />
140
- Option Description
208
+ <DropdownMenuItem
209
+ icon={
210
+ <Icon
211
+ type="heroicons"
212
+ name="pencil"
213
+ className="size-4 shrink-0"
214
+ />
215
+ }
216
+ >
217
+ Edit
141
218
  </DropdownMenuItem>
142
- <DropdownMenuItem>
143
- <Icon type="heroicons" name="trash" className="size-4 shrink-0" />
144
- Option Description
219
+ <DropdownMenuItem
220
+ icon={
221
+ <Icon
222
+ type="heroicons"
223
+ name="document-duplicate"
224
+ className="size-4 shrink-0"
225
+ />
226
+ }
227
+ >
228
+ Duplicate
145
229
  </DropdownMenuItem>
146
- <DropdownMenuItem disabled>
147
- <Icon type="heroicons" name="arrow-path" className="size-4 shrink-0" />
148
- Option Description
230
+ <DropdownMenuItem
231
+ disabled
232
+ icon={
233
+ <Icon
234
+ type="heroicons"
235
+ name="trash"
236
+ className="size-4 shrink-0"
237
+ />
238
+ }
239
+ >
240
+ Delete
149
241
  </DropdownMenuItem>
150
242
  </DropdownMenuContent>
151
243
  </DropdownMenu>
@@ -167,40 +259,68 @@ export const WithCheckbox = {
167
259
  return (
168
260
  <div className="flex gap-8 items-start flex-wrap">
169
261
  <div>
170
- <p className="typography-small4 text-text-g-contrast-medium mb-2">All States — Checkbox</p>
171
- <DropdownMenu open>
262
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
263
+ All States — Checkbox
264
+ </p>
265
+ <DropdownMenu>
172
266
  <DropdownMenuTrigger asChild>
173
267
  <ActionButton variant="icon">
174
268
  <Icon type="heroicons" name="ellipsis-vertical" />
175
269
  </ActionButton>
176
270
  </DropdownMenuTrigger>
177
- <DropdownMenuContent className="relative" style={{ position: "static", transform: "none" }}>
178
- <DropdownMenuCheckboxItem>Option Description</DropdownMenuCheckboxItem>
179
- <DropdownMenuCheckboxItem className="!bg-[var(--dropdown-menu-hover-bg)]">Option Description (Hover)</DropdownMenuCheckboxItem>
180
- <DropdownMenuCheckboxItem checked>Option Description</DropdownMenuCheckboxItem>
181
- <DropdownMenuCheckboxItem disabled>Option Description</DropdownMenuCheckboxItem>
182
- <DropdownMenuCheckboxItem checked disabled>Option Description</DropdownMenuCheckboxItem>
271
+ <DropdownMenuContent
272
+ className="relative"
273
+ style={{ position: "static", transform: "none" }}
274
+ >
275
+ <DropdownMenuCheckboxItem>
276
+ Option Description
277
+ </DropdownMenuCheckboxItem>
278
+ <DropdownMenuCheckboxItem className="!bg-[var(--dropdown-menu-hover-bg)]">
279
+ Option Description (Hover)
280
+ </DropdownMenuCheckboxItem>
281
+ <DropdownMenuCheckboxItem checked>
282
+ Option Description
283
+ </DropdownMenuCheckboxItem>
284
+ <DropdownMenuCheckboxItem disabled>
285
+ Option Description
286
+ </DropdownMenuCheckboxItem>
287
+ <DropdownMenuCheckboxItem checked disabled>
288
+ Option Description
289
+ </DropdownMenuCheckboxItem>
183
290
  </DropdownMenuContent>
184
291
  </DropdownMenu>
185
292
  </div>
186
293
 
187
294
  <div>
188
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
295
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
296
+ Interactive
297
+ </p>
189
298
  <DropdownMenu>
190
299
  <DropdownMenuTrigger asChild>
191
300
  <Button variant="outline">Open Menu</Button>
192
301
  </DropdownMenuTrigger>
193
302
  <DropdownMenuContent>
194
- <DropdownMenuCheckboxItem checked={checked1} onCheckedChange={setChecked1}>
303
+ <DropdownMenuCheckboxItem
304
+ checked={checked1}
305
+ onCheckedChange={setChecked1}
306
+ >
307
+ Option Description
308
+ </DropdownMenuCheckboxItem>
309
+ <DropdownMenuCheckboxItem
310
+ checked={checked2}
311
+ onCheckedChange={setChecked2}
312
+ >
195
313
  Option Description
196
314
  </DropdownMenuCheckboxItem>
197
- <DropdownMenuCheckboxItem checked={checked2} onCheckedChange={setChecked2}>
315
+ <DropdownMenuCheckboxItem
316
+ checked={checked3}
317
+ onCheckedChange={setChecked3}
318
+ >
198
319
  Option Description
199
320
  </DropdownMenuCheckboxItem>
200
- <DropdownMenuCheckboxItem checked={checked3} onCheckedChange={setChecked3}>
321
+ <DropdownMenuCheckboxItem disabled>
201
322
  Option Description
202
323
  </DropdownMenuCheckboxItem>
203
- <DropdownMenuCheckboxItem disabled>Option Description</DropdownMenuCheckboxItem>
204
324
  </DropdownMenuContent>
205
325
  </DropdownMenu>
206
326
  </div>
@@ -217,14 +337,19 @@ export const WithSection = {
217
337
  render: () => (
218
338
  <div className="flex gap-8 items-start flex-wrap">
219
339
  <div>
220
- <p className="typography-small4 text-text-g-contrast-medium mb-2">With Section Header</p>
221
- <DropdownMenu open>
340
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
341
+ With Section Header
342
+ </p>
343
+ <DropdownMenu>
222
344
  <DropdownMenuTrigger asChild>
223
345
  <ActionButton variant="icon">
224
346
  <Icon type="heroicons" name="ellipsis-vertical" />
225
347
  </ActionButton>
226
348
  </DropdownMenuTrigger>
227
- <DropdownMenuContent className="relative" style={{ position: "static", transform: "none" }}>
349
+ <DropdownMenuContent
350
+ className="relative"
351
+ style={{ position: "static", transform: "none" }}
352
+ >
228
353
  <DropdownMenuLabel>Section Name</DropdownMenuLabel>
229
354
  <DropdownMenuItem>Option Description</DropdownMenuItem>
230
355
  <DropdownMenuItem>Option Description</DropdownMenuItem>
@@ -241,7 +366,9 @@ export const WithSection = {
241
366
  </div>
242
367
 
243
368
  <div>
244
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
369
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
370
+ Interactive
371
+ </p>
245
372
  <DropdownMenu>
246
373
  <DropdownMenuTrigger asChild>
247
374
  <Button variant="outline">Open Menu</Button>
@@ -285,14 +412,16 @@ export const WithSearch = {
285
412
  "Project Theta",
286
413
  ];
287
414
  const filtered = allOptions.filter((o) =>
288
- o.toLowerCase().includes(query.toLowerCase())
415
+ o.toLowerCase().includes(query.toLowerCase()),
289
416
  );
290
417
 
291
418
  return (
292
419
  <div className="flex gap-8 items-start flex-wrap">
293
420
  <div>
294
- <p className="typography-small4 text-text-g-contrast-medium mb-2">With Search Field</p>
295
- <DropdownMenu open>
421
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
422
+ With Search Field
423
+ </p>
424
+ <DropdownMenu>
296
425
  <DropdownMenuTrigger asChild>
297
426
  <ActionButton variant="icon">
298
427
  <Icon type="heroicons" name="ellipsis-vertical" />
@@ -304,7 +433,11 @@ export const WithSearch = {
304
433
  onInteractOutside={(e: Event) => e.preventDefault()}
305
434
  >
306
435
  <div className="flex items-center px-4 py-2 border-b border-[var(--dropdown-menu-seperator-bg)]">
307
- <Icon type="heroicons" name="magnifying-glass" className="size-[14px] shrink-0 text-text-g-contrast-medium mr-1" />
436
+ <Icon
437
+ type="heroicons"
438
+ name="magnifying-glass"
439
+ className="size-[14px] shrink-0 text-text-g-contrast-medium mr-1"
440
+ />
308
441
  <Input
309
442
  variant="flat"
310
443
  size="sm"
@@ -327,14 +460,20 @@ export const WithSearch = {
327
460
  </div>
328
461
 
329
462
  <div>
330
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
463
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
464
+ Interactive
465
+ </p>
331
466
  <DropdownMenu>
332
467
  <DropdownMenuTrigger asChild>
333
468
  <Button variant="outline">Open Menu</Button>
334
469
  </DropdownMenuTrigger>
335
470
  <DropdownMenuContent className="w-[230px]">
336
471
  <div className="flex items-center px-4 py-2 border-b border-[var(--dropdown-menu-seperator-bg)]">
337
- <Icon type="heroicons" name="magnifying-glass" className="size-[14px] shrink-0 text-text-g-contrast-medium mr-1" />
472
+ <Icon
473
+ type="heroicons"
474
+ name="magnifying-glass"
475
+ className="size-[14px] shrink-0 text-text-g-contrast-medium mr-1"
476
+ />
338
477
  <Input
339
478
  variant="flat"
340
479
  size="sm"
@@ -363,8 +502,10 @@ export const CanScroll = {
363
502
  render: () => (
364
503
  <div className="flex gap-8 items-start flex-wrap">
365
504
  <div>
366
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Scrollable List</p>
367
- <DropdownMenu open>
505
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
506
+ Scrollable List
507
+ </p>
508
+ <DropdownMenu>
368
509
  <DropdownMenuTrigger asChild>
369
510
  <ActionButton variant="icon">
370
511
  <Icon type="heroicons" name="ellipsis-vertical" />
@@ -375,21 +516,27 @@ export const CanScroll = {
375
516
  style={{ position: "static", transform: "none" }}
376
517
  >
377
518
  {Array.from({ length: 10 }, (_, i) => (
378
- <DropdownMenuItem key={i}>Option Description {i + 1}</DropdownMenuItem>
519
+ <DropdownMenuItem key={i}>
520
+ Option Description {i + 1}
521
+ </DropdownMenuItem>
379
522
  ))}
380
523
  </DropdownMenuContent>
381
524
  </DropdownMenu>
382
525
  </div>
383
526
 
384
527
  <div>
385
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
528
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
529
+ Interactive
530
+ </p>
386
531
  <DropdownMenu>
387
532
  <DropdownMenuTrigger asChild>
388
533
  <Button variant="outline">Open Menu</Button>
389
534
  </DropdownMenuTrigger>
390
535
  <DropdownMenuContent className="max-h-[270px] overflow-y-auto">
391
536
  {Array.from({ length: 10 }, (_, i) => (
392
- <DropdownMenuItem key={i}>Option Description {i + 1}</DropdownMenuItem>
537
+ <DropdownMenuItem key={i}>
538
+ Option Description {i + 1}
539
+ </DropdownMenuItem>
393
540
  ))}
394
541
  </DropdownMenuContent>
395
542
  </DropdownMenu>
@@ -406,8 +553,10 @@ export const DoubleScroll = {
406
553
  render: () => (
407
554
  <div className="flex gap-8 items-start flex-wrap">
408
555
  <div>
409
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Two Scrollable Sections</p>
410
- <DropdownMenu open>
556
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
557
+ Two Scrollable Sections
558
+ </p>
559
+ <DropdownMenu>
411
560
  <DropdownMenuTrigger asChild>
412
561
  <ActionButton variant="icon">
413
562
  <Icon type="heroicons" name="ellipsis-vertical" />
@@ -420,14 +569,18 @@ export const DoubleScroll = {
420
569
  <DropdownMenuLabel>Section A</DropdownMenuLabel>
421
570
  <div className="max-h-[270px] overflow-y-auto">
422
571
  {Array.from({ length: 5 }, (_, i) => (
423
- <DropdownMenuItem key={i}>Option Description {i + 1}</DropdownMenuItem>
572
+ <DropdownMenuItem key={i}>
573
+ Option Description {i + 1}
574
+ </DropdownMenuItem>
424
575
  ))}
425
576
  </div>
426
577
  <DropdownMenuSeparator />
427
578
  <DropdownMenuLabel>Section B</DropdownMenuLabel>
428
579
  <div className="max-h-[216px] overflow-y-auto">
429
580
  {Array.from({ length: 4 }, (_, i) => (
430
- <DropdownMenuItem key={i}>Option Description {i + 1}</DropdownMenuItem>
581
+ <DropdownMenuItem key={i}>
582
+ Option Description {i + 1}
583
+ </DropdownMenuItem>
431
584
  ))}
432
585
  </div>
433
586
  </DropdownMenuContent>
@@ -435,7 +588,9 @@ export const DoubleScroll = {
435
588
  </div>
436
589
 
437
590
  <div>
438
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Interactive</p>
591
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
592
+ Interactive
593
+ </p>
439
594
  <DropdownMenu>
440
595
  <DropdownMenuTrigger asChild>
441
596
  <Button variant="outline">Open Menu</Button>
@@ -444,14 +599,18 @@ export const DoubleScroll = {
444
599
  <DropdownMenuLabel>Section A</DropdownMenuLabel>
445
600
  <div className="max-h-[270px] overflow-y-auto">
446
601
  {Array.from({ length: 5 }, (_, i) => (
447
- <DropdownMenuItem key={i}>Option Description {i + 1}</DropdownMenuItem>
602
+ <DropdownMenuItem key={i}>
603
+ Option Description {i + 1}
604
+ </DropdownMenuItem>
448
605
  ))}
449
606
  </div>
450
607
  <DropdownMenuSeparator />
451
608
  <DropdownMenuLabel>Section B</DropdownMenuLabel>
452
609
  <div className="max-h-[216px] overflow-y-auto">
453
610
  {Array.from({ length: 4 }, (_, i) => (
454
- <DropdownMenuItem key={i}>Option Description {i + 1}</DropdownMenuItem>
611
+ <DropdownMenuItem key={i}>
612
+ Option Description {i + 1}
613
+ </DropdownMenuItem>
455
614
  ))}
456
615
  </div>
457
616
  </DropdownMenuContent>
@@ -467,36 +626,426 @@ export const DoubleScroll = {
467
626
  export const SubMenu = {
468
627
  name: "Sub Menu",
469
628
  render: () => (
470
- <DropdownMenu>
471
- <DropdownMenuTrigger asChild>
472
- <Button variant="outline">Open Menu</Button>
473
- </DropdownMenuTrigger>
474
- <DropdownMenuContent>
475
- <DropdownMenuLabel>My Account</DropdownMenuLabel>
476
- <DropdownMenuSeparator />
477
- <DropdownMenuItem>Profile</DropdownMenuItem>
478
- <DropdownMenuItem>Billing</DropdownMenuItem>
479
- <DropdownMenuItem>Team</DropdownMenuItem>
480
- <DropdownMenuSeparator />
481
- <DropdownMenuGroup>
482
- <DropdownMenuSub>
483
- <DropdownMenuSubTrigger>
484
- <Icon type="heroicons" name="user-group" className="size-4 shrink-0" />
485
- Invite users
486
- </DropdownMenuSubTrigger>
487
- <DropdownMenuPortal>
488
- <DropdownMenuSubContent>
489
- <DropdownMenuItem>Email</DropdownMenuItem>
490
- <DropdownMenuItem>Message</DropdownMenuItem>
491
- <DropdownMenuSeparator />
492
- <DropdownMenuItem>More...</DropdownMenuItem>
493
- </DropdownMenuSubContent>
494
- </DropdownMenuPortal>
495
- </DropdownMenuSub>
496
- <DropdownMenuCheckboxItem>Panel</DropdownMenuCheckboxItem>
497
- </DropdownMenuGroup>
498
- </DropdownMenuContent>
499
- </DropdownMenu>
629
+ <div className="flex gap-8 items-center flex-wrap">
630
+ <DropdownMenu>
631
+ <DropdownMenuTrigger asChild>
632
+ <Button variant="outline">Open Menu</Button>
633
+ </DropdownMenuTrigger>
634
+ <DropdownMenuContent>
635
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
636
+ <DropdownMenuSeparator />
637
+ <DropdownMenuItem>Profile</DropdownMenuItem>
638
+ <DropdownMenuItem>Billing</DropdownMenuItem>
639
+ <DropdownMenuItem>Team</DropdownMenuItem>
640
+ <DropdownMenuSeparator />
641
+ <DropdownMenuGroup>
642
+ <DropdownMenuSub>
643
+ <DropdownMenuSubTrigger>
644
+ <Icon
645
+ type="heroicons"
646
+ name="user-group"
647
+ className="size-4 shrink-0"
648
+ />
649
+ Invite users
650
+ </DropdownMenuSubTrigger>
651
+ <DropdownMenuPortal>
652
+ <DropdownMenuSubContent>
653
+ <DropdownMenuItem>Email</DropdownMenuItem>
654
+ <DropdownMenuItem>Message</DropdownMenuItem>
655
+ <DropdownMenuSeparator />
656
+ <DropdownMenuItem>More...</DropdownMenuItem>
657
+ </DropdownMenuSubContent>
658
+ </DropdownMenuPortal>
659
+ </DropdownMenuSub>
660
+ <DropdownMenuCheckboxItem>Panel</DropdownMenuCheckboxItem>
661
+ </DropdownMenuGroup>
662
+ </DropdownMenuContent>
663
+ </DropdownMenu>
664
+ </div>
665
+ ),
666
+ } satisfies StoryObj;
667
+
668
+ // ---------------------------------------------------------------------------
669
+ // Figma: Radio items — single select via DropdownMenuRadioGroup
670
+ // ---------------------------------------------------------------------------
671
+ export const WithRadio = {
672
+ name: "With Radio",
673
+ render: () => {
674
+ const [theme, setTheme] = useState("light");
675
+ const [position, setPosition] = useState("top");
676
+
677
+ return (
678
+ <div className="flex gap-8 items-start flex-wrap">
679
+ <div>
680
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
681
+ All States — Radio
682
+ </p>
683
+ <DropdownMenu>
684
+ <DropdownMenuTrigger asChild>
685
+ <ActionButton variant="icon">
686
+ <Icon type="heroicons" name="ellipsis-vertical" />
687
+ </ActionButton>
688
+ </DropdownMenuTrigger>
689
+ <DropdownMenuContent
690
+ className="relative"
691
+ style={{ position: "static", transform: "none" }}
692
+ >
693
+ <DropdownMenuRadioGroup value="light">
694
+ <DropdownMenuRadioItem value="unselected">
695
+ Option Description
696
+ </DropdownMenuRadioItem>
697
+ <DropdownMenuRadioItem
698
+ value="unselected2"
699
+ className="!bg-[var(--dropdown-menu-hover-bg)]"
700
+ >
701
+ Option Description (Hover)
702
+ </DropdownMenuRadioItem>
703
+ <DropdownMenuRadioItem value="light">
704
+ Option Description (Selected)
705
+ </DropdownMenuRadioItem>
706
+ <DropdownMenuRadioItem value="dis" disabled>
707
+ Option Description (Disabled)
708
+ </DropdownMenuRadioItem>
709
+ <DropdownMenuRadioItem value="light" disabled>
710
+ Option Description (Selected + Disabled)
711
+ </DropdownMenuRadioItem>
712
+ </DropdownMenuRadioGroup>
713
+ </DropdownMenuContent>
714
+ </DropdownMenu>
715
+ </div>
716
+
717
+ <div>
718
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
719
+ Interactive — Theme
720
+ </p>
721
+ <DropdownMenu>
722
+ <DropdownMenuTrigger asChild>
723
+ <Button variant="outline">Theme: {theme}</Button>
724
+ </DropdownMenuTrigger>
725
+ <DropdownMenuContent>
726
+ <DropdownMenuLabel>Theme</DropdownMenuLabel>
727
+ <DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
728
+ <DropdownMenuRadioItem value="light">
729
+ Light
730
+ </DropdownMenuRadioItem>
731
+ <DropdownMenuRadioItem value="dark">Dark</DropdownMenuRadioItem>
732
+ <DropdownMenuRadioItem value="system">
733
+ System
734
+ </DropdownMenuRadioItem>
735
+ </DropdownMenuRadioGroup>
736
+ </DropdownMenuContent>
737
+ </DropdownMenu>
738
+ </div>
739
+
740
+ <div>
741
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
742
+ Interactive — Multiple Groups
743
+ </p>
744
+ <DropdownMenu>
745
+ <DropdownMenuTrigger asChild>
746
+ <Button variant="outline">Open Menu</Button>
747
+ </DropdownMenuTrigger>
748
+ <DropdownMenuContent>
749
+ <DropdownMenuLabel>Theme</DropdownMenuLabel>
750
+ <DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
751
+ <DropdownMenuRadioItem value="light">
752
+ Light
753
+ </DropdownMenuRadioItem>
754
+ <DropdownMenuRadioItem value="dark">Dark</DropdownMenuRadioItem>
755
+ <DropdownMenuRadioItem value="system">
756
+ System
757
+ </DropdownMenuRadioItem>
758
+ </DropdownMenuRadioGroup>
759
+ <DropdownMenuSeparator />
760
+ <DropdownMenuLabel>Position</DropdownMenuLabel>
761
+ <DropdownMenuRadioGroup
762
+ value={position}
763
+ onValueChange={setPosition}
764
+ >
765
+ <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
766
+ <DropdownMenuRadioItem value="bottom">
767
+ Bottom
768
+ </DropdownMenuRadioItem>
769
+ <DropdownMenuRadioItem value="right">
770
+ Right
771
+ </DropdownMenuRadioItem>
772
+ </DropdownMenuRadioGroup>
773
+ </DropdownMenuContent>
774
+ </DropdownMenu>
775
+ </div>
776
+ </div>
777
+ );
778
+ },
779
+ } satisfies StoryObj;
780
+
781
+ // ---------------------------------------------------------------------------
782
+ // Radio with Icon — single select with leading icon via icon prop
783
+ // ---------------------------------------------------------------------------
784
+ export const WithRadioAndIcon = {
785
+ name: "With Radio + Icon",
786
+ render: () => {
787
+ const [theme, setTheme] = useState("dark");
788
+
789
+ return (
790
+ <div className="flex gap-8 items-start flex-wrap">
791
+ <div>
792
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
793
+ All States — Radio + Icon
794
+ </p>
795
+ <DropdownMenu>
796
+ <DropdownMenuTrigger asChild>
797
+ <ActionButton variant="icon">
798
+ <Icon type="heroicons" name="ellipsis-vertical" />
799
+ </ActionButton>
800
+ </DropdownMenuTrigger>
801
+ <DropdownMenuContent
802
+ className="relative"
803
+ style={{ position: "static", transform: "none" }}
804
+ >
805
+ <DropdownMenuRadioGroup value="dark">
806
+ <DropdownMenuRadioItem
807
+ value="light"
808
+ icon={
809
+ <Icon
810
+ type="heroicons"
811
+ name="sun"
812
+ className="size-4 shrink-0"
813
+ />
814
+ }
815
+ >
816
+ Light
817
+ </DropdownMenuRadioItem>
818
+ <DropdownMenuRadioItem
819
+ value="system"
820
+ className="!bg-[var(--dropdown-menu-hover-bg)]"
821
+ icon={
822
+ <Icon
823
+ type="heroicons"
824
+ name="computer-desktop"
825
+ className="size-4 shrink-0"
826
+ />
827
+ }
828
+ >
829
+ System (Hover)
830
+ </DropdownMenuRadioItem>
831
+ <DropdownMenuRadioItem
832
+ value="dark"
833
+ icon={
834
+ <Icon
835
+ type="heroicons"
836
+ name="moon"
837
+ className="size-4 shrink-0"
838
+ />
839
+ }
840
+ >
841
+ Dark (Selected)
842
+ </DropdownMenuRadioItem>
843
+ <DropdownMenuRadioItem
844
+ value="custom"
845
+ disabled
846
+ icon={
847
+ <Icon
848
+ type="heroicons"
849
+ name="paint-brush"
850
+ className="size-4 shrink-0"
851
+ />
852
+ }
853
+ >
854
+ Custom (Disabled)
855
+ </DropdownMenuRadioItem>
856
+ <DropdownMenuRadioItem
857
+ value="dark"
858
+ disabled
859
+ icon={
860
+ <Icon
861
+ type="heroicons"
862
+ name="moon"
863
+ className="size-4 shrink-0"
864
+ />
865
+ }
866
+ >
867
+ Dark (Selected + Disabled)
868
+ </DropdownMenuRadioItem>
869
+ </DropdownMenuRadioGroup>
870
+ </DropdownMenuContent>
871
+ </DropdownMenu>
872
+ </div>
873
+
874
+ <div>
875
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
876
+ Interactive
877
+ </p>
878
+ <DropdownMenu>
879
+ <DropdownMenuTrigger asChild>
880
+ <Button variant="outline">Theme: {theme}</Button>
881
+ </DropdownMenuTrigger>
882
+ <DropdownMenuContent>
883
+ <DropdownMenuLabel>Theme</DropdownMenuLabel>
884
+ <DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
885
+ <DropdownMenuRadioItem
886
+ value="light"
887
+ icon={
888
+ <Icon
889
+ type="heroicons"
890
+ name="sun"
891
+ className="size-4 shrink-0"
892
+ />
893
+ }
894
+ >
895
+ Light
896
+ </DropdownMenuRadioItem>
897
+ <DropdownMenuRadioItem
898
+ value="dark"
899
+ icon={
900
+ <Icon
901
+ type="heroicons"
902
+ name="moon"
903
+ className="size-4 shrink-0"
904
+ />
905
+ }
906
+ >
907
+ Dark
908
+ </DropdownMenuRadioItem>
909
+ <DropdownMenuRadioItem
910
+ value="system"
911
+ icon={
912
+ <Icon
913
+ type="heroicons"
914
+ name="computer-desktop"
915
+ className="size-4 shrink-0"
916
+ />
917
+ }
918
+ >
919
+ System
920
+ </DropdownMenuRadioItem>
921
+ <DropdownMenuRadioItem
922
+ value="custom"
923
+ disabled
924
+ icon={
925
+ <Icon
926
+ type="heroicons"
927
+ name="paint-brush"
928
+ className="size-4"
929
+ />
930
+ }
931
+ >
932
+ Custom
933
+ </DropdownMenuRadioItem>
934
+ </DropdownMenuRadioGroup>
935
+ </DropdownMenuContent>
936
+ </DropdownMenu>
937
+ </div>
938
+ </div>
939
+ );
940
+ },
941
+ } satisfies StoryObj;
942
+
943
+ // ---------------------------------------------------------------------------
944
+ // DropdownMenuShortcut — keyboard shortcut label on the right side of item
945
+ // ---------------------------------------------------------------------------
946
+ export const WithShortcut = {
947
+ name: "With Shortcut",
948
+ render: () => (
949
+ <div className="flex gap-8 items-start flex-wrap">
950
+ <div>
951
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
952
+ All States — Shortcut
953
+ </p>
954
+ <DropdownMenu>
955
+ <DropdownMenuTrigger asChild>
956
+ <ActionButton variant="icon">
957
+ <Icon type="heroicons" name="ellipsis-vertical" />
958
+ </ActionButton>
959
+ </DropdownMenuTrigger>
960
+ <DropdownMenuContent
961
+ className="relative"
962
+ style={{ position: "static", transform: "none" }}
963
+ >
964
+ <DropdownMenuItem>
965
+ New Tab
966
+ <DropdownMenuShortcut>⌘T</DropdownMenuShortcut>
967
+ </DropdownMenuItem>
968
+ <DropdownMenuItem className="!bg-[var(--dropdown-menu-hover-bg)]">
969
+ New Window (Hover)
970
+ <DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
971
+ </DropdownMenuItem>
972
+ <DropdownMenuSeparator />
973
+ <DropdownMenuItem>
974
+ <Icon
975
+ type="heroicons"
976
+ name="pencil"
977
+ className="size-4 shrink-0"
978
+ />
979
+ Edit
980
+ <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>
981
+ </DropdownMenuItem>
982
+ <DropdownMenuItem>
983
+ <Icon
984
+ type="heroicons"
985
+ name="document-duplicate"
986
+ className="size-4 shrink-0"
987
+ />
988
+ Duplicate
989
+ <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
990
+ </DropdownMenuItem>
991
+ <DropdownMenuSeparator />
992
+ <DropdownMenuItem disabled>
993
+ <Icon type="heroicons" name="trash" className="size-4 shrink-0" />
994
+ Delete
995
+ <DropdownMenuShortcut>⌫</DropdownMenuShortcut>
996
+ </DropdownMenuItem>
997
+ </DropdownMenuContent>
998
+ </DropdownMenu>
999
+ </div>
1000
+
1001
+ <div>
1002
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1003
+ Interactive
1004
+ </p>
1005
+ <DropdownMenu>
1006
+ <DropdownMenuTrigger asChild>
1007
+ <Button variant="outline">Open Menu</Button>
1008
+ </DropdownMenuTrigger>
1009
+ <DropdownMenuContent className="w-52">
1010
+ <DropdownMenuLabel>Actions</DropdownMenuLabel>
1011
+ <DropdownMenuSeparator />
1012
+ <DropdownMenuItem>
1013
+ New Tab
1014
+ <DropdownMenuShortcut>⌘T</DropdownMenuShortcut>
1015
+ </DropdownMenuItem>
1016
+ <DropdownMenuItem>
1017
+ New Window
1018
+ <DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
1019
+ </DropdownMenuItem>
1020
+ <DropdownMenuSeparator />
1021
+ <DropdownMenuItem>
1022
+ <Icon
1023
+ type="heroicons"
1024
+ name="pencil"
1025
+ className="size-4 shrink-0"
1026
+ />
1027
+ Edit
1028
+ <DropdownMenuShortcut>⌘E</DropdownMenuShortcut>
1029
+ </DropdownMenuItem>
1030
+ <DropdownMenuItem>
1031
+ <Icon
1032
+ type="heroicons"
1033
+ name="document-duplicate"
1034
+ className="size-4 shrink-0"
1035
+ />
1036
+ Duplicate
1037
+ <DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
1038
+ </DropdownMenuItem>
1039
+ <DropdownMenuSeparator />
1040
+ <DropdownMenuItem disabled>
1041
+ <Icon type="heroicons" name="trash" className="size-4 shrink-0" />
1042
+ Delete
1043
+ <DropdownMenuShortcut>⌫</DropdownMenuShortcut>
1044
+ </DropdownMenuItem>
1045
+ </DropdownMenuContent>
1046
+ </DropdownMenu>
1047
+ </div>
1048
+ </div>
500
1049
  ),
501
1050
  } satisfies StoryObj;
502
1051
 
@@ -508,7 +1057,9 @@ export const TriggerVariants = {
508
1057
  render: () => (
509
1058
  <div className="flex gap-8 items-center flex-wrap">
510
1059
  <div>
511
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Text Trigger</p>
1060
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1061
+ Text Trigger
1062
+ </p>
512
1063
  <DropdownMenu>
513
1064
  <DropdownMenuTrigger>Open</DropdownMenuTrigger>
514
1065
  <DropdownMenuContent>
@@ -520,7 +1071,9 @@ export const TriggerVariants = {
520
1071
  </div>
521
1072
 
522
1073
  <div>
523
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Button Trigger</p>
1074
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1075
+ Button Trigger
1076
+ </p>
524
1077
  <DropdownMenu>
525
1078
  <DropdownMenuTrigger asChild>
526
1079
  <Button variant="outline">Open Menu</Button>
@@ -534,7 +1087,9 @@ export const TriggerVariants = {
534
1087
  </div>
535
1088
 
536
1089
  <div>
537
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Icon Button Trigger</p>
1090
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1091
+ Icon Button Trigger
1092
+ </p>
538
1093
  <DropdownMenu>
539
1094
  <DropdownMenuTrigger asChild>
540
1095
  <ActionButton variant="icon">
@@ -550,7 +1105,9 @@ export const TriggerVariants = {
550
1105
  </div>
551
1106
 
552
1107
  <div>
553
- <p className="typography-small4 text-text-g-contrast-medium mb-2">Horizontal dots</p>
1108
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1109
+ Horizontal dots
1110
+ </p>
554
1111
  <DropdownMenu>
555
1112
  <DropdownMenuTrigger asChild>
556
1113
  <ActionButton variant="icon">
@@ -559,11 +1116,19 @@ export const TriggerVariants = {
559
1116
  </DropdownMenuTrigger>
560
1117
  <DropdownMenuContent>
561
1118
  <DropdownMenuItem>
562
- <Icon type="heroicons" name="pencil" className="size-4 shrink-0" />
1119
+ <Icon
1120
+ type="heroicons"
1121
+ name="pencil"
1122
+ className="size-4 shrink-0"
1123
+ />
563
1124
  Edit
564
1125
  </DropdownMenuItem>
565
1126
  <DropdownMenuItem>
566
- <Icon type="heroicons" name="document-duplicate" className="size-4 shrink-0" />
1127
+ <Icon
1128
+ type="heroicons"
1129
+ name="document-duplicate"
1130
+ className="size-4 shrink-0"
1131
+ />
567
1132
  Duplicate
568
1133
  </DropdownMenuItem>
569
1134
  <DropdownMenuSeparator />
@@ -577,3 +1142,375 @@ export const TriggerVariants = {
577
1142
  </div>
578
1143
  ),
579
1144
  } satisfies StoryObj;
1145
+
1146
+ // ---------------------------------------------------------------------------
1147
+ // Complex showcase — real-world patterns combining all item types
1148
+ // ---------------------------------------------------------------------------
1149
+ export const ComplexShowcase = {
1150
+ name: "Complex Showcase",
1151
+ render: () => {
1152
+ const [theme, setTheme] = useState("dark");
1153
+ const [density, setDensity] = useState("comfortable");
1154
+ const [sortBy, setSortBy] = useState("name");
1155
+ const [sortDir, setSortDir] = useState("asc");
1156
+ const [showHidden, setShowHidden] = useState(false);
1157
+ const [showExtensions, setShowExtensions] = useState(true);
1158
+ const [showPreview, setShowPreview] = useState(true);
1159
+
1160
+ return (
1161
+ <div className="flex gap-8 items-start flex-wrap">
1162
+ {/* Static: File manager — MenuItem + RadioGroup + CheckboxItem */}
1163
+ <div>
1164
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1165
+ File Manager Actions
1166
+ </p>
1167
+ <DropdownMenu>
1168
+ <DropdownMenuTrigger asChild>
1169
+ <ActionButton variant="icon">
1170
+ <Icon type="heroicons" name="ellipsis-vertical" />
1171
+ </ActionButton>
1172
+ </DropdownMenuTrigger>
1173
+ <DropdownMenuContent
1174
+ className="relative w-[220px]"
1175
+ style={{ position: "static", transform: "none" }}
1176
+ >
1177
+ <DropdownMenuItem
1178
+ icon={
1179
+ <Icon
1180
+ type="heroicons"
1181
+ name="pencil"
1182
+ className="size-4 shrink-0"
1183
+ />
1184
+ }
1185
+ >
1186
+ Rename
1187
+ </DropdownMenuItem>
1188
+ <DropdownMenuItem
1189
+ icon={
1190
+ <Icon
1191
+ type="heroicons"
1192
+ name="document-duplicate"
1193
+ className="size-4 shrink-0"
1194
+ />
1195
+ }
1196
+ >
1197
+ Duplicate
1198
+ </DropdownMenuItem>
1199
+ <DropdownMenuSeparator />
1200
+ <DropdownMenuLabel>Sort By</DropdownMenuLabel>
1201
+ <DropdownMenuRadioGroup value="name">
1202
+ <DropdownMenuRadioItem value="name">Name</DropdownMenuRadioItem>
1203
+ <DropdownMenuRadioItem value="date">
1204
+ Date Modified
1205
+ </DropdownMenuRadioItem>
1206
+ <DropdownMenuRadioItem value="size">Size</DropdownMenuRadioItem>
1207
+ </DropdownMenuRadioGroup>
1208
+ <DropdownMenuSeparator />
1209
+ <DropdownMenuLabel>Show</DropdownMenuLabel>
1210
+ <DropdownMenuCheckboxItem>Hidden Files</DropdownMenuCheckboxItem>
1211
+ <DropdownMenuCheckboxItem checked>
1212
+ File Extensions
1213
+ </DropdownMenuCheckboxItem>
1214
+ <DropdownMenuCheckboxItem checked>
1215
+ Preview Panel
1216
+ </DropdownMenuCheckboxItem>
1217
+ <DropdownMenuSeparator />
1218
+ <DropdownMenuItem
1219
+ disabled
1220
+ icon={
1221
+ <Icon
1222
+ type="heroicons"
1223
+ name="trash"
1224
+ className="size-4 shrink-0"
1225
+ />
1226
+ }
1227
+ >
1228
+ Delete
1229
+ </DropdownMenuItem>
1230
+ </DropdownMenuContent>
1231
+ </DropdownMenu>
1232
+ </div>
1233
+
1234
+ {/* Static: Editor settings — multiple RadioGroups per section */}
1235
+ <div>
1236
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1237
+ Editor Settings (Multiple RadioGroups)
1238
+ </p>
1239
+ <DropdownMenu>
1240
+ <DropdownMenuTrigger asChild>
1241
+ <ActionButton variant="icon">
1242
+ <Icon type="heroicons" name="cog-6-tooth" />
1243
+ </ActionButton>
1244
+ </DropdownMenuTrigger>
1245
+ <DropdownMenuContent
1246
+ className="relative w-[220px]"
1247
+ style={{ position: "static", transform: "none" }}
1248
+ >
1249
+ <DropdownMenuLabel>Theme</DropdownMenuLabel>
1250
+ <DropdownMenuRadioGroup value="dark">
1251
+ <DropdownMenuRadioItem
1252
+ value="light"
1253
+ icon={
1254
+ <Icon
1255
+ type="heroicons"
1256
+ name="sun"
1257
+ className="size-4 shrink-0"
1258
+ />
1259
+ }
1260
+ >
1261
+ Light
1262
+ </DropdownMenuRadioItem>
1263
+ <DropdownMenuRadioItem
1264
+ value="dark"
1265
+ icon={
1266
+ <Icon
1267
+ type="heroicons"
1268
+ name="moon"
1269
+ className="size-4 shrink-0"
1270
+ />
1271
+ }
1272
+ >
1273
+ Dark
1274
+ </DropdownMenuRadioItem>
1275
+ <DropdownMenuRadioItem
1276
+ value="system"
1277
+ icon={
1278
+ <Icon
1279
+ type="heroicons"
1280
+ name="computer-desktop"
1281
+ className="size-4 shrink-0"
1282
+ />
1283
+ }
1284
+ >
1285
+ System
1286
+ </DropdownMenuRadioItem>
1287
+ </DropdownMenuRadioGroup>
1288
+ <DropdownMenuSeparator />
1289
+ <DropdownMenuLabel>Density</DropdownMenuLabel>
1290
+ <DropdownMenuRadioGroup value="comfortable">
1291
+ <DropdownMenuRadioItem value="compact">
1292
+ Compact
1293
+ </DropdownMenuRadioItem>
1294
+ <DropdownMenuRadioItem value="comfortable">
1295
+ Comfortable
1296
+ </DropdownMenuRadioItem>
1297
+ <DropdownMenuRadioItem value="spacious">
1298
+ Spacious
1299
+ </DropdownMenuRadioItem>
1300
+ </DropdownMenuRadioGroup>
1301
+ <DropdownMenuSeparator />
1302
+ <DropdownMenuLabel>Sort Direction</DropdownMenuLabel>
1303
+ <DropdownMenuRadioGroup value="asc">
1304
+ <DropdownMenuRadioItem
1305
+ value="asc"
1306
+ icon={
1307
+ <Icon
1308
+ type="heroicons"
1309
+ name="bars-arrow-up"
1310
+ className="size-4 shrink-0"
1311
+ />
1312
+ }
1313
+ >
1314
+ Ascending
1315
+ </DropdownMenuRadioItem>
1316
+ <DropdownMenuRadioItem
1317
+ value="desc"
1318
+ icon={
1319
+ <Icon
1320
+ type="heroicons"
1321
+ name="bars-arrow-down"
1322
+ className="size-4 shrink-0"
1323
+ />
1324
+ }
1325
+ >
1326
+ Descending
1327
+ </DropdownMenuRadioItem>
1328
+ </DropdownMenuRadioGroup>
1329
+ </DropdownMenuContent>
1330
+ </DropdownMenu>
1331
+ </div>
1332
+
1333
+ {/* Interactive: File Manager */}
1334
+ <div>
1335
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1336
+ Interactive — File Manager
1337
+ </p>
1338
+ <DropdownMenu>
1339
+ <DropdownMenuTrigger asChild>
1340
+ <Button variant="outline">Options</Button>
1341
+ </DropdownMenuTrigger>
1342
+ <DropdownMenuContent className="w-[220px]">
1343
+ <DropdownMenuItem
1344
+ icon={
1345
+ <Icon
1346
+ type="heroicons"
1347
+ name="pencil"
1348
+ className="size-4 shrink-0"
1349
+ />
1350
+ }
1351
+ >
1352
+ Rename
1353
+ </DropdownMenuItem>
1354
+ <DropdownMenuItem
1355
+ icon={
1356
+ <Icon
1357
+ type="heroicons"
1358
+ name="document-duplicate"
1359
+ className="size-4 shrink-0"
1360
+ />
1361
+ }
1362
+ >
1363
+ Duplicate
1364
+ </DropdownMenuItem>
1365
+ <DropdownMenuSeparator />
1366
+ <DropdownMenuLabel>Sort By</DropdownMenuLabel>
1367
+ <DropdownMenuRadioGroup value={sortBy} onValueChange={setSortBy}>
1368
+ <DropdownMenuRadioItem value="name">Name</DropdownMenuRadioItem>
1369
+ <DropdownMenuRadioItem value="date">
1370
+ Date Modified
1371
+ </DropdownMenuRadioItem>
1372
+ <DropdownMenuRadioItem value="size">Size</DropdownMenuRadioItem>
1373
+ </DropdownMenuRadioGroup>
1374
+ <DropdownMenuSeparator />
1375
+ <DropdownMenuLabel>Show</DropdownMenuLabel>
1376
+ <DropdownMenuCheckboxItem
1377
+ checked={showHidden}
1378
+ onCheckedChange={setShowHidden}
1379
+ onSelect={(e) => e.preventDefault()}
1380
+ >
1381
+ Hidden Files
1382
+ </DropdownMenuCheckboxItem>
1383
+ <DropdownMenuCheckboxItem
1384
+ checked={showExtensions}
1385
+ onCheckedChange={setShowExtensions}
1386
+ onSelect={(e) => e.preventDefault()}
1387
+ >
1388
+ File Extensions
1389
+ </DropdownMenuCheckboxItem>
1390
+ <DropdownMenuCheckboxItem
1391
+ checked={showPreview}
1392
+ onCheckedChange={setShowPreview}
1393
+ onSelect={(e) => e.preventDefault()}
1394
+ >
1395
+ Preview Panel
1396
+ </DropdownMenuCheckboxItem>
1397
+ <DropdownMenuSeparator />
1398
+ <DropdownMenuItem
1399
+ disabled
1400
+ icon={
1401
+ <Icon
1402
+ type="heroicons"
1403
+ name="trash"
1404
+ className="size-4 shrink-0"
1405
+ />
1406
+ }
1407
+ >
1408
+ Delete
1409
+ </DropdownMenuItem>
1410
+ </DropdownMenuContent>
1411
+ </DropdownMenu>
1412
+ </div>
1413
+
1414
+ {/* Interactive: Editor Settings */}
1415
+ <div>
1416
+ <p className="typography-small4 text-text-g-contrast-medium mb-2">
1417
+ Interactive — Editor Settings
1418
+ </p>
1419
+ <DropdownMenu>
1420
+ <DropdownMenuTrigger asChild>
1421
+ <Button variant="outline">Settings</Button>
1422
+ </DropdownMenuTrigger>
1423
+ <DropdownMenuContent className="w-[220px]">
1424
+ <DropdownMenuLabel>Theme</DropdownMenuLabel>
1425
+ <DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
1426
+ <DropdownMenuRadioItem
1427
+ value="light"
1428
+ icon={
1429
+ <Icon
1430
+ type="heroicons"
1431
+ name="sun"
1432
+ className="size-4 shrink-0"
1433
+ />
1434
+ }
1435
+ >
1436
+ Light
1437
+ </DropdownMenuRadioItem>
1438
+ <DropdownMenuRadioItem
1439
+ value="dark"
1440
+ icon={
1441
+ <Icon
1442
+ type="heroicons"
1443
+ name="moon"
1444
+ className="size-4 shrink-0"
1445
+ />
1446
+ }
1447
+ >
1448
+ Dark
1449
+ </DropdownMenuRadioItem>
1450
+ <DropdownMenuRadioItem
1451
+ value="system"
1452
+ icon={
1453
+ <Icon
1454
+ type="heroicons"
1455
+ name="computer-desktop"
1456
+ className="size-4 shrink-0"
1457
+ />
1458
+ }
1459
+ >
1460
+ System
1461
+ </DropdownMenuRadioItem>
1462
+ </DropdownMenuRadioGroup>
1463
+ <DropdownMenuSeparator />
1464
+ <DropdownMenuLabel>Density</DropdownMenuLabel>
1465
+ <DropdownMenuRadioGroup
1466
+ value={density}
1467
+ onValueChange={setDensity}
1468
+ >
1469
+ <DropdownMenuRadioItem value="compact">
1470
+ Compact
1471
+ </DropdownMenuRadioItem>
1472
+ <DropdownMenuRadioItem value="comfortable">
1473
+ Comfortable
1474
+ </DropdownMenuRadioItem>
1475
+ <DropdownMenuRadioItem value="spacious">
1476
+ Spacious
1477
+ </DropdownMenuRadioItem>
1478
+ </DropdownMenuRadioGroup>
1479
+ <DropdownMenuSeparator />
1480
+ <DropdownMenuLabel>Sort Direction</DropdownMenuLabel>
1481
+ <DropdownMenuRadioGroup
1482
+ value={sortDir}
1483
+ onValueChange={setSortDir}
1484
+ >
1485
+ <DropdownMenuRadioItem
1486
+ value="asc"
1487
+ icon={
1488
+ <Icon
1489
+ type="heroicons"
1490
+ name="bars-arrow-up"
1491
+ className="size-4 shrink-0"
1492
+ />
1493
+ }
1494
+ >
1495
+ Ascending
1496
+ </DropdownMenuRadioItem>
1497
+ <DropdownMenuRadioItem
1498
+ value="desc"
1499
+ icon={
1500
+ <Icon
1501
+ type="heroicons"
1502
+ name="bars-arrow-down"
1503
+ className="size-4 shrink-0"
1504
+ />
1505
+ }
1506
+ >
1507
+ Descending
1508
+ </DropdownMenuRadioItem>
1509
+ </DropdownMenuRadioGroup>
1510
+ </DropdownMenuContent>
1511
+ </DropdownMenu>
1512
+ </div>
1513
+ </div>
1514
+ );
1515
+ },
1516
+ } satisfies StoryObj;