@bug-on/m3-expressive 1.3.1 → 1.3.2

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 (51) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +88 -60
  3. package/dist/buttons.d.mts +3 -3
  4. package/dist/buttons.d.ts +3 -3
  5. package/dist/{core-CAU8g2HY.d.mts → core-D8FdHY6I.d.mts} +1 -1
  6. package/dist/{core-DRrLnsnJ.d.ts → core-DyEy8H9Z.d.ts} +1 -1
  7. package/dist/core.d.mts +2 -2
  8. package/dist/core.d.ts +2 -2
  9. package/dist/feedback.js +1 -1
  10. package/dist/feedback.js.map +1 -1
  11. package/dist/feedback.mjs +1 -1
  12. package/dist/feedback.mjs.map +1 -1
  13. package/dist/forms.d.mts +4 -3
  14. package/dist/forms.d.ts +4 -3
  15. package/dist/forms.js +5084 -2987
  16. package/dist/forms.js.map +1 -1
  17. package/dist/forms.mjs +5083 -2989
  18. package/dist/forms.mjs.map +1 -1
  19. package/dist/{icon-button-USJo7AqO.d.mts → icon-button-CxyJv7UV.d.mts} +1 -1
  20. package/dist/{icon-button-CqdQBsRe.d.ts → icon-button-Di8VX6ou.d.ts} +1 -1
  21. package/dist/index.d.mts +12 -82
  22. package/dist/index.d.ts +12 -82
  23. package/dist/index.js +2635 -1119
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +2483 -979
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/layout.d.mts +481 -33
  28. package/dist/layout.d.ts +481 -33
  29. package/dist/layout.js +1499 -220
  30. package/dist/layout.js.map +1 -1
  31. package/dist/layout.mjs +1471 -208
  32. package/dist/layout.mjs.map +1 -1
  33. package/dist/{md3-D0_Z7IXj.d.mts → md3-BQhRygSi.d.mts} +1 -1
  34. package/dist/{md3-D0_Z7IXj.d.ts → md3-BQhRygSi.d.ts} +1 -1
  35. package/dist/menu-types-rZNQFO7Y.d.mts +315 -0
  36. package/dist/menu-types-rZNQFO7Y.d.ts +315 -0
  37. package/dist/navigation.d.mts +5 -289
  38. package/dist/navigation.d.ts +5 -289
  39. package/dist/navigation.js +423 -250
  40. package/dist/navigation.js.map +1 -1
  41. package/dist/navigation.mjs +415 -243
  42. package/dist/navigation.mjs.map +1 -1
  43. package/dist/overlays.d.mts +2 -2
  44. package/dist/overlays.d.ts +2 -2
  45. package/dist/{side-sheet-modal-Dgjt739k.d.mts → side-sheet-modal-64FGhDxL.d.mts} +1 -1
  46. package/dist/{side-sheet-modal-DdEZR6Vl.d.ts → side-sheet-modal-Bd5Qqvp9.d.ts} +1 -1
  47. package/dist/{split-button-trailing-uncheckable-DTQJjzsB.d.ts → split-button-trailing-uncheckable-CGzk7KcG.d.ts} +1 -1
  48. package/dist/{split-button-trailing-uncheckable-CIVEYgjY.d.mts → split-button-trailing-uncheckable-gAz6OAIi.d.mts} +1 -1
  49. package/dist/{text-field-Ear3hCSq.d.mts → text-field-4OlT9o8s.d.mts} +155 -5
  50. package/dist/{text-field-CiOmDM_8.d.ts → text-field-DARNdj14.d.ts} +155 -5
  51. package/package.json +3 -3
@@ -28,4 +28,4 @@ type PolymorphicProps<C extends ElementType, Props = object> = Props & Omit<Comp
28
28
  children?: ReactNode;
29
29
  };
30
30
 
31
- export type { MD3SlotWidth as M, PolymorphicProps as P, MD3ColorStyle as a, MD3Shape as b, MD3Size as c, PolymorphicRef as d };
31
+ export type { MD3ColorStyle as M, PolymorphicProps as P, MD3Shape as a, MD3Size as b, PolymorphicRef as c, MD3SlotWidth as d };
@@ -28,4 +28,4 @@ type PolymorphicProps<C extends ElementType, Props = object> = Props & Omit<Comp
28
28
  children?: ReactNode;
29
29
  };
30
30
 
31
- export type { MD3SlotWidth as M, PolymorphicProps as P, MD3ColorStyle as a, MD3Shape as b, MD3Size as c, PolymorphicRef as d };
31
+ export type { MD3ColorStyle as M, PolymorphicProps as P, MD3Shape as a, MD3Size as b, PolymorphicRef as c, MD3SlotWidth as d };
@@ -0,0 +1,315 @@
1
+ import * as React from 'react';
2
+
3
+ /** Color variant of the menu — standard (surface-based) or vibrant (tertiary-based). */
4
+ type MenuColorVariant = "standard" | "vibrant";
5
+ /** Visual variant of the menu. */
6
+ type MenuVariant = "baseline" | "expressive";
7
+ /** Layout density for menu items: 0 (default: 48dp), -2 (40dp), -4 (32dp). */
8
+ type MenuDensity = 0 | -2 | -4;
9
+ /**
10
+ * Which Radix primitive family drives this menu:
11
+ * - `dropdown` → @radix-ui/react-dropdown-menu (button, text field, icon trigger)
12
+ * - `context` → @radix-ui/react-context-menu (right-click / long-press trigger)
13
+ * - `static` → plain HTML via Slot (VerticalMenu — always-visible)
14
+ */
15
+ type MenuPrimitive = "dropdown" | "context" | "static";
16
+ /**
17
+ * Position of a MenuItem within its group or menu.
18
+ * Controls the shape morphing (border-radius) applied to each item.
19
+ *
20
+ * - `leading` → first item: top corners rounded more (CornerMedium top, CornerExtraSmall bottom)
21
+ * - `middle` → middle items: CornerExtraSmall all corners
22
+ * - `trailing` → last item: bottom corners rounded more (CornerExtraSmall top, CornerMedium bottom)
23
+ * - `standalone` → only item in group: CornerExtraSmall (same as middle, but semantically distinct)
24
+ */
25
+ type MenuItemPosition = "standalone" | "leading" | "middle" | "trailing";
26
+ /**
27
+ * Position of a MenuGroup within the popup container.
28
+ * Controls the container's border-radius shape morphing.
29
+ */
30
+ type MenuGroupPosition = "standalone" | "leading" | "middle" | "trailing";
31
+ interface MenuProps {
32
+ /** Menu items and groups */
33
+ children: React.ReactNode;
34
+ /**
35
+ * Color variant of the menu.
36
+ * Only applies when `variant="expressive"`. Baseline menus always use baseline colors.
37
+ * - `standard`: surface-container-low background
38
+ * - `vibrant`: tertiary-container background (use sparingly, high emphasis)
39
+ */
40
+ colorVariant?: MenuColorVariant;
41
+ /**
42
+ * Layout density of menu items: 0 (48dp), -2 (40dp), -4 (32dp).
43
+ * @default 0
44
+ */
45
+ density?: MenuDensity;
46
+ /**
47
+ * Visual variant of the menu.
48
+ * - `baseline`: original M3 specs (4dp corners, no shape morphing)
49
+ * - `expressive`: M3 Expressive specs (shape morphing, rounded groups)
50
+ * @default "baseline"
51
+ */
52
+ variant?: MenuVariant;
53
+ /**
54
+ * @deprecated Use `variant` instead. Will be removed in next major version.
55
+ */
56
+ menuVariant?: MenuVariant;
57
+ /**
58
+ * Controlled open state. When provided, the menu acts as a controlled component.
59
+ * Pair with `onOpenChange` to manage state externally.
60
+ */
61
+ open?: boolean;
62
+ /**
63
+ * Called when the menu's open state changes (both controlled and uncontrolled).
64
+ * Required when using `open` for controlled mode.
65
+ */
66
+ onOpenChange?: (open: boolean) => void;
67
+ /** Additional className for the root element */
68
+ className?: string;
69
+ }
70
+ interface MenuTriggerProps {
71
+ children: React.ReactNode;
72
+ /** If true, merges props with the child element instead of wrapping */
73
+ asChild?: boolean;
74
+ className?: string;
75
+ }
76
+ interface MenuContentProps {
77
+ children: React.ReactNode;
78
+ /** Gap between menu and anchor in pixels. Default: 6 */
79
+ sideOffset?: number;
80
+ /** Preferred side of the anchor to render the menu. */
81
+ side?: "top" | "bottom" | "left" | "right";
82
+ /** Preferred alignment relative to the anchor. */
83
+ align?: "start" | "center" | "end";
84
+ /**
85
+ * When true, disables overflow-hidden on the container so nested SubMenus
86
+ * can escape the bounds. Required when using SubMenu.
87
+ */
88
+ hasOverflow?: boolean;
89
+ /** Override colorVariant from MenuContext (only for expressive variant) */
90
+ colorVariant?: MenuColorVariant;
91
+ /**
92
+ * Separation style between groups (only applies when variant="expressive").
93
+ * - `gap` → 2dp visual gap, transparent container
94
+ * - `divider` → solid container, no gap
95
+ * Default: "gap"
96
+ */
97
+ separatorStyle?: VerticalMenuSeparatorStyle;
98
+ /**
99
+ * When true, automatically sets the menu popover width to match the trigger width
100
+ * using Radix CSS variable `--radix-dropdown-menu-trigger-width`.
101
+ */
102
+ matchTriggerWidth?: boolean;
103
+ /**
104
+ * Maximum height of the scrollable content area inside the menu.
105
+ * When content exceeds this height, a ScrollArea scrollbar is activated.
106
+ * Set to undefined to disable.
107
+ * @default "360px"
108
+ */
109
+ maxHeight?: string;
110
+ /**
111
+ * Ref attached to the inner scrolling viewport element (ScrollArea.Viewport).
112
+ * Useful for virtualization hooks (e.g. passing as root for IntersectionObserver).
113
+ */
114
+ viewportRef?: React.Ref<HTMLDivElement>;
115
+ /**
116
+ * Callback providing the inner scrolling viewport element when mounted.
117
+ */
118
+ onViewportRef?: (node: HTMLDivElement | null) => void;
119
+ className?: string;
120
+ }
121
+ interface MenuItemProps {
122
+ /** Primary label text of the item */
123
+ children: React.ReactNode;
124
+ /** Callback when the item is clicked */
125
+ onClick?: React.MouseEventHandler<HTMLDivElement>;
126
+ /**
127
+ * Optional leading icon (20dp).
128
+ * For unselected state in selectable items; replaced by check icon when selected.
129
+ */
130
+ leadingIcon?: React.ReactNode;
131
+ /** Optional trailing icon (20dp) or chevron for submenus */
132
+ trailingIcon?: React.ReactNode;
133
+ /** Supporting text below the primary label (body-medium) */
134
+ supportingText?: React.ReactNode;
135
+ /** Trailing keyboard shortcut text e.g. "Ctrl+C", "⌘C" */
136
+ trailingText?: string;
137
+ /**
138
+ * Whether this item is selected/checked.
139
+ * When true: shows check icon (leading slot) and applies selected container color.
140
+ * Overrides itemPosition shape with `rounded-m3-md`.
141
+ */
142
+ selected?: boolean;
143
+ /** Whether this item is disabled */
144
+ disabled?: boolean;
145
+ /**
146
+ * Controls shape morphing based on position within its group.
147
+ * Automatically injected by MenuGroup via React.cloneElement when grouping is used.
148
+ */
149
+ itemPosition?: MenuItemPosition;
150
+ /** Override colorVariant from MenuContext */
151
+ colorVariant?: MenuColorVariant;
152
+ /** Layout density of this menu item: 0 (48dp), -2 (40dp), -4 (32dp). */
153
+ density?: MenuDensity;
154
+ /** If true, keeps the menu open after clicking (e.g. for multi-select items) */
155
+ keepOpen?: boolean;
156
+ className?: string;
157
+ /** Optional value for radio items. Required when role='menuitemradio'. */
158
+ value?: string;
159
+ /** Internal flag used by SubMenu to render this item as a SubTrigger primitive. */
160
+ isSubTrigger?: boolean;
161
+ /** ARIA role override. Defaults to 'menuitem', 'menuitemcheckbox', or 'menuitemradio' based on selected prop. */
162
+ role?: string;
163
+ /** Internal flag: true if rendered inside a gap-variant expressive menu */
164
+ isGapVariant?: boolean;
165
+ }
166
+ interface MenuGroupProps {
167
+ /** MenuItem children — itemPosition is auto-injected */
168
+ children: React.ReactNode;
169
+ /**
170
+ * Optional label displayed at the top of the group.
171
+ * Uses labelLarge typography with 12dp horizontal padding.
172
+ */
173
+ label?: string;
174
+ /**
175
+ * Zero-based index of this group in the parent menu.
176
+ * Used to determine shape (leading/middle/trailing/standalone).
177
+ * Auto-provided when using MenuContent's grouping utilities.
178
+ */
179
+ index?: number;
180
+ /**
181
+ * Total number of groups in the parent menu.
182
+ * Used together with index to determine shape.
183
+ */
184
+ count?: number;
185
+ /** Override colorVariant from MenuContext */
186
+ colorVariant?: MenuColorVariant;
187
+ /** Internal flag: true if rendered inside a gap-variant vertical menu (to adjust padding) */
188
+ isGapVariant?: boolean;
189
+ /** Optionally injected when nested inside another MenuGroup */
190
+ itemPosition?: MenuItemPosition;
191
+ className?: string;
192
+ }
193
+ interface MenuDividerProps {
194
+ className?: string;
195
+ isGapVariant?: boolean;
196
+ }
197
+ interface SubMenuProps {
198
+ /** The SubMenu children (another MenuContent) */
199
+ children: React.ReactNode;
200
+ /** The trigger element (typically a MenuItem with trailing chevron) */
201
+ trigger: React.ReactNode;
202
+ /** Preferred side to open the submenu. Default: 'right' */
203
+ side?: "left" | "right";
204
+ /** Override colorVariant from MenuContext */
205
+ colorVariant?: MenuColorVariant;
206
+ /** Delay in ms before submenu opens on hover. Default: 200 */
207
+ hoverOpenDelay?: number;
208
+ /** Delay in ms before submenu closes on pointer-leave. Default: 300 */
209
+ hoverCloseDelay?: number;
210
+ }
211
+ /**
212
+ * How groups within a VerticalMenuContent are separated.
213
+ * - `gap` → 2dp gap between groups (SegmentedMenuTokens.SegmentedGap)
214
+ * - `divider` → outline-variant horizontal rule between groups (MenuDefaults.HorizontalDividerPadding)
215
+ * - `none` → solid container without dividers between groups/items
216
+ */
217
+ type VerticalMenuSeparatorStyle = "gap" | "divider" | "none";
218
+ /**
219
+ * Root of an always-visible vertical menu (no trigger, no popup).
220
+ * Provides `MenuContext` with `colorVariant` to all descendants.
221
+ */
222
+ interface VerticalMenuProps {
223
+ children: React.ReactNode;
224
+ /**
225
+ * Color variant of the menu.
226
+ * - `standard`: surface-container-low background (default)
227
+ * - `vibrant`: tertiary-container background
228
+ */
229
+ colorVariant?: MenuColorVariant;
230
+ className?: string;
231
+ }
232
+ /**
233
+ * Container that renders VerticalMenuGroup children in a vertical list.
234
+ * Handles separator injection (gap or divider) and auto-injects `index`/`count` into groups.
235
+ */
236
+ interface VerticalMenuContentProps {
237
+ children: React.ReactNode;
238
+ /**
239
+ * Separation style between groups.
240
+ * - `gap` → 2dp visual gap (default, matches MD3 Expressive spec image 1 left)
241
+ * - `divider` → horizontal `outline-variant` rule (matches MD3 Expressive spec image 1 right)
242
+ */
243
+ separatorStyle?: VerticalMenuSeparatorStyle;
244
+ /** Override colorVariant from VerticalMenu root */
245
+ colorVariant?: MenuColorVariant;
246
+ className?: string;
247
+ }
248
+ /** A group within a VerticalMenu. Alias of MenuGroupProps. */
249
+ interface VerticalMenuGroupProps extends MenuGroupProps {
250
+ }
251
+ /** A plain horizontal divider for use between groups in a VerticalMenuContent with `separatorStyle="divider"`. */
252
+ interface VerticalMenuDividerProps {
253
+ className?: string;
254
+ /** Optionally injected by VerticalMenuContent */
255
+ index?: number;
256
+ /** Optionally injected by VerticalMenuContent */
257
+ count?: number;
258
+ /** Optionally injected by VerticalMenuContent */
259
+ isGapVariant?: boolean;
260
+ }
261
+ /**
262
+ * Root of a context menu (right-click / long-press triggered popup).
263
+ *
264
+ * Wraps @radix-ui/react-context-menu Root and provides MenuContext with
265
+ * `menuPrimitive="context"` so MenuItem automatically uses ContextMenu primitives.
266
+ */
267
+ interface ContextMenuProps {
268
+ children: React.ReactNode;
269
+ /**
270
+ * Visual variant of the context menu.
271
+ * - `baseline`: original M3 specs (4dp corners, no shape morphing)
272
+ * - `expressive`: M3 Expressive specs (shape morphing, rounded groups)
273
+ * @default "baseline"
274
+ */
275
+ variant?: MenuVariant;
276
+ /** Color variant. Only applies when `variant="expressive"`. */
277
+ colorVariant?: MenuColorVariant;
278
+ /** Additional className */
279
+ className?: string;
280
+ }
281
+ interface ContextMenuTriggerProps {
282
+ children: React.ReactNode;
283
+ /** If true, merges props with the child element instead of wrapping */
284
+ asChild?: boolean;
285
+ className?: string;
286
+ }
287
+ interface ContextMenuContentProps {
288
+ children: React.ReactNode;
289
+ /** Override colorVariant from ContextMenuContext */
290
+ colorVariant?: MenuColorVariant;
291
+ /**
292
+ * When true, disables overflow-hidden so nested SubMenus can escape bounds.
293
+ * Required when using SubMenu inside ContextMenu.
294
+ */
295
+ hasOverflow?: boolean;
296
+ /**
297
+ * Separation style between groups (only applies when variant="expressive").
298
+ * - `gap` → 2dp visual gap, transparent container
299
+ * - `divider` → solid container, no gap
300
+ * Default: "gap"
301
+ */
302
+ separatorStyle?: VerticalMenuSeparatorStyle;
303
+ /**
304
+ * Maximum height of the scrollable content area inside the context menu.
305
+ * @default "360px"
306
+ */
307
+ maxHeight?: string;
308
+ /** Ref attached to the inner scrolling viewport element. */
309
+ viewportRef?: React.Ref<HTMLDivElement>;
310
+ /** Callback providing the inner scrolling viewport element when mounted. */
311
+ onViewportRef?: (node: HTMLDivElement | null) => void;
312
+ className?: string;
313
+ }
314
+
315
+ export type { ContextMenuContentProps as C, MenuColorVariant as M, SubMenuProps as S, VerticalMenuContentProps as V, ContextMenuProps as a, ContextMenuTriggerProps as b, MenuContentProps as c, MenuDividerProps as d, MenuGroupPosition as e, MenuGroupProps as f, MenuItemPosition as g, MenuItemProps as h, MenuPrimitive as i, MenuProps as j, MenuTriggerProps as k, MenuVariant as l, VerticalMenuDividerProps as m, VerticalMenuGroupProps as n, VerticalMenuProps as o, VerticalMenuSeparatorStyle as p, MenuDensity as q };
@@ -0,0 +1,315 @@
1
+ import * as React from 'react';
2
+
3
+ /** Color variant of the menu — standard (surface-based) or vibrant (tertiary-based). */
4
+ type MenuColorVariant = "standard" | "vibrant";
5
+ /** Visual variant of the menu. */
6
+ type MenuVariant = "baseline" | "expressive";
7
+ /** Layout density for menu items: 0 (default: 48dp), -2 (40dp), -4 (32dp). */
8
+ type MenuDensity = 0 | -2 | -4;
9
+ /**
10
+ * Which Radix primitive family drives this menu:
11
+ * - `dropdown` → @radix-ui/react-dropdown-menu (button, text field, icon trigger)
12
+ * - `context` → @radix-ui/react-context-menu (right-click / long-press trigger)
13
+ * - `static` → plain HTML via Slot (VerticalMenu — always-visible)
14
+ */
15
+ type MenuPrimitive = "dropdown" | "context" | "static";
16
+ /**
17
+ * Position of a MenuItem within its group or menu.
18
+ * Controls the shape morphing (border-radius) applied to each item.
19
+ *
20
+ * - `leading` → first item: top corners rounded more (CornerMedium top, CornerExtraSmall bottom)
21
+ * - `middle` → middle items: CornerExtraSmall all corners
22
+ * - `trailing` → last item: bottom corners rounded more (CornerExtraSmall top, CornerMedium bottom)
23
+ * - `standalone` → only item in group: CornerExtraSmall (same as middle, but semantically distinct)
24
+ */
25
+ type MenuItemPosition = "standalone" | "leading" | "middle" | "trailing";
26
+ /**
27
+ * Position of a MenuGroup within the popup container.
28
+ * Controls the container's border-radius shape morphing.
29
+ */
30
+ type MenuGroupPosition = "standalone" | "leading" | "middle" | "trailing";
31
+ interface MenuProps {
32
+ /** Menu items and groups */
33
+ children: React.ReactNode;
34
+ /**
35
+ * Color variant of the menu.
36
+ * Only applies when `variant="expressive"`. Baseline menus always use baseline colors.
37
+ * - `standard`: surface-container-low background
38
+ * - `vibrant`: tertiary-container background (use sparingly, high emphasis)
39
+ */
40
+ colorVariant?: MenuColorVariant;
41
+ /**
42
+ * Layout density of menu items: 0 (48dp), -2 (40dp), -4 (32dp).
43
+ * @default 0
44
+ */
45
+ density?: MenuDensity;
46
+ /**
47
+ * Visual variant of the menu.
48
+ * - `baseline`: original M3 specs (4dp corners, no shape morphing)
49
+ * - `expressive`: M3 Expressive specs (shape morphing, rounded groups)
50
+ * @default "baseline"
51
+ */
52
+ variant?: MenuVariant;
53
+ /**
54
+ * @deprecated Use `variant` instead. Will be removed in next major version.
55
+ */
56
+ menuVariant?: MenuVariant;
57
+ /**
58
+ * Controlled open state. When provided, the menu acts as a controlled component.
59
+ * Pair with `onOpenChange` to manage state externally.
60
+ */
61
+ open?: boolean;
62
+ /**
63
+ * Called when the menu's open state changes (both controlled and uncontrolled).
64
+ * Required when using `open` for controlled mode.
65
+ */
66
+ onOpenChange?: (open: boolean) => void;
67
+ /** Additional className for the root element */
68
+ className?: string;
69
+ }
70
+ interface MenuTriggerProps {
71
+ children: React.ReactNode;
72
+ /** If true, merges props with the child element instead of wrapping */
73
+ asChild?: boolean;
74
+ className?: string;
75
+ }
76
+ interface MenuContentProps {
77
+ children: React.ReactNode;
78
+ /** Gap between menu and anchor in pixels. Default: 6 */
79
+ sideOffset?: number;
80
+ /** Preferred side of the anchor to render the menu. */
81
+ side?: "top" | "bottom" | "left" | "right";
82
+ /** Preferred alignment relative to the anchor. */
83
+ align?: "start" | "center" | "end";
84
+ /**
85
+ * When true, disables overflow-hidden on the container so nested SubMenus
86
+ * can escape the bounds. Required when using SubMenu.
87
+ */
88
+ hasOverflow?: boolean;
89
+ /** Override colorVariant from MenuContext (only for expressive variant) */
90
+ colorVariant?: MenuColorVariant;
91
+ /**
92
+ * Separation style between groups (only applies when variant="expressive").
93
+ * - `gap` → 2dp visual gap, transparent container
94
+ * - `divider` → solid container, no gap
95
+ * Default: "gap"
96
+ */
97
+ separatorStyle?: VerticalMenuSeparatorStyle;
98
+ /**
99
+ * When true, automatically sets the menu popover width to match the trigger width
100
+ * using Radix CSS variable `--radix-dropdown-menu-trigger-width`.
101
+ */
102
+ matchTriggerWidth?: boolean;
103
+ /**
104
+ * Maximum height of the scrollable content area inside the menu.
105
+ * When content exceeds this height, a ScrollArea scrollbar is activated.
106
+ * Set to undefined to disable.
107
+ * @default "360px"
108
+ */
109
+ maxHeight?: string;
110
+ /**
111
+ * Ref attached to the inner scrolling viewport element (ScrollArea.Viewport).
112
+ * Useful for virtualization hooks (e.g. passing as root for IntersectionObserver).
113
+ */
114
+ viewportRef?: React.Ref<HTMLDivElement>;
115
+ /**
116
+ * Callback providing the inner scrolling viewport element when mounted.
117
+ */
118
+ onViewportRef?: (node: HTMLDivElement | null) => void;
119
+ className?: string;
120
+ }
121
+ interface MenuItemProps {
122
+ /** Primary label text of the item */
123
+ children: React.ReactNode;
124
+ /** Callback when the item is clicked */
125
+ onClick?: React.MouseEventHandler<HTMLDivElement>;
126
+ /**
127
+ * Optional leading icon (20dp).
128
+ * For unselected state in selectable items; replaced by check icon when selected.
129
+ */
130
+ leadingIcon?: React.ReactNode;
131
+ /** Optional trailing icon (20dp) or chevron for submenus */
132
+ trailingIcon?: React.ReactNode;
133
+ /** Supporting text below the primary label (body-medium) */
134
+ supportingText?: React.ReactNode;
135
+ /** Trailing keyboard shortcut text e.g. "Ctrl+C", "⌘C" */
136
+ trailingText?: string;
137
+ /**
138
+ * Whether this item is selected/checked.
139
+ * When true: shows check icon (leading slot) and applies selected container color.
140
+ * Overrides itemPosition shape with `rounded-m3-md`.
141
+ */
142
+ selected?: boolean;
143
+ /** Whether this item is disabled */
144
+ disabled?: boolean;
145
+ /**
146
+ * Controls shape morphing based on position within its group.
147
+ * Automatically injected by MenuGroup via React.cloneElement when grouping is used.
148
+ */
149
+ itemPosition?: MenuItemPosition;
150
+ /** Override colorVariant from MenuContext */
151
+ colorVariant?: MenuColorVariant;
152
+ /** Layout density of this menu item: 0 (48dp), -2 (40dp), -4 (32dp). */
153
+ density?: MenuDensity;
154
+ /** If true, keeps the menu open after clicking (e.g. for multi-select items) */
155
+ keepOpen?: boolean;
156
+ className?: string;
157
+ /** Optional value for radio items. Required when role='menuitemradio'. */
158
+ value?: string;
159
+ /** Internal flag used by SubMenu to render this item as a SubTrigger primitive. */
160
+ isSubTrigger?: boolean;
161
+ /** ARIA role override. Defaults to 'menuitem', 'menuitemcheckbox', or 'menuitemradio' based on selected prop. */
162
+ role?: string;
163
+ /** Internal flag: true if rendered inside a gap-variant expressive menu */
164
+ isGapVariant?: boolean;
165
+ }
166
+ interface MenuGroupProps {
167
+ /** MenuItem children — itemPosition is auto-injected */
168
+ children: React.ReactNode;
169
+ /**
170
+ * Optional label displayed at the top of the group.
171
+ * Uses labelLarge typography with 12dp horizontal padding.
172
+ */
173
+ label?: string;
174
+ /**
175
+ * Zero-based index of this group in the parent menu.
176
+ * Used to determine shape (leading/middle/trailing/standalone).
177
+ * Auto-provided when using MenuContent's grouping utilities.
178
+ */
179
+ index?: number;
180
+ /**
181
+ * Total number of groups in the parent menu.
182
+ * Used together with index to determine shape.
183
+ */
184
+ count?: number;
185
+ /** Override colorVariant from MenuContext */
186
+ colorVariant?: MenuColorVariant;
187
+ /** Internal flag: true if rendered inside a gap-variant vertical menu (to adjust padding) */
188
+ isGapVariant?: boolean;
189
+ /** Optionally injected when nested inside another MenuGroup */
190
+ itemPosition?: MenuItemPosition;
191
+ className?: string;
192
+ }
193
+ interface MenuDividerProps {
194
+ className?: string;
195
+ isGapVariant?: boolean;
196
+ }
197
+ interface SubMenuProps {
198
+ /** The SubMenu children (another MenuContent) */
199
+ children: React.ReactNode;
200
+ /** The trigger element (typically a MenuItem with trailing chevron) */
201
+ trigger: React.ReactNode;
202
+ /** Preferred side to open the submenu. Default: 'right' */
203
+ side?: "left" | "right";
204
+ /** Override colorVariant from MenuContext */
205
+ colorVariant?: MenuColorVariant;
206
+ /** Delay in ms before submenu opens on hover. Default: 200 */
207
+ hoverOpenDelay?: number;
208
+ /** Delay in ms before submenu closes on pointer-leave. Default: 300 */
209
+ hoverCloseDelay?: number;
210
+ }
211
+ /**
212
+ * How groups within a VerticalMenuContent are separated.
213
+ * - `gap` → 2dp gap between groups (SegmentedMenuTokens.SegmentedGap)
214
+ * - `divider` → outline-variant horizontal rule between groups (MenuDefaults.HorizontalDividerPadding)
215
+ * - `none` → solid container without dividers between groups/items
216
+ */
217
+ type VerticalMenuSeparatorStyle = "gap" | "divider" | "none";
218
+ /**
219
+ * Root of an always-visible vertical menu (no trigger, no popup).
220
+ * Provides `MenuContext` with `colorVariant` to all descendants.
221
+ */
222
+ interface VerticalMenuProps {
223
+ children: React.ReactNode;
224
+ /**
225
+ * Color variant of the menu.
226
+ * - `standard`: surface-container-low background (default)
227
+ * - `vibrant`: tertiary-container background
228
+ */
229
+ colorVariant?: MenuColorVariant;
230
+ className?: string;
231
+ }
232
+ /**
233
+ * Container that renders VerticalMenuGroup children in a vertical list.
234
+ * Handles separator injection (gap or divider) and auto-injects `index`/`count` into groups.
235
+ */
236
+ interface VerticalMenuContentProps {
237
+ children: React.ReactNode;
238
+ /**
239
+ * Separation style between groups.
240
+ * - `gap` → 2dp visual gap (default, matches MD3 Expressive spec image 1 left)
241
+ * - `divider` → horizontal `outline-variant` rule (matches MD3 Expressive spec image 1 right)
242
+ */
243
+ separatorStyle?: VerticalMenuSeparatorStyle;
244
+ /** Override colorVariant from VerticalMenu root */
245
+ colorVariant?: MenuColorVariant;
246
+ className?: string;
247
+ }
248
+ /** A group within a VerticalMenu. Alias of MenuGroupProps. */
249
+ interface VerticalMenuGroupProps extends MenuGroupProps {
250
+ }
251
+ /** A plain horizontal divider for use between groups in a VerticalMenuContent with `separatorStyle="divider"`. */
252
+ interface VerticalMenuDividerProps {
253
+ className?: string;
254
+ /** Optionally injected by VerticalMenuContent */
255
+ index?: number;
256
+ /** Optionally injected by VerticalMenuContent */
257
+ count?: number;
258
+ /** Optionally injected by VerticalMenuContent */
259
+ isGapVariant?: boolean;
260
+ }
261
+ /**
262
+ * Root of a context menu (right-click / long-press triggered popup).
263
+ *
264
+ * Wraps @radix-ui/react-context-menu Root and provides MenuContext with
265
+ * `menuPrimitive="context"` so MenuItem automatically uses ContextMenu primitives.
266
+ */
267
+ interface ContextMenuProps {
268
+ children: React.ReactNode;
269
+ /**
270
+ * Visual variant of the context menu.
271
+ * - `baseline`: original M3 specs (4dp corners, no shape morphing)
272
+ * - `expressive`: M3 Expressive specs (shape morphing, rounded groups)
273
+ * @default "baseline"
274
+ */
275
+ variant?: MenuVariant;
276
+ /** Color variant. Only applies when `variant="expressive"`. */
277
+ colorVariant?: MenuColorVariant;
278
+ /** Additional className */
279
+ className?: string;
280
+ }
281
+ interface ContextMenuTriggerProps {
282
+ children: React.ReactNode;
283
+ /** If true, merges props with the child element instead of wrapping */
284
+ asChild?: boolean;
285
+ className?: string;
286
+ }
287
+ interface ContextMenuContentProps {
288
+ children: React.ReactNode;
289
+ /** Override colorVariant from ContextMenuContext */
290
+ colorVariant?: MenuColorVariant;
291
+ /**
292
+ * When true, disables overflow-hidden so nested SubMenus can escape bounds.
293
+ * Required when using SubMenu inside ContextMenu.
294
+ */
295
+ hasOverflow?: boolean;
296
+ /**
297
+ * Separation style between groups (only applies when variant="expressive").
298
+ * - `gap` → 2dp visual gap, transparent container
299
+ * - `divider` → solid container, no gap
300
+ * Default: "gap"
301
+ */
302
+ separatorStyle?: VerticalMenuSeparatorStyle;
303
+ /**
304
+ * Maximum height of the scrollable content area inside the context menu.
305
+ * @default "360px"
306
+ */
307
+ maxHeight?: string;
308
+ /** Ref attached to the inner scrolling viewport element. */
309
+ viewportRef?: React.Ref<HTMLDivElement>;
310
+ /** Callback providing the inner scrolling viewport element when mounted. */
311
+ onViewportRef?: (node: HTMLDivElement | null) => void;
312
+ className?: string;
313
+ }
314
+
315
+ export type { ContextMenuContentProps as C, MenuColorVariant as M, SubMenuProps as S, VerticalMenuContentProps as V, ContextMenuProps as a, ContextMenuTriggerProps as b, MenuContentProps as c, MenuDividerProps as d, MenuGroupPosition as e, MenuGroupProps as f, MenuItemPosition as g, MenuItemProps as h, MenuPrimitive as i, MenuProps as j, MenuTriggerProps as k, MenuVariant as l, VerticalMenuDividerProps as m, VerticalMenuGroupProps as n, VerticalMenuProps as o, VerticalMenuSeparatorStyle as p, MenuDensity as q };