@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
@@ -0,0 +1,611 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Menu } from "./Menu";
4
+ import Button from "../../components/Button/Button";
5
+ import ActionButton from "../../components/ActionButton/ActionButton";
6
+ import Icon from "../../components/Icon/Icon";
7
+ import { ChevronDownIcon } from "@heroicons/react/16/solid";
8
+ import { Switch } from "../../components/Switch/Switch";
9
+ const meta = {
10
+ title: "Patterns/Menu",
11
+ component: Menu,
12
+ parameters: {
13
+ layout: "fullscreen",
14
+ },
15
+ decorators: [
16
+ (Story) => (_jsx("div", { className: "p-10 flex gap-8 flex-wrap bg-workspace-surface min-h-screen", children: _jsx(Story, {}) })),
17
+ ],
18
+ };
19
+ export default meta;
20
+ // ---------------------------------------------------------------------------
21
+ // Basic — default items, separator, disabled, danger
22
+ // ---------------------------------------------------------------------------
23
+ export const Basic = {
24
+ name: "Basic (Default Items)",
25
+ render: () => (_jsxs("div", { className: "flex gap-8 items-start flex-wrap", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Icon button trigger" }), _jsx(Menu, { trigger: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }), items: [
26
+ { type: "item", item: { value: "1", label: "Option 1" } },
27
+ { type: "item", item: { value: "2", label: "Option 2" } },
28
+ {
29
+ type: "item",
30
+ item: { value: "3", label: "Option 3 (Selected)" },
31
+ },
32
+ {
33
+ type: "item",
34
+ item: {
35
+ value: "4",
36
+ label: "Option 4 (Disabled)",
37
+ disabled: true,
38
+ },
39
+ },
40
+ { type: "separator" },
41
+ {
42
+ type: "item",
43
+ item: { value: "delete", label: "Delete", danger: true },
44
+ },
45
+ ], selectedValues: ["3"], onSelect: (v) => console.log("selected:", v) })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Button trigger + label section" }), _jsx(Menu, { trigger: _jsx(Button, { variant: "outline", children: "My Account" }), items: [
46
+ { type: "label", label: "My Account" },
47
+ { type: "item", item: { value: "profile", label: "Profile" } },
48
+ { type: "item", item: { value: "settings", label: "Settings" } },
49
+ { type: "separator" },
50
+ { type: "item", item: { value: "logout", label: "Logout" } },
51
+ ], onSelect: (v) => console.log("selected:", v) })] })] })),
52
+ };
53
+ // ---------------------------------------------------------------------------
54
+ // With Icons
55
+ // ---------------------------------------------------------------------------
56
+ export const WithIcons = {
57
+ name: "With Icons",
58
+ render: () => (_jsxs("div", { className: "flex gap-8 items-start flex-wrap", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Items with leading icon" }), _jsx(Menu, { trigger: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }), align: "end", items: [
59
+ {
60
+ type: "item",
61
+ item: {
62
+ value: "profile",
63
+ label: "Profile",
64
+ icon: _jsx(Icon, { type: "heroicons", name: "user", className: "size-4" }),
65
+ },
66
+ },
67
+ {
68
+ type: "item",
69
+ item: {
70
+ value: "settings",
71
+ label: "Settings",
72
+ icon: (_jsx(Icon, { type: "heroicons", name: "cog-6-tooth", className: "size-4" })),
73
+ },
74
+ },
75
+ {
76
+ type: "item",
77
+ item: {
78
+ value: "billing",
79
+ label: "Billing",
80
+ icon: (_jsx(Icon, { type: "heroicons", name: "credit-card", className: "size-4" })),
81
+ },
82
+ },
83
+ { type: "separator" },
84
+ {
85
+ type: "item",
86
+ item: {
87
+ value: "logout",
88
+ label: "Logout",
89
+ icon: (_jsx(Icon, { type: "heroicons", name: "arrow-right-on-rectangle", className: "size-4" })),
90
+ danger: true,
91
+ },
92
+ },
93
+ ], onSelect: (v) => console.log("selected:", v) })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "With icon + disabled" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: ["Actions ", _jsx(ChevronDownIcon, { className: "size-4 ml-2" })] }), items: [
94
+ {
95
+ type: "item",
96
+ item: {
97
+ value: "edit",
98
+ label: "Edit",
99
+ icon: (_jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4" })),
100
+ },
101
+ },
102
+ {
103
+ type: "item",
104
+ item: {
105
+ value: "duplicate",
106
+ label: "Duplicate",
107
+ icon: (_jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4" })),
108
+ disabled: true,
109
+ },
110
+ },
111
+ {
112
+ type: "item",
113
+ item: {
114
+ value: "archive",
115
+ label: "Archive",
116
+ icon: (_jsx(Icon, { type: "heroicons", name: "archive-box", className: "size-4" })),
117
+ },
118
+ },
119
+ { type: "separator" },
120
+ {
121
+ type: "item",
122
+ item: {
123
+ value: "delete",
124
+ label: "Delete",
125
+ icon: _jsx(Icon, { type: "heroicons", name: "trash", className: "size-4" }),
126
+ danger: true,
127
+ },
128
+ },
129
+ ], onSelect: (v) => console.log("selected:", v) })] })] })),
130
+ };
131
+ // ---------------------------------------------------------------------------
132
+ // With Checkbox — multi-select toggle
133
+ // ---------------------------------------------------------------------------
134
+ export const WithCheckbox = {
135
+ name: "With Checkbox",
136
+ render: () => {
137
+ const [checked, setChecked] = useState({
138
+ notifications: true,
139
+ emails: false,
140
+ updates: true,
141
+ });
142
+ const items = [
143
+ { type: "label", label: "Preferences" },
144
+ {
145
+ type: "item",
146
+ item: {
147
+ value: "notifications",
148
+ label: "Notifications",
149
+ type: "checkbox",
150
+ checked: checked.notifications,
151
+ },
152
+ },
153
+ {
154
+ type: "item",
155
+ item: {
156
+ value: "emails",
157
+ label: "Email Alerts",
158
+ type: "checkbox",
159
+ checked: checked.emails,
160
+ },
161
+ },
162
+ {
163
+ type: "item",
164
+ item: {
165
+ value: "updates",
166
+ label: "Product Updates",
167
+ type: "checkbox",
168
+ checked: checked.updates,
169
+ },
170
+ },
171
+ {
172
+ type: "item",
173
+ item: {
174
+ value: "disabled-feature",
175
+ label: "Disabled Feature",
176
+ type: "checkbox",
177
+ checked: false,
178
+ disabled: true,
179
+ },
180
+ },
181
+ ];
182
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Click to toggle (menu stays open for checkboxes)" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: ["Preferences ", _jsx(ChevronDownIcon, { className: "size-4 ml-2" })] }), items: items, onSelect: (value) => {
183
+ setChecked((prev) => (Object.assign(Object.assign({}, prev), { [value]: !prev[value] })));
184
+ } })] }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "State:" }), _jsx("pre", { className: "text-xs", children: JSON.stringify(checked, null, 2) })] })] }));
185
+ },
186
+ };
187
+ // ---------------------------------------------------------------------------
188
+ // With Radio — single-select group
189
+ // ---------------------------------------------------------------------------
190
+ export const WithRadio = {
191
+ name: "With Radio",
192
+ render: () => {
193
+ const [theme, setTheme] = useState("light");
194
+ const [density, setDensity] = useState("comfortable");
195
+ const themeItems = [
196
+ { type: "label", label: "Theme" },
197
+ { type: "item", item: { value: "light", label: "Light", type: "radio" } },
198
+ { type: "item", item: { value: "dark", label: "Dark", type: "radio" } },
199
+ {
200
+ type: "item",
201
+ item: { value: "system", label: "System", type: "radio" },
202
+ },
203
+ ];
204
+ const densityItems = [
205
+ { type: "label", label: "Density" },
206
+ {
207
+ type: "item",
208
+ item: { value: "compact", label: "Compact", type: "radio" },
209
+ },
210
+ {
211
+ type: "item",
212
+ item: { value: "comfortable", label: "Comfortable", type: "radio" },
213
+ },
214
+ {
215
+ type: "item",
216
+ item: { value: "spacious", label: "Spacious", type: "radio" },
217
+ },
218
+ {
219
+ type: "item",
220
+ item: {
221
+ value: "disabled-opt",
222
+ label: "Disabled Option",
223
+ type: "radio",
224
+ disabled: true,
225
+ },
226
+ },
227
+ ];
228
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Theme selector" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: ["Theme: ", theme, " ", _jsx(ChevronDownIcon, { className: "size-4 ml-2" })] }), items: themeItems, selectedValues: [theme], onSelect: (value) => setTheme(value) })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Density selector + disabled" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: ["Density: ", density, " ", _jsx(ChevronDownIcon, { className: "size-4 ml-2" })] }), items: densityItems, selectedValues: [density], onSelect: (value) => setDensity(value) })] })] }));
229
+ },
230
+ };
231
+ // ---------------------------------------------------------------------------
232
+ // Multiple Radio Groups — separated by separator
233
+ // ---------------------------------------------------------------------------
234
+ export const MultipleRadioGroups = {
235
+ name: "Multiple Radio Groups",
236
+ render: () => {
237
+ const [theme, setTheme] = useState("light");
238
+ const [language, setLanguage] = useState("en");
239
+ const items = [
240
+ { type: "label", label: "Theme" },
241
+ { type: "item", item: { value: "light", label: "Light", type: "radio" } },
242
+ { type: "item", item: { value: "dark", label: "Dark", type: "radio" } },
243
+ { type: "separator" },
244
+ { type: "label", label: "Language" },
245
+ { type: "item", item: { value: "en", label: "English", type: "radio" } },
246
+ { type: "item", item: { value: "th", label: "ภาษาไทย", type: "radio" } },
247
+ { type: "item", item: { value: "ja", label: "日本語", type: "radio" } },
248
+ ];
249
+ const handleSelect = (value) => {
250
+ if (["light", "dark"].includes(value))
251
+ setTheme(value);
252
+ else if (["en", "th", "ja"].includes(value))
253
+ setLanguage(value);
254
+ };
255
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Two independent radio groups" }), _jsx(Menu, { trigger: _jsx(Button, { variant: "outline", children: "Settings" }), items: items, selectedValues: [theme, language], onSelect: handleSelect })] }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "State:" }), _jsx("pre", { className: "text-xs", children: JSON.stringify({ theme, language }, null, 2) })] })] }));
256
+ },
257
+ };
258
+ // ---------------------------------------------------------------------------
259
+ // Custom Items — type="custom" render prop
260
+ // ---------------------------------------------------------------------------
261
+ export const CustomItems = {
262
+ name: "Custom Items",
263
+ render: () => {
264
+ const items = [
265
+ { type: "label", label: "Recent Projects" },
266
+ {
267
+ type: "custom",
268
+ render: () => (_jsxs("div", { className: "px-4 py-3 hover:bg-[var(--dropdown-menu-hover-bg)] cursor-pointer transition-colors", children: [_jsx("div", { className: "typography-subtitle4 text-text-g-contrast-high", children: "Project Alpha" }), _jsx("div", { className: "typography-small4 text-text-g-contrast-medium", children: "Updated 2 hours ago" })] })),
269
+ },
270
+ {
271
+ type: "custom",
272
+ render: () => (_jsxs("div", { className: "px-4 py-3 hover:bg-[var(--dropdown-menu-hover-bg)] cursor-pointer transition-colors", children: [_jsx("div", { className: "typography-subtitle4 text-text-g-contrast-high", children: "Project Beta" }), _jsx("div", { className: "typography-small4 text-text-g-contrast-medium", children: "Updated yesterday" })] })),
273
+ },
274
+ { type: "separator" },
275
+ {
276
+ type: "item",
277
+ item: {
278
+ value: "view-all",
279
+ label: "View All Projects",
280
+ icon: _jsx(Icon, { type: "heroicons", name: "folder-open", className: "size-4" }),
281
+ },
282
+ },
283
+ ];
284
+ return (_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Mix of custom render + regular items" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: ["Projects ", _jsx(ChevronDownIcon, { className: "size-4 ml-2" })] }), items: items, onSelect: (v) => console.log("selected:", v) })] }));
285
+ },
286
+ };
287
+ // ---------------------------------------------------------------------------
288
+ // With Submenu — type="submenu" uses DropdownMenuSub natively
289
+ // ---------------------------------------------------------------------------
290
+ export const WithSubmenu = {
291
+ name: "With Submenu",
292
+ render: () => {
293
+ const [selected, setSelected] = useState(null);
294
+ const [permission, setPermission] = useState("perm-view");
295
+ const items = [
296
+ {
297
+ type: "item",
298
+ item: {
299
+ value: "new-file",
300
+ label: "New File",
301
+ icon: (_jsx(Icon, { type: "heroicons", name: "document-plus", className: "size-4" })),
302
+ },
303
+ },
304
+ {
305
+ type: "submenu",
306
+ label: "New From Template",
307
+ icon: (_jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4" })),
308
+ items: [
309
+ {
310
+ type: "item",
311
+ item: { value: "tpl-blank", label: "Blank Document" },
312
+ },
313
+ { type: "item", item: { value: "tpl-report", label: "Report" } },
314
+ {
315
+ type: "item",
316
+ item: { value: "tpl-presentation", label: "Presentation" },
317
+ },
318
+ { type: "separator" },
319
+ {
320
+ type: "item",
321
+ item: {
322
+ value: "tpl-browse",
323
+ label: "Browse Templates…",
324
+ icon: (_jsx(Icon, { type: "heroicons", name: "arrow-top-right-on-square", className: "size-4" })),
325
+ },
326
+ },
327
+ ],
328
+ },
329
+ { type: "separator" },
330
+ {
331
+ type: "submenu",
332
+ label: "Share",
333
+ icon: _jsx(Icon, { type: "heroicons", name: "share", className: "size-4" }),
334
+ items: [
335
+ {
336
+ type: "item",
337
+ item: {
338
+ value: "share-link",
339
+ label: "Copy Link",
340
+ icon: _jsx(Icon, { type: "heroicons", name: "link", className: "size-4" }),
341
+ },
342
+ },
343
+ {
344
+ type: "item",
345
+ item: {
346
+ value: "share-email",
347
+ label: "Send via Email",
348
+ icon: (_jsx(Icon, { type: "heroicons", name: "envelope", className: "size-4" })),
349
+ },
350
+ },
351
+ { type: "separator" },
352
+ {
353
+ // Nested submenu inside submenu
354
+ type: "submenu",
355
+ label: "Permissions",
356
+ items: [
357
+ {
358
+ type: "item",
359
+ item: {
360
+ value: "perm-view",
361
+ label: "Viewer",
362
+ type: "radio",
363
+ },
364
+ },
365
+ {
366
+ type: "item",
367
+ item: {
368
+ value: "perm-comment",
369
+ label: "Commenter",
370
+ type: "radio",
371
+ },
372
+ },
373
+ {
374
+ type: "item",
375
+ item: {
376
+ value: "perm-edit",
377
+ label: "Editor",
378
+ type: "radio",
379
+ },
380
+ },
381
+ ],
382
+ },
383
+ ],
384
+ },
385
+ { type: "separator" },
386
+ {
387
+ type: "item",
388
+ item: {
389
+ value: "delete",
390
+ label: "Move to Trash",
391
+ icon: _jsx(Icon, { type: "heroicons", name: "trash", className: "size-4" }),
392
+ danger: true,
393
+ },
394
+ },
395
+ ];
396
+ const handleSelect = (value) => {
397
+ if (value.startsWith("perm-"))
398
+ setPermission(value);
399
+ else
400
+ setSelected(value);
401
+ };
402
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Submenu (hover to reveal) \u2014 3 levels deep" }), _jsx(Menu, { trigger: _jsx(Button, { variant: "outline", children: "File" }), items: items, selectedValues: [permission], onSelect: handleSelect })] }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "State:" }), _jsx("pre", { className: "text-xs", children: JSON.stringify({ selected, permission }, null, 2) })] })] }));
403
+ },
404
+ };
405
+ // ---------------------------------------------------------------------------
406
+ // Complex — mixed types, multi-section
407
+ // ---------------------------------------------------------------------------
408
+ export const ComplexMenu = {
409
+ name: "Complex (Mixed Types)",
410
+ render: () => {
411
+ const [preferences, setPreferences] = useState({
412
+ notifications: true,
413
+ emails: false,
414
+ });
415
+ const [theme, setTheme] = useState("light");
416
+ const items = [
417
+ { type: "label", label: "My Account" },
418
+ {
419
+ type: "item",
420
+ item: {
421
+ value: "profile",
422
+ label: "Profile",
423
+ icon: _jsx(Icon, { type: "heroicons", name: "user", className: "size-4" }),
424
+ onClick: () => console.log("Go to profile"),
425
+ },
426
+ },
427
+ {
428
+ type: "item",
429
+ item: {
430
+ value: "billing",
431
+ label: "Billing",
432
+ icon: _jsx(Icon, { type: "heroicons", name: "credit-card", className: "size-4" }),
433
+ onClick: () => console.log("Go to billing"),
434
+ },
435
+ },
436
+ { type: "separator" },
437
+ { type: "label", label: "Notifications" },
438
+ {
439
+ type: "item",
440
+ item: {
441
+ value: "notifications",
442
+ label: "Push Notifications",
443
+ type: "checkbox",
444
+ checked: preferences.notifications,
445
+ },
446
+ },
447
+ {
448
+ type: "item",
449
+ item: {
450
+ value: "emails",
451
+ label: "Email Notifications",
452
+ type: "checkbox",
453
+ checked: preferences.emails,
454
+ },
455
+ },
456
+ { type: "separator" },
457
+ { type: "label", label: "Theme" },
458
+ {
459
+ type: "item",
460
+ item: { value: "light", label: "Light Mode", type: "radio" },
461
+ },
462
+ {
463
+ type: "item",
464
+ item: { value: "dark", label: "Dark Mode", type: "radio" },
465
+ },
466
+ {
467
+ type: "item",
468
+ item: { value: "system", label: "System", type: "radio" },
469
+ },
470
+ { type: "separator" },
471
+ {
472
+ type: "item",
473
+ item: {
474
+ value: "logout",
475
+ label: "Logout",
476
+ icon: (_jsx(Icon, { type: "heroicons", name: "arrow-right-on-rectangle", className: "size-4" })),
477
+ danger: true,
478
+ onClick: () => console.log("Logout"),
479
+ },
480
+ },
481
+ ];
482
+ const handleSelect = (value, item) => {
483
+ if (item.type === "checkbox") {
484
+ const key = value;
485
+ if (key in preferences)
486
+ setPreferences((prev) => (Object.assign(Object.assign({}, prev), { [key]: !prev[key] })));
487
+ }
488
+ else if (item.type === "radio") {
489
+ setTheme(value);
490
+ }
491
+ };
492
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Account menu \u2014 all item types combined" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: ["Account ", _jsx(ChevronDownIcon, { className: "size-4 ml-2" })] }), items: items, selectedValues: [theme], onSelect: handleSelect })] }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "State:" }), _jsx("pre", { className: "text-xs", children: JSON.stringify({ preferences, theme }, null, 2) })] })] }));
493
+ },
494
+ };
495
+ // ---------------------------------------------------------------------------
496
+ // Multi-Select via Checkbox
497
+ // ---------------------------------------------------------------------------
498
+ export const MultiSelectPattern = {
499
+ name: "Multi-Select Pattern",
500
+ render: () => {
501
+ const [selectedValues, setSelectedValues] = useState(["react"]);
502
+ const options = [
503
+ { value: "react", label: "React" },
504
+ { value: "vue", label: "Vue" },
505
+ { value: "angular", label: "Angular" },
506
+ { value: "svelte", label: "Svelte" },
507
+ { value: "solid", label: "Solid" },
508
+ ];
509
+ const items = options.map((opt) => ({
510
+ type: "item",
511
+ item: {
512
+ value: opt.value,
513
+ label: opt.label,
514
+ type: "checkbox",
515
+ checked: selectedValues.includes(opt.value),
516
+ },
517
+ }));
518
+ const displayText = selectedValues.length > 0
519
+ ? selectedValues
520
+ .map((v) => { var _a; return (_a = options.find((o) => o.value === v)) === null || _a === void 0 ? void 0 : _a.label; })
521
+ .join(", ")
522
+ : "Select frameworks…";
523
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", className: "w-64 justify-between", children: [_jsx("span", { className: "truncate", children: displayText }), _jsx(ChevronDownIcon, { className: "size-4 ml-2 shrink-0" })] }), items: items, onSelect: (value) => {
524
+ setSelectedValues((prev) => prev.includes(value)
525
+ ? prev.filter((v) => v !== value)
526
+ : [...prev, value]);
527
+ } }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "Selected:" }), _jsx("pre", { className: "text-xs", children: JSON.stringify(selectedValues, null, 2) })] })] }));
528
+ },
529
+ };
530
+ // ---------------------------------------------------------------------------
531
+ // Figma: "Change Status" — header slot + section labels + custom badge items
532
+ // ---------------------------------------------------------------------------
533
+ export const ChangeStatus = {
534
+ name: "Figma: Change Status",
535
+ render: () => {
536
+ const [status, setStatus] = useState("todo");
537
+ const [open, setOpen] = useState(false);
538
+ const statusItems = [
539
+ { type: "label", label: "To do" },
540
+ {
541
+ type: "item",
542
+ item: { value: "todo", label: "To do", type: "radio" },
543
+ },
544
+ { type: "separator" },
545
+ { type: "label", label: "In progress" },
546
+ {
547
+ type: "item",
548
+ item: {
549
+ value: "in-progress",
550
+ label: "In Progress",
551
+ type: "radio",
552
+ icon: (_jsx("span", { className: "inline-flex items-center px-3 py-0.5 rounded-lg text-xs font-medium bg-yellow-400/10 text-yellow-400", children: "In Progress" })),
553
+ },
554
+ },
555
+ {
556
+ type: "item",
557
+ item: {
558
+ value: "ready-review",
559
+ label: "Ready to review",
560
+ type: "radio",
561
+ icon: (_jsx("span", { className: "inline-flex items-center px-3 py-0.5 rounded-lg text-xs font-medium bg-blue-400/10 text-blue-400", children: "Ready to review" })),
562
+ },
563
+ },
564
+ {
565
+ type: "item",
566
+ item: {
567
+ value: "in-review",
568
+ label: "In review",
569
+ type: "radio",
570
+ icon: (_jsx("span", { className: "inline-flex items-center px-3 py-0.5 rounded-lg text-xs font-medium bg-red-400/10 text-red-400", children: "In review" })),
571
+ },
572
+ },
573
+ { type: "separator" },
574
+ { type: "label", label: "Completed" },
575
+ {
576
+ type: "item",
577
+ item: {
578
+ value: "completed",
579
+ label: "Completed",
580
+ type: "radio",
581
+ icon: (_jsx("span", { className: "inline-flex items-center px-3 py-0.5 rounded-lg text-xs font-medium bg-green-400/10 text-green-400", children: "Completed" })),
582
+ },
583
+ },
584
+ ];
585
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "With header (title + settings + close)" }), _jsx(Menu, { trigger: _jsx(Button, { variant: "outline", children: "Change Status" }), open: open, onOpenChange: setOpen, header: _jsxs("div", { className: "flex items-center justify-between px-6 py-3", children: [_jsx("span", { className: "typography-subtitle4 text-text-g-contrast-high", children: "Status" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(ActionButton, { variant: "icon", size: "sm", children: _jsx(Icon, { type: "heroicons", name: "cog6-tooth", className: "size-4" }) }), _jsx(ActionButton, { variant: "icon", size: "sm", onClick: () => setOpen(false), children: _jsx(Icon, { type: "heroicons", name: "xmark", className: "size-4" }) })] })] }), items: statusItems, selectedValues: [status], onSelect: (v) => setStatus(v) })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "No header (simple list)" }), _jsx(Menu, { trigger: _jsx(Button, { variant: "outline", children: "Status" }), items: statusItems, selectedValues: [status], onSelect: (v) => setStatus(v) })] }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "Selected:" }), _jsx("pre", { className: "text-xs", children: status })] })] }));
586
+ },
587
+ };
588
+ // ---------------------------------------------------------------------------
589
+ // Figma: "Manage Column" — header with actions + toggle rows + drag handle
590
+ // ---------------------------------------------------------------------------
591
+ export const ManageColumn = {
592
+ name: "Figma: Manage Column",
593
+ render: () => {
594
+ const [open, setOpen] = useState(false);
595
+ const [columns, setColumns] = useState([
596
+ { id: "name", label: "Name", visible: true },
597
+ { id: "status", label: "Status", visible: true },
598
+ { id: "assignee", label: "Assignee", visible: false },
599
+ { id: "due-date", label: "Due date", visible: true },
600
+ { id: "priority", label: "Priority", visible: false },
601
+ ]);
602
+ const toggleColumn = (id) => setColumns((prev) => prev.map((col) => col.id === id ? Object.assign(Object.assign({}, col), { visible: !col.visible }) : col));
603
+ const showAll = () => setColumns((prev) => prev.map((col) => (Object.assign(Object.assign({}, col), { visible: true }))));
604
+ const hideAll = () => setColumns((prev) => prev.map((col) => (Object.assign(Object.assign({}, col), { visible: false }))));
605
+ const items = columns.map((col) => ({
606
+ type: "custom",
607
+ render: () => (_jsxs("div", { className: "flex items-center gap-3 px-4 py-3 hover:bg-[var(--dropdown-menu-hover-bg)] cursor-default transition-colors", children: [_jsx(Icon, { type: "heroicons", name: "bars-2", className: "size-4 text-text-g-contrast-medium shrink-0 cursor-grab" }), _jsx(Switch, { checked: col.visible, onCheckedChange: () => toggleColumn(col.id) }), _jsx("span", { className: "typography-subtitle4 text-text-g-contrast-high flex-1", children: col.label })] }, col.id)),
608
+ }));
609
+ return (_jsxs("div", { className: "flex gap-8 items-start", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Manage Column panel" }), _jsx(Menu, { trigger: _jsxs(Button, { variant: "outline", children: [_jsx(Icon, { type: "heroicons", name: "view-columns", className: "size-4 mr-2" }), "Manage Columns"] }), open: open, onOpenChange: setOpen, header: _jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "typography-subtitle4 text-text-g-contrast-high", children: "Manage column" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { className: "typography-small4 text-text-g-contrast-medium hover:text-text-g-contrast-high transition-colors", onClick: hideAll, children: "Hide all" }), _jsx("button", { className: "typography-small4 text-[var(--dropdown-menu-checkbox-checked-bg)] hover:opacity-80 transition-opacity", onClick: showAll, children: "Show all" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => setOpen(false), children: "Done" })] })] }), items: items, contentClassName: "w-80" })] }), _jsxs("div", { className: "text-sm text-text-g-contrast-medium", children: [_jsx("p", { className: "font-semibold mb-1", children: "Columns:" }), _jsx("pre", { className: "text-xs", children: JSON.stringify(columns.map((c) => ({ [c.label]: c.visible })), null, 2) })] })] }));
610
+ },
611
+ };