@revikornmann/muka-ui 0.17.0 → 0.19.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 (182) hide show
  1. package/README.md +81 -60
  2. package/cli/bin/muka-ui.js +12 -5
  3. package/cli/commands/brand.js +33 -14
  4. package/cli/commands/init.js +21 -17
  5. package/cli/commands/install-skill.js +84 -26
  6. package/cli/templates/AGENTS.md +128 -0
  7. package/cli/templates/CLAUDE.md +8 -88
  8. package/cli/templates/muka-ui-guidelines.md +50 -14
  9. package/dist/cjs/components/ActionSheet/ActionSheet.js +1 -1
  10. package/dist/cjs/components/Breadcrumb/Breadcrumb.css +11 -3
  11. package/dist/cjs/components/Breadcrumb/Breadcrumb.js +19 -1
  12. package/dist/cjs/components/Breadcrumb/Breadcrumb.js.map +1 -1
  13. package/dist/cjs/components/Combobox/Combobox.css +116 -132
  14. package/dist/cjs/components/Combobox/Combobox.js +175 -52
  15. package/dist/cjs/components/Combobox/Combobox.js.map +1 -1
  16. package/dist/cjs/components/Combobox/index.js.map +1 -1
  17. package/dist/cjs/components/ContextSelect/ContextSelect.css +117 -0
  18. package/dist/cjs/components/ContextSelect/ContextSelect.js +49 -0
  19. package/dist/cjs/components/ContextSelect/ContextSelect.js.map +1 -0
  20. package/dist/cjs/components/ContextSelect/index.js +11 -0
  21. package/dist/cjs/components/ContextSelect/index.js.map +1 -0
  22. package/dist/cjs/components/DropdownSelect/DropdownSelect.css +225 -0
  23. package/dist/cjs/components/DropdownSelect/DropdownSelect.js +106 -0
  24. package/dist/cjs/components/DropdownSelect/DropdownSelect.js.map +1 -0
  25. package/dist/cjs/components/DropdownSelect/index.js +6 -0
  26. package/dist/cjs/components/DropdownSelect/index.js.map +1 -0
  27. package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js +11 -0
  28. package/dist/cjs/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
  29. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js +11 -0
  30. package/dist/cjs/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  31. package/dist/cjs/components/Icon/iconRegistry.js +11 -0
  32. package/dist/cjs/components/Icon/iconRegistry.js.map +1 -1
  33. package/dist/cjs/components/Input/Input.css +45 -8
  34. package/dist/cjs/components/Input/Input.js +14 -3
  35. package/dist/cjs/components/Input/Input.js.map +1 -1
  36. package/dist/cjs/components/Menu/Menu.css +213 -17
  37. package/dist/cjs/components/Menu/Menu.js +429 -39
  38. package/dist/cjs/components/Menu/Menu.js.map +1 -1
  39. package/dist/cjs/components/Menu/index.js +5 -1
  40. package/dist/cjs/components/Menu/index.js.map +1 -1
  41. package/dist/cjs/components/ProgressTracker/ProgressTracker.css +273 -22
  42. package/dist/cjs/components/ProgressTracker/ProgressTracker.js +109 -9
  43. package/dist/cjs/components/ProgressTracker/ProgressTracker.js.map +1 -1
  44. package/dist/cjs/components/Scrollbar/Scrollbar.css +124 -0
  45. package/dist/cjs/components/Scrollbar/Scrollbar.js +118 -0
  46. package/dist/cjs/components/Scrollbar/Scrollbar.js.map +1 -0
  47. package/dist/cjs/components/Scrollbar/index.js +11 -0
  48. package/dist/cjs/components/Scrollbar/index.js.map +1 -0
  49. package/dist/cjs/components/index.js +13 -16
  50. package/dist/cjs/components/index.js.map +1 -1
  51. package/dist/esm/components/ActionSheet/ActionSheet.js +1 -1
  52. package/dist/esm/components/Breadcrumb/Breadcrumb.css +11 -3
  53. package/dist/esm/components/Breadcrumb/Breadcrumb.js +19 -1
  54. package/dist/esm/components/Breadcrumb/Breadcrumb.js.map +1 -1
  55. package/dist/esm/components/Combobox/Combobox.css +116 -132
  56. package/dist/esm/components/Combobox/Combobox.js +177 -54
  57. package/dist/esm/components/Combobox/Combobox.js.map +1 -1
  58. package/dist/esm/components/Combobox/index.js +1 -1
  59. package/dist/esm/components/Combobox/index.js.map +1 -1
  60. package/dist/esm/components/ContextSelect/ContextSelect.css +117 -0
  61. package/dist/esm/components/ContextSelect/ContextSelect.js +45 -0
  62. package/dist/esm/components/ContextSelect/ContextSelect.js.map +1 -0
  63. package/dist/esm/components/ContextSelect/index.js +3 -0
  64. package/dist/esm/components/ContextSelect/index.js.map +1 -0
  65. package/dist/esm/components/DropdownSelect/DropdownSelect.css +225 -0
  66. package/dist/esm/components/DropdownSelect/DropdownSelect.js +102 -0
  67. package/dist/esm/components/DropdownSelect/DropdownSelect.js.map +1 -0
  68. package/dist/esm/components/DropdownSelect/index.js +2 -0
  69. package/dist/esm/components/DropdownSelect/index.js.map +1 -0
  70. package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js +7 -0
  71. package/dist/esm/components/Icon/custom/ArrowDropUpDownIcon.js.map +1 -0
  72. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js +7 -0
  73. package/dist/esm/components/Icon/custom/ArrowReturnIcon.js.map +1 -0
  74. package/dist/esm/components/Icon/iconRegistry.js +11 -0
  75. package/dist/esm/components/Icon/iconRegistry.js.map +1 -1
  76. package/dist/esm/components/Input/Input.css +45 -8
  77. package/dist/esm/components/Input/Input.js +14 -3
  78. package/dist/esm/components/Input/Input.js.map +1 -1
  79. package/dist/esm/components/Menu/Menu.css +213 -17
  80. package/dist/esm/components/Menu/Menu.js +428 -40
  81. package/dist/esm/components/Menu/Menu.js.map +1 -1
  82. package/dist/esm/components/Menu/index.js +1 -1
  83. package/dist/esm/components/Menu/index.js.map +1 -1
  84. package/dist/esm/components/ProgressTracker/ProgressTracker.css +273 -22
  85. package/dist/esm/components/ProgressTracker/ProgressTracker.js +110 -10
  86. package/dist/esm/components/ProgressTracker/ProgressTracker.js.map +1 -1
  87. package/dist/esm/components/Scrollbar/Scrollbar.css +124 -0
  88. package/dist/esm/components/Scrollbar/Scrollbar.js +114 -0
  89. package/dist/esm/components/Scrollbar/Scrollbar.js.map +1 -0
  90. package/dist/esm/components/Scrollbar/index.js +3 -0
  91. package/dist/esm/components/Scrollbar/index.js.map +1 -0
  92. package/dist/esm/components/index.js +4 -2
  93. package/dist/esm/components/index.js.map +1 -1
  94. package/dist/styles/components/Breadcrumb.css +11 -3
  95. package/dist/styles/components/Combobox.css +116 -132
  96. package/dist/styles/components/ContextSelect.css +117 -0
  97. package/dist/styles/components/DropdownSelect.css +225 -0
  98. package/dist/styles/components/Input.css +45 -8
  99. package/dist/styles/components/Menu.css +213 -17
  100. package/dist/styles/components/ProgressTracker.css +273 -22
  101. package/dist/styles/components/Scrollbar.css +124 -0
  102. package/dist/styles/components/Typography.css +89 -0
  103. package/dist/styles/index.css +1526 -480
  104. package/dist/styles/muka-dark.css +1526 -480
  105. package/dist/styles/muka-light.css +1526 -480
  106. package/dist/styles/tokens-bouwplan-dark.css +9 -6
  107. package/dist/styles/tokens-bouwplan-light.css +9 -6
  108. package/dist/styles/tokens-fscl-dark.css +29 -26
  109. package/dist/styles/tokens-fscl-light.css +29 -26
  110. package/dist/styles/tokens-grip-dark.css +8 -5
  111. package/dist/styles/tokens-grip-light.css +8 -5
  112. package/dist/styles/tokens-muka-dark.css +8 -5
  113. package/dist/styles/tokens-muka-light.css +8 -5
  114. package/dist/styles/tokens-wireframe-dark.css +53 -50
  115. package/dist/styles/tokens-wireframe-light.css +53 -50
  116. package/dist/styles/wireframe-dark.css +1571 -525
  117. package/dist/styles/wireframe-light.css +1571 -525
  118. package/dist/types/components/ActionSheet/ActionSheet.d.ts +1 -1
  119. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts +27 -3
  120. package/dist/types/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  121. package/dist/types/components/Combobox/Combobox.d.ts +38 -38
  122. package/dist/types/components/Combobox/Combobox.d.ts.map +1 -1
  123. package/dist/types/components/Combobox/index.d.ts +1 -1
  124. package/dist/types/components/Combobox/index.d.ts.map +1 -1
  125. package/dist/types/components/ContextSelect/ContextSelect.d.ts +62 -0
  126. package/dist/types/components/ContextSelect/ContextSelect.d.ts.map +1 -0
  127. package/dist/types/components/ContextSelect/index.d.ts +3 -0
  128. package/dist/types/components/ContextSelect/index.d.ts.map +1 -0
  129. package/dist/types/components/DataTable/DataTable.d.ts +1 -1
  130. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts +71 -0
  131. package/dist/types/components/DropdownSelect/DropdownSelect.d.ts.map +1 -0
  132. package/dist/types/components/DropdownSelect/index.d.ts +2 -0
  133. package/dist/types/components/DropdownSelect/index.d.ts.map +1 -0
  134. package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts +9 -0
  135. package/dist/types/components/Icon/custom/ArrowDropUpDownIcon.d.ts.map +1 -0
  136. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts +9 -0
  137. package/dist/types/components/Icon/custom/ArrowReturnIcon.d.ts.map +1 -0
  138. package/dist/types/components/Icon/iconRegistry.d.ts.map +1 -1
  139. package/dist/types/components/Input/Input.d.ts +5 -0
  140. package/dist/types/components/Input/Input.d.ts.map +1 -1
  141. package/dist/types/components/Menu/Menu.d.ts +99 -29
  142. package/dist/types/components/Menu/Menu.d.ts.map +1 -1
  143. package/dist/types/components/Menu/index.d.ts +2 -2
  144. package/dist/types/components/Menu/index.d.ts.map +1 -1
  145. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts +29 -8
  146. package/dist/types/components/ProgressTracker/ProgressTracker.d.ts.map +1 -1
  147. package/dist/types/components/Scrollbar/Scrollbar.d.ts +19 -0
  148. package/dist/types/components/Scrollbar/Scrollbar.d.ts.map +1 -0
  149. package/dist/types/components/Scrollbar/index.d.ts +3 -0
  150. package/dist/types/components/Scrollbar/index.d.ts.map +1 -0
  151. package/dist/types/components/index.d.ts +5 -4
  152. package/dist/types/components/index.d.ts.map +1 -1
  153. package/docs/consumers/README.md +116 -37
  154. package/docs/consumers/brand.md +261 -0
  155. package/docs/consumers/figma-console-mcp.md +116 -0
  156. package/docs/consumers/setup-instructions.md +98 -12
  157. package/docs/consumers/skills.md +79 -0
  158. package/package.json +4 -6
  159. package/scripts/postinstall-nudge.js +8 -4
  160. package/skills/add-brand/SKILL.md +204 -0
  161. package/skills/add-brand/reference.md +160 -0
  162. package/skills/figma-to-code/SKILL.md +127 -0
  163. package/skills/pull-from-figma/SKILL.md +123 -0
  164. package/skills/push-to-figma/SKILL.md +172 -0
  165. package/skills/setup-muka/SKILL.md +73 -13
  166. package/tokens/README.md +40 -18
  167. package/tokens/t2-alias/brand/bouwplan/fonts.json +1 -1
  168. package/tokens/t2-alias/brand/fscl/fonts.json +3 -3
  169. package/tokens/t2-alias/brand/wireframe/fonts.json +2 -2
  170. package/tokens/t4-components/menu.json +20 -5
  171. package/dist/cjs/components/ContextMenu/ContextMenu.js +0 -186
  172. package/dist/cjs/components/ContextMenu/ContextMenu.js.map +0 -1
  173. package/dist/cjs/components/ContextMenu/index.js +0 -17
  174. package/dist/cjs/components/ContextMenu/index.js.map +0 -1
  175. package/dist/esm/components/ContextMenu/ContextMenu.js +0 -145
  176. package/dist/esm/components/ContextMenu/ContextMenu.js.map +0 -1
  177. package/dist/esm/components/ContextMenu/index.js +0 -2
  178. package/dist/esm/components/ContextMenu/index.js.map +0 -1
  179. package/dist/types/components/ContextMenu/ContextMenu.d.ts +0 -188
  180. package/dist/types/components/ContextMenu/ContextMenu.d.ts.map +0 -1
  181. package/dist/types/components/ContextMenu/index.d.ts +0 -3
  182. package/dist/types/components/ContextMenu/index.d.ts.map +0 -1
@@ -34,132 +34,518 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  };
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
- exports.MenuSubContent = exports.MenuSubTrigger = exports.MenuSub = exports.MenuRadioItem = exports.MenuRadioGroup = exports.MenuCheckboxItem = exports.MenuGroup = exports.MenuSeparator = exports.MenuItem = exports.MenuContent = exports.MenuTrigger = exports.Menu = void 0;
37
+ exports.MenuSubContent = exports.MenuSubTrigger = exports.MenuSub = exports.MenuRadioItem = exports.MenuRadioGroup = exports.MenuCheckboxItem = exports.MenuGroup = exports.MenuSeparator = exports.MenuItem = exports.MenuSearch = exports.MenuContent = exports.MenuTrigger = exports.DropdownMenu = exports.Menu = void 0;
38
+ exports.useMenuSearch = useMenuSearch;
39
+ exports.highlightMenuMatch = highlightMenuMatch;
38
40
  const jsx_runtime_1 = require("react/jsx-runtime");
39
41
  const react_1 = __importStar(require("react"));
40
42
  const DropdownMenuPrimitive = __importStar(require("@radix-ui/react-dropdown-menu"));
43
+ const ContextMenuPrimitive = __importStar(require("@radix-ui/react-context-menu"));
41
44
  const Icon_1 = require("../Icon");
45
+ const Scrollbar_1 = require("../Scrollbar");
42
46
  require("./Menu.css");
43
- const MenuContext = (0, react_1.createContext)({});
47
+ const MenuContext = (0, react_1.createContext)({ trigger: 'click', open: false });
48
+ const MenuSearchContext = (0, react_1.createContext)({
49
+ query: '',
50
+ setQuery: () => { },
51
+ searchable: false,
52
+ highlightedId: null,
53
+ registerSearchNavItem: () => () => { },
54
+ moveHighlight: () => { },
55
+ selectHighlighted: () => { },
56
+ });
57
+ const MenuSearchHitsContext = (0, react_1.createContext)(null);
58
+ function useReportVisibleSearchResult(visible) {
59
+ const report = (0, react_1.useContext)(MenuSearchHitsContext);
60
+ (0, react_1.useLayoutEffect)(() => {
61
+ if (!visible || !report)
62
+ return undefined;
63
+ report(1);
64
+ return () => report(-1);
65
+ }, [visible, report]);
66
+ }
44
67
  /**
45
- * Menu Component
46
- *
47
- * A dropdown menu for displaying actions and options.
48
- * Built on Radix UI DropdownMenu for accessibility and keyboard navigation.
68
+ * Registers an enabled, visible row for MenuSearch arrow/Enter navigation.
69
+ * Returns whether this row is the current search highlight.
70
+ */
71
+ function useSearchNavHighlight(options) {
72
+ const { enabled, disabled, select } = options;
73
+ const { searchable, highlightedId, registerSearchNavItem } = useMenuSearch();
74
+ const id = react_1.default.useId();
75
+ const selectRef = (0, react_1.useRef)(select);
76
+ selectRef.current = select;
77
+ (0, react_1.useLayoutEffect)(() => {
78
+ if (!searchable || !enabled || disabled)
79
+ return undefined;
80
+ return registerSearchNavItem({
81
+ id,
82
+ disabled: false,
83
+ select: () => selectRef.current(),
84
+ });
85
+ }, [searchable, enabled, disabled, id, registerSearchNavItem]);
86
+ return searchable && enabled && !disabled && highlightedId === id;
87
+ }
88
+ function useMenuSearch() {
89
+ return (0, react_1.useContext)(MenuSearchContext);
90
+ }
91
+ function useMenuPrimitives() {
92
+ const { trigger } = (0, react_1.useContext)(MenuContext);
93
+ return trigger === 'context' ? ContextMenuPrimitive : DropdownMenuPrimitive;
94
+ }
95
+ /** Bold the first case-insensitive match of `query` within `text`. */
96
+ function highlightMenuMatch(text, query) {
97
+ if (!query)
98
+ return text;
99
+ const lower = text.toLowerCase();
100
+ const q = query.toLowerCase();
101
+ const index = lower.indexOf(q);
102
+ if (index === -1)
103
+ return text;
104
+ const before = text.slice(0, index);
105
+ const match = text.slice(index, index + query.length);
106
+ const after = text.slice(index + query.length);
107
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [before, (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__match", children: match }), after] }));
108
+ }
109
+ function getSearchableText(children) {
110
+ if (typeof children === 'string' || typeof children === 'number') {
111
+ return String(children);
112
+ }
113
+ if (Array.isArray(children)) {
114
+ return children.map(getSearchableText).join('');
115
+ }
116
+ if (react_1.default.isValidElement(children)) {
117
+ const props = children.props;
118
+ return getSearchableText(props.children);
119
+ }
120
+ return '';
121
+ }
122
+ function matchesSearch(children, query) {
123
+ if (!query)
124
+ return true;
125
+ return getSearchableText(children).toLowerCase().includes(query.toLowerCase());
126
+ }
127
+ /**
128
+ * Menu (Dropdown Menu)
49
129
  *
50
- * @example
51
- * ```tsx
52
- * <Menu>
53
- * <MenuTrigger asChild>
54
- * <Button>Open Menu</Button>
55
- * </MenuTrigger>
56
- * <MenuContent>
57
- * <MenuItem onSelect={() => console.log('Edit')}>Edit</MenuItem>
58
- * <MenuItem onSelect={() => console.log('Delete')} destructive>Delete</MenuItem>
59
- * </MenuContent>
60
- * </Menu>
61
- * ```
130
+ * Shared action-menu surface for click and right-click triggers.
131
+ * Built on Radix DropdownMenu / ContextMenu.
62
132
  */
63
- const Menu = ({ children, open, onOpenChange, defaultOpen, modal = true, }) => {
64
- return ((0, jsx_runtime_1.jsx)(MenuContext.Provider, { value: { onOpenChange }, children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Root, { open: open, onOpenChange: onOpenChange, defaultOpen: defaultOpen, modal: modal, children: children }) }));
133
+ const Menu = ({ children, trigger = 'click', open, onOpenChange, defaultOpen, modal = true, }) => {
134
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, react_1.useState)(Boolean(defaultOpen));
135
+ const isControlled = open !== undefined;
136
+ const isOpen = isControlled ? Boolean(open) : uncontrolledOpen;
137
+ const handleOpenChange = (0, react_1.useCallback)((next) => {
138
+ if (!isControlled) {
139
+ setUncontrolledOpen(next);
140
+ }
141
+ onOpenChange?.(next);
142
+ }, [isControlled, onOpenChange]);
143
+ const value = (0, react_1.useMemo)(() => ({ trigger, open: isOpen }), [trigger, isOpen]);
144
+ if (trigger === 'context') {
145
+ return ((0, jsx_runtime_1.jsx)(MenuContext.Provider, { value: value, children: (0, jsx_runtime_1.jsx)(ContextMenuPrimitive.Root, { onOpenChange: handleOpenChange, modal: modal, children: children }) }));
146
+ }
147
+ return ((0, jsx_runtime_1.jsx)(MenuContext.Provider, { value: value, children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Root, { open: open, onOpenChange: handleOpenChange, defaultOpen: defaultOpen, modal: modal, children: children }) }));
65
148
  };
66
149
  exports.Menu = Menu;
150
+ /** Alias for Figma / docs naming parity with "Dropdown Menu". */
151
+ exports.DropdownMenu = exports.Menu;
67
152
  /**
68
- * MenuTrigger - Button that opens the menu
153
+ * MenuTrigger — opens the menu on click or right-click depending on `Menu.trigger`.
69
154
  */
70
- exports.MenuTrigger = react_1.default.forwardRef(({ children, asChild = false, className = '' }, ref) => {
71
- return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Trigger, { ref: ref, asChild: asChild, className: className || undefined, children: children }));
155
+ exports.MenuTrigger = react_1.default.forwardRef(({ children, asChild = false, disabled = false, className = '' }, ref) => {
156
+ const { trigger } = (0, react_1.useContext)(MenuContext);
157
+ const Primitives = useMenuPrimitives();
158
+ if (trigger === 'context') {
159
+ const triggerClasses = ['muka-context-menu__trigger', className]
160
+ .filter(Boolean)
161
+ .join(' ');
162
+ return ((0, jsx_runtime_1.jsx)(ContextMenuPrimitive.Trigger, { ref: ref, asChild: asChild, disabled: disabled, className: triggerClasses || undefined, children: children }));
163
+ }
164
+ return ((0, jsx_runtime_1.jsx)(Primitives.Trigger, { ref: ref, asChild: asChild, disabled: disabled, className: className || undefined, children: children }));
72
165
  });
73
166
  exports.MenuTrigger.displayName = 'MenuTrigger';
74
167
  /**
75
- * MenuContent - The dropdown container for menu items
168
+ * MenuContent — dropdown / context menu surface with optional search + scrollbar.
76
169
  */
77
- exports.MenuContent = react_1.default.forwardRef(({ children, align = 'start', side = 'bottom', sideOffset = 4, alignOffset = 0, className = '', loop = true, onCloseAutoFocus, }, ref) => {
78
- const contentClasses = ['muka-menu__content', className].filter(Boolean).join(' ');
79
- return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Content, { ref: ref, align: align, side: side, sideOffset: sideOffset, alignOffset: alignOffset, className: contentClasses, loop: loop, onCloseAutoFocus: onCloseAutoFocus, children: children }) }));
170
+ function isMenuSearchElement(child) {
171
+ return (react_1.default.isValidElement(child) &&
172
+ typeof child.type !== 'string' &&
173
+ Boolean(child.type &&
174
+ typeof child.type === 'object' &&
175
+ 'displayName' in child.type &&
176
+ child.type.displayName === 'MenuSearch'));
177
+ }
178
+ function partitionMenuChildren(children) {
179
+ const search = [];
180
+ const items = [];
181
+ react_1.default.Children.forEach(children, (child) => {
182
+ if (isMenuSearchElement(child)) {
183
+ search.push(child);
184
+ }
185
+ else {
186
+ items.push(child);
187
+ }
188
+ });
189
+ return { search, items };
190
+ }
191
+ exports.MenuContent = react_1.default.forwardRef(({ children, align = 'start', side = 'bottom', sideOffset = 4, alignOffset = 0, className = '', style, loop = true, onOpenAutoFocus, onCloseAutoFocus, searchable = false, scrollbar = false, }, ref) => {
192
+ const { trigger, open } = (0, react_1.useContext)(MenuContext);
193
+ const [query, setQuery] = (0, react_1.useState)('');
194
+ const [searchHits, setSearchHits] = (0, react_1.useState)(0);
195
+ const [highlightedId, setHighlightedId] = (0, react_1.useState)(null);
196
+ const viewportRef = (0, react_1.useRef)(null);
197
+ const searchNavItemsRef = (0, react_1.useRef)([]);
198
+ // Clear search when the menu closes so the next open shows all options.
199
+ (0, react_1.useEffect)(() => {
200
+ if (!open) {
201
+ setQuery('');
202
+ setHighlightedId(null);
203
+ }
204
+ }, [open]);
205
+ const reportSearchHits = (0, react_1.useCallback)((delta) => {
206
+ setSearchHits((count) => count + delta);
207
+ }, []);
208
+ const registerSearchNavItem = (0, react_1.useCallback)((item) => {
209
+ searchNavItemsRef.current.push(item);
210
+ return () => {
211
+ searchNavItemsRef.current = searchNavItemsRef.current.filter((entry) => entry.id !== item.id);
212
+ };
213
+ }, []);
214
+ const moveHighlight = (0, react_1.useCallback)((delta) => {
215
+ const enabled = searchNavItemsRef.current.filter((item) => !item.disabled);
216
+ if (enabled.length === 0) {
217
+ setHighlightedId(null);
218
+ return;
219
+ }
220
+ setHighlightedId((current) => {
221
+ const index = enabled.findIndex((item) => item.id === current);
222
+ const from = index === -1 ? (delta > 0 ? -1 : 0) : index;
223
+ const next = (from + delta + enabled.length) % enabled.length;
224
+ return enabled[next].id;
225
+ });
226
+ }, []);
227
+ const highlightedIdRef = (0, react_1.useRef)(null);
228
+ highlightedIdRef.current = highlightedId;
229
+ const selectHighlighted = (0, react_1.useCallback)(() => {
230
+ const enabled = searchNavItemsRef.current.filter((item) => !item.disabled);
231
+ const currentId = highlightedIdRef.current;
232
+ const target = enabled.find((item) => item.id === currentId) ?? enabled[0] ?? null;
233
+ target?.select();
234
+ }, []);
235
+ // After children register, pin highlight to the first enabled row (or keep
236
+ // the current one when it is still in the filtered list).
237
+ (0, react_1.useLayoutEffect)(() => {
238
+ if (!searchable) {
239
+ searchNavItemsRef.current = [];
240
+ if (highlightedIdRef.current !== null)
241
+ setHighlightedId(null);
242
+ return;
243
+ }
244
+ const enabled = searchNavItemsRef.current.filter((item) => !item.disabled);
245
+ setHighlightedId((current) => {
246
+ if (current && enabled.some((item) => item.id === current))
247
+ return current;
248
+ return enabled[0]?.id ?? null;
249
+ });
250
+ });
251
+ (0, react_1.useLayoutEffect)(() => {
252
+ if (!highlightedId || !viewportRef.current)
253
+ return;
254
+ const active = viewportRef.current.querySelector('.muka-menu__item[data-highlighted]');
255
+ if (typeof active?.scrollIntoView === 'function') {
256
+ active.scrollIntoView({ block: 'nearest' });
257
+ }
258
+ }, [highlightedId]);
259
+ const handleQueryChange = (0, react_1.useCallback)((next) => {
260
+ setQuery(next);
261
+ // Force re-pin to the first match on the next layout pass.
262
+ setHighlightedId(null);
263
+ }, []);
264
+ const searchValue = (0, react_1.useMemo)(() => ({
265
+ query,
266
+ setQuery: handleQueryChange,
267
+ searchable,
268
+ highlightedId,
269
+ registerSearchNavItem,
270
+ moveHighlight,
271
+ selectHighlighted,
272
+ }), [
273
+ query,
274
+ handleQueryChange,
275
+ searchable,
276
+ highlightedId,
277
+ registerSearchNavItem,
278
+ moveHighlight,
279
+ selectHighlighted,
280
+ ]);
281
+ // Prefer the sticky search field so typing + arrow/Enter nav work immediately.
282
+ const handleOpenAutoFocus = (0, react_1.useCallback)((event) => {
283
+ if (onOpenAutoFocus) {
284
+ onOpenAutoFocus(event);
285
+ return;
286
+ }
287
+ if (!searchable)
288
+ return;
289
+ const content = event.currentTarget;
290
+ const input = content?.querySelector?.('.muka-menu__search-input');
291
+ if (input) {
292
+ event.preventDefault();
293
+ input.focus();
294
+ }
295
+ }, [onOpenAutoFocus, searchable]);
296
+ const { search, items } = partitionMenuChildren(children);
297
+ const searchNodes = search.length > 0 ? search : searchable ? (0, jsx_runtime_1.jsx)(exports.MenuSearch, {}) : null;
298
+ const contentClasses = [
299
+ 'muka-menu__content',
300
+ searchable && 'muka-menu__content--searchable',
301
+ scrollbar && 'muka-menu__content--scrollbar',
302
+ className,
303
+ ]
304
+ .filter(Boolean)
305
+ .join(' ');
306
+ const body = ((0, jsx_runtime_1.jsx)(MenuSearchContext.Provider, { value: searchValue, children: (0, jsx_runtime_1.jsxs)(MenuSearchHitsContext.Provider, { value: reportSearchHits, children: [searchNodes, (0, jsx_runtime_1.jsxs)("div", { className: "muka-menu__body", children: [(0, jsx_runtime_1.jsxs)("div", { className: "muka-menu__viewport", ref: viewportRef, children: [items, searchable && query && searchHits === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "muka-menu__empty", role: "status", children: "No results" })) : null] }), scrollbar ? (0, jsx_runtime_1.jsx)(Scrollbar_1.Scrollbar, { viewportRef: viewportRef }) : null] })] }) }));
307
+ // Radix types omit onOpenAutoFocus from menu Content (private FocusScope prop),
308
+ // but it is supported at runtime — required so searchable menus focus the field.
309
+ if (trigger === 'context') {
310
+ const contextContentProps = {
311
+ ref,
312
+ alignOffset,
313
+ className: contentClasses,
314
+ style,
315
+ loop,
316
+ onOpenAutoFocus: handleOpenAutoFocus,
317
+ onCloseAutoFocus,
318
+ children: body,
319
+ };
320
+ return ((0, jsx_runtime_1.jsx)(ContextMenuPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(ContextMenuPrimitive.Content, { ...contextContentProps }) }));
321
+ }
322
+ const dropdownContentProps = {
323
+ ref,
324
+ align,
325
+ side,
326
+ sideOffset,
327
+ alignOffset,
328
+ className: contentClasses,
329
+ style,
330
+ loop,
331
+ onOpenAutoFocus: handleOpenAutoFocus,
332
+ onCloseAutoFocus,
333
+ children: body,
334
+ };
335
+ return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Content, { ...dropdownContentProps }) }));
80
336
  });
81
337
  exports.MenuContent.displayName = 'MenuContent';
338
+ /**
339
+ * MenuSearch — sticky search header for filtering menu items.
340
+ * Must be used inside a `MenuContent` with `searchable`.
341
+ */
342
+ exports.MenuSearch = react_1.default.forwardRef(({ placeholder = 'Search', size = 'md', className = '', 'aria-label': ariaLabel }, ref) => {
343
+ const { query, setQuery, searchable, moveHighlight, selectHighlighted, } = useMenuSearch();
344
+ const handleKeyDown = (0, react_1.useCallback)((e) => {
345
+ // Keep typing from driving Radix typeahead, but own arrow/Enter for
346
+ // highlight + commit while focus stays in the search field.
347
+ if (e.key === 'ArrowDown') {
348
+ e.preventDefault();
349
+ e.stopPropagation();
350
+ moveHighlight(1);
351
+ return;
352
+ }
353
+ if (e.key === 'ArrowUp') {
354
+ e.preventDefault();
355
+ e.stopPropagation();
356
+ moveHighlight(-1);
357
+ return;
358
+ }
359
+ if (e.key === 'Enter') {
360
+ e.preventDefault();
361
+ e.stopPropagation();
362
+ selectHighlighted();
363
+ return;
364
+ }
365
+ e.stopPropagation();
366
+ }, [moveHighlight, selectHighlighted]);
367
+ if (!searchable) {
368
+ return null;
369
+ }
370
+ const iconSize = size === 'sm' ? 'xs' : 'sm';
371
+ const rootClasses = [
372
+ 'muka-menu__search',
373
+ size === 'sm' && 'muka-menu__search--sm',
374
+ className,
375
+ ]
376
+ .filter(Boolean)
377
+ .join(' ');
378
+ return ((0, jsx_runtime_1.jsxs)("div", { className: rootClasses, "data-muka-menu-search": "", children: [(0, jsx_runtime_1.jsx)("span", { className: "muka-menu__search-icon", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "search", variant: "line", size: iconSize }) }), (0, jsx_runtime_1.jsx)("input", { ref: ref, type: "search", className: "muka-menu__search-input", value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, "aria-label": ariaLabel || placeholder, autoComplete: "off", autoCorrect: "off", spellCheck: false }), query.length > 0 && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "muka-menu__search-clear", onClick: () => setQuery(''), "aria-label": "Clear search", tabIndex: -1, children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "close", variant: "line", size: iconSize }) }))] }));
379
+ });
380
+ exports.MenuSearch.displayName = 'MenuSearch';
82
381
  /**
83
382
  * MenuItem - An action item within the menu
84
383
  */
85
- exports.MenuItem = react_1.default.forwardRef(({ children, onSelect, disabled = false, destructive = false, icon, shortcut, className = '', }, ref) => {
384
+ exports.MenuItem = react_1.default.forwardRef(({ children, onSelect, disabled = false, destructive = false, icon, shortcut, hint, highlighted = false, id, className = '', textValue, }, ref) => {
385
+ const Primitives = useMenuPrimitives();
386
+ const { query, searchable } = useMenuSearch();
387
+ const labelText = textValue ?? getSearchableText(children);
388
+ const hidden = Boolean(searchable && query && !matchesSearch(labelText, query));
389
+ useReportVisibleSearchResult(searchable && Boolean(query) && !hidden);
390
+ const itemRef = (0, react_1.useRef)(null);
391
+ const setRefs = (0, react_1.useCallback)((node) => {
392
+ itemRef.current = node;
393
+ if (typeof ref === 'function')
394
+ ref(node);
395
+ else if (ref)
396
+ ref.current = node;
397
+ }, [ref]);
398
+ const searchHighlighted = useSearchNavHighlight({
399
+ enabled: searchable && !hidden,
400
+ disabled,
401
+ select: () => itemRef.current?.click(),
402
+ });
403
+ if (hidden) {
404
+ return null;
405
+ }
406
+ const isHighlighted = highlighted || searchHighlighted;
407
+ const showEnterHint = (hint === 'enter' || searchHighlighted) && !shortcut;
86
408
  const itemClasses = [
87
409
  'muka-menu__item',
410
+ showEnterHint && 'muka-menu__item--hint-enter',
411
+ shortcut && 'muka-menu__item--has-shortcut',
88
412
  destructive && 'muka-menu__item--destructive',
89
413
  disabled && 'muka-menu__item--disabled',
90
414
  className,
91
415
  ]
92
416
  .filter(Boolean)
93
417
  .join(' ');
94
- return ((0, jsx_runtime_1.jsxs)(DropdownMenuPrimitive.Item, { ref: ref, className: itemClasses, onSelect: onSelect, disabled: disabled, children: [icon && (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-icon", children: icon }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: children }), shortcut && (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-shortcut", children: shortcut })] }));
418
+ return ((0, jsx_runtime_1.jsxs)(Primitives.Item, { ref: setRefs, id: id, className: itemClasses, onSelect: onSelect, disabled: disabled, textValue: labelText, "aria-label": searchable && query ? labelText : undefined, "data-highlighted": isHighlighted ? '' : undefined, children: [icon && (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-icon", children: icon }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: searchable && query ? highlightMenuMatch(labelText, query) : children }), shortcut ? ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-shortcut", children: shortcut })) : showEnterHint ? ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-hint", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "arrow-return", size: "md", color: "var(--color-text-muted-default)" }) })) : null] }));
95
419
  });
96
420
  exports.MenuItem.displayName = 'MenuItem';
97
421
  /**
98
422
  * MenuSeparator - A visual divider between menu items
99
423
  */
100
424
  exports.MenuSeparator = react_1.default.forwardRef(({ className = '' }, ref) => {
425
+ const Primitives = useMenuPrimitives();
101
426
  const separatorClasses = ['muka-menu__separator', className].filter(Boolean).join(' ');
102
- return (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Separator, { ref: ref, className: separatorClasses });
427
+ return (0, jsx_runtime_1.jsx)(Primitives.Separator, { ref: ref, className: separatorClasses });
103
428
  });
104
429
  exports.MenuSeparator.displayName = 'MenuSeparator';
105
430
  /**
106
431
  * MenuGroup - A labeled group of menu items
107
432
  */
108
433
  exports.MenuGroup = react_1.default.forwardRef(({ children, label, className = '' }, ref) => {
434
+ const Primitives = useMenuPrimitives();
109
435
  const groupClasses = ['muka-menu__group', className].filter(Boolean).join(' ');
110
- return ((0, jsx_runtime_1.jsxs)(DropdownMenuPrimitive.Group, { ref: ref, className: groupClasses, children: [label && ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Label, { className: "muka-menu__group-label", children: label })), children] }));
436
+ return ((0, jsx_runtime_1.jsxs)(Primitives.Group, { ref: ref, className: groupClasses, children: [label && (0, jsx_runtime_1.jsx)(Primitives.Label, { className: "muka-menu__group-label", children: label }), children] }));
111
437
  });
112
438
  exports.MenuGroup.displayName = 'MenuGroup';
113
439
  /**
114
440
  * MenuCheckboxItem - A checkable menu item
115
441
  */
116
- exports.MenuCheckboxItem = react_1.default.forwardRef(({ children, checked, onCheckedChange, disabled = false, icon, className = '' }, ref) => {
442
+ exports.MenuCheckboxItem = react_1.default.forwardRef(({ children, checked, onCheckedChange, disabled = false, icon, indicator: indicatorPlacement = 'leading', className = '', textValue, }, ref) => {
443
+ const Primitives = useMenuPrimitives();
444
+ const { query, searchable } = useMenuSearch();
445
+ const labelText = textValue ?? getSearchableText(children);
446
+ const hidden = Boolean(searchable && query && !matchesSearch(labelText, query));
447
+ useReportVisibleSearchResult(searchable && Boolean(query) && !hidden);
448
+ const itemRef = (0, react_1.useRef)(null);
449
+ const setRefs = (0, react_1.useCallback)((node) => {
450
+ itemRef.current = node;
451
+ if (typeof ref === 'function')
452
+ ref(node);
453
+ else if (ref)
454
+ ref.current = node;
455
+ }, [ref]);
456
+ const searchHighlighted = useSearchNavHighlight({
457
+ enabled: searchable && !hidden,
458
+ disabled,
459
+ select: () => itemRef.current?.click(),
460
+ });
461
+ if (hidden) {
462
+ return null;
463
+ }
464
+ const trailing = indicatorPlacement === 'trailing' || Boolean(icon);
465
+ // Search highlight owns the trailing slot for the return affordance.
466
+ const showTrailingCheck = trailing && !searchHighlighted;
117
467
  const itemClasses = [
118
468
  'muka-menu__item',
119
469
  'muka-menu__item--checkbox',
470
+ trailing && 'muka-menu__item--checkbox-trailing',
471
+ searchHighlighted && 'muka-menu__item--hint-enter',
120
472
  disabled && 'muka-menu__item--disabled',
121
473
  className,
122
474
  ]
123
475
  .filter(Boolean)
124
476
  .join(' ');
125
- const indicator = ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-indicator", children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "check", size: "sm" }) }) }));
126
- return ((0, jsx_runtime_1.jsxs)(DropdownMenuPrimitive.CheckboxItem, { ref: ref, className: itemClasses, checked: checked, onCheckedChange: onCheckedChange, disabled: disabled, children: [icon ? (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-icon", children: icon }) : indicator, (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: children }), icon ? indicator : null] }));
477
+ const indicator = ((0, jsx_runtime_1.jsx)("span", { className: [
478
+ 'muka-menu__item-indicator',
479
+ trailing && 'muka-menu__item-indicator--trailing',
480
+ ]
481
+ .filter(Boolean)
482
+ .join(' '), children: (0, jsx_runtime_1.jsx)(Primitives.ItemIndicator, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "check", size: "md", color: trailing
483
+ ? 'var(--color-text-subtle-default)'
484
+ : undefined }) }) }));
485
+ return ((0, jsx_runtime_1.jsxs)(Primitives.CheckboxItem, { ref: setRefs, className: itemClasses, checked: checked, onCheckedChange: onCheckedChange, disabled: disabled, textValue: labelText, "aria-label": searchable && query ? labelText : undefined, "data-highlighted": searchHighlighted ? '' : undefined, children: [icon ? (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-icon", children: icon }) : null, !trailing ? indicator : null, (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: searchable && query ? highlightMenuMatch(labelText, query) : children }), showTrailingCheck ? indicator : null, searchHighlighted ? ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-hint", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "arrow-return", size: "md", color: "var(--color-text-muted-default)" }) })) : null] }));
127
486
  });
128
487
  exports.MenuCheckboxItem.displayName = 'MenuCheckboxItem';
129
488
  /**
130
489
  * MenuRadioGroup - A group of radio menu items
131
490
  */
132
491
  exports.MenuRadioGroup = react_1.default.forwardRef(({ children, value, onValueChange, className = '' }, ref) => {
492
+ const Primitives = useMenuPrimitives();
133
493
  const groupClasses = ['muka-menu__radio-group', className].filter(Boolean).join(' ');
134
- return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.RadioGroup, { ref: ref, className: groupClasses, value: value, onValueChange: onValueChange, children: children }));
494
+ return ((0, jsx_runtime_1.jsx)(Primitives.RadioGroup, { ref: ref, className: groupClasses, value: value, onValueChange: onValueChange, children: children }));
135
495
  });
136
496
  exports.MenuRadioGroup.displayName = 'MenuRadioGroup';
137
497
  /**
138
498
  * MenuRadioItem - A radio option within a MenuRadioGroup
139
499
  */
140
- exports.MenuRadioItem = react_1.default.forwardRef(({ children, value, disabled = false, className = '' }, ref) => {
500
+ exports.MenuRadioItem = react_1.default.forwardRef(({ children, value, disabled = false, className = '', indicator = 'dot', textValue, }, ref) => {
501
+ const Primitives = useMenuPrimitives();
502
+ const { query, searchable } = useMenuSearch();
503
+ const labelText = textValue ?? getSearchableText(children);
504
+ const hidden = Boolean(searchable && query && !matchesSearch(labelText, query));
505
+ useReportVisibleSearchResult(searchable && Boolean(query) && !hidden);
506
+ const itemRef = (0, react_1.useRef)(null);
507
+ const setRefs = (0, react_1.useCallback)((node) => {
508
+ itemRef.current = node;
509
+ if (typeof ref === 'function')
510
+ ref(node);
511
+ else if (ref)
512
+ ref.current = node;
513
+ }, [ref]);
514
+ const searchHighlighted = useSearchNavHighlight({
515
+ enabled: searchable && !hidden,
516
+ disabled,
517
+ select: () => itemRef.current?.click(),
518
+ });
519
+ if (hidden) {
520
+ return null;
521
+ }
522
+ const showTrailingCheck = indicator === 'check' && !searchHighlighted;
141
523
  const itemClasses = [
142
524
  'muka-menu__item',
143
525
  'muka-menu__item--radio',
526
+ indicator === 'check' && 'muka-menu__item--radio-check',
527
+ searchHighlighted && 'muka-menu__item--hint-enter',
144
528
  disabled && 'muka-menu__item--disabled',
145
529
  className,
146
530
  ]
147
531
  .filter(Boolean)
148
532
  .join(' ');
149
- return ((0, jsx_runtime_1.jsxs)(DropdownMenuPrimitive.RadioItem, { ref: ref, className: itemClasses, value: value, disabled: disabled, children: [(0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-indicator", children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__radio-dot" }) }) }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: children })] }));
533
+ return ((0, jsx_runtime_1.jsxs)(Primitives.RadioItem, { ref: setRefs, className: itemClasses, value: value, disabled: disabled, textValue: labelText, "aria-label": searchable && query ? labelText : undefined, "data-highlighted": searchHighlighted ? '' : undefined, children: [indicator === 'dot' && ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-indicator", children: (0, jsx_runtime_1.jsx)(Primitives.ItemIndicator, { children: (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__radio-dot" }) }) })), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: searchable && query ? highlightMenuMatch(labelText, query) : children }), showTrailingCheck && ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-indicator muka-menu__item-indicator--trailing", children: (0, jsx_runtime_1.jsx)(Primitives.ItemIndicator, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "check", size: "md", color: "var(--color-text-subtle-default)" }) }) })), searchHighlighted ? ((0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-hint", "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "arrow-return", size: "md", color: "var(--color-text-muted-default)" }) })) : null] }));
150
534
  });
151
535
  exports.MenuRadioItem.displayName = 'MenuRadioItem';
152
536
  /**
153
537
  * MenuSub - A submenu container
154
538
  */
155
539
  const MenuSub = ({ children, open, onOpenChange, defaultOpen, }) => {
156
- return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Sub, { open: open, onOpenChange: onOpenChange, defaultOpen: defaultOpen, children: children }));
540
+ const Primitives = useMenuPrimitives();
541
+ return ((0, jsx_runtime_1.jsx)(Primitives.Sub, { open: open, onOpenChange: onOpenChange, defaultOpen: defaultOpen, children: children }));
157
542
  };
158
543
  exports.MenuSub = MenuSub;
159
544
  /**
160
545
  * MenuSubTrigger - Trigger that opens a submenu
161
546
  */
162
547
  exports.MenuSubTrigger = react_1.default.forwardRef(({ children, icon, disabled = false, className = '' }, ref) => {
548
+ const Primitives = useMenuPrimitives();
163
549
  const itemClasses = [
164
550
  'muka-menu__item',
165
551
  'muka-menu__item--sub-trigger',
@@ -168,16 +554,20 @@ exports.MenuSubTrigger = react_1.default.forwardRef(({ children, icon, disabled
168
554
  ]
169
555
  .filter(Boolean)
170
556
  .join(' ');
171
- return ((0, jsx_runtime_1.jsxs)(DropdownMenuPrimitive.SubTrigger, { ref: ref, className: itemClasses, disabled: disabled, children: [icon && (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-icon", children: icon }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: children }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-chevron", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "arrow-right", variant: "line", size: "sm" }) })] }));
557
+ return ((0, jsx_runtime_1.jsxs)(Primitives.SubTrigger, { ref: ref, className: itemClasses, disabled: disabled, children: [icon && (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-icon", children: icon }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-label", children: children }), (0, jsx_runtime_1.jsx)("span", { className: "muka-menu__item-chevron", children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { name: "arrow-right", variant: "line", size: "sm" }) })] }));
172
558
  });
173
559
  exports.MenuSubTrigger.displayName = 'MenuSubTrigger';
174
560
  /**
175
561
  * MenuSubContent - The dropdown container for submenu items
176
562
  */
177
563
  exports.MenuSubContent = react_1.default.forwardRef(({ children, sideOffset = 2, alignOffset = -4, className = '', loop = true }, ref) => {
564
+ const { trigger } = (0, react_1.useContext)(MenuContext);
178
565
  const contentClasses = ['muka-menu__content', 'muka-menu__content--sub', className]
179
566
  .filter(Boolean)
180
567
  .join(' ');
568
+ if (trigger === 'context') {
569
+ return ((0, jsx_runtime_1.jsx)(ContextMenuPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(ContextMenuPrimitive.SubContent, { ref: ref, sideOffset: sideOffset, alignOffset: alignOffset, className: contentClasses, loop: loop, children: children }) }));
570
+ }
181
571
  return ((0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.Portal, { children: (0, jsx_runtime_1.jsx)(DropdownMenuPrimitive.SubContent, { ref: ref, sideOffset: sideOffset, alignOffset: alignOffset, className: contentClasses, loop: loop, children: children }) }));
182
572
  });
183
573
  exports.MenuSubContent.displayName = 'MenuSubContent';