@recursica/mantine-adapter 0.10.0 → 0.12.0

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 (79) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +6 -28
  3. package/dist/mantine-adapter.cjs +1 -1
  4. package/dist/mantine-adapter.cjs.map +1 -1
  5. package/dist/mantine-adapter.css +1 -1
  6. package/dist/mantine-adapter.js +1650 -1344
  7. package/dist/mantine-adapter.js.map +1 -1
  8. package/dist/src/components/Checkbox/Checkbox.d.ts +3 -1
  9. package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +21 -0
  10. package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +2 -0
  11. package/dist/src/components/Label/Label.d.ts +1 -3
  12. package/dist/src/components/Menu/Menu.d.ts +85 -3
  13. package/dist/src/components/Radio/Radio.d.ts +3 -1
  14. package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
  15. package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +6 -6
  16. package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
  17. package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +7 -1
  18. package/dist/src/components/ReadOnlyField/index.d.ts +2 -0
  19. package/dist/src/components/Switch/Switch.d.ts +3 -1
  20. package/dist/src/components/index.d.ts +1 -0
  21. package/dist/src/utils/RequireAccessibleLabel.d.ts +18 -0
  22. package/package.json +1 -1
  23. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +6 -4
  24. package/src/components/Avatar/Avatar.stories.tsx +10 -5
  25. package/src/components/Badge/Badge.stories.tsx +2 -1
  26. package/src/components/Button/Button.stories.tsx +2 -4
  27. package/src/components/Checkbox/Checkbox.module.css +1 -1
  28. package/src/components/Checkbox/Checkbox.stories.tsx +24 -3
  29. package/src/components/Checkbox/Checkbox.tsx +72 -15
  30. package/src/components/Checkbox/CheckboxGroup.stories.tsx +26 -25
  31. package/src/components/Checkbox/CheckboxGroup.tsx +38 -58
  32. package/src/components/Container/Container.stories.tsx +6 -3
  33. package/src/components/DatePicker/DatePicker.stories.tsx +1 -5
  34. package/src/components/Dropdown/Dropdown.stories.tsx +0 -3
  35. package/src/components/Dropdown/Dropdown.tsx +6 -5
  36. package/src/components/FileInput/FileInput.stories.tsx +1 -5
  37. package/src/components/FileUpload/FileUpload.stories.tsx +1 -5
  38. package/src/components/Flex/Flex.stories.tsx +6 -3
  39. package/src/components/FormControlLayout/FormControlLayout.module.css +80 -0
  40. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +82 -0
  41. package/src/components/FormControlLayout/FormControlLayout.tsx +78 -0
  42. package/src/components/FormControlWrapper/FormControlWrapper.module.css +3 -41
  43. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +18 -5
  44. package/src/components/FormControlWrapper/FormControlWrapper.tsx +28 -41
  45. package/src/components/Group/Group.stories.tsx +6 -3
  46. package/src/components/Label/Label.module.css +0 -37
  47. package/src/components/Label/Label.stories.tsx +8 -9
  48. package/src/components/Label/Label.tsx +2 -7
  49. package/src/components/Loader/Loader.stories.tsx +10 -5
  50. package/src/components/Menu/MENU_IMPLEMENTATION_NOTES.md +78 -0
  51. package/src/components/Menu/Menu.module.css +244 -0
  52. package/src/components/Menu/Menu.stories.tsx +309 -5
  53. package/src/components/Menu/Menu.tsx +317 -4
  54. package/src/components/NumberInput/NumberInput.stories.tsx +1 -5
  55. package/src/components/Radio/Radio.stories.tsx +22 -8
  56. package/src/components/Radio/Radio.tsx +134 -75
  57. package/src/components/Radio/RadioGroup.stories.tsx +26 -7
  58. package/src/components/Radio/RadioGroup.tsx +37 -57
  59. package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
  60. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +43 -0
  61. package/src/components/ReadOnlyField/ReadOnlyField.tsx +30 -3
  62. package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
  63. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +3 -1
  64. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +10 -2
  65. package/src/components/ReadOnlyField/index.ts +2 -0
  66. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +1 -5
  67. package/src/components/Slider/Slider.stories.tsx +1 -5
  68. package/src/components/Stack/Stack.stories.tsx +6 -3
  69. package/src/components/Switch/Switch.module.css +2 -10
  70. package/src/components/Switch/Switch.stories.tsx +42 -27
  71. package/src/components/Switch/Switch.tsx +138 -89
  72. package/src/components/Switch/SwitchGroup.stories.tsx +28 -8
  73. package/src/components/Switch/SwitchGroup.tsx +37 -57
  74. package/src/components/TextArea/TextArea.stories.tsx +0 -3
  75. package/src/components/TextArea/TextArea.tsx +6 -5
  76. package/src/components/TextField/TextField.tsx +6 -5
  77. package/src/components/TimePicker/TimePicker.stories.tsx +1 -5
  78. package/src/components/index.ts +1 -0
  79. package/src/utils/RequireAccessibleLabel.ts +12 -0
@@ -0,0 +1,244 @@
1
+ /* HARDCODED VALUES:
2
+ - border-style: solid. Structural rendering rule for the dropdown border (Mantine uses Paper which may not set border natively).
3
+ - opacity: 0.5 on disabled items. Recursica has no dedicated disabled-opacity token for menu items.
4
+ - NOTE: overflow is intentionally NOT set on .dropdown. Mantine renders sub-menu dropdowns
5
+ inside the parent dropdown DOM tree using Floating UI absolute positioning. Setting
6
+ overflow: hidden clips sub-menus; overflow-y: auto causes unwanted scrollbars.
7
+ - All structural layout (flex, cursor, pointer-events on disabled) is deferred to Mantine's
8
+ native behavior. We only override visual design tokens (colors, typography, spacing, borders).
9
+ */
10
+
11
+ /* ======================================
12
+ DROPDOWN CONTAINER
13
+ ====================================== */
14
+
15
+ .dropdown {
16
+ background-color: var(
17
+ --recursica_ui-kit_components_menu_properties_colors_background
18
+ );
19
+ border-style: solid; /* HARDCODE: Mantine Paper does not set border-style natively */
20
+ border-width: var(--recursica_ui-kit_components_menu_properties_border-size);
21
+ border-color: var(
22
+ --recursica_ui-kit_components_menu_properties_colors_border-color
23
+ );
24
+ border-radius: var(
25
+ --recursica_ui-kit_components_menu_properties_border-radius
26
+ );
27
+ box-shadow: var(--recursica_ui-kit_components_menu_properties_elevation);
28
+
29
+ min-width: var(--recursica_ui-kit_components_menu_properties_min-width);
30
+ max-width: var(--recursica_ui-kit_components_menu_properties_max-width);
31
+
32
+ padding: var(
33
+ --recursica_ui-kit_components_menu-item_properties_divider-item-gap
34
+ );
35
+ }
36
+
37
+ /* ======================================
38
+ MENU ITEM
39
+ ====================================== */
40
+
41
+ .item {
42
+ position: relative;
43
+
44
+ /* Geometry */
45
+ padding: var(
46
+ --recursica_ui-kit_components_menu-item_properties_vertical-padding
47
+ )
48
+ var(--recursica_ui-kit_components_menu-item_properties_horizontal-padding);
49
+ border-radius: var(
50
+ --recursica_ui-kit_components_menu-item_properties_border-radius
51
+ );
52
+
53
+ /* Typography */
54
+ font-family: var(
55
+ --recursica_ui-kit_components_menu-item_properties_text_font-family
56
+ );
57
+ font-size: var(
58
+ --recursica_ui-kit_components_menu-item_properties_text_font-size
59
+ );
60
+ font-style: var(
61
+ --recursica_ui-kit_components_menu-item_properties_text_font-style
62
+ );
63
+ font-weight: var(
64
+ --recursica_ui-kit_components_menu-item_properties_text_font-weight
65
+ );
66
+ letter-spacing: var(
67
+ --recursica_ui-kit_components_menu-item_properties_text_letter-spacing
68
+ );
69
+ line-height: var(
70
+ --recursica_ui-kit_components_menu-item_properties_text_line-height
71
+ );
72
+ text-decoration: var(
73
+ --recursica_ui-kit_components_menu-item_properties_text_text-decoration
74
+ );
75
+ text-transform: var(
76
+ --recursica_ui-kit_components_menu-item_properties_text_text-transform
77
+ );
78
+
79
+ /* Default State: Unselected */
80
+ background-color: var(
81
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
82
+ );
83
+ color: var(
84
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_text
85
+ );
86
+ opacity: var(
87
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_opacity
88
+ );
89
+ }
90
+
91
+ /* Override Mantine's native hover background to use our overlay technique */
92
+ .item:hover {
93
+ background-color: var(
94
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
95
+ );
96
+ }
97
+
98
+ /* Hover overlay using ::after pseudo-element (same technique as Accordion) */
99
+ .item::after {
100
+ content: "";
101
+ position: absolute;
102
+ inset: 0;
103
+ border-radius: inherit;
104
+ z-index: 0;
105
+ pointer-events: none;
106
+ background-color: var(
107
+ --recursica_ui-kit_components_menu-item_properties_hover-color
108
+ );
109
+ opacity: 0;
110
+ transition: opacity 150ms ease;
111
+ }
112
+
113
+ .item:hover:not([data-disabled])::after {
114
+ opacity: var(
115
+ --recursica_ui-kit_components_menu-item_properties_hover-opacity,
116
+ 0.1
117
+ );
118
+ }
119
+
120
+ /* Selected item state */
121
+ .item[data-selected] {
122
+ background-color: var(
123
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_background
124
+ );
125
+ color: var(
126
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_text
127
+ );
128
+ opacity: var(
129
+ --recursica_ui-kit_components_menu-item_properties_colors_selected-item_opacity
130
+ );
131
+ }
132
+
133
+ /* Hovered item state (keyboard navigation) */
134
+ .item[data-hovered] {
135
+ background-color: var(
136
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_background
137
+ );
138
+ }
139
+ .item[data-hovered]::after {
140
+ opacity: var(
141
+ --recursica_ui-kit_components_menu-item_properties_hover-opacity,
142
+ 0.1
143
+ );
144
+ }
145
+
146
+ /* Disabled item */
147
+ .item[data-disabled] {
148
+ /* HARDCODE: 0.5 opacity fallback; no dedicated disabled-opacity token for menu items */
149
+ opacity: 0.5;
150
+ }
151
+
152
+ /* ======================================
153
+ ITEM LABEL
154
+ ====================================== */
155
+
156
+ .itemLabel {
157
+ position: relative;
158
+ z-index: 1;
159
+ color: inherit;
160
+ }
161
+
162
+ /* ======================================
163
+ ITEM SECTION (LEFT / RIGHT ICONS)
164
+ ====================================== */
165
+
166
+ .itemSection {
167
+ position: relative;
168
+ z-index: 1;
169
+ color: inherit;
170
+ }
171
+
172
+ /* ======================================
173
+ DIVIDER
174
+ ====================================== */
175
+
176
+ .divider {
177
+ height: var(
178
+ --recursica_ui-kit_components_menu-item_properties_divider-height
179
+ );
180
+ background-color: var(
181
+ --recursica_ui-kit_components_menu-item_properties_colors_divider-color
182
+ );
183
+ opacity: var(
184
+ --recursica_ui-kit_components_menu-item_properties_divider-opacity
185
+ );
186
+ margin: var(
187
+ --recursica_ui-kit_components_menu-item_properties_divider-item-gap
188
+ )
189
+ 0;
190
+ }
191
+
192
+ /* ======================================
193
+ SECTION LABEL
194
+ ====================================== */
195
+
196
+ .label {
197
+ padding: var(
198
+ --recursica_ui-kit_components_menu-item_properties_vertical-padding
199
+ )
200
+ var(--recursica_ui-kit_components_menu-item_properties_horizontal-padding);
201
+
202
+ /* Supporting Text Typography */
203
+ font-family: var(
204
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-family
205
+ );
206
+ font-size: var(
207
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-size
208
+ );
209
+ font-style: var(
210
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-style
211
+ );
212
+ font-weight: var(
213
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_font-weight
214
+ );
215
+ letter-spacing: var(
216
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_letter-spacing
217
+ );
218
+ line-height: var(
219
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_line-height
220
+ );
221
+ text-decoration: var(
222
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_text-decoration
223
+ );
224
+ text-transform: var(
225
+ --recursica_ui-kit_components_menu-item_properties_supporting-text_text-transform
226
+ );
227
+
228
+ color: var(
229
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_supporting-text-color
230
+ );
231
+ opacity: var(
232
+ --recursica_ui-kit_components_menu-item_properties_colors_unselected-item_supporting-text-opacity
233
+ );
234
+ }
235
+
236
+ /* ======================================
237
+ SUB-MENU CHEVRON
238
+ ====================================== */
239
+
240
+ .chevron {
241
+ position: relative;
242
+ z-index: 1;
243
+ color: inherit;
244
+ }
@@ -1,17 +1,321 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { Menu } from "./Menu";
3
- import { ComingSoon } from "@recursica/storybook-template";
3
+ import { Button } from "../Button";
4
4
 
5
- const meta: Meta<typeof Menu> = {
6
- title: "UI-Kit/🚧 Menu",
5
+ /**
6
+ * Menu story axes:
7
+ * - trigger: click (default) vs hover behavior
8
+ * - position: dropdown alignment relative to target
9
+ * - withArrow: arrow indicator on the dropdown
10
+ * - content variations: icons, dividers, labels, disabled items, submenus
11
+ * - layer: tested via the global Layer decorator (withLayer/layer args)
12
+ */
13
+
14
+ const SettingsIcon = () => (
15
+ <svg
16
+ xmlns="http://www.w3.org/2000/svg"
17
+ width="14"
18
+ height="14"
19
+ viewBox="0 0 24 24"
20
+ fill="none"
21
+ stroke="currentColor"
22
+ strokeWidth="2"
23
+ strokeLinecap="round"
24
+ strokeLinejoin="round"
25
+ >
26
+ <circle cx="12" cy="12" r="3" />
27
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
28
+ </svg>
29
+ );
30
+
31
+ const SearchIcon = () => (
32
+ <svg
33
+ xmlns="http://www.w3.org/2000/svg"
34
+ width="14"
35
+ height="14"
36
+ viewBox="0 0 24 24"
37
+ fill="none"
38
+ stroke="currentColor"
39
+ strokeWidth="2"
40
+ strokeLinecap="round"
41
+ strokeLinejoin="round"
42
+ >
43
+ <circle cx="11" cy="11" r="8" />
44
+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
45
+ </svg>
46
+ );
47
+
48
+ const MessageIcon = () => (
49
+ <svg
50
+ xmlns="http://www.w3.org/2000/svg"
51
+ width="14"
52
+ height="14"
53
+ viewBox="0 0 24 24"
54
+ fill="none"
55
+ stroke="currentColor"
56
+ strokeWidth="2"
57
+ strokeLinecap="round"
58
+ strokeLinejoin="round"
59
+ >
60
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
61
+ </svg>
62
+ );
63
+
64
+ const ImageIcon = () => (
65
+ <svg
66
+ xmlns="http://www.w3.org/2000/svg"
67
+ width="14"
68
+ height="14"
69
+ viewBox="0 0 24 24"
70
+ fill="none"
71
+ stroke="currentColor"
72
+ strokeWidth="2"
73
+ strokeLinecap="round"
74
+ strokeLinejoin="round"
75
+ >
76
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
77
+ <circle cx="8.5" cy="8.5" r="1.5" />
78
+ <polyline points="21 15 16 10 5 21" />
79
+ </svg>
80
+ );
81
+
82
+ const TrashIcon = () => (
83
+ <svg
84
+ xmlns="http://www.w3.org/2000/svg"
85
+ width="14"
86
+ height="14"
87
+ viewBox="0 0 24 24"
88
+ fill="none"
89
+ stroke="currentColor"
90
+ strokeWidth="2"
91
+ strokeLinecap="round"
92
+ strokeLinejoin="round"
93
+ >
94
+ <polyline points="3 6 5 6 21 6" />
95
+ <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
96
+ </svg>
97
+ );
98
+
99
+ const ArrowsIcon = () => (
100
+ <svg
101
+ xmlns="http://www.w3.org/2000/svg"
102
+ width="14"
103
+ height="14"
104
+ viewBox="0 0 24 24"
105
+ fill="none"
106
+ stroke="currentColor"
107
+ strokeWidth="2"
108
+ strokeLinecap="round"
109
+ strokeLinejoin="round"
110
+ >
111
+ <polyline points="17 1 21 5 17 9" />
112
+ <path d="M3 11V9a4 4 0 0 1 4-4h14" />
113
+ <polyline points="7 23 3 19 7 15" />
114
+ <path d="M21 13v2a4 4 0 0 1-4 4H3" />
115
+ </svg>
116
+ );
117
+
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ type MenuStoryArgs = Record<string, any>;
120
+
121
+ const meta: Meta = {
122
+ title: "UI-Kit/Menu",
7
123
  component: Menu,
8
124
  tags: ["autodocs"],
125
+ argTypes: {
126
+ trigger: {
127
+ control: "select",
128
+ options: ["click", "hover", "click-hover"],
129
+ description:
130
+ "Determines how the menu is triggered: click (default), hover, or both.",
131
+ },
132
+ position: {
133
+ control: "select",
134
+ options: [
135
+ "bottom",
136
+ "bottom-start",
137
+ "bottom-end",
138
+ "top",
139
+ "top-start",
140
+ "top-end",
141
+ "left",
142
+ "left-start",
143
+ "left-end",
144
+ "right",
145
+ "right-start",
146
+ "right-end",
147
+ ],
148
+ description: "The position of the dropdown relative to the target.",
149
+ },
150
+ withArrow: {
151
+ control: "boolean",
152
+ description: "Whether to display an arrow pointing to the target.",
153
+ },
154
+ offset: {
155
+ control: "number",
156
+ description:
157
+ "Distance in px between the dropdown and the target element.",
158
+ },
159
+ opened: {
160
+ control: "boolean",
161
+ description:
162
+ "Controlled open state. Leave undefined for uncontrolled behavior.",
163
+ },
164
+ },
165
+ parameters: {
166
+ docs: {
167
+ description: {
168
+ component: `
169
+ The \`Menu\` component combines a list of secondary actions into a single interactive overlay area, wrapping Mantine's composable \`Menu\` while enforcing strict Recursica design token styling.
170
+
171
+ ### Composable API
172
+
173
+ Menu uses a dot-notation composition pattern:
174
+ - \`<Menu>\` — Root container managing open/close state
175
+ - \`<Menu.Target>\` — Wrapper for the trigger element (must be a single element supporting ref)
176
+ - \`<Menu.Dropdown>\` — The popup panel
177
+ - \`<Menu.Item>\` — An actionable item with optional \`leftSection\` / \`rightSection\`
178
+ - \`<Menu.Divider>\` — A visual separator
179
+ - \`<Menu.Label>\` — A non-interactive section header
180
+
181
+ ### Sub-menus
182
+ Nested menus are supported via \`<Menu.Sub>\`, \`<Menu.Sub.Target>\`, \`<Menu.Sub.Item>\`, and \`<Menu.Sub.Dropdown>\`.
183
+
184
+ ### Design Token Limitations
185
+ Mantine's \`color\` prop on \`Menu.Item\` is stripped in strict mode to enforce design token adherence. Use \`overStyled={true}\` to bypass this restriction.
186
+ `,
187
+ },
188
+ },
189
+ },
9
190
  };
10
191
 
11
192
  export default meta;
12
193
 
13
- type Story = StoryObj<typeof Menu>;
194
+ type Story = StoryObj<MenuStoryArgs>;
14
195
 
15
196
  export const Default: Story = {
16
- render: () => <ComingSoon componentName="Menu" />,
197
+ args: {
198
+ trigger: "click",
199
+ position: "bottom-start",
200
+ withArrow: false,
201
+ offset: 5,
202
+ opened: undefined,
203
+ },
204
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
205
+ render: ({ withLayer, layer, ...args }: MenuStoryArgs) => {
206
+ return (
207
+ <Menu {...args}>
208
+ <Menu.Target>
209
+ <Button variant="solid">Toggle Menu</Button>
210
+ </Menu.Target>
211
+
212
+ <Menu.Dropdown>
213
+ <Menu.Label>Application</Menu.Label>
214
+ <Menu.Item leftSection={<SettingsIcon />}>Settings</Menu.Item>
215
+ <Menu.Item leftSection={<MessageIcon />}>Messages</Menu.Item>
216
+ <Menu.Item leftSection={<ImageIcon />}>Gallery</Menu.Item>
217
+ <Menu.Item leftSection={<SearchIcon />}>Search</Menu.Item>
218
+
219
+ <Menu.Divider />
220
+
221
+ <Menu.Label>Danger zone</Menu.Label>
222
+ <Menu.Item leftSection={<ArrowsIcon />}>Transfer my data</Menu.Item>
223
+ <Menu.Item leftSection={<TrashIcon />}>Delete my account</Menu.Item>
224
+ </Menu.Dropdown>
225
+ </Menu>
226
+ );
227
+ },
228
+ };
229
+
230
+ export const WithDisabledItems: Story = {
231
+ args: {
232
+ position: "bottom-start",
233
+ },
234
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
235
+ render: ({ withLayer, layer, ...args }: MenuStoryArgs) => {
236
+ return (
237
+ <Menu {...args}>
238
+ <Menu.Target>
239
+ <Button variant="solid">Menu with Disabled</Button>
240
+ </Menu.Target>
241
+
242
+ <Menu.Dropdown>
243
+ <Menu.Item leftSection={<SettingsIcon />}>Settings</Menu.Item>
244
+ <Menu.Item leftSection={<SearchIcon />} disabled>
245
+ Search (disabled)
246
+ </Menu.Item>
247
+ <Menu.Item leftSection={<MessageIcon />}>Messages</Menu.Item>
248
+ <Menu.Item leftSection={<TrashIcon />} disabled>
249
+ Delete (disabled)
250
+ </Menu.Item>
251
+ </Menu.Dropdown>
252
+ </Menu>
253
+ );
254
+ },
255
+ };
256
+
257
+ export const WithSubmenus: Story = {
258
+ args: {
259
+ position: "bottom-start",
260
+ width: 200,
261
+ },
262
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
263
+ render: ({ withLayer, layer, ...args }: MenuStoryArgs) => {
264
+ return (
265
+ <Menu {...args}>
266
+ <Menu.Target>
267
+ <Button variant="solid">Menu with Submenus</Button>
268
+ </Menu.Target>
269
+
270
+ <Menu.Dropdown>
271
+ <Menu.Item>Dashboard</Menu.Item>
272
+ <Menu.Sub>
273
+ <Menu.Sub.Target>
274
+ <Menu.Sub.Item>Products</Menu.Sub.Item>
275
+ </Menu.Sub.Target>
276
+ <Menu.Sub.Dropdown>
277
+ <Menu.Item>All products</Menu.Item>
278
+ <Menu.Item>Categories</Menu.Item>
279
+ <Menu.Item>Tags</Menu.Item>
280
+ </Menu.Sub.Dropdown>
281
+ </Menu.Sub>
282
+ <Menu.Sub>
283
+ <Menu.Sub.Target>
284
+ <Menu.Sub.Item>Orders</Menu.Sub.Item>
285
+ </Menu.Sub.Target>
286
+ <Menu.Sub.Dropdown>
287
+ <Menu.Item>Open</Menu.Item>
288
+ <Menu.Item>Completed</Menu.Item>
289
+ <Menu.Item>Cancelled</Menu.Item>
290
+ </Menu.Sub.Dropdown>
291
+ </Menu.Sub>
292
+ </Menu.Dropdown>
293
+ </Menu>
294
+ );
295
+ },
296
+ };
297
+
298
+ export const HoverTrigger: Story = {
299
+ args: {
300
+ trigger: "click-hover",
301
+ position: "bottom-start",
302
+ openDelay: 100,
303
+ closeDelay: 400,
304
+ },
305
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
306
+ render: ({ withLayer, layer, ...args }: MenuStoryArgs) => {
307
+ return (
308
+ <Menu {...args}>
309
+ <Menu.Target>
310
+ <Button variant="solid">Hover or Click</Button>
311
+ </Menu.Target>
312
+
313
+ <Menu.Dropdown>
314
+ <Menu.Item leftSection={<SettingsIcon />}>Settings</Menu.Item>
315
+ <Menu.Item leftSection={<MessageIcon />}>Messages</Menu.Item>
316
+ <Menu.Item leftSection={<ImageIcon />}>Gallery</Menu.Item>
317
+ </Menu.Dropdown>
318
+ </Menu>
319
+ );
320
+ },
17
321
  };