@arun-dev/headless 4.6.0 → 4.7.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.
@@ -0,0 +1,33 @@
1
+ // src/core/rovingFocus.ts
2
+ function byDocumentOrder(a, b) {
3
+ const x = a.ref.current;
4
+ const y = b.ref.current;
5
+ if (!x || !y) return 0;
6
+ return x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
7
+ }
8
+ function rovingIndex(key, {
9
+ count,
10
+ current,
11
+ orientation,
12
+ rtl
13
+ }) {
14
+ if (count === 0) return null;
15
+ const [prevKey, nextKey] = orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : rtl ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"];
16
+ switch (key) {
17
+ case nextKey:
18
+ return current < 0 ? 0 : (current + 1) % count;
19
+ case prevKey:
20
+ return current < 0 ? count - 1 : (current - 1 + count) % count;
21
+ case "Home":
22
+ return 0;
23
+ case "End":
24
+ return count - 1;
25
+ default:
26
+ return null;
27
+ }
28
+ }
29
+
30
+ export {
31
+ byDocumentOrder,
32
+ rovingIndex
33
+ };
@@ -0,0 +1,438 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/menu/index.ts
21
+ var menu_exports = {};
22
+ __export(menu_exports, {
23
+ Menu: () => index_parts_exports
24
+ });
25
+ module.exports = __toCommonJS(menu_exports);
26
+
27
+ // src/menu/index.parts.ts
28
+ var index_parts_exports = {};
29
+ __export(index_parts_exports, {
30
+ Item: () => MenuItem,
31
+ Popup: () => MenuPopup,
32
+ Root: () => MenuRoot,
33
+ Trigger: () => MenuTrigger
34
+ });
35
+
36
+ // src/menu/MenuRoot.tsx
37
+ var import_react3 = require("react");
38
+
39
+ // src/core/anchoring.ts
40
+ function anchorNameFor(id) {
41
+ return `--hl-anchor-${id.replace(/[^a-zA-Z0-9_-]/g, "")}`;
42
+ }
43
+ var POSITION_AREA = {
44
+ bottom: { start: "bottom span-right", center: "bottom", end: "bottom span-left" },
45
+ top: { start: "top span-right", center: "top", end: "top span-left" },
46
+ right: { start: "right span-bottom", center: "right", end: "right span-top" },
47
+ left: { start: "left span-bottom", center: "left", end: "left span-top" }
48
+ };
49
+ function anchoredPopupStyle(anchorName, side, align) {
50
+ return {
51
+ positionAnchor: anchorName,
52
+ positionArea: POSITION_AREA[side][align],
53
+ // Flip across the axis it opens on; the other axis is left alone.
54
+ positionTryFallbacks: side === "top" || side === "bottom" ? "flip-block" : "flip-inline"
55
+ };
56
+ }
57
+ function anchoredDataAttributes(side, align) {
58
+ return { "data-side": side, "data-align": align };
59
+ }
60
+
61
+ // src/core/rovingFocus.ts
62
+ function byDocumentOrder(a, b) {
63
+ const x = a.ref.current;
64
+ const y = b.ref.current;
65
+ if (!x || !y) return 0;
66
+ return x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
67
+ }
68
+ function rovingIndex(key, {
69
+ count,
70
+ current,
71
+ orientation,
72
+ rtl
73
+ }) {
74
+ if (count === 0) return null;
75
+ const [prevKey, nextKey] = orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : rtl ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"];
76
+ switch (key) {
77
+ case nextKey:
78
+ return current < 0 ? 0 : (current + 1) % count;
79
+ case prevKey:
80
+ return current < 0 ? count - 1 : (current - 1 + count) % count;
81
+ case "Home":
82
+ return 0;
83
+ case "End":
84
+ return count - 1;
85
+ default:
86
+ return null;
87
+ }
88
+ }
89
+
90
+ // src/core/useControlled.ts
91
+ var import_react = require("react");
92
+ function useControlled({
93
+ controlled,
94
+ default: defaultValue,
95
+ name = "Component",
96
+ state = "value"
97
+ }) {
98
+ const { current: isControlled } = (0, import_react.useRef)(controlled !== void 0);
99
+ const [uncontrolled, setUncontrolled] = (0, import_react.useState)(defaultValue);
100
+ const defaultRef = (0, import_react.useRef)(defaultValue);
101
+ const value = isControlled ? controlled : uncontrolled;
102
+ if (process.env.NODE_ENV !== "production") {
103
+ if (isControlled !== (controlled !== void 0)) {
104
+ console.error(
105
+ `${name}: cannot switch between controlled and uncontrolled \`${state}\`. Decide which one this component is for the whole of its life.`
106
+ );
107
+ }
108
+ if (!isControlled && defaultRef.current !== defaultValue) {
109
+ console.error(
110
+ `${name}: cannot change the default \`${state}\` after mount. It is only read once, so later changes are silently ignored.`
111
+ );
112
+ }
113
+ }
114
+ const setValue = (0, import_react.useCallback)(
115
+ (next) => {
116
+ if (!isControlled) setUncontrolled(next);
117
+ },
118
+ [isControlled]
119
+ );
120
+ return [value, setValue];
121
+ }
122
+
123
+ // src/menu/MenuRootContext.ts
124
+ var import_react2 = require("react");
125
+ var MenuRootContext = (0, import_react2.createContext)(null);
126
+ function useMenuRootContext(part) {
127
+ const context = (0, import_react2.useContext)(MenuRootContext);
128
+ if (context === null) {
129
+ throw new Error(`<Menu.${part}> must be rendered inside <Menu.Root>.`);
130
+ }
131
+ return context;
132
+ }
133
+
134
+ // src/menu/MenuRoot.tsx
135
+ var import_jsx_runtime = require("react/jsx-runtime");
136
+ function MenuRoot({
137
+ open: openProp,
138
+ defaultOpen,
139
+ onOpenChange,
140
+ focusableWhenDisabled = false,
141
+ children
142
+ }) {
143
+ const [open, setOpenState] = useControlled({
144
+ controlled: openProp,
145
+ default: defaultOpen ?? false,
146
+ name: "Menu.Root",
147
+ state: "open"
148
+ });
149
+ const setOpen = (0, import_react3.useCallback)(
150
+ (next) => {
151
+ if (next === open) return;
152
+ setOpenState(next);
153
+ onOpenChange?.(next);
154
+ },
155
+ [open, setOpenState, onOpenChange]
156
+ );
157
+ const [items, setItems] = (0, import_react3.useState)([]);
158
+ const register = (0, import_react3.useCallback)((entry) => {
159
+ setItems((current) => [...current, entry].sort(byDocumentOrder));
160
+ return () => setItems((current) => current.filter((i) => i !== entry));
161
+ }, []);
162
+ const navigableItems = (0, import_react3.useMemo)(
163
+ () => focusableWhenDisabled ? items : items.filter((i) => !i.disabled),
164
+ [items, focusableWhenDisabled]
165
+ );
166
+ const id = (0, import_react3.useId)();
167
+ const triggerRef = (0, import_react3.useRef)(null);
168
+ const focusOnOpenRef = (0, import_react3.useRef)("first");
169
+ const context = (0, import_react3.useMemo)(
170
+ () => ({
171
+ open,
172
+ setOpen,
173
+ navigableItems,
174
+ focusableWhenDisabled,
175
+ register,
176
+ focusOnOpenRef,
177
+ triggerId: `${id}-trigger`,
178
+ popupId: `${id}-popup`,
179
+ anchorName: anchorNameFor(id),
180
+ triggerRef
181
+ }),
182
+ [open, setOpen, navigableItems, focusableWhenDisabled, register, id]
183
+ );
184
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MenuRootContext.Provider, { value: context, children });
185
+ }
186
+
187
+ // src/core/useRender.ts
188
+ var import_react4 = require("react");
189
+
190
+ // src/core/mergeProps.ts
191
+ function isEventHandler(key) {
192
+ return key.length > 2 && key.startsWith("on") && key[2] === key[2]?.toUpperCase();
193
+ }
194
+ function mergeRefs(...refs) {
195
+ return (node) => {
196
+ const cleanups = refs.map((ref) => {
197
+ if (typeof ref === "function") {
198
+ const result = ref(node);
199
+ return typeof result === "function" ? result : () => ref(null);
200
+ }
201
+ if (ref && typeof ref === "object") {
202
+ ref.current = node;
203
+ return () => {
204
+ ref.current = null;
205
+ };
206
+ }
207
+ return void 0;
208
+ });
209
+ return () => {
210
+ cleanups.forEach((cleanup) => {
211
+ if (typeof cleanup === "function") cleanup();
212
+ });
213
+ };
214
+ };
215
+ }
216
+ function isSyntheticEvent(event) {
217
+ return typeof event === "object" && event !== null && "nativeEvent" in event;
218
+ }
219
+ function makeEventPreventable(event) {
220
+ if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
221
+ const target = event;
222
+ target.preventComponentHandler = () => {
223
+ target.componentHandlerPrevented = true;
224
+ };
225
+ }
226
+ function isComponentHandlerPrevented(event) {
227
+ return typeof event === "object" && event !== null && event.componentHandlerPrevented === true;
228
+ }
229
+ function chainHandlers(earlier, value) {
230
+ return (...args) => {
231
+ const event = args[0];
232
+ if (isSyntheticEvent(event)) makeEventPreventable(event);
233
+ value(...args);
234
+ if (isComponentHandlerPrevented(event)) return;
235
+ earlier(...args);
236
+ };
237
+ }
238
+ function mergeProps(...objects) {
239
+ const merged = {};
240
+ for (const props of objects) {
241
+ if (!props) continue;
242
+ for (const key of Object.keys(props)) {
243
+ const value = props[key];
244
+ if (value === void 0) continue;
245
+ if (isEventHandler(key) && typeof value === "function") {
246
+ const earlier = merged[key];
247
+ merged[key] = typeof earlier === "function" ? chainHandlers(earlier, value) : value;
248
+ } else if (key === "className") {
249
+ merged.className = merged.className ? `${String(merged.className)} ${String(value)}` : value;
250
+ } else if (key === "style") {
251
+ merged.style = { ...merged.style, ...value };
252
+ } else if (key === "ref") {
253
+ merged.ref = merged.ref ? mergeRefs(merged.ref, value) : value;
254
+ } else {
255
+ merged[key] = value;
256
+ }
257
+ }
258
+ }
259
+ return merged;
260
+ }
261
+
262
+ // src/core/useRender.ts
263
+ function useRender({
264
+ render,
265
+ defaultTagName,
266
+ props,
267
+ consumerProps
268
+ }) {
269
+ const merged = mergeProps(props, consumerProps);
270
+ if ((0, import_react4.isValidElement)(render)) {
271
+ return (0, import_react4.cloneElement)(render, mergeProps(merged, render.props));
272
+ }
273
+ return (0, import_react4.createElement)(defaultTagName, merged);
274
+ }
275
+
276
+ // src/menu/menuDataAttributes.ts
277
+ function menuDataAttributes({ open }) {
278
+ return {
279
+ "data-open": open ? "" : void 0,
280
+ "data-closed": open ? void 0 : ""
281
+ };
282
+ }
283
+ function menuItemDataAttributes(disabled) {
284
+ return { "data-disabled": disabled ? "" : void 0 };
285
+ }
286
+
287
+ // src/menu/MenuTrigger.tsx
288
+ function MenuTrigger({ className, children, render, ...rest }) {
289
+ const { open, setOpen, focusOnOpenRef, triggerId, popupId, anchorName, triggerRef } = useMenuRootContext("Trigger");
290
+ return useRender({
291
+ render,
292
+ defaultTagName: "button",
293
+ props: {
294
+ type: "button",
295
+ id: triggerId,
296
+ "aria-haspopup": "menu",
297
+ "aria-expanded": open,
298
+ "aria-controls": popupId,
299
+ ...menuDataAttributes({ open }),
300
+ style: { anchorName },
301
+ className,
302
+ children,
303
+ ref: triggerRef,
304
+ onClick() {
305
+ focusOnOpenRef.current = "first";
306
+ setOpen(!open);
307
+ },
308
+ onKeyDown(event) {
309
+ if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
310
+ event.preventDefault();
311
+ focusOnOpenRef.current = event.key === "ArrowUp" ? "last" : "first";
312
+ setOpen(true);
313
+ }
314
+ },
315
+ consumerProps: rest
316
+ });
317
+ }
318
+
319
+ // src/menu/MenuPopup.tsx
320
+ var import_react5 = require("react");
321
+ function MenuPopup({
322
+ side = "bottom",
323
+ align = "start",
324
+ className,
325
+ children,
326
+ render,
327
+ ...rest
328
+ }) {
329
+ const {
330
+ open,
331
+ setOpen,
332
+ navigableItems,
333
+ focusOnOpenRef,
334
+ triggerId,
335
+ popupId,
336
+ anchorName,
337
+ triggerRef
338
+ } = useMenuRootContext("Popup");
339
+ const elementRef = (0, import_react5.useRef)(null);
340
+ const focusPendingRef = (0, import_react5.useRef)(false);
341
+ const [, resync] = (0, import_react5.useReducer)((n) => n + 1, 0);
342
+ (0, import_react5.useEffect)(() => {
343
+ const popup = elementRef.current;
344
+ if (!popup || typeof popup.showPopover !== "function") return;
345
+ const shown = popup.matches(":popover-open");
346
+ if (open && !shown) {
347
+ popup.showPopover({ source: triggerRef.current ?? void 0 });
348
+ if (!popup.matches(":popover-open")) setOpen(false);
349
+ else focusPendingRef.current = true;
350
+ } else if (!open && shown) {
351
+ focusPendingRef.current = false;
352
+ popup.hidePopover();
353
+ }
354
+ if (focusPendingRef.current && navigableItems.length > 0) {
355
+ focusPendingRef.current = false;
356
+ const target = focusOnOpenRef.current === "last" ? navigableItems.at(-1) : navigableItems[0];
357
+ target?.ref.current?.focus();
358
+ }
359
+ });
360
+ return useRender({
361
+ render,
362
+ defaultTagName: "div",
363
+ props: {
364
+ id: popupId,
365
+ popover: "auto",
366
+ role: "menu",
367
+ "aria-labelledby": triggerId,
368
+ ...anchoredDataAttributes(side, align),
369
+ ...menuDataAttributes({ open }),
370
+ style: anchoredPopupStyle(anchorName, side, align),
371
+ className,
372
+ children,
373
+ ref: elementRef,
374
+ onKeyDown(event) {
375
+ if (event.key === "Tab") {
376
+ setOpen(false);
377
+ return;
378
+ }
379
+ const current = navigableItems.findIndex((i) => i.ref.current === event.target);
380
+ if (current < 0 && event.target !== event.currentTarget) return;
381
+ const next = rovingIndex(event.key, {
382
+ count: navigableItems.length,
383
+ current,
384
+ orientation: "vertical",
385
+ rtl: false
386
+ });
387
+ if (next === null) return;
388
+ event.preventDefault();
389
+ navigableItems[next]?.ref.current?.focus();
390
+ },
391
+ onToggle(event) {
392
+ if (event.target !== event.currentTarget) return;
393
+ if (event.nativeEvent.newState !== "closed") return;
394
+ setOpen(false);
395
+ resync();
396
+ }
397
+ },
398
+ consumerProps: rest
399
+ });
400
+ }
401
+
402
+ // src/menu/MenuItem.tsx
403
+ var import_react6 = require("react");
404
+ function MenuItem({
405
+ disabled = false,
406
+ onClick,
407
+ className,
408
+ children,
409
+ render,
410
+ ...rest
411
+ }) {
412
+ const { setOpen, focusableWhenDisabled, register } = useMenuRootContext("Item");
413
+ const elementRef = (0, import_react6.useRef)(null);
414
+ (0, import_react6.useLayoutEffect)(() => register({ disabled, ref: elementRef }), [register, disabled]);
415
+ return useRender({
416
+ render,
417
+ defaultTagName: "button",
418
+ props: {
419
+ type: "button",
420
+ role: "menuitem",
421
+ tabIndex: -1,
422
+ disabled: disabled && !focusableWhenDisabled || void 0,
423
+ "aria-disabled": disabled && focusableWhenDisabled || void 0,
424
+ ...menuItemDataAttributes(disabled),
425
+ className,
426
+ children,
427
+ ref: elementRef,
428
+ onClick() {
429
+ if (!disabled) setOpen(false);
430
+ }
431
+ },
432
+ consumerProps: disabled ? rest : { ...rest, onClick }
433
+ });
434
+ }
435
+ // Annotate the CommonJS export names for ESM import in node:
436
+ 0 && (module.exports = {
437
+ Menu
438
+ });
@@ -0,0 +1,115 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, ReactElement, Ref, ComponentPropsWithRef } from 'react';
3
+ import { A as AnchorSide, a as AnchorAlign } from '../anchoring-Btxi0QwC.cjs';
4
+
5
+ type MenuRootProps = {
6
+ /**
7
+ * Controlled state. Provide `onOpenChange` alongside it.
8
+ *
9
+ * Never `undefined` once mounted: the mode is latched at mount, as for Switch.
10
+ */
11
+ open?: boolean;
12
+ /** Initial state when uncontrolled. Read once, at mount. */
13
+ defaultOpen?: boolean;
14
+ /**
15
+ * Called on every request to open or close — Trigger, an Item, Tab, Esc, or a click
16
+ * outside. A controlled menu moves only if the parent accepts it.
17
+ */
18
+ onOpenChange?: (open: boolean) => void;
19
+ /**
20
+ * Keeps disabled items in the arrow-key sequence, so a screen reader announces them as
21
+ * unavailable. They still cannot be activated. Off by default: the arrows skip them.
22
+ */
23
+ focusableWhenDisabled?: boolean;
24
+ children?: ReactNode;
25
+ };
26
+ /**
27
+ * A menu button, by the WAI-ARIA pattern: a Trigger that opens a list of actions. Holds the
28
+ * state and shares it with its parts. Renders no element of its own.
29
+ *
30
+ * The popup is a native `popover`, anchored like Popover (decision 12): the platform supplies
31
+ * the top layer, light dismiss, Esc and focus return. This component adds state, one setter
32
+ * every close goes through, and the arrow-key focus a menu needs (`core/rovingFocus`).
33
+ *
34
+ * Each Item registers its own `disabled` from its props; the Root never reads it back from
35
+ * the DOM (decision 10). Elements are kept only to move focus to.
36
+ */
37
+ declare function MenuRoot({ open: openProp, defaultOpen, onOpenChange, focusableWhenDisabled, children, }: MenuRootProps): react.JSX.Element;
38
+
39
+ type MenuTriggerOwnProps = {
40
+ /** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
41
+ render?: ReactElement;
42
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
43
+ ref?: Ref<HTMLElement>;
44
+ };
45
+ type MenuTriggerProps = MenuTriggerOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuTriggerOwnProps>;
46
+ /**
47
+ * The menu button. A native `<button>`, so a click, Enter and Space open the menu at its
48
+ * first item with no key handling here; Down does the same, and Up opens it at the last.
49
+ * It is what the popup is anchored to, and names it: the popup is `aria-labelledby` it.
50
+ */
51
+ declare function MenuTrigger({ className, children, render, ...rest }: MenuTriggerProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
52
+
53
+ type MenuSide = AnchorSide;
54
+ type MenuAlign = AnchorAlign;
55
+ type MenuPopupOwnProps = {
56
+ /** Which side of the trigger to open on. Flips to the opposite side when there is no room. */
57
+ side?: MenuSide;
58
+ /** Where along that side: flush with the trigger's start or end edge, or centred on it. */
59
+ align?: MenuAlign;
60
+ /** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
61
+ render?: ReactElement;
62
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
63
+ ref?: Ref<HTMLElement>;
64
+ };
65
+ type MenuPopupProps = MenuPopupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuPopupOwnProps | 'popover'>;
66
+ /**
67
+ * The menu: a native `popover="auto"` with `role="menu"`, anchored to the Trigger as
68
+ * Popover's popup is (decision 12), and labelled by it.
69
+ *
70
+ * Opening moves focus to the first item — the last, when Up on the Trigger opened it. Up
71
+ * and Down then move between items, wrapping, with Home and End; disabled items are skipped
72
+ * unless the Root sets `focusableWhenDisabled`. Tab closes the menu and lets focus move on.
73
+ *
74
+ * Light dismiss and Esc close the element before anyone is asked; the `toggle` event
75
+ * reports it through the Root, and the element reopens if the state stays open. Focus
76
+ * returns to the Trigger, the invoker, whenever the menu hides with focus inside it.
77
+ */
78
+ declare function MenuPopup({ side, align, className, children, render, ...rest }: MenuPopupProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
79
+
80
+ type MenuItemOwnProps = {
81
+ /**
82
+ * Cannot be activated. Skipped by the arrow keys, unless the Root sets
83
+ * `focusableWhenDisabled`.
84
+ */
85
+ disabled?: boolean;
86
+ /** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
87
+ render?: ReactElement;
88
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
89
+ ref?: Ref<HTMLElement>;
90
+ };
91
+ type MenuItemProps = MenuItemOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuItemOwnProps>;
92
+ /**
93
+ * One action. A native `<button>`, so Enter, Space and a click activate it with no key
94
+ * handling here: put the action in `onClick`. Activating it closes the menu — call
95
+ * `event.preventComponentHandler()` in your `onClick` to keep it open.
96
+ *
97
+ * `tabIndex={-1}`: the menu moves focus between items itself, and Tab leaves the menu.
98
+ *
99
+ * Disabled, it is a native `disabled` button, out of focus and activation. With the Root's
100
+ * `focusableWhenDisabled` it is `aria-disabled` instead, which keeps it focusable, so the
101
+ * activation a native `disabled` would block is blocked here: your `onClick` is not
102
+ * attached while it is disabled.
103
+ */
104
+ declare function MenuItem({ disabled, onClick, className, children, render, ...rest }: MenuItemProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
105
+
106
+ declare namespace index_parts {
107
+ export { MenuItem as Item, MenuPopup as Popup, MenuRoot as Root, MenuTrigger as Trigger };
108
+ }
109
+
110
+ /** The state Menu.Root shares with its parts, and projects as `data-*` attributes. */
111
+ type MenuState = {
112
+ open: boolean;
113
+ };
114
+
115
+ export { index_parts as Menu, type MenuAlign, type MenuItemProps, type MenuPopupProps, type MenuRootProps, type MenuSide, type MenuState, type MenuTriggerProps };
@@ -0,0 +1,115 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, ReactElement, Ref, ComponentPropsWithRef } from 'react';
3
+ import { A as AnchorSide, a as AnchorAlign } from '../anchoring-Btxi0QwC.js';
4
+
5
+ type MenuRootProps = {
6
+ /**
7
+ * Controlled state. Provide `onOpenChange` alongside it.
8
+ *
9
+ * Never `undefined` once mounted: the mode is latched at mount, as for Switch.
10
+ */
11
+ open?: boolean;
12
+ /** Initial state when uncontrolled. Read once, at mount. */
13
+ defaultOpen?: boolean;
14
+ /**
15
+ * Called on every request to open or close — Trigger, an Item, Tab, Esc, or a click
16
+ * outside. A controlled menu moves only if the parent accepts it.
17
+ */
18
+ onOpenChange?: (open: boolean) => void;
19
+ /**
20
+ * Keeps disabled items in the arrow-key sequence, so a screen reader announces them as
21
+ * unavailable. They still cannot be activated. Off by default: the arrows skip them.
22
+ */
23
+ focusableWhenDisabled?: boolean;
24
+ children?: ReactNode;
25
+ };
26
+ /**
27
+ * A menu button, by the WAI-ARIA pattern: a Trigger that opens a list of actions. Holds the
28
+ * state and shares it with its parts. Renders no element of its own.
29
+ *
30
+ * The popup is a native `popover`, anchored like Popover (decision 12): the platform supplies
31
+ * the top layer, light dismiss, Esc and focus return. This component adds state, one setter
32
+ * every close goes through, and the arrow-key focus a menu needs (`core/rovingFocus`).
33
+ *
34
+ * Each Item registers its own `disabled` from its props; the Root never reads it back from
35
+ * the DOM (decision 10). Elements are kept only to move focus to.
36
+ */
37
+ declare function MenuRoot({ open: openProp, defaultOpen, onOpenChange, focusableWhenDisabled, children, }: MenuRootProps): react.JSX.Element;
38
+
39
+ type MenuTriggerOwnProps = {
40
+ /** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
41
+ render?: ReactElement;
42
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
43
+ ref?: Ref<HTMLElement>;
44
+ };
45
+ type MenuTriggerProps = MenuTriggerOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuTriggerOwnProps>;
46
+ /**
47
+ * The menu button. A native `<button>`, so a click, Enter and Space open the menu at its
48
+ * first item with no key handling here; Down does the same, and Up opens it at the last.
49
+ * It is what the popup is anchored to, and names it: the popup is `aria-labelledby` it.
50
+ */
51
+ declare function MenuTrigger({ className, children, render, ...rest }: MenuTriggerProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
52
+
53
+ type MenuSide = AnchorSide;
54
+ type MenuAlign = AnchorAlign;
55
+ type MenuPopupOwnProps = {
56
+ /** Which side of the trigger to open on. Flips to the opposite side when there is no room. */
57
+ side?: MenuSide;
58
+ /** Where along that side: flush with the trigger's start or end edge, or centred on it. */
59
+ align?: MenuAlign;
60
+ /** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
61
+ render?: ReactElement;
62
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
63
+ ref?: Ref<HTMLElement>;
64
+ };
65
+ type MenuPopupProps = MenuPopupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuPopupOwnProps | 'popover'>;
66
+ /**
67
+ * The menu: a native `popover="auto"` with `role="menu"`, anchored to the Trigger as
68
+ * Popover's popup is (decision 12), and labelled by it.
69
+ *
70
+ * Opening moves focus to the first item — the last, when Up on the Trigger opened it. Up
71
+ * and Down then move between items, wrapping, with Home and End; disabled items are skipped
72
+ * unless the Root sets `focusableWhenDisabled`. Tab closes the menu and lets focus move on.
73
+ *
74
+ * Light dismiss and Esc close the element before anyone is asked; the `toggle` event
75
+ * reports it through the Root, and the element reopens if the state stays open. Focus
76
+ * returns to the Trigger, the invoker, whenever the menu hides with focus inside it.
77
+ */
78
+ declare function MenuPopup({ side, align, className, children, render, ...rest }: MenuPopupProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
79
+
80
+ type MenuItemOwnProps = {
81
+ /**
82
+ * Cannot be activated. Skipped by the arrow keys, unless the Root sets
83
+ * `focusableWhenDisabled`.
84
+ */
85
+ disabled?: boolean;
86
+ /** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
87
+ render?: ReactElement;
88
+ /** Ref to the rendered element. Merged with any ref on the `render` element. */
89
+ ref?: Ref<HTMLElement>;
90
+ };
91
+ type MenuItemProps = MenuItemOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuItemOwnProps>;
92
+ /**
93
+ * One action. A native `<button>`, so Enter, Space and a click activate it with no key
94
+ * handling here: put the action in `onClick`. Activating it closes the menu — call
95
+ * `event.preventComponentHandler()` in your `onClick` to keep it open.
96
+ *
97
+ * `tabIndex={-1}`: the menu moves focus between items itself, and Tab leaves the menu.
98
+ *
99
+ * Disabled, it is a native `disabled` button, out of focus and activation. With the Root's
100
+ * `focusableWhenDisabled` it is `aria-disabled` instead, which keeps it focusable, so the
101
+ * activation a native `disabled` would block is blocked here: your `onClick` is not
102
+ * attached while it is disabled.
103
+ */
104
+ declare function MenuItem({ disabled, onClick, className, children, render, ...rest }: MenuItemProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
105
+
106
+ declare namespace index_parts {
107
+ export { MenuItem as Item, MenuPopup as Popup, MenuRoot as Root, MenuTrigger as Trigger };
108
+ }
109
+
110
+ /** The state Menu.Root shares with its parts, and projects as `data-*` attributes. */
111
+ type MenuState = {
112
+ open: boolean;
113
+ };
114
+
115
+ export { index_parts as Menu, type MenuAlign, type MenuItemProps, type MenuPopupProps, type MenuRootProps, type MenuSide, type MenuState, type MenuTriggerProps };