@rovula/ui 0.1.20 → 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 (99) hide show
  1. package/dist/cjs/bundle.css +316 -43
  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 +45 -30
  12. package/dist/cjs/types/components/Form/Form.d.ts +2 -1
  13. package/dist/cjs/types/components/Form/Form.stories.d.ts +4 -0
  14. package/dist/cjs/types/components/ScrollArea/ScrollArea.d.ts +38 -0
  15. package/dist/cjs/types/components/ScrollArea/ScrollArea.stories.d.ts +301 -0
  16. package/dist/cjs/types/index.d.ts +4 -1
  17. package/dist/cjs/types/patterns/menu/Menu.d.ts +70 -0
  18. package/dist/cjs/types/{components/Menu → patterns/menu}/Menu.stories.d.ts +17 -10
  19. package/dist/cjs/types/utils/mergeRefs.d.ts +20 -0
  20. package/dist/components/Avatar/Avatar.styles.js +2 -2
  21. package/dist/components/Badge/Badge.js +36 -0
  22. package/dist/components/Badge/Badge.stories.js +51 -0
  23. package/dist/components/Badge/Badge.styles.js +62 -0
  24. package/dist/components/Badge/index.js +2 -0
  25. package/dist/components/Dropdown/Dropdown.js +54 -163
  26. package/dist/components/Dropdown/Dropdown.stories.js +29 -0
  27. package/dist/components/DropdownMenu/DropdownMenu.js +24 -13
  28. package/dist/components/DropdownMenu/DropdownMenu.stories.js +120 -88
  29. package/dist/components/Form/Form.js +11 -4
  30. package/dist/components/Form/Form.stories.js +27 -0
  31. package/dist/components/ScrollArea/ScrollArea.js +50 -0
  32. package/dist/components/ScrollArea/ScrollArea.stories.js +56 -0
  33. package/dist/components/TextInput/TextInput.js +6 -3
  34. package/dist/esm/bundle.css +316 -43
  35. package/dist/esm/bundle.js +1545 -1545
  36. package/dist/esm/bundle.js.map +1 -1
  37. package/dist/esm/types/components/Badge/Badge.d.ts +40 -0
  38. package/dist/esm/types/components/Badge/Badge.stories.d.ts +295 -0
  39. package/dist/esm/types/components/Badge/Badge.styles.d.ts +7 -0
  40. package/dist/esm/types/components/Badge/index.d.ts +2 -0
  41. package/dist/esm/types/components/Dropdown/Dropdown.d.ts +4 -8
  42. package/dist/esm/types/components/Dropdown/Dropdown.stories.d.ts +1 -6
  43. package/dist/esm/types/components/DropdownMenu/DropdownMenu.d.ts +5 -1
  44. package/dist/esm/types/components/DropdownMenu/DropdownMenu.stories.d.ts +45 -30
  45. package/dist/esm/types/components/Form/Form.d.ts +2 -1
  46. package/dist/esm/types/components/Form/Form.stories.d.ts +4 -0
  47. package/dist/esm/types/components/ScrollArea/ScrollArea.d.ts +38 -0
  48. package/dist/esm/types/components/ScrollArea/ScrollArea.stories.d.ts +301 -0
  49. package/dist/esm/types/index.d.ts +4 -1
  50. package/dist/esm/types/patterns/menu/Menu.d.ts +70 -0
  51. package/dist/esm/types/{components/Menu → patterns/menu}/Menu.stories.d.ts +17 -10
  52. package/dist/esm/types/utils/mergeRefs.d.ts +20 -0
  53. package/dist/index.d.ts +156 -74
  54. package/dist/index.js +3 -1
  55. package/dist/patterns/menu/Menu.js +95 -0
  56. package/dist/patterns/menu/Menu.stories.js +611 -0
  57. package/dist/src/theme/global.css +485 -57
  58. package/dist/utils/mergeRefs.js +42 -0
  59. package/package.json +1 -1
  60. package/src/components/Avatar/Avatar.styles.ts +2 -2
  61. package/src/components/Badge/Badge.stories.tsx +128 -0
  62. package/src/components/Badge/Badge.styles.ts +70 -0
  63. package/src/components/Badge/Badge.tsx +103 -0
  64. package/src/components/Badge/index.ts +3 -0
  65. package/src/components/Dropdown/Dropdown.stories.tsx +170 -1
  66. package/src/components/Dropdown/Dropdown.tsx +186 -276
  67. package/src/components/DropdownMenu/DropdownMenu.stories.tsx +1375 -253
  68. package/src/components/DropdownMenu/DropdownMenu.tsx +118 -55
  69. package/src/components/Form/Form.stories.tsx +70 -0
  70. package/src/components/Form/Form.tsx +23 -0
  71. package/src/components/ScrollArea/ScrollArea.stories.tsx +229 -0
  72. package/src/components/ScrollArea/ScrollArea.tsx +72 -0
  73. package/src/components/TextInput/TextInput.tsx +6 -3
  74. package/src/index.ts +4 -1
  75. package/src/patterns/menu/Menu.stories.tsx +1100 -0
  76. package/src/patterns/menu/Menu.tsx +282 -0
  77. package/src/theme/global.css +84 -11
  78. package/src/theme/themes/xspector/baseline.css +1 -1
  79. package/src/theme/themes/xspector/components/scrollbar.css +12 -0
  80. package/src/theme/tokens/baseline.css +3 -1
  81. package/src/theme/tokens/components/badge.css +54 -0
  82. package/src/theme/tokens/components/dropdown-menu.css +16 -5
  83. package/src/theme/tokens/components/scrollbar.css +18 -0
  84. package/src/utils/mergeRefs.ts +46 -0
  85. package/dist/cjs/types/components/Menu/Menu.d.ts +0 -65
  86. package/dist/cjs/types/components/Menu/helpers.d.ts +0 -19
  87. package/dist/cjs/types/components/Menu/index.d.ts +0 -4
  88. package/dist/components/Menu/Menu.js +0 -64
  89. package/dist/components/Menu/Menu.stories.js +0 -406
  90. package/dist/components/Menu/helpers.js +0 -28
  91. package/dist/components/Menu/index.js +0 -3
  92. package/dist/esm/types/components/Menu/Menu.d.ts +0 -65
  93. package/dist/esm/types/components/Menu/helpers.d.ts +0 -19
  94. package/dist/esm/types/components/Menu/index.d.ts +0 -4
  95. package/src/components/Menu/Menu.stories.tsx +0 -586
  96. package/src/components/Menu/Menu.tsx +0 -235
  97. package/src/components/Menu/helpers.ts +0 -45
  98. package/src/components/Menu/index.ts +0 -7
  99. package/src/theme/themes/xspector/components/dropdown-menu.css +0 -28
@@ -1,116 +1,148 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./DropdownMenu";
2
+ import { useState } from "react";
3
+ import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./DropdownMenu";
3
4
  import Button from "../Button/Button";
4
- import Icon from "../Icon/Icon";
5
5
  import ActionButton from "../ActionButton/ActionButton";
6
+ import Icon from "../Icon/Icon";
7
+ import { Input } from "../Input/Input";
6
8
  const meta = {
7
9
  title: "Components/DropdownMenu",
8
10
  component: DropdownMenu,
9
- // tags: ["autodocs"],
10
11
  parameters: {
11
12
  layout: "fullscreen",
12
13
  },
13
14
  decorators: [
14
- (Story) => (_jsx("div", { className: "p-5 flex w-full", children: _jsx(Story, {}) })),
15
+ (Story) => (_jsx("div", { className: "p-10 flex gap-8 flex-wrap bg-workspace-surface min-h-screen", children: _jsx(Story, {}) })),
15
16
  ],
16
17
  };
17
18
  export default meta;
18
- export const Default = {
19
- args: {
20
- // DropdownMenu: "Lorem Ipsum",
21
- // value: "Lorem Ipsum",
22
- // fullwidth: true,
23
- },
24
- render: (args) => {
25
- console.log("args ", args);
26
- const props = Object.assign({}, args);
27
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { children: "Open" }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { disabled: true, children: "Option Description" }), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "check", className: "size-4" }), "Option Description"] }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] }) }) }));
28
- },
19
+ // ---------------------------------------------------------------------------
20
+ // Figma: Normal dropdown / action menu
21
+ // Shows all item states: Default, Hover, Selected, Disabled, Selected+Disabled
22
+ // ---------------------------------------------------------------------------
23
+ export const AllStates = {
24
+ name: "All States (Normal)",
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: "All States" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { className: "!bg-[var(--dropdown-menu-hover-bg)]", children: "Option Description (Hover)" }), _jsx(DropdownMenuItem, { selected: true, children: "Option Description" }), _jsx(DropdownMenuItem, { disabled: true, children: "Option Description" }), _jsx(DropdownMenuItem, { selected: true, disabled: true, children: "Option Description" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { selected: true, children: "Option Description" }), _jsx(DropdownMenuItem, { disabled: true, children: "Option Description" }), _jsx(DropdownMenuItem, { selected: true, disabled: true, children: "Option Description" })] })] })] })] })),
29
26
  };
27
+ // ---------------------------------------------------------------------------
28
+ // Figma: Have icon
29
+ // Items with leading icon
30
+ // ---------------------------------------------------------------------------
30
31
  export const WithIcon = {
31
- args: {
32
- // DropdownMenu: "Lorem Ipsum",
33
- // value: "Lorem Ipsum",
34
- // fullwidth: true,
35
- },
36
- render: (args) => {
37
- console.log("args ", args);
38
- const props = Object.assign({}, args);
39
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open" }) }), _jsxs(DropdownMenuContent, { children: [_jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] }), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] }), _jsxs(DropdownMenuItem, { disabled: true, children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] })] })] }) }) }));
40
- },
32
+ name: "With Icon",
33
+ 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: "All States \u2014 With Icon" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4 shrink-0" }), children: "Option Description" }), _jsx(DropdownMenuItem, { className: "!bg-[var(--dropdown-menu-hover-bg)]", icon: _jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4 shrink-0" }), children: "Option Description (Hover)" }), _jsx(DropdownMenuItem, { selected: true, icon: _jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4 shrink-0" }), children: "Option Description (Selected)" }), _jsx(DropdownMenuItem, { disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4 shrink-0" }), children: "Option Description (Disabled)" }), _jsx(DropdownMenuItem, { selected: true, disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4 shrink-0" }), children: "Option Description (Selected + Disabled)" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4 shrink-0" }), children: "Launch" }), _jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4 shrink-0" }), children: "Edit" }), _jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4 shrink-0" }), children: "Duplicate" }), _jsx(DropdownMenuItem, { disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "trash", className: "size-4 shrink-0" }), children: "Delete" })] })] })] })] })),
41
34
  };
42
- export const WithLabel = {
43
- args: {
44
- // DropdownMenu: "Lorem Ipsum",
45
- // value: "Lorem Ipsum",
46
- // fullwidth: true,
47
- },
48
- render: (args) => {
49
- console.log("args ", args);
50
- const props = Object.assign({}, args);
51
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Sort by" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] }) }) }));
35
+ // ---------------------------------------------------------------------------
36
+ // Figma: Checkbox items (Have icon=No, Checkbox=Yes)
37
+ // ---------------------------------------------------------------------------
38
+ export const WithCheckbox = {
39
+ name: "With Checkbox",
40
+ render: () => {
41
+ const [checked1, setChecked1] = useState(false);
42
+ const [checked2, setChecked2] = useState(true);
43
+ const [checked3, setChecked3] = useState(false);
44
+ return (_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: "All States \u2014 Checkbox" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuCheckboxItem, { children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { className: "!bg-[var(--dropdown-menu-hover-bg)]", children: "Option Description (Hover)" }), _jsx(DropdownMenuCheckboxItem, { checked: true, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { disabled: true, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { checked: true, disabled: true, children: "Option Description" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuCheckboxItem, { checked: checked1, onCheckedChange: setChecked1, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { checked: checked2, onCheckedChange: setChecked2, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { checked: checked3, onCheckedChange: setChecked3, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { disabled: true, children: "Option Description" })] })] })] })] }));
52
45
  },
53
46
  };
54
- export const Checkboxes = {
55
- args: {
56
- // DropdownMenu: "Lorem Ipsum",
57
- // value: "Lorem Ipsum",
58
- // fullwidth: true,
59
- },
60
- render: (args) => {
61
- console.log("args ", args);
62
- const props = Object.assign({}, args);
63
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuCheckboxItem, { children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { checked: true, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { disabled: true, children: "Option Description" }), _jsx(DropdownMenuCheckboxItem, { checked: true, disabled: true, children: "Option Description" }), _jsxs(DropdownMenuCheckboxItem, { children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] }), _jsxs(DropdownMenuCheckboxItem, { checked: true, children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] }), _jsxs(DropdownMenuCheckboxItem, { disabled: true, children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] }), _jsxs(DropdownMenuCheckboxItem, { checked: true, disabled: true, children: [_jsx(Icon, { type: "heroicons", name: "rocket-launch", className: "size-4" }), _jsx("span", { children: "Option Description" })] })] })] }) }) }));
47
+ // ---------------------------------------------------------------------------
48
+ // Figma: Have section (DropdownMenuLabel as section header)
49
+ // ---------------------------------------------------------------------------
50
+ export const WithSection = {
51
+ name: "Have Section",
52
+ 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: "With Section Header" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuLabel, { children: "Section Name" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Section Name" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "Section Name" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Section Name" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] })] })] })),
53
+ };
54
+ // ---------------------------------------------------------------------------
55
+ // Figma: Have search
56
+ // Dropdown with search input at the top
57
+ // ---------------------------------------------------------------------------
58
+ export const WithSearch = {
59
+ name: "Have Search",
60
+ render: () => {
61
+ const [query, setQuery] = useState("");
62
+ const allOptions = [
63
+ "Option Description",
64
+ "Project Alpha",
65
+ "Project Beta",
66
+ "Project Gamma",
67
+ "Project Delta",
68
+ "Project Epsilon",
69
+ "Project Zeta",
70
+ "Project Eta",
71
+ "Project Theta",
72
+ ];
73
+ const filtered = allOptions.filter((o) => o.toLowerCase().includes(query.toLowerCase()));
74
+ return (_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: "With Search Field" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative w-[230px]", style: { position: "static", transform: "none" }, onInteractOutside: (e) => e.preventDefault(), children: [_jsxs("div", { className: "flex items-center px-4 py-2 border-b border-[var(--dropdown-menu-seperator-bg)]", children: [_jsx(Icon, { type: "heroicons", name: "magnifying-glass", className: "size-[14px] shrink-0 text-text-g-contrast-medium mr-1" }), _jsx(Input, { variant: "flat", size: "sm", className: "flex-1 !p-0 !ring-0 typography-small1 placeholder:text-text-g-contrast-medium", placeholder: "Search", value: query, onChange: (e) => setQuery(e.target.value) })] }), filtered.map((label) => (_jsx(DropdownMenuItem, { children: label }, label))), filtered.length === 0 && (_jsx("div", { className: "px-4 py-3 typography-subtitle4 text-text-g-contrast-medium", children: "No results found" }))] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { className: "w-[230px]", children: [_jsxs("div", { className: "flex items-center px-4 py-2 border-b border-[var(--dropdown-menu-seperator-bg)]", children: [_jsx(Icon, { type: "heroicons", name: "magnifying-glass", className: "size-[14px] shrink-0 text-text-g-contrast-medium mr-1" }), _jsx(Input, { variant: "flat", size: "sm", className: "flex-1 !p-0 !ring-0 typography-small1 placeholder:text-text-g-contrast-medium", placeholder: "Search" })] }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] })] })] }));
64
75
  },
65
76
  };
77
+ // ---------------------------------------------------------------------------
78
+ // Figma: Can scroll — long list, overflow-y scrollable
79
+ // ---------------------------------------------------------------------------
80
+ export const CanScroll = {
81
+ name: "Can Scroll",
82
+ 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: "Scrollable List" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsx(DropdownMenuContent, { className: "relative max-h-[270px] overflow-y-auto", style: { position: "static", transform: "none" }, children: Array.from({ length: 10 }, (_, i) => (_jsxs(DropdownMenuItem, { children: ["Option Description ", i + 1] }, i))) })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsx(DropdownMenuContent, { className: "max-h-[270px] overflow-y-auto", children: Array.from({ length: 10 }, (_, i) => (_jsxs(DropdownMenuItem, { children: ["Option Description ", i + 1] }, i))) })] })] })] })),
83
+ };
84
+ // ---------------------------------------------------------------------------
85
+ // Figma: Double scroll — two separate scrollable sections with section headers
86
+ // ---------------------------------------------------------------------------
87
+ export const DoubleScroll = {
88
+ name: "Double Scroll",
89
+ 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: "Two Scrollable Sections" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuLabel, { children: "Section A" }), _jsx("div", { className: "max-h-[270px] overflow-y-auto", children: Array.from({ length: 5 }, (_, i) => (_jsxs(DropdownMenuItem, { children: ["Option Description ", i + 1] }, i))) }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Section B" }), _jsx("div", { className: "max-h-[216px] overflow-y-auto", children: Array.from({ length: 4 }, (_, i) => (_jsxs(DropdownMenuItem, { children: ["Option Description ", i + 1] }, i))) })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "Section A" }), _jsx("div", { className: "max-h-[270px] overflow-y-auto", children: Array.from({ length: 5 }, (_, i) => (_jsxs(DropdownMenuItem, { children: ["Option Description ", i + 1] }, i))) }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Section B" }), _jsx("div", { className: "max-h-[216px] overflow-y-auto", children: Array.from({ length: 4 }, (_, i) => (_jsxs(DropdownMenuItem, { children: ["Option Description ", i + 1] }, i))) })] })] })] })] })),
90
+ };
91
+ // ---------------------------------------------------------------------------
92
+ // Figma: Sub menu (existing, preserved)
93
+ // ---------------------------------------------------------------------------
66
94
  export const SubMenu = {
67
- args: {
68
- // DropdownMenu: "Lorem Ipsum",
69
- // value: "Lorem Ipsum",
70
- // fullwidth: true,
71
- },
72
- render: (args) => {
73
- console.log("args ", args);
74
- const props = Object.assign({}, args);
75
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { children: "Open" }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "My Account" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { children: "Profile" }), _jsx(DropdownMenuItem, { children: "Billing" }), _jsx(DropdownMenuItem, { children: "Team" }), _jsx(DropdownMenuItem, { children: "Subscription" }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuGroup, { children: [_jsxs(DropdownMenuSub, { children: [_jsx(DropdownMenuSubTrigger, { children: _jsx("span", { children: "Invite users" }) }), _jsx(DropdownMenuPortal, { children: _jsxs(DropdownMenuSubContent, { children: [_jsx(DropdownMenuItem, { children: _jsx("span", { children: "Email" }) }), _jsx(DropdownMenuItem, { children: _jsx("span", { children: "Message" }) }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { children: _jsx("span", { children: "More..." }) })] }) })] }), _jsx(DropdownMenuCheckboxItem, { children: "Panel" })] })] })] }) }) }));
76
- },
95
+ name: "Sub Menu",
96
+ render: () => (_jsx("div", { className: "flex gap-8 items-center flex-wrap", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "My Account" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { children: "Profile" }), _jsx(DropdownMenuItem, { children: "Billing" }), _jsx(DropdownMenuItem, { children: "Team" }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuGroup, { children: [_jsxs(DropdownMenuSub, { children: [_jsxs(DropdownMenuSubTrigger, { children: [_jsx(Icon, { type: "heroicons", name: "user-group", className: "size-4 shrink-0" }), "Invite users"] }), _jsx(DropdownMenuPortal, { children: _jsxs(DropdownMenuSubContent, { children: [_jsx(DropdownMenuItem, { children: "Email" }), _jsx(DropdownMenuItem, { children: "Message" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { children: "More..." })] }) })] }), _jsx(DropdownMenuCheckboxItem, { children: "Panel" })] })] })] }) })),
77
97
  };
78
- export const OnIcon = {
79
- args: {
80
- // DropdownMenu: "Lorem Ipsum",
81
- // value: "Lorem Ipsum",
82
- // fullwidth: true,
83
- },
84
- render: (args) => {
85
- console.log("args ", args);
86
- const props = Object.assign({}, args);
87
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] }) }) }));
98
+ // ---------------------------------------------------------------------------
99
+ // Figma: Radio items — single select via DropdownMenuRadioGroup
100
+ // ---------------------------------------------------------------------------
101
+ export const WithRadio = {
102
+ name: "With Radio",
103
+ render: () => {
104
+ const [theme, setTheme] = useState("light");
105
+ const [position, setPosition] = useState("top");
106
+ return (_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: "All States \u2014 Radio" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsx(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: _jsxs(DropdownMenuRadioGroup, { value: "light", children: [_jsx(DropdownMenuRadioItem, { value: "unselected", children: "Option Description" }), _jsx(DropdownMenuRadioItem, { value: "unselected2", className: "!bg-[var(--dropdown-menu-hover-bg)]", children: "Option Description (Hover)" }), _jsx(DropdownMenuRadioItem, { value: "light", children: "Option Description (Selected)" }), _jsx(DropdownMenuRadioItem, { value: "dis", disabled: true, children: "Option Description (Disabled)" }), _jsx(DropdownMenuRadioItem, { value: "light", disabled: true, children: "Option Description (Selected + Disabled)" })] }) })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive \u2014 Theme" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", children: ["Theme: ", theme] }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "Theme" }), _jsxs(DropdownMenuRadioGroup, { value: theme, onValueChange: setTheme, children: [_jsx(DropdownMenuRadioItem, { value: "light", children: "Light" }), _jsx(DropdownMenuRadioItem, { value: "dark", children: "Dark" }), _jsx(DropdownMenuRadioItem, { value: "system", children: "System" })] })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive \u2014 Multiple Groups" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "Theme" }), _jsxs(DropdownMenuRadioGroup, { value: theme, onValueChange: setTheme, children: [_jsx(DropdownMenuRadioItem, { value: "light", children: "Light" }), _jsx(DropdownMenuRadioItem, { value: "dark", children: "Dark" }), _jsx(DropdownMenuRadioItem, { value: "system", children: "System" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Position" }), _jsxs(DropdownMenuRadioGroup, { value: position, onValueChange: setPosition, children: [_jsx(DropdownMenuRadioItem, { value: "top", children: "Top" }), _jsx(DropdownMenuRadioItem, { value: "bottom", children: "Bottom" }), _jsx(DropdownMenuRadioItem, { value: "right", children: "Right" })] })] })] })] })] }));
88
107
  },
89
108
  };
90
- export const AsChild = {
91
- args: {
92
- // DropdownMenu: "Lorem Ipsum",
93
- // value: "Lorem Ipsum",
94
- // fullwidth: true,
95
- },
96
- render: (args) => {
97
- console.log("args ", args);
98
- const props = Object.assign({}, args);
99
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] }) }) }));
109
+ // ---------------------------------------------------------------------------
110
+ // Radio with Icon — single select with leading icon via icon prop
111
+ // ---------------------------------------------------------------------------
112
+ export const WithRadioAndIcon = {
113
+ name: "With Radio + Icon",
114
+ render: () => {
115
+ const [theme, setTheme] = useState("dark");
116
+ return (_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: "All States \u2014 Radio + Icon" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsx(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: _jsxs(DropdownMenuRadioGroup, { value: "dark", children: [_jsx(DropdownMenuRadioItem, { value: "light", icon: _jsx(Icon, { type: "heroicons", name: "sun", className: "size-4 shrink-0" }), children: "Light" }), _jsx(DropdownMenuRadioItem, { value: "system", className: "!bg-[var(--dropdown-menu-hover-bg)]", icon: _jsx(Icon, { type: "heroicons", name: "computer-desktop", className: "size-4 shrink-0" }), children: "System (Hover)" }), _jsx(DropdownMenuRadioItem, { value: "dark", icon: _jsx(Icon, { type: "heroicons", name: "moon", className: "size-4 shrink-0" }), children: "Dark (Selected)" }), _jsx(DropdownMenuRadioItem, { value: "custom", disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "paint-brush", className: "size-4 shrink-0" }), children: "Custom (Disabled)" }), _jsx(DropdownMenuRadioItem, { value: "dark", disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "moon", className: "size-4 shrink-0" }), children: "Dark (Selected + Disabled)" })] }) })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", children: ["Theme: ", theme] }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "Theme" }), _jsxs(DropdownMenuRadioGroup, { value: theme, onValueChange: setTheme, children: [_jsx(DropdownMenuRadioItem, { value: "light", icon: _jsx(Icon, { type: "heroicons", name: "sun", className: "size-4 shrink-0" }), children: "Light" }), _jsx(DropdownMenuRadioItem, { value: "dark", icon: _jsx(Icon, { type: "heroicons", name: "moon", className: "size-4 shrink-0" }), children: "Dark" }), _jsx(DropdownMenuRadioItem, { value: "system", icon: _jsx(Icon, { type: "heroicons", name: "computer-desktop", className: "size-4 shrink-0" }), children: "System" }), _jsx(DropdownMenuRadioItem, { value: "custom", disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "paint-brush", className: "size-4" }), children: "Custom" })] })] })] })] })] }));
100
117
  },
101
118
  };
102
- export const Position = {
103
- args: {
104
- side: "bottom",
105
- align: "center",
106
- sideOffset: 5,
107
- alignOffset: 0,
108
- },
109
- render: (args) => {
110
- console.log("args ", args);
111
- const props = Object.assign({}, args);
112
- return (_jsx("div", { className: "flex flex-row gap-4 w-full", children: _jsx("div", { className: "flex flex-1 justify-center items-center space-x-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, Object.assign({}, args, { side: "bottom" // controls the side (top, bottom, left, right)
113
- , align: "start" // controls the alignment (start, center, end)
114
- , sideOffset: 5, alignOffset: 0, children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] }))] }) }) }));
119
+ // ---------------------------------------------------------------------------
120
+ // DropdownMenuShortcut — keyboard shortcut label on the right side of item
121
+ // ---------------------------------------------------------------------------
122
+ export const WithShortcut = {
123
+ name: "With Shortcut",
124
+ 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: "All States \u2014 Shortcut" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative", style: { position: "static", transform: "none" }, children: [_jsxs(DropdownMenuItem, { children: ["New Tab", _jsx(DropdownMenuShortcut, { children: "\u2318T" })] }), _jsxs(DropdownMenuItem, { className: "!bg-[var(--dropdown-menu-hover-bg)]", children: ["New Window (Hover)", _jsx(DropdownMenuShortcut, { children: "\u2318N" })] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4 shrink-0" }), "Edit", _jsx(DropdownMenuShortcut, { children: "\u2318E" })] }), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4 shrink-0" }), "Duplicate", _jsx(DropdownMenuShortcut, { children: "\u2318D" })] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { disabled: true, children: [_jsx(Icon, { type: "heroicons", name: "trash", className: "size-4 shrink-0" }), "Delete", _jsx(DropdownMenuShortcut, { children: "\u232B" })] })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { className: "w-52", children: [_jsx(DropdownMenuLabel, { children: "Actions" }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { children: ["New Tab", _jsx(DropdownMenuShortcut, { children: "\u2318T" })] }), _jsxs(DropdownMenuItem, { children: ["New Window", _jsx(DropdownMenuShortcut, { children: "\u2318N" })] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4 shrink-0" }), "Edit", _jsx(DropdownMenuShortcut, { children: "\u2318E" })] }), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4 shrink-0" }), "Duplicate", _jsx(DropdownMenuShortcut, { children: "\u2318D" })] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { disabled: true, children: [_jsx(Icon, { type: "heroicons", name: "trash", className: "size-4 shrink-0" }), "Delete", _jsx(DropdownMenuShortcut, { children: "\u232B" })] })] })] })] })] })),
125
+ };
126
+ // ---------------------------------------------------------------------------
127
+ // Trigger variants (on icon button, etc.)
128
+ // ---------------------------------------------------------------------------
129
+ export const TriggerVariants = {
130
+ name: "Trigger Variants",
131
+ render: () => (_jsxs("div", { className: "flex gap-8 items-center flex-wrap", children: [_jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Text Trigger" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { children: "Open" }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Button Trigger" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Icon Button Trigger" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" }), _jsx(DropdownMenuItem, { children: "Option Description" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Horizontal dots" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-horizontal" }) }) }), _jsxs(DropdownMenuContent, { children: [_jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4 shrink-0" }), "Edit"] }), _jsxs(DropdownMenuItem, { children: [_jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4 shrink-0" }), "Duplicate"] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { disabled: true, children: [_jsx(Icon, { type: "heroicons", name: "trash", className: "size-4 shrink-0" }), "Delete"] })] })] })] })] })),
132
+ };
133
+ // ---------------------------------------------------------------------------
134
+ // Complex showcase — real-world patterns combining all item types
135
+ // ---------------------------------------------------------------------------
136
+ export const ComplexShowcase = {
137
+ name: "Complex Showcase",
138
+ render: () => {
139
+ const [theme, setTheme] = useState("dark");
140
+ const [density, setDensity] = useState("comfortable");
141
+ const [sortBy, setSortBy] = useState("name");
142
+ const [sortDir, setSortDir] = useState("asc");
143
+ const [showHidden, setShowHidden] = useState(false);
144
+ const [showExtensions, setShowExtensions] = useState(true);
145
+ const [showPreview, setShowPreview] = useState(true);
146
+ return (_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: "File Manager Actions" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "ellipsis-vertical" }) }) }), _jsxs(DropdownMenuContent, { className: "relative w-[220px]", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4 shrink-0" }), children: "Rename" }), _jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4 shrink-0" }), children: "Duplicate" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Sort By" }), _jsxs(DropdownMenuRadioGroup, { value: "name", children: [_jsx(DropdownMenuRadioItem, { value: "name", children: "Name" }), _jsx(DropdownMenuRadioItem, { value: "date", children: "Date Modified" }), _jsx(DropdownMenuRadioItem, { value: "size", children: "Size" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Show" }), _jsx(DropdownMenuCheckboxItem, { children: "Hidden Files" }), _jsx(DropdownMenuCheckboxItem, { checked: true, children: "File Extensions" }), _jsx(DropdownMenuCheckboxItem, { checked: true, children: "Preview Panel" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "trash", className: "size-4 shrink-0" }), children: "Delete" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Editor Settings (Multiple RadioGroups)" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ActionButton, { variant: "icon", children: _jsx(Icon, { type: "heroicons", name: "cog-6-tooth" }) }) }), _jsxs(DropdownMenuContent, { className: "relative w-[220px]", style: { position: "static", transform: "none" }, children: [_jsx(DropdownMenuLabel, { children: "Theme" }), _jsxs(DropdownMenuRadioGroup, { value: "dark", children: [_jsx(DropdownMenuRadioItem, { value: "light", icon: _jsx(Icon, { type: "heroicons", name: "sun", className: "size-4 shrink-0" }), children: "Light" }), _jsx(DropdownMenuRadioItem, { value: "dark", icon: _jsx(Icon, { type: "heroicons", name: "moon", className: "size-4 shrink-0" }), children: "Dark" }), _jsx(DropdownMenuRadioItem, { value: "system", icon: _jsx(Icon, { type: "heroicons", name: "computer-desktop", className: "size-4 shrink-0" }), children: "System" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Density" }), _jsxs(DropdownMenuRadioGroup, { value: "comfortable", children: [_jsx(DropdownMenuRadioItem, { value: "compact", children: "Compact" }), _jsx(DropdownMenuRadioItem, { value: "comfortable", children: "Comfortable" }), _jsx(DropdownMenuRadioItem, { value: "spacious", children: "Spacious" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Sort Direction" }), _jsxs(DropdownMenuRadioGroup, { value: "asc", children: [_jsx(DropdownMenuRadioItem, { value: "asc", icon: _jsx(Icon, { type: "heroicons", name: "bars-arrow-up", className: "size-4 shrink-0" }), children: "Ascending" }), _jsx(DropdownMenuRadioItem, { value: "desc", icon: _jsx(Icon, { type: "heroicons", name: "bars-arrow-down", className: "size-4 shrink-0" }), children: "Descending" })] })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive \u2014 File Manager" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Options" }) }), _jsxs(DropdownMenuContent, { className: "w-[220px]", children: [_jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "pencil", className: "size-4 shrink-0" }), children: "Rename" }), _jsx(DropdownMenuItem, { icon: _jsx(Icon, { type: "heroicons", name: "document-duplicate", className: "size-4 shrink-0" }), children: "Duplicate" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Sort By" }), _jsxs(DropdownMenuRadioGroup, { value: sortBy, onValueChange: setSortBy, children: [_jsx(DropdownMenuRadioItem, { value: "name", children: "Name" }), _jsx(DropdownMenuRadioItem, { value: "date", children: "Date Modified" }), _jsx(DropdownMenuRadioItem, { value: "size", children: "Size" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Show" }), _jsx(DropdownMenuCheckboxItem, { checked: showHidden, onCheckedChange: setShowHidden, onSelect: (e) => e.preventDefault(), children: "Hidden Files" }), _jsx(DropdownMenuCheckboxItem, { checked: showExtensions, onCheckedChange: setShowExtensions, onSelect: (e) => e.preventDefault(), children: "File Extensions" }), _jsx(DropdownMenuCheckboxItem, { checked: showPreview, onCheckedChange: setShowPreview, onSelect: (e) => e.preventDefault(), children: "Preview Panel" }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { disabled: true, icon: _jsx(Icon, { type: "heroicons", name: "trash", className: "size-4 shrink-0" }), children: "Delete" })] })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Interactive \u2014 Editor Settings" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Settings" }) }), _jsxs(DropdownMenuContent, { className: "w-[220px]", children: [_jsx(DropdownMenuLabel, { children: "Theme" }), _jsxs(DropdownMenuRadioGroup, { value: theme, onValueChange: setTheme, children: [_jsx(DropdownMenuRadioItem, { value: "light", icon: _jsx(Icon, { type: "heroicons", name: "sun", className: "size-4 shrink-0" }), children: "Light" }), _jsx(DropdownMenuRadioItem, { value: "dark", icon: _jsx(Icon, { type: "heroicons", name: "moon", className: "size-4 shrink-0" }), children: "Dark" }), _jsx(DropdownMenuRadioItem, { value: "system", icon: _jsx(Icon, { type: "heroicons", name: "computer-desktop", className: "size-4 shrink-0" }), children: "System" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Density" }), _jsxs(DropdownMenuRadioGroup, { value: density, onValueChange: setDensity, children: [_jsx(DropdownMenuRadioItem, { value: "compact", children: "Compact" }), _jsx(DropdownMenuRadioItem, { value: "comfortable", children: "Comfortable" }), _jsx(DropdownMenuRadioItem, { value: "spacious", children: "Spacious" })] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Sort Direction" }), _jsxs(DropdownMenuRadioGroup, { value: sortDir, onValueChange: setSortDir, children: [_jsx(DropdownMenuRadioItem, { value: "asc", icon: _jsx(Icon, { type: "heroicons", name: "bars-arrow-up", className: "size-4 shrink-0" }), children: "Ascending" }), _jsx(DropdownMenuRadioItem, { value: "desc", icon: _jsx(Icon, { type: "heroicons", name: "bars-arrow-down", className: "size-4 shrink-0" }), children: "Descending" })] })] })] })] })] }));
115
147
  },
116
148
  };
@@ -9,9 +9,9 @@ var __rest = (this && this.__rest) || function (s, e) {
9
9
  }
10
10
  return t;
11
11
  };
12
- import { jsx as _jsx } from "react/jsx-runtime";
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import React from "react";
14
- import { FormProvider, useForm, } from "react-hook-form";
14
+ import { FormProvider, useForm, useFormContext, } from "react-hook-form";
15
15
  import { yupResolver } from "@hookform/resolvers/yup";
16
16
  export const createYupResolver = (schema) => yupResolver(schema);
17
17
  export const createControlledForm = ({ methods, defaultValues, controllerRef, }) => {
@@ -52,8 +52,15 @@ export const useControlledForm = ({ defaultValues, controllerRef, resolver, vali
52
52
  FormRoot: stableRef.current.FormRoot,
53
53
  };
54
54
  };
55
+ const FormStateObserver = ({ onFormStateChange, }) => {
56
+ const { formState } = useFormContext();
57
+ React.useEffect(() => {
58
+ onFormStateChange(formState);
59
+ }, [formState, onFormStateChange]);
60
+ return null;
61
+ };
55
62
  const FormInner = (_a, ref) => {
56
- var { children, defaultValues, methods: externalMethods, controllerRef, onSubmit, onInvalidSubmit, resolver, validationSchema, mode = "onSubmit", reValidateMode = "onChange", noValidate = true } = _a, formProps = __rest(_a, ["children", "defaultValues", "methods", "controllerRef", "onSubmit", "onInvalidSubmit", "resolver", "validationSchema", "mode", "reValidateMode", "noValidate"]);
63
+ var { children, defaultValues, methods: externalMethods, controllerRef, onSubmit, onInvalidSubmit, onFormStateChange, resolver, validationSchema, mode = "onSubmit", reValidateMode = "onChange", noValidate = true } = _a, formProps = __rest(_a, ["children", "defaultValues", "methods", "controllerRef", "onSubmit", "onInvalidSubmit", "onFormStateChange", "resolver", "validationSchema", "mode", "reValidateMode", "noValidate"]);
57
64
  const resolvedResolver = resolver !== null && resolver !== void 0 ? resolver : (validationSchema
58
65
  ? createYupResolver(validationSchema)
59
66
  : undefined);
@@ -82,7 +89,7 @@ const FormInner = (_a, ref) => {
82
89
  controllerRef.current = null;
83
90
  };
84
91
  }, [controllerRef, controller]);
85
- return (_jsx(FormProvider, Object.assign({}, methods, { children: _jsx("form", Object.assign({}, formProps, { noValidate: noValidate, onSubmit: methods.handleSubmit(onSubmit, onInvalidSubmit), children: typeof children === "function" ? children(methods) : children })) })));
92
+ return (_jsx(FormProvider, Object.assign({}, methods, { children: _jsxs("form", Object.assign({}, formProps, { noValidate: noValidate, onSubmit: methods.handleSubmit(onSubmit, onInvalidSubmit), children: [onFormStateChange && (_jsx(FormStateObserver, { onFormStateChange: onFormStateChange })), typeof children === "function" ? children(methods) : children] })) })));
86
93
  };
87
94
  export const Form = React.forwardRef(FormInner);
88
95
  export default Form;
@@ -162,6 +162,33 @@ export const RenderPropsCodeControl = {
162
162
  } }), _jsx("div", { className: "flex gap-2", children: _jsx(Button, { type: "submit", disabled: !formState.isValid || formState.isSubmitting, isLoading: formState.isSubmitting, children: "Submit with code" }) })] })) }));
163
163
  },
164
164
  };
165
+ export const FormStateChangeCallback = {
166
+ args: {},
167
+ render: () => {
168
+ const [isFormValid, setIsFormValid] = useState(false);
169
+ const [isDirty, setIsDirty] = useState(false);
170
+ const [submitCount, setSubmitCount] = useState(0);
171
+ const schema = yup.object({
172
+ title: yup.string().required("Title is required"),
173
+ description: yup
174
+ .string()
175
+ .required("Description is required")
176
+ .min(10, "Description must be at least 10 characters"),
177
+ });
178
+ return (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "rounded-md border border-bg-stroke1 bg-bg-bg2 p-3 text-xs text-text-g-contrast-medium space-y-1", children: [_jsxs("div", { children: ["Validity:", " ", _jsx("span", { className: isFormValid ? "text-state-success-default" : "text-state-error-default", children: isFormValid ? "valid" : "invalid" })] }), _jsxs("div", { children: ["Dirty: ", isDirty ? "yes" : "no"] }), _jsxs("div", { children: ["Submit count: ", submitCount] })] }), _jsxs(Form, { className: "flex flex-col gap-3", defaultValues: { title: "", description: "" }, mode: "onTouched", reValidateMode: "onChange", validationSchema: schema, onSubmit: (values) => {
179
+ setSubmitCount((prev) => prev + 1);
180
+ // eslint-disable-next-line no-console
181
+ console.log("Submitted:", values);
182
+ }, onFormStateChange: (formState) => {
183
+ setIsFormValid(formState.isValid);
184
+ setIsDirty(formState.isDirty);
185
+ }, children: [_jsx(Field, { name: "title", component: TextInput, componentProps: { label: "Title", required: true } }), _jsx(Field, { name: "description", component: TextInput, componentProps: {
186
+ label: "Description",
187
+ helperText: "At least 10 characters",
188
+ required: true,
189
+ } }), _jsx(Button, { type: "submit", disabled: !isFormValid, children: "Submit" })] })] }));
190
+ },
191
+ };
165
192
  export const HigherLayerCodeControl = {
166
193
  args: {},
167
194
  render: () => {
@@ -0,0 +1,50 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import * as React from "react";
14
+ import { cn } from "@/utils/cn";
15
+ const sizeClass = {
16
+ m: "ui-scrollbar ui-scrollbar-m",
17
+ s: "ui-scrollbar ui-scrollbar-s",
18
+ xs: "ui-scrollbar ui-scrollbar-xs",
19
+ };
20
+ const directionClass = {
21
+ vertical: "overflow-y-auto overflow-x-hidden",
22
+ horizontal: "overflow-x-auto overflow-y-hidden",
23
+ both: "overflow-auto",
24
+ };
25
+ /**
26
+ * ScrollArea
27
+ *
28
+ * A thin wrapper that applies the design-system scrollbar style to any
29
+ * scrollable container. Use `scrollbarSize` to pick the Figma size variant
30
+ * and `direction` to control which axis scrolls.
31
+ *
32
+ * **Client usage:**
33
+ * ```tsx
34
+ * <ScrollArea className="max-h-[270px]">
35
+ * {items.map(item => <div key={item.id}>{item.label}</div>)}
36
+ * </ScrollArea>
37
+ * ```
38
+ *
39
+ * For a double-scroll layout (two independent sections inside one dropdown),
40
+ * wrap each section individually:
41
+ * ```tsx
42
+ * <ScrollArea className="max-h-[160px]">...section A items...</ScrollArea>
43
+ * <ScrollArea className="max-h-[160px]">...section B items...</ScrollArea>
44
+ * ```
45
+ */
46
+ export const ScrollArea = React.forwardRef((_a, ref) => {
47
+ var { className, scrollbarSize = "s", direction = "vertical", children } = _a, props = __rest(_a, ["className", "scrollbarSize", "direction", "children"]);
48
+ return (_jsx("div", Object.assign({ ref: ref, className: cn(directionClass[direction], sizeClass[scrollbarSize], className) }, props, { children: children })));
49
+ });
50
+ ScrollArea.displayName = "ScrollArea";
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ScrollArea } from "./ScrollArea";
3
+ const meta = {
4
+ title: "Components/ScrollArea",
5
+ component: ScrollArea,
6
+ parameters: {
7
+ layout: "fullscreen",
8
+ },
9
+ decorators: [
10
+ (Story) => (_jsx("div", { className: "p-10 flex gap-8 flex-wrap bg-workspace-surface min-h-screen", children: _jsx(Story, {}) })),
11
+ ],
12
+ };
13
+ export default meta;
14
+ const ITEMS = Array.from({ length: 12 }, (_, i) => `Option Description ${i + 1}`);
15
+ // ---------------------------------------------------------------------------
16
+ // Size variants (Figma: Size=M / S / XS)
17
+ // ---------------------------------------------------------------------------
18
+ export const Sizes = {
19
+ name: "Size Variants",
20
+ render: () => (_jsx("div", { className: "flex gap-10 items-start", children: ["m", "s", "xs"].map((size) => (_jsxs("div", { children: [_jsxs("p", { className: "typography-small4 text-text-g-contrast-medium mb-2 uppercase", children: ["Size ", size] }), _jsx(ScrollArea, { scrollbarSize: size, className: "max-h-[270px] w-[200px] rounded-lg bg-modal-surface", children: ITEMS.map((label) => (_jsx("div", { className: "px-4 py-3 typography-subtitle4 text-text-g-contrast-high", children: label }, label))) })] }, size))) })),
21
+ };
22
+ // ---------------------------------------------------------------------------
23
+ // Vertical scroll (Figma: Can Scroll)
24
+ // ---------------------------------------------------------------------------
25
+ export const VerticalScroll = {
26
+ name: "Vertical Scroll",
27
+ render: () => (_jsxs("div", { children: [_jsxs("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: ["Single scrollable list \u2014 use", " ", _jsx("code", { className: "text-xs", children: "<ScrollArea className=\"max-h-[...]\">" })] }), _jsx(ScrollArea, { className: "max-h-[270px] w-[230px] rounded-lg bg-modal-surface", children: ITEMS.map((label) => (_jsx("div", { className: "px-4 py-3 typography-subtitle4 text-text-g-contrast-high", children: label }, label))) })] })),
28
+ };
29
+ // ---------------------------------------------------------------------------
30
+ // Horizontal scroll (Figma: Horizontal=Yes)
31
+ // ---------------------------------------------------------------------------
32
+ export const HorizontalScroll = {
33
+ name: "Horizontal Scroll",
34
+ render: () => (_jsxs("div", { children: [_jsxs("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: ["Horizontal \u2014 pass", " ", _jsx("code", { className: "text-xs", children: "direction=\"horizontal\"" })] }), _jsx(ScrollArea, { direction: "horizontal", className: "max-w-[300px] rounded-lg bg-modal-surface", children: _jsx("div", { className: "flex", children: ITEMS.map((label) => (_jsx("div", { className: "shrink-0 w-[140px] px-4 py-3 typography-subtitle4 text-text-g-contrast-high border-r border-[var(--dropdown-menu-seperator-bg)]", children: label }, label))) }) })] })),
35
+ };
36
+ // ---------------------------------------------------------------------------
37
+ // Double scroll (Figma: Double Scroll — two independent sections)
38
+ // ---------------------------------------------------------------------------
39
+ export const DoubleScroll = {
40
+ name: "Double Scroll",
41
+ render: () => (_jsxs("div", { children: [_jsxs("p", { className: "typography-small4 text-text-g-contrast-medium mb-4", children: ["Two independent scrollable sections inside one container.", _jsx("br", {}), "Wrap each section in its own", " ", _jsx("code", { className: "text-xs", children: "<ScrollArea>" }), "."] }), _jsxs("div", { className: "w-[230px] rounded-lg bg-modal-surface overflow-hidden", children: [_jsx("div", { className: "px-3 pt-4 pb-2 typography-small4 text-text-g-contrast-high", children: "Section A" }), _jsx(ScrollArea, { className: "max-h-[160px]", children: ITEMS.slice(0, 8).map((label) => (_jsx("div", { className: "px-4 py-3 typography-subtitle4 text-text-g-contrast-high", children: label }, label))) }), _jsx("div", { className: "h-px bg-[var(--dropdown-menu-seperator-bg)] my-2" }), _jsx("div", { className: "px-3 pt-2 pb-2 typography-small4 text-text-g-contrast-high", children: "Section B" }), _jsx(ScrollArea, { className: "max-h-[160px]", children: ITEMS.slice(0, 8).map((label) => (_jsx("div", { className: "px-4 py-3 typography-subtitle4 text-text-g-contrast-high", children: label }, label))) })] })] })),
42
+ };
43
+ // ---------------------------------------------------------------------------
44
+ // Usage with DropdownMenu (Figma: Can Scroll / Double Scroll in dropdown)
45
+ // ---------------------------------------------------------------------------
46
+ export const WithDropdownMenu = {
47
+ name: "Usage with DropdownMenu",
48
+ render: () => {
49
+ // Inline-import to avoid circular storybook deps — client should import from "@core/ui"
50
+ const { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,
51
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
52
+ } = require("../DropdownMenu/DropdownMenu");
53
+ const Button = require("../Button/Button").default;
54
+ return (_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: "Can Scroll" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsx(DropdownMenuContent, { children: _jsx(ScrollArea, { className: "max-h-[270px]", children: ITEMS.map((label) => (_jsx(DropdownMenuItem, { children: label }, label))) }) })] })] }), _jsxs("div", { children: [_jsx("p", { className: "typography-small4 text-text-g-contrast-medium mb-2", children: "Double Scroll" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Open Menu" }) }), _jsxs(DropdownMenuContent, { children: [_jsx(DropdownMenuLabel, { children: "Section A" }), _jsx(ScrollArea, { className: "max-h-[160px]", children: ITEMS.slice(0, 8).map((label) => (_jsx(DropdownMenuItem, { children: label }, label))) }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuLabel, { children: "Section B" }), _jsx(ScrollArea, { className: "max-h-[160px]", children: ITEMS.slice(0, 8).map((label) => (_jsx(DropdownMenuItem, { children: label }, label))) })] })] })] })] }));
55
+ },
56
+ };
@@ -10,7 +10,8 @@ var __rest = (this && this.__rest) || function (s, e) {
10
10
  return t;
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
- import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, } from "react";
13
+ import { forwardRef, useCallback, useMemo, useRef, } from "react";
14
+ import { useStableMergedRef } from "@/utils/mergeRefs";
14
15
  import { helperTextVariant, iconActionVariant, inlineEndIconWrapperVariant, inlineStartIconWrapperVariant, inputVariant, labelVariant, searchIconVariant, segmentedIconWrapperVariant, } from "./TextInput.styles";
15
16
  import { CircleAlert, CircleX, Search, } from "lucide-react";
16
17
  import { cn } from "@/utils/cn";
@@ -18,6 +19,9 @@ export const TextInput = forwardRef((_a, ref) => {
18
19
  var { id, label, size = "md", rounded = "normal", variant = "outline", type = "text", iconMode = "solid", helperText, errorMessage, warningMessage, status, fullwidth = true, disabled = false, error = false, warning = false, required = true, isFloatingLabel = true, keepCloseIconOnValue = false, keepFooterSpace = true, hasClearIcon = true, hasSearchIcon = false, startIcon, endIcon, labelClassName, onClickStartIcon, onClickEndIcon, renderStartIcon, renderEndIcon, classes, normalize, format, trimOnCommit, normalizeOnCommit } = _a, props = __rest(_a, ["id", "label", "size", "rounded", "variant", "type", "iconMode", "helperText", "errorMessage", "warningMessage", "status", "fullwidth", "disabled", "error", "warning", "required", "isFloatingLabel", "keepCloseIconOnValue", "keepFooterSpace", "hasClearIcon", "hasSearchIcon", "startIcon", "endIcon", "labelClassName", "onClickStartIcon", "onClickEndIcon", "renderStartIcon", "renderEndIcon", "classes", "normalize", "format", "trimOnCommit", "normalizeOnCommit"]);
19
20
  const inputRef = useRef(null);
20
21
  const _id = id || `${type}-${label}-input`;
22
+ // Stable merged ref — identity never changes so Headless UI (or any library
23
+ // that watches refs) won't trigger detach/re-attach loops.
24
+ const stableRef = useStableMergedRef(ref, inputRef);
21
25
  const hasLeftSectionIcon = !!startIcon || !!renderStartIcon;
22
26
  const hasRightSectionIcon = !!endIcon || !!renderEndIcon;
23
27
  const feedbackStatus = status ||
@@ -81,7 +85,6 @@ export const TextInput = forwardRef((_a, ref) => {
81
85
  warning: isWarning,
82
86
  position: "end",
83
87
  });
84
- useImperativeHandle(ref, () => inputRef === null || inputRef === void 0 ? void 0 : inputRef.current);
85
88
  const handleChange = useCallback((e) => {
86
89
  var _a;
87
90
  if (normalize) {
@@ -183,7 +186,7 @@ export const TextInput = forwardRef((_a, ref) => {
183
186
  renderEndIcon,
184
187
  handleOnClickRightSectionIcon,
185
188
  ]);
186
- return (_jsxs("div", { className: `inline-flex flex-col ${fullwidth ? "w-full" : ""}`, children: [_jsxs("div", { className: "relative", children: [_jsx("input", Object.assign({}, props, { placeholder: " ", ref: inputRef, type: type, id: _id, disabled: disabled, value: displayValue, className: cn(inputClassname, props.className), onChange: normalize ? handleChange : props.onChange, onBlur: trimOnCommit || normalizeOnCommit ? handleBlur : props.onBlur, onKeyDown: trimOnCommit || normalizeOnCommit ? handleKeyDown : props.onKeyDown })), hasSearchIcon && !hasLeftSectionIcon && (_jsx("div", { className: cn(inlineStartIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconSearchWrapper), children: _jsx(Search, { className: cn(searchIconClassname, classes === null || classes === void 0 ? void 0 : classes.icon) }) })), startIconElement, hasClearIcon && !hasRightSectionIcon && (_jsx("div", { className: cn(inlineEndIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconWrapper), style: {
189
+ return (_jsxs("div", { className: `inline-flex flex-col ${fullwidth ? "w-full" : ""}`, children: [_jsxs("div", { className: "relative", children: [_jsx("input", Object.assign({}, props, { placeholder: " ", ref: stableRef, type: type, id: _id, disabled: disabled, value: displayValue, className: cn(inputClassname, props.className), onChange: normalize ? handleChange : props.onChange, onBlur: trimOnCommit || normalizeOnCommit ? handleBlur : props.onBlur, onKeyDown: trimOnCommit || normalizeOnCommit ? handleKeyDown : props.onKeyDown })), hasSearchIcon && !hasLeftSectionIcon && (_jsx("div", { className: cn(inlineStartIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconSearchWrapper), children: _jsx(Search, { className: cn(searchIconClassname, classes === null || classes === void 0 ? void 0 : classes.icon) }) })), startIconElement, hasClearIcon && !hasRightSectionIcon && (_jsx("div", { className: cn(inlineEndIconWrapperClassname, classes === null || classes === void 0 ? void 0 : classes.iconWrapper), style: {
187
190
  display: keepCloseIconOnValue && props.value ? "flex" : undefined,
188
191
  }, children: _jsx(CircleX, { className: cn(iconActionClassname,
189
192
  // 'fill-none stroke-current',