@arun-dev/headless 4.14.0 → 4.15.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.
- package/dist/chunk-ETNICT5M.js +8 -0
- package/dist/combobox/index.cjs +3 -1
- package/dist/combobox/index.js +3 -3
- package/dist/menu/index.cjs +311 -19
- package/dist/menu/index.d.cts +144 -10
- package/dist/menu/index.d.ts +144 -10
- package/dist/menu/index.js +307 -19
- package/package.json +1 -1
package/dist/combobox/index.cjs
CHANGED
|
@@ -133,10 +133,12 @@ function useControlled({
|
|
|
133
133
|
return [value, setValue];
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
// src/
|
|
136
|
+
// src/core/fold.ts
|
|
137
137
|
function fold(text) {
|
|
138
138
|
return text.normalize("NFD").replace(/\p{M}/gu, "").toLocaleLowerCase();
|
|
139
139
|
}
|
|
140
|
+
|
|
141
|
+
// src/combobox/defaultFilter.ts
|
|
140
142
|
function defaultFilter(items, query, itemToString) {
|
|
141
143
|
const needle = fold(query.trim());
|
|
142
144
|
if (needle === "") return [...items];
|
package/dist/combobox/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fold
|
|
3
|
+
} from "../chunk-ETNICT5M.js";
|
|
1
4
|
import {
|
|
2
5
|
anchorNameFor,
|
|
3
6
|
anchoredDataAttributes,
|
|
@@ -40,9 +43,6 @@ __export(index_parts_exports, {
|
|
|
40
43
|
import { useCallback, useDeferredValue, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
41
44
|
|
|
42
45
|
// src/combobox/defaultFilter.ts
|
|
43
|
-
function fold(text) {
|
|
44
|
-
return text.normalize("NFD").replace(/\p{M}/gu, "").toLocaleLowerCase();
|
|
45
|
-
}
|
|
46
46
|
function defaultFilter(items, query, itemToString) {
|
|
47
47
|
const needle = fold(query.trim());
|
|
48
48
|
if (needle === "") return [...items];
|
package/dist/menu/index.cjs
CHANGED
|
@@ -27,8 +27,14 @@ module.exports = __toCommonJS(menu_exports);
|
|
|
27
27
|
// src/menu/index.parts.ts
|
|
28
28
|
var index_parts_exports = {};
|
|
29
29
|
__export(index_parts_exports, {
|
|
30
|
+
CheckboxItem: () => MenuCheckboxItem,
|
|
31
|
+
Group: () => MenuGroup,
|
|
32
|
+
GroupLabel: () => MenuGroupLabel,
|
|
30
33
|
Item: () => MenuItem,
|
|
34
|
+
ItemIndicator: () => MenuItemIndicator,
|
|
31
35
|
Popup: () => MenuPopup,
|
|
36
|
+
RadioGroup: () => MenuRadioGroup,
|
|
37
|
+
RadioItem: () => MenuRadioItem,
|
|
32
38
|
Root: () => MenuRoot,
|
|
33
39
|
Trigger: () => MenuTrigger
|
|
34
40
|
});
|
|
@@ -280,9 +286,6 @@ function menuDataAttributes({ open }) {
|
|
|
280
286
|
"data-closed": open ? void 0 : ""
|
|
281
287
|
};
|
|
282
288
|
}
|
|
283
|
-
function menuItemDataAttributes(disabled) {
|
|
284
|
-
return { "data-disabled": disabled ? "" : void 0 };
|
|
285
|
-
}
|
|
286
289
|
|
|
287
290
|
// src/menu/MenuTrigger.tsx
|
|
288
291
|
function MenuTrigger({ className, children, render, ...rest }) {
|
|
@@ -317,7 +320,58 @@ function MenuTrigger({ className, children, render, ...rest }) {
|
|
|
317
320
|
}
|
|
318
321
|
|
|
319
322
|
// src/menu/MenuPopup.tsx
|
|
323
|
+
var import_react6 = require("react");
|
|
324
|
+
|
|
325
|
+
// src/core/typeahead.ts
|
|
320
326
|
var import_react5 = require("react");
|
|
327
|
+
|
|
328
|
+
// src/core/fold.ts
|
|
329
|
+
function fold(text) {
|
|
330
|
+
return text.normalize("NFD").replace(/\p{M}/gu, "").toLocaleLowerCase();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/core/typeahead.ts
|
|
334
|
+
var TYPEAHEAD_TIMEOUT = 500;
|
|
335
|
+
function textOf(node) {
|
|
336
|
+
let text = "";
|
|
337
|
+
import_react5.Children.forEach(node, (child) => {
|
|
338
|
+
if (typeof child === "string" || typeof child === "number") text += child;
|
|
339
|
+
else if ((0, import_react5.isValidElement)(child)) text += textOf(child.props.children);
|
|
340
|
+
});
|
|
341
|
+
return text;
|
|
342
|
+
}
|
|
343
|
+
function typeaheadIndex(labels, current, search) {
|
|
344
|
+
const count = labels.length;
|
|
345
|
+
if (count === 0 || search === "") return null;
|
|
346
|
+
const [first = "", ...others] = [...search];
|
|
347
|
+
const repeated = others.every((char) => char === first);
|
|
348
|
+
const needle = fold(repeated ? first : search);
|
|
349
|
+
const start = current < 0 ? 0 : repeated ? current + 1 : current;
|
|
350
|
+
for (let step = 0; step < count; step += 1) {
|
|
351
|
+
const index = (start + step) % count;
|
|
352
|
+
if (fold(labels[index] ?? "").startsWith(needle)) return index;
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
function useTypeahead() {
|
|
357
|
+
const searchRef = (0, import_react5.useRef)("");
|
|
358
|
+
const timerRef = (0, import_react5.useRef)(void 0);
|
|
359
|
+
(0, import_react5.useEffect)(() => () => clearTimeout(timerRef.current), []);
|
|
360
|
+
return (0, import_react5.useCallback)((event) => {
|
|
361
|
+
const { key } = event;
|
|
362
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return null;
|
|
363
|
+
if ([...key].length !== 1) return null;
|
|
364
|
+
if (key === " " && searchRef.current === "") return null;
|
|
365
|
+
searchRef.current += key;
|
|
366
|
+
clearTimeout(timerRef.current);
|
|
367
|
+
timerRef.current = setTimeout(() => {
|
|
368
|
+
searchRef.current = "";
|
|
369
|
+
}, TYPEAHEAD_TIMEOUT);
|
|
370
|
+
return searchRef.current;
|
|
371
|
+
}, []);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/menu/MenuPopup.tsx
|
|
321
375
|
function MenuPopup({
|
|
322
376
|
side = "bottom",
|
|
323
377
|
align = "start",
|
|
@@ -336,10 +390,11 @@ function MenuPopup({
|
|
|
336
390
|
anchorName,
|
|
337
391
|
triggerRef
|
|
338
392
|
} = useMenuRootContext("Popup");
|
|
339
|
-
const elementRef = (0,
|
|
340
|
-
const focusPendingRef = (0,
|
|
341
|
-
const [, resync] = (0,
|
|
342
|
-
|
|
393
|
+
const elementRef = (0, import_react6.useRef)(null);
|
|
394
|
+
const focusPendingRef = (0, import_react6.useRef)(false);
|
|
395
|
+
const [, resync] = (0, import_react6.useReducer)((n) => n + 1, 0);
|
|
396
|
+
const typeahead = useTypeahead();
|
|
397
|
+
(0, import_react6.useEffect)(() => {
|
|
343
398
|
const popup = elementRef.current;
|
|
344
399
|
if (!popup || typeof popup.showPopover !== "function") return;
|
|
345
400
|
const shown = popup.matches(":popover-open");
|
|
@@ -378,12 +433,18 @@ function MenuPopup({
|
|
|
378
433
|
}
|
|
379
434
|
const current = navigableItems.findIndex((i) => i.ref.current === event.target);
|
|
380
435
|
if (current < 0 && event.target !== event.currentTarget) return;
|
|
381
|
-
const
|
|
436
|
+
const search = typeahead(event);
|
|
437
|
+
const next = search === null ? rovingIndex(event.key, {
|
|
382
438
|
count: navigableItems.length,
|
|
383
439
|
current,
|
|
384
440
|
orientation: "vertical",
|
|
385
441
|
rtl: false
|
|
386
|
-
})
|
|
442
|
+
}) : typeaheadIndex(
|
|
443
|
+
navigableItems.map((i) => i.textValue),
|
|
444
|
+
current,
|
|
445
|
+
search
|
|
446
|
+
);
|
|
447
|
+
if (search !== null) event.preventDefault();
|
|
387
448
|
if (next === null) return;
|
|
388
449
|
event.preventDefault();
|
|
389
450
|
navigableItems[next]?.ref.current?.focus();
|
|
@@ -399,32 +460,62 @@ function MenuPopup({
|
|
|
399
460
|
});
|
|
400
461
|
}
|
|
401
462
|
|
|
463
|
+
// src/menu/useMenuItem.ts
|
|
464
|
+
var import_react7 = require("react");
|
|
465
|
+
function useMenuItem(part, { disabled, textValue, children }) {
|
|
466
|
+
const { setOpen, focusableWhenDisabled, register } = useMenuRootContext(part);
|
|
467
|
+
const ref = (0, import_react7.useRef)(null);
|
|
468
|
+
const text = textValue ?? textOf(children);
|
|
469
|
+
(0, import_react7.useLayoutEffect)(() => register({ disabled, textValue: text, ref }), [register, disabled, text]);
|
|
470
|
+
return {
|
|
471
|
+
setOpen,
|
|
472
|
+
itemProps: {
|
|
473
|
+
type: "button",
|
|
474
|
+
tabIndex: -1,
|
|
475
|
+
disabled: disabled && !focusableWhenDisabled || void 0,
|
|
476
|
+
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
477
|
+
"data-disabled": disabled ? "" : void 0,
|
|
478
|
+
ref
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
var MenuItemIndicatorContext = (0, import_react7.createContext)(null);
|
|
483
|
+
function useMenuItemIndicatorContext() {
|
|
484
|
+
const context = (0, import_react7.useContext)(MenuItemIndicatorContext);
|
|
485
|
+
if (context === null) {
|
|
486
|
+
throw new Error(
|
|
487
|
+
"<Menu.ItemIndicator> must be rendered inside <Menu.CheckboxItem> or <Menu.RadioItem>."
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
return context;
|
|
491
|
+
}
|
|
492
|
+
function menuCheckableDataAttributes({ checked, disabled }) {
|
|
493
|
+
return {
|
|
494
|
+
"data-checked": checked ? "" : void 0,
|
|
495
|
+
"data-unchecked": checked ? void 0 : "",
|
|
496
|
+
"data-disabled": disabled ? "" : void 0
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
402
500
|
// src/menu/MenuItem.tsx
|
|
403
|
-
var import_react6 = require("react");
|
|
404
501
|
function MenuItem({
|
|
405
502
|
disabled = false,
|
|
503
|
+
textValue,
|
|
406
504
|
onClick,
|
|
407
505
|
className,
|
|
408
506
|
children,
|
|
409
507
|
render,
|
|
410
508
|
...rest
|
|
411
509
|
}) {
|
|
412
|
-
const { setOpen,
|
|
413
|
-
const elementRef = (0, import_react6.useRef)(null);
|
|
414
|
-
(0, import_react6.useLayoutEffect)(() => register({ disabled, ref: elementRef }), [register, disabled]);
|
|
510
|
+
const { setOpen, itemProps } = useMenuItem("Item", { disabled, textValue, children });
|
|
415
511
|
return useRender({
|
|
416
512
|
render,
|
|
417
513
|
defaultTagName: "button",
|
|
418
514
|
props: {
|
|
419
|
-
|
|
515
|
+
...itemProps,
|
|
420
516
|
role: "menuitem",
|
|
421
|
-
tabIndex: -1,
|
|
422
|
-
disabled: disabled && !focusableWhenDisabled || void 0,
|
|
423
|
-
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
424
|
-
...menuItemDataAttributes(disabled),
|
|
425
517
|
className,
|
|
426
518
|
children,
|
|
427
|
-
ref: elementRef,
|
|
428
519
|
onClick() {
|
|
429
520
|
if (!disabled) setOpen(false);
|
|
430
521
|
}
|
|
@@ -432,6 +523,207 @@ function MenuItem({
|
|
|
432
523
|
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
433
524
|
});
|
|
434
525
|
}
|
|
526
|
+
|
|
527
|
+
// src/menu/MenuCheckboxItem.tsx
|
|
528
|
+
var import_react8 = require("react");
|
|
529
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
530
|
+
function MenuCheckboxItem({
|
|
531
|
+
checked: checkedProp,
|
|
532
|
+
defaultChecked,
|
|
533
|
+
onCheckedChange,
|
|
534
|
+
closeOnClick = false,
|
|
535
|
+
disabled = false,
|
|
536
|
+
textValue,
|
|
537
|
+
onClick,
|
|
538
|
+
className,
|
|
539
|
+
children,
|
|
540
|
+
render,
|
|
541
|
+
...rest
|
|
542
|
+
}) {
|
|
543
|
+
const { setOpen, itemProps } = useMenuItem("CheckboxItem", { disabled, textValue, children });
|
|
544
|
+
const [checked, setChecked] = useControlled({
|
|
545
|
+
controlled: checkedProp,
|
|
546
|
+
default: defaultChecked ?? false,
|
|
547
|
+
name: "Menu.CheckboxItem",
|
|
548
|
+
state: "checked"
|
|
549
|
+
});
|
|
550
|
+
const state = (0, import_react8.useMemo)(() => ({ checked, disabled }), [checked, disabled]);
|
|
551
|
+
const element = useRender({
|
|
552
|
+
render,
|
|
553
|
+
defaultTagName: "button",
|
|
554
|
+
props: {
|
|
555
|
+
...itemProps,
|
|
556
|
+
role: "menuitemcheckbox",
|
|
557
|
+
"aria-checked": checked,
|
|
558
|
+
...menuCheckableDataAttributes(state),
|
|
559
|
+
className,
|
|
560
|
+
children,
|
|
561
|
+
onClick() {
|
|
562
|
+
if (disabled) return;
|
|
563
|
+
setChecked(!checked);
|
|
564
|
+
onCheckedChange?.(!checked);
|
|
565
|
+
if (closeOnClick) setOpen(false);
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
569
|
+
});
|
|
570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MenuItemIndicatorContext.Provider, { value: state, children: element });
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// src/menu/MenuRadioGroup.tsx
|
|
574
|
+
var import_react10 = require("react");
|
|
575
|
+
|
|
576
|
+
// src/menu/MenuGroup.tsx
|
|
577
|
+
var import_react9 = require("react");
|
|
578
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
579
|
+
var MenuGroupContext = (0, import_react9.createContext)(null);
|
|
580
|
+
function useMenuGroupContext() {
|
|
581
|
+
return (0, import_react9.useContext)(MenuGroupContext);
|
|
582
|
+
}
|
|
583
|
+
function useMenuGroupElement(part, {
|
|
584
|
+
render,
|
|
585
|
+
props,
|
|
586
|
+
consumerProps
|
|
587
|
+
}) {
|
|
588
|
+
useMenuRootContext(part);
|
|
589
|
+
const labelId = `${(0, import_react9.useId)()}-label`;
|
|
590
|
+
const [hasLabel, setHasLabel] = (0, import_react9.useState)(false);
|
|
591
|
+
const registerLabel = (0, import_react9.useCallback)(() => {
|
|
592
|
+
setHasLabel(true);
|
|
593
|
+
return () => setHasLabel(false);
|
|
594
|
+
}, []);
|
|
595
|
+
const context = (0, import_react9.useMemo)(() => ({ labelId, registerLabel }), [labelId, registerLabel]);
|
|
596
|
+
const element = useRender({
|
|
597
|
+
render,
|
|
598
|
+
defaultTagName: "div",
|
|
599
|
+
props: { role: "group", "aria-labelledby": hasLabel ? labelId : void 0, ...props },
|
|
600
|
+
consumerProps
|
|
601
|
+
});
|
|
602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuGroupContext.Provider, { value: context, children: element });
|
|
603
|
+
}
|
|
604
|
+
function MenuGroup({ className, children, render, ...rest }) {
|
|
605
|
+
return useMenuGroupElement("Group", {
|
|
606
|
+
render,
|
|
607
|
+
props: { className, children },
|
|
608
|
+
consumerProps: rest
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/menu/MenuRadioGroup.tsx
|
|
613
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
614
|
+
var MenuRadioGroupContext = (0, import_react10.createContext)(null);
|
|
615
|
+
function useMenuRadioGroupContext() {
|
|
616
|
+
const context = (0, import_react10.useContext)(MenuRadioGroupContext);
|
|
617
|
+
if (context === null) {
|
|
618
|
+
throw new Error("<Menu.RadioItem> must be rendered inside <Menu.RadioGroup>.");
|
|
619
|
+
}
|
|
620
|
+
return context;
|
|
621
|
+
}
|
|
622
|
+
function MenuRadioGroup({
|
|
623
|
+
value: valueProp,
|
|
624
|
+
defaultValue,
|
|
625
|
+
onValueChange,
|
|
626
|
+
disabled = false,
|
|
627
|
+
className,
|
|
628
|
+
children,
|
|
629
|
+
render,
|
|
630
|
+
...rest
|
|
631
|
+
}) {
|
|
632
|
+
const [value, setValue] = useControlled({
|
|
633
|
+
controlled: valueProp,
|
|
634
|
+
default: defaultValue ?? null,
|
|
635
|
+
name: "Menu.RadioGroup",
|
|
636
|
+
state: "value"
|
|
637
|
+
});
|
|
638
|
+
const select = (0, import_react10.useCallback)(
|
|
639
|
+
(next) => {
|
|
640
|
+
if (next === value) return;
|
|
641
|
+
setValue(next);
|
|
642
|
+
onValueChange?.(next);
|
|
643
|
+
},
|
|
644
|
+
[value, setValue, onValueChange]
|
|
645
|
+
);
|
|
646
|
+
const context = (0, import_react10.useMemo)(() => ({ value, disabled, select }), [value, disabled, select]);
|
|
647
|
+
const element = useMenuGroupElement("RadioGroup", {
|
|
648
|
+
render,
|
|
649
|
+
props: { "data-disabled": disabled ? "" : void 0, className, children },
|
|
650
|
+
consumerProps: rest
|
|
651
|
+
});
|
|
652
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MenuRadioGroupContext.Provider, { value: context, children: element });
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/menu/MenuRadioItem.tsx
|
|
656
|
+
var import_react11 = require("react");
|
|
657
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
658
|
+
function MenuRadioItem({
|
|
659
|
+
value,
|
|
660
|
+
closeOnClick = false,
|
|
661
|
+
disabled: disabledProp = false,
|
|
662
|
+
textValue,
|
|
663
|
+
onClick,
|
|
664
|
+
className,
|
|
665
|
+
children,
|
|
666
|
+
render,
|
|
667
|
+
...rest
|
|
668
|
+
}) {
|
|
669
|
+
const group = useMenuRadioGroupContext();
|
|
670
|
+
const disabled = disabledProp || group.disabled;
|
|
671
|
+
const { setOpen, itemProps } = useMenuItem("RadioItem", { disabled, textValue, children });
|
|
672
|
+
const checked = group.value === value;
|
|
673
|
+
const state = (0, import_react11.useMemo)(() => ({ checked, disabled }), [checked, disabled]);
|
|
674
|
+
const element = useRender({
|
|
675
|
+
render,
|
|
676
|
+
defaultTagName: "button",
|
|
677
|
+
props: {
|
|
678
|
+
...itemProps,
|
|
679
|
+
role: "menuitemradio",
|
|
680
|
+
"aria-checked": checked,
|
|
681
|
+
...menuCheckableDataAttributes(state),
|
|
682
|
+
className,
|
|
683
|
+
children,
|
|
684
|
+
onClick() {
|
|
685
|
+
if (disabled) return;
|
|
686
|
+
group.select(value);
|
|
687
|
+
if (closeOnClick) setOpen(false);
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
691
|
+
});
|
|
692
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MenuItemIndicatorContext.Provider, { value: state, children: element });
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// src/menu/MenuItemIndicator.tsx
|
|
696
|
+
function MenuItemIndicator({
|
|
697
|
+
className,
|
|
698
|
+
children,
|
|
699
|
+
render,
|
|
700
|
+
...rest
|
|
701
|
+
}) {
|
|
702
|
+
const state = useMenuItemIndicatorContext();
|
|
703
|
+
return useRender({
|
|
704
|
+
render,
|
|
705
|
+
defaultTagName: "span",
|
|
706
|
+
props: { "aria-hidden": true, ...menuCheckableDataAttributes(state), className, children },
|
|
707
|
+
consumerProps: rest
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// src/menu/MenuGroupLabel.tsx
|
|
712
|
+
var import_react12 = require("react");
|
|
713
|
+
function MenuGroupLabel({ className, children, render, ...rest }) {
|
|
714
|
+
const group = useMenuGroupContext();
|
|
715
|
+
if (group === null) {
|
|
716
|
+
throw new Error("<Menu.GroupLabel> must be rendered inside <Menu.Group> or <Menu.RadioGroup>.");
|
|
717
|
+
}
|
|
718
|
+
const { labelId, registerLabel } = group;
|
|
719
|
+
(0, import_react12.useLayoutEffect)(registerLabel, [registerLabel]);
|
|
720
|
+
return useRender({
|
|
721
|
+
render,
|
|
722
|
+
defaultTagName: "div",
|
|
723
|
+
props: { id: labelId, className, children },
|
|
724
|
+
consumerProps: rest
|
|
725
|
+
});
|
|
726
|
+
}
|
|
435
727
|
// Annotate the CommonJS export names for ESM import in node:
|
|
436
728
|
0 && (module.exports = {
|
|
437
729
|
Menu
|
package/dist/menu/index.d.cts
CHANGED
|
@@ -68,8 +68,9 @@ type MenuPopupProps = MenuPopupOwnProps & Omit<ComponentPropsWithRef<'div'>, key
|
|
|
68
68
|
* Popover's popup is (decision 12), and labelled by it.
|
|
69
69
|
*
|
|
70
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;
|
|
72
|
-
*
|
|
71
|
+
* and Down then move between items, wrapping, with Home and End; typing moves to the next item
|
|
72
|
+
* whose text starts with what was typed. Disabled items are skipped by both, unless the Root
|
|
73
|
+
* sets `focusableWhenDisabled`. Tab closes the menu and lets focus move on.
|
|
73
74
|
*
|
|
74
75
|
* Light dismiss and Esc close the element before anyone is asked; the `toggle` event
|
|
75
76
|
* reports it through the Root, and the element reopens if the state stays open. Focus
|
|
@@ -83,6 +84,11 @@ type MenuItemOwnProps = {
|
|
|
83
84
|
* `focusableWhenDisabled`.
|
|
84
85
|
*/
|
|
85
86
|
disabled?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* The text typeahead matches. Defaults to the text in `children`; set it when that text is
|
|
89
|
+
* rendered by a component of your own, or differs from what should be typed.
|
|
90
|
+
*/
|
|
91
|
+
textValue?: string;
|
|
86
92
|
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
87
93
|
render?: ReactElement;
|
|
88
94
|
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
@@ -94,17 +100,145 @@ type MenuItemProps = MenuItemOwnProps & Omit<ComponentPropsWithRef<'button'>, ke
|
|
|
94
100
|
* handling here: put the action in `onClick`. Activating it closes the menu — call
|
|
95
101
|
* `event.preventComponentHandler()` in your `onClick` to keep it open.
|
|
96
102
|
*
|
|
97
|
-
*
|
|
103
|
+
* Disabled, your `onClick` is not attached, so an `aria-disabled` item under the Root's
|
|
104
|
+
* `focusableWhenDisabled` cannot run it either.
|
|
105
|
+
*/
|
|
106
|
+
declare function MenuItem({ disabled, textValue, onClick, className, children, render, ...rest }: MenuItemProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
107
|
+
|
|
108
|
+
type MenuCheckboxItemOwnProps = {
|
|
109
|
+
/**
|
|
110
|
+
* Controlled state. Provide `onCheckedChange` alongside it.
|
|
111
|
+
*
|
|
112
|
+
* Never `undefined` once mounted: the mode is latched at mount, as for Checkbox.
|
|
113
|
+
*/
|
|
114
|
+
checked?: boolean;
|
|
115
|
+
/** Initial state when uncontrolled. Read once, at mount. */
|
|
116
|
+
defaultChecked?: boolean;
|
|
117
|
+
/** Called with the new state, in both controlled and uncontrolled modes. */
|
|
118
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
119
|
+
/** Closes the menu when activated. Off by default: a setting is often changed with others. */
|
|
120
|
+
closeOnClick?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Cannot be activated. Skipped by the arrow keys, unless the Root sets
|
|
123
|
+
* `focusableWhenDisabled`.
|
|
124
|
+
*/
|
|
125
|
+
disabled?: boolean;
|
|
126
|
+
/** The text typeahead matches. Defaults to the text in `children`. */
|
|
127
|
+
textValue?: string;
|
|
128
|
+
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
129
|
+
render?: ReactElement;
|
|
130
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
131
|
+
ref?: Ref<HTMLElement>;
|
|
132
|
+
};
|
|
133
|
+
type MenuCheckboxItemProps = MenuCheckboxItemOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuCheckboxItemOwnProps>;
|
|
134
|
+
/**
|
|
135
|
+
* A setting that is on or off: `role="menuitemcheckbox"` with `aria-checked`, on a native
|
|
136
|
+
* `<button>`. Activating it toggles the state and leaves the menu open, unless `closeOnClick`.
|
|
137
|
+
* Your `onClick` runs first; `event.preventComponentHandler()` there stops the toggle.
|
|
98
138
|
*
|
|
99
|
-
*
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
139
|
+
* Holds its own state through `useControlled`; an ItemIndicator inside reads it.
|
|
140
|
+
*/
|
|
141
|
+
declare function MenuCheckboxItem({ checked: checkedProp, defaultChecked, onCheckedChange, closeOnClick, disabled, textValue, onClick, className, children, render, ...rest }: MenuCheckboxItemProps): react.JSX.Element;
|
|
142
|
+
|
|
143
|
+
type MenuRadioGroupOwnProps = {
|
|
144
|
+
/**
|
|
145
|
+
* Controlled value — the `value` of the checked RadioItem, or `null` for none. Provide
|
|
146
|
+
* `onValueChange` alongside it.
|
|
147
|
+
*
|
|
148
|
+
* Never `undefined` once mounted: the mode is latched at mount, as for RadioGroup.
|
|
149
|
+
*/
|
|
150
|
+
value?: string | null;
|
|
151
|
+
/** Initial value when uncontrolled. Read once, at mount. */
|
|
152
|
+
defaultValue?: string | null;
|
|
153
|
+
/** Called with the value of the RadioItem being checked, in both modes. */
|
|
154
|
+
onValueChange?: (value: string) => void;
|
|
155
|
+
/** Disables every RadioItem inside. */
|
|
156
|
+
disabled?: boolean;
|
|
157
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
158
|
+
render?: ReactElement;
|
|
159
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
160
|
+
ref?: Ref<HTMLElement>;
|
|
161
|
+
};
|
|
162
|
+
type MenuRadioGroupProps = MenuRadioGroupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuRadioGroupOwnProps | 'defaultValue'>;
|
|
163
|
+
/**
|
|
164
|
+
* One choice among several: a `role="group"` that owns a value, and the RadioItems inside
|
|
165
|
+
* derive `checked` from it — as RadioGroup does for radios. Named by a GroupLabel inside, as a
|
|
166
|
+
* Group is.
|
|
167
|
+
*/
|
|
168
|
+
declare function MenuRadioGroup({ value: valueProp, defaultValue, onValueChange, disabled, className, children, render, ...rest }: MenuRadioGroupProps): react.JSX.Element;
|
|
169
|
+
|
|
170
|
+
type MenuRadioItemOwnProps = {
|
|
171
|
+
/** This item's value in its RadioGroup. Checked while the group's `value` equals it. */
|
|
172
|
+
value: string;
|
|
173
|
+
/** Closes the menu when activated. Off by default, as for CheckboxItem. */
|
|
174
|
+
closeOnClick?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Cannot be activated. Skipped by the arrow keys, unless the Root sets
|
|
177
|
+
* `focusableWhenDisabled`. The RadioGroup's `disabled` disables it too.
|
|
178
|
+
*/
|
|
179
|
+
disabled?: boolean;
|
|
180
|
+
/** The text typeahead matches. Defaults to the text in `children`. */
|
|
181
|
+
textValue?: string;
|
|
182
|
+
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
183
|
+
render?: ReactElement;
|
|
184
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
185
|
+
ref?: Ref<HTMLElement>;
|
|
186
|
+
};
|
|
187
|
+
type MenuRadioItemProps = MenuRadioItemOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuRadioItemOwnProps>;
|
|
188
|
+
/**
|
|
189
|
+
* One choice in a RadioGroup: `role="menuitemradio"` with `aria-checked`, on a native
|
|
190
|
+
* `<button>`. Activating it checks it and leaves the menu open, unless `closeOnClick`; the
|
|
191
|
+
* checked item stays checked when activated again. Your `onClick` runs first;
|
|
192
|
+
* `event.preventComponentHandler()` there stops the change.
|
|
193
|
+
*/
|
|
194
|
+
declare function MenuRadioItem({ value, closeOnClick, disabled: disabledProp, textValue, onClick, className, children, render, ...rest }: MenuRadioItemProps): react.JSX.Element;
|
|
195
|
+
|
|
196
|
+
type MenuItemIndicatorOwnProps = {
|
|
197
|
+
/** Element to render instead of the default `<span>`. Props and ref are merged onto it. */
|
|
198
|
+
render?: ReactElement;
|
|
199
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
200
|
+
ref?: Ref<HTMLElement>;
|
|
201
|
+
};
|
|
202
|
+
type MenuItemIndicatorProps = MenuItemIndicatorOwnProps & Omit<ComponentPropsWithRef<'span'>, keyof MenuItemIndicatorOwnProps>;
|
|
203
|
+
/**
|
|
204
|
+
* Where the check goes, in a CheckboxItem or a RadioItem — one part for both, since it reads
|
|
205
|
+
* the same `checked` from either. Ships no glyph, as Checkbox.Indicator ships none: supply it as
|
|
206
|
+
* children, or draw it off the `data-*` attributes, which match the item's.
|
|
207
|
+
*
|
|
208
|
+
* Always rendered, in every state, so an unchecked item keeps its space and its label lines up
|
|
209
|
+
* with the checked ones. Hidden from assistive technology: the item announces `aria-checked`.
|
|
210
|
+
*/
|
|
211
|
+
declare function MenuItemIndicator({ className, children, render, ...rest }: MenuItemIndicatorProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
212
|
+
|
|
213
|
+
type MenuGroupOwnProps = {
|
|
214
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
215
|
+
render?: ReactElement;
|
|
216
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
217
|
+
ref?: Ref<HTMLElement>;
|
|
218
|
+
};
|
|
219
|
+
type MenuGroupProps = MenuGroupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuGroupOwnProps>;
|
|
220
|
+
/**
|
|
221
|
+
* Items under a label: `role="group"`, named by its GroupLabel — the menu → group → item
|
|
222
|
+
* structure APG allows. The arrow keys and typeahead run through every group's items as one
|
|
223
|
+
* list, past the labels.
|
|
224
|
+
*/
|
|
225
|
+
declare function MenuGroup({ className, children, render, ...rest }: MenuGroupProps): react.JSX.Element;
|
|
226
|
+
|
|
227
|
+
type MenuGroupLabelOwnProps = {
|
|
228
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
229
|
+
render?: ReactElement;
|
|
230
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
231
|
+
ref?: Ref<HTMLElement>;
|
|
232
|
+
};
|
|
233
|
+
type MenuGroupLabelProps = MenuGroupLabelOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuGroupLabelOwnProps>;
|
|
234
|
+
/**
|
|
235
|
+
* Names its Group or RadioGroup. Shown in the menu, but not an item: it cannot be activated,
|
|
236
|
+
* and the arrow keys and typeahead pass it.
|
|
103
237
|
*/
|
|
104
|
-
declare function
|
|
238
|
+
declare function MenuGroupLabel({ className, children, render, ...rest }: MenuGroupLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
105
239
|
|
|
106
240
|
declare namespace index_parts {
|
|
107
|
-
export { MenuItem as Item, MenuPopup as Popup, MenuRoot as Root, MenuTrigger as Trigger };
|
|
241
|
+
export { MenuCheckboxItem as CheckboxItem, MenuGroup as Group, MenuGroupLabel as GroupLabel, MenuItem as Item, MenuItemIndicator as ItemIndicator, MenuPopup as Popup, MenuRadioGroup as RadioGroup, MenuRadioItem as RadioItem, MenuRoot as Root, MenuTrigger as Trigger };
|
|
108
242
|
}
|
|
109
243
|
|
|
110
244
|
/** The state Menu.Root shares with its parts, and projects as `data-*` attributes. */
|
|
@@ -112,4 +246,4 @@ type MenuState = {
|
|
|
112
246
|
open: boolean;
|
|
113
247
|
};
|
|
114
248
|
|
|
115
|
-
export { index_parts as Menu, type MenuAlign, type MenuItemProps, type MenuPopupProps, type MenuRootProps, type MenuSide, type MenuState, type MenuTriggerProps };
|
|
249
|
+
export { index_parts as Menu, type MenuAlign, type MenuCheckboxItemProps, type MenuGroupLabelProps, type MenuGroupProps, type MenuItemIndicatorProps, type MenuItemProps, type MenuPopupProps, type MenuRadioGroupProps, type MenuRadioItemProps, type MenuRootProps, type MenuSide, type MenuState, type MenuTriggerProps };
|
package/dist/menu/index.d.ts
CHANGED
|
@@ -68,8 +68,9 @@ type MenuPopupProps = MenuPopupOwnProps & Omit<ComponentPropsWithRef<'div'>, key
|
|
|
68
68
|
* Popover's popup is (decision 12), and labelled by it.
|
|
69
69
|
*
|
|
70
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;
|
|
72
|
-
*
|
|
71
|
+
* and Down then move between items, wrapping, with Home and End; typing moves to the next item
|
|
72
|
+
* whose text starts with what was typed. Disabled items are skipped by both, unless the Root
|
|
73
|
+
* sets `focusableWhenDisabled`. Tab closes the menu and lets focus move on.
|
|
73
74
|
*
|
|
74
75
|
* Light dismiss and Esc close the element before anyone is asked; the `toggle` event
|
|
75
76
|
* reports it through the Root, and the element reopens if the state stays open. Focus
|
|
@@ -83,6 +84,11 @@ type MenuItemOwnProps = {
|
|
|
83
84
|
* `focusableWhenDisabled`.
|
|
84
85
|
*/
|
|
85
86
|
disabled?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* The text typeahead matches. Defaults to the text in `children`; set it when that text is
|
|
89
|
+
* rendered by a component of your own, or differs from what should be typed.
|
|
90
|
+
*/
|
|
91
|
+
textValue?: string;
|
|
86
92
|
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
87
93
|
render?: ReactElement;
|
|
88
94
|
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
@@ -94,17 +100,145 @@ type MenuItemProps = MenuItemOwnProps & Omit<ComponentPropsWithRef<'button'>, ke
|
|
|
94
100
|
* handling here: put the action in `onClick`. Activating it closes the menu — call
|
|
95
101
|
* `event.preventComponentHandler()` in your `onClick` to keep it open.
|
|
96
102
|
*
|
|
97
|
-
*
|
|
103
|
+
* Disabled, your `onClick` is not attached, so an `aria-disabled` item under the Root's
|
|
104
|
+
* `focusableWhenDisabled` cannot run it either.
|
|
105
|
+
*/
|
|
106
|
+
declare function MenuItem({ disabled, textValue, onClick, className, children, render, ...rest }: MenuItemProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
107
|
+
|
|
108
|
+
type MenuCheckboxItemOwnProps = {
|
|
109
|
+
/**
|
|
110
|
+
* Controlled state. Provide `onCheckedChange` alongside it.
|
|
111
|
+
*
|
|
112
|
+
* Never `undefined` once mounted: the mode is latched at mount, as for Checkbox.
|
|
113
|
+
*/
|
|
114
|
+
checked?: boolean;
|
|
115
|
+
/** Initial state when uncontrolled. Read once, at mount. */
|
|
116
|
+
defaultChecked?: boolean;
|
|
117
|
+
/** Called with the new state, in both controlled and uncontrolled modes. */
|
|
118
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
119
|
+
/** Closes the menu when activated. Off by default: a setting is often changed with others. */
|
|
120
|
+
closeOnClick?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Cannot be activated. Skipped by the arrow keys, unless the Root sets
|
|
123
|
+
* `focusableWhenDisabled`.
|
|
124
|
+
*/
|
|
125
|
+
disabled?: boolean;
|
|
126
|
+
/** The text typeahead matches. Defaults to the text in `children`. */
|
|
127
|
+
textValue?: string;
|
|
128
|
+
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
129
|
+
render?: ReactElement;
|
|
130
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
131
|
+
ref?: Ref<HTMLElement>;
|
|
132
|
+
};
|
|
133
|
+
type MenuCheckboxItemProps = MenuCheckboxItemOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuCheckboxItemOwnProps>;
|
|
134
|
+
/**
|
|
135
|
+
* A setting that is on or off: `role="menuitemcheckbox"` with `aria-checked`, on a native
|
|
136
|
+
* `<button>`. Activating it toggles the state and leaves the menu open, unless `closeOnClick`.
|
|
137
|
+
* Your `onClick` runs first; `event.preventComponentHandler()` there stops the toggle.
|
|
98
138
|
*
|
|
99
|
-
*
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
139
|
+
* Holds its own state through `useControlled`; an ItemIndicator inside reads it.
|
|
140
|
+
*/
|
|
141
|
+
declare function MenuCheckboxItem({ checked: checkedProp, defaultChecked, onCheckedChange, closeOnClick, disabled, textValue, onClick, className, children, render, ...rest }: MenuCheckboxItemProps): react.JSX.Element;
|
|
142
|
+
|
|
143
|
+
type MenuRadioGroupOwnProps = {
|
|
144
|
+
/**
|
|
145
|
+
* Controlled value — the `value` of the checked RadioItem, or `null` for none. Provide
|
|
146
|
+
* `onValueChange` alongside it.
|
|
147
|
+
*
|
|
148
|
+
* Never `undefined` once mounted: the mode is latched at mount, as for RadioGroup.
|
|
149
|
+
*/
|
|
150
|
+
value?: string | null;
|
|
151
|
+
/** Initial value when uncontrolled. Read once, at mount. */
|
|
152
|
+
defaultValue?: string | null;
|
|
153
|
+
/** Called with the value of the RadioItem being checked, in both modes. */
|
|
154
|
+
onValueChange?: (value: string) => void;
|
|
155
|
+
/** Disables every RadioItem inside. */
|
|
156
|
+
disabled?: boolean;
|
|
157
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
158
|
+
render?: ReactElement;
|
|
159
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
160
|
+
ref?: Ref<HTMLElement>;
|
|
161
|
+
};
|
|
162
|
+
type MenuRadioGroupProps = MenuRadioGroupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuRadioGroupOwnProps | 'defaultValue'>;
|
|
163
|
+
/**
|
|
164
|
+
* One choice among several: a `role="group"` that owns a value, and the RadioItems inside
|
|
165
|
+
* derive `checked` from it — as RadioGroup does for radios. Named by a GroupLabel inside, as a
|
|
166
|
+
* Group is.
|
|
167
|
+
*/
|
|
168
|
+
declare function MenuRadioGroup({ value: valueProp, defaultValue, onValueChange, disabled, className, children, render, ...rest }: MenuRadioGroupProps): react.JSX.Element;
|
|
169
|
+
|
|
170
|
+
type MenuRadioItemOwnProps = {
|
|
171
|
+
/** This item's value in its RadioGroup. Checked while the group's `value` equals it. */
|
|
172
|
+
value: string;
|
|
173
|
+
/** Closes the menu when activated. Off by default, as for CheckboxItem. */
|
|
174
|
+
closeOnClick?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Cannot be activated. Skipped by the arrow keys, unless the Root sets
|
|
177
|
+
* `focusableWhenDisabled`. The RadioGroup's `disabled` disables it too.
|
|
178
|
+
*/
|
|
179
|
+
disabled?: boolean;
|
|
180
|
+
/** The text typeahead matches. Defaults to the text in `children`. */
|
|
181
|
+
textValue?: string;
|
|
182
|
+
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
183
|
+
render?: ReactElement;
|
|
184
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
185
|
+
ref?: Ref<HTMLElement>;
|
|
186
|
+
};
|
|
187
|
+
type MenuRadioItemProps = MenuRadioItemOwnProps & Omit<ComponentPropsWithRef<'button'>, keyof MenuRadioItemOwnProps>;
|
|
188
|
+
/**
|
|
189
|
+
* One choice in a RadioGroup: `role="menuitemradio"` with `aria-checked`, on a native
|
|
190
|
+
* `<button>`. Activating it checks it and leaves the menu open, unless `closeOnClick`; the
|
|
191
|
+
* checked item stays checked when activated again. Your `onClick` runs first;
|
|
192
|
+
* `event.preventComponentHandler()` there stops the change.
|
|
193
|
+
*/
|
|
194
|
+
declare function MenuRadioItem({ value, closeOnClick, disabled: disabledProp, textValue, onClick, className, children, render, ...rest }: MenuRadioItemProps): react.JSX.Element;
|
|
195
|
+
|
|
196
|
+
type MenuItemIndicatorOwnProps = {
|
|
197
|
+
/** Element to render instead of the default `<span>`. Props and ref are merged onto it. */
|
|
198
|
+
render?: ReactElement;
|
|
199
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
200
|
+
ref?: Ref<HTMLElement>;
|
|
201
|
+
};
|
|
202
|
+
type MenuItemIndicatorProps = MenuItemIndicatorOwnProps & Omit<ComponentPropsWithRef<'span'>, keyof MenuItemIndicatorOwnProps>;
|
|
203
|
+
/**
|
|
204
|
+
* Where the check goes, in a CheckboxItem or a RadioItem — one part for both, since it reads
|
|
205
|
+
* the same `checked` from either. Ships no glyph, as Checkbox.Indicator ships none: supply it as
|
|
206
|
+
* children, or draw it off the `data-*` attributes, which match the item's.
|
|
207
|
+
*
|
|
208
|
+
* Always rendered, in every state, so an unchecked item keeps its space and its label lines up
|
|
209
|
+
* with the checked ones. Hidden from assistive technology: the item announces `aria-checked`.
|
|
210
|
+
*/
|
|
211
|
+
declare function MenuItemIndicator({ className, children, render, ...rest }: MenuItemIndicatorProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
212
|
+
|
|
213
|
+
type MenuGroupOwnProps = {
|
|
214
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
215
|
+
render?: ReactElement;
|
|
216
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
217
|
+
ref?: Ref<HTMLElement>;
|
|
218
|
+
};
|
|
219
|
+
type MenuGroupProps = MenuGroupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuGroupOwnProps>;
|
|
220
|
+
/**
|
|
221
|
+
* Items under a label: `role="group"`, named by its GroupLabel — the menu → group → item
|
|
222
|
+
* structure APG allows. The arrow keys and typeahead run through every group's items as one
|
|
223
|
+
* list, past the labels.
|
|
224
|
+
*/
|
|
225
|
+
declare function MenuGroup({ className, children, render, ...rest }: MenuGroupProps): react.JSX.Element;
|
|
226
|
+
|
|
227
|
+
type MenuGroupLabelOwnProps = {
|
|
228
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
229
|
+
render?: ReactElement;
|
|
230
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
231
|
+
ref?: Ref<HTMLElement>;
|
|
232
|
+
};
|
|
233
|
+
type MenuGroupLabelProps = MenuGroupLabelOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof MenuGroupLabelOwnProps>;
|
|
234
|
+
/**
|
|
235
|
+
* Names its Group or RadioGroup. Shown in the menu, but not an item: it cannot be activated,
|
|
236
|
+
* and the arrow keys and typeahead pass it.
|
|
103
237
|
*/
|
|
104
|
-
declare function
|
|
238
|
+
declare function MenuGroupLabel({ className, children, render, ...rest }: MenuGroupLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
105
239
|
|
|
106
240
|
declare namespace index_parts {
|
|
107
|
-
export { MenuItem as Item, MenuPopup as Popup, MenuRoot as Root, MenuTrigger as Trigger };
|
|
241
|
+
export { MenuCheckboxItem as CheckboxItem, MenuGroup as Group, MenuGroupLabel as GroupLabel, MenuItem as Item, MenuItemIndicator as ItemIndicator, MenuPopup as Popup, MenuRadioGroup as RadioGroup, MenuRadioItem as RadioItem, MenuRoot as Root, MenuTrigger as Trigger };
|
|
108
242
|
}
|
|
109
243
|
|
|
110
244
|
/** The state Menu.Root shares with its parts, and projects as `data-*` attributes. */
|
|
@@ -112,4 +246,4 @@ type MenuState = {
|
|
|
112
246
|
open: boolean;
|
|
113
247
|
};
|
|
114
248
|
|
|
115
|
-
export { index_parts as Menu, type MenuAlign, type MenuItemProps, type MenuPopupProps, type MenuRootProps, type MenuSide, type MenuState, type MenuTriggerProps };
|
|
249
|
+
export { index_parts as Menu, type MenuAlign, type MenuCheckboxItemProps, type MenuGroupLabelProps, type MenuGroupProps, type MenuItemIndicatorProps, type MenuItemProps, type MenuPopupProps, type MenuRadioGroupProps, type MenuRadioItemProps, type MenuRootProps, type MenuSide, type MenuState, type MenuTriggerProps };
|
package/dist/menu/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fold
|
|
3
|
+
} from "../chunk-ETNICT5M.js";
|
|
1
4
|
import {
|
|
2
5
|
anchorNameFor,
|
|
3
6
|
anchoredDataAttributes,
|
|
@@ -18,8 +21,14 @@ import {
|
|
|
18
21
|
// src/menu/index.parts.ts
|
|
19
22
|
var index_parts_exports = {};
|
|
20
23
|
__export(index_parts_exports, {
|
|
24
|
+
CheckboxItem: () => MenuCheckboxItem,
|
|
25
|
+
Group: () => MenuGroup,
|
|
26
|
+
GroupLabel: () => MenuGroupLabel,
|
|
21
27
|
Item: () => MenuItem,
|
|
28
|
+
ItemIndicator: () => MenuItemIndicator,
|
|
22
29
|
Popup: () => MenuPopup,
|
|
30
|
+
RadioGroup: () => MenuRadioGroup,
|
|
31
|
+
RadioItem: () => MenuRadioItem,
|
|
23
32
|
Root: () => MenuRoot,
|
|
24
33
|
Trigger: () => MenuTrigger
|
|
25
34
|
});
|
|
@@ -98,9 +107,6 @@ function menuDataAttributes({ open }) {
|
|
|
98
107
|
"data-closed": open ? void 0 : ""
|
|
99
108
|
};
|
|
100
109
|
}
|
|
101
|
-
function menuItemDataAttributes(disabled) {
|
|
102
|
-
return { "data-disabled": disabled ? "" : void 0 };
|
|
103
|
-
}
|
|
104
110
|
|
|
105
111
|
// src/menu/MenuTrigger.tsx
|
|
106
112
|
function MenuTrigger({ className, children, render, ...rest }) {
|
|
@@ -135,7 +141,51 @@ function MenuTrigger({ className, children, render, ...rest }) {
|
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
// src/menu/MenuPopup.tsx
|
|
138
|
-
import { useEffect, useReducer, useRef as
|
|
144
|
+
import { useEffect as useEffect2, useReducer, useRef as useRef3 } from "react";
|
|
145
|
+
|
|
146
|
+
// src/core/typeahead.ts
|
|
147
|
+
import { Children, isValidElement, useCallback as useCallback2, useEffect, useRef as useRef2 } from "react";
|
|
148
|
+
var TYPEAHEAD_TIMEOUT = 500;
|
|
149
|
+
function textOf(node) {
|
|
150
|
+
let text = "";
|
|
151
|
+
Children.forEach(node, (child) => {
|
|
152
|
+
if (typeof child === "string" || typeof child === "number") text += child;
|
|
153
|
+
else if (isValidElement(child)) text += textOf(child.props.children);
|
|
154
|
+
});
|
|
155
|
+
return text;
|
|
156
|
+
}
|
|
157
|
+
function typeaheadIndex(labels, current, search) {
|
|
158
|
+
const count = labels.length;
|
|
159
|
+
if (count === 0 || search === "") return null;
|
|
160
|
+
const [first = "", ...others] = [...search];
|
|
161
|
+
const repeated = others.every((char) => char === first);
|
|
162
|
+
const needle = fold(repeated ? first : search);
|
|
163
|
+
const start = current < 0 ? 0 : repeated ? current + 1 : current;
|
|
164
|
+
for (let step = 0; step < count; step += 1) {
|
|
165
|
+
const index = (start + step) % count;
|
|
166
|
+
if (fold(labels[index] ?? "").startsWith(needle)) return index;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
function useTypeahead() {
|
|
171
|
+
const searchRef = useRef2("");
|
|
172
|
+
const timerRef = useRef2(void 0);
|
|
173
|
+
useEffect(() => () => clearTimeout(timerRef.current), []);
|
|
174
|
+
return useCallback2((event) => {
|
|
175
|
+
const { key } = event;
|
|
176
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return null;
|
|
177
|
+
if ([...key].length !== 1) return null;
|
|
178
|
+
if (key === " " && searchRef.current === "") return null;
|
|
179
|
+
searchRef.current += key;
|
|
180
|
+
clearTimeout(timerRef.current);
|
|
181
|
+
timerRef.current = setTimeout(() => {
|
|
182
|
+
searchRef.current = "";
|
|
183
|
+
}, TYPEAHEAD_TIMEOUT);
|
|
184
|
+
return searchRef.current;
|
|
185
|
+
}, []);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/menu/MenuPopup.tsx
|
|
139
189
|
function MenuPopup({
|
|
140
190
|
side = "bottom",
|
|
141
191
|
align = "start",
|
|
@@ -154,10 +204,11 @@ function MenuPopup({
|
|
|
154
204
|
anchorName,
|
|
155
205
|
triggerRef
|
|
156
206
|
} = useMenuRootContext("Popup");
|
|
157
|
-
const elementRef =
|
|
158
|
-
const focusPendingRef =
|
|
207
|
+
const elementRef = useRef3(null);
|
|
208
|
+
const focusPendingRef = useRef3(false);
|
|
159
209
|
const [, resync] = useReducer((n) => n + 1, 0);
|
|
160
|
-
|
|
210
|
+
const typeahead = useTypeahead();
|
|
211
|
+
useEffect2(() => {
|
|
161
212
|
const popup = elementRef.current;
|
|
162
213
|
if (!popup || typeof popup.showPopover !== "function") return;
|
|
163
214
|
const shown = popup.matches(":popover-open");
|
|
@@ -196,12 +247,18 @@ function MenuPopup({
|
|
|
196
247
|
}
|
|
197
248
|
const current = navigableItems.findIndex((i) => i.ref.current === event.target);
|
|
198
249
|
if (current < 0 && event.target !== event.currentTarget) return;
|
|
199
|
-
const
|
|
250
|
+
const search = typeahead(event);
|
|
251
|
+
const next = search === null ? rovingIndex(event.key, {
|
|
200
252
|
count: navigableItems.length,
|
|
201
253
|
current,
|
|
202
254
|
orientation: "vertical",
|
|
203
255
|
rtl: false
|
|
204
|
-
})
|
|
256
|
+
}) : typeaheadIndex(
|
|
257
|
+
navigableItems.map((i) => i.textValue),
|
|
258
|
+
current,
|
|
259
|
+
search
|
|
260
|
+
);
|
|
261
|
+
if (search !== null) event.preventDefault();
|
|
205
262
|
if (next === null) return;
|
|
206
263
|
event.preventDefault();
|
|
207
264
|
navigableItems[next]?.ref.current?.focus();
|
|
@@ -217,32 +274,62 @@ function MenuPopup({
|
|
|
217
274
|
});
|
|
218
275
|
}
|
|
219
276
|
|
|
277
|
+
// src/menu/useMenuItem.ts
|
|
278
|
+
import { createContext as createContext2, useContext as useContext2, useLayoutEffect, useRef as useRef4 } from "react";
|
|
279
|
+
function useMenuItem(part, { disabled, textValue, children }) {
|
|
280
|
+
const { setOpen, focusableWhenDisabled, register } = useMenuRootContext(part);
|
|
281
|
+
const ref = useRef4(null);
|
|
282
|
+
const text = textValue ?? textOf(children);
|
|
283
|
+
useLayoutEffect(() => register({ disabled, textValue: text, ref }), [register, disabled, text]);
|
|
284
|
+
return {
|
|
285
|
+
setOpen,
|
|
286
|
+
itemProps: {
|
|
287
|
+
type: "button",
|
|
288
|
+
tabIndex: -1,
|
|
289
|
+
disabled: disabled && !focusableWhenDisabled || void 0,
|
|
290
|
+
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
291
|
+
"data-disabled": disabled ? "" : void 0,
|
|
292
|
+
ref
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
var MenuItemIndicatorContext = createContext2(null);
|
|
297
|
+
function useMenuItemIndicatorContext() {
|
|
298
|
+
const context = useContext2(MenuItemIndicatorContext);
|
|
299
|
+
if (context === null) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
"<Menu.ItemIndicator> must be rendered inside <Menu.CheckboxItem> or <Menu.RadioItem>."
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
return context;
|
|
305
|
+
}
|
|
306
|
+
function menuCheckableDataAttributes({ checked, disabled }) {
|
|
307
|
+
return {
|
|
308
|
+
"data-checked": checked ? "" : void 0,
|
|
309
|
+
"data-unchecked": checked ? void 0 : "",
|
|
310
|
+
"data-disabled": disabled ? "" : void 0
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
220
314
|
// src/menu/MenuItem.tsx
|
|
221
|
-
import { useLayoutEffect, useRef as useRef3 } from "react";
|
|
222
315
|
function MenuItem({
|
|
223
316
|
disabled = false,
|
|
317
|
+
textValue,
|
|
224
318
|
onClick,
|
|
225
319
|
className,
|
|
226
320
|
children,
|
|
227
321
|
render,
|
|
228
322
|
...rest
|
|
229
323
|
}) {
|
|
230
|
-
const { setOpen,
|
|
231
|
-
const elementRef = useRef3(null);
|
|
232
|
-
useLayoutEffect(() => register({ disabled, ref: elementRef }), [register, disabled]);
|
|
324
|
+
const { setOpen, itemProps } = useMenuItem("Item", { disabled, textValue, children });
|
|
233
325
|
return useRender({
|
|
234
326
|
render,
|
|
235
327
|
defaultTagName: "button",
|
|
236
328
|
props: {
|
|
237
|
-
|
|
329
|
+
...itemProps,
|
|
238
330
|
role: "menuitem",
|
|
239
|
-
tabIndex: -1,
|
|
240
|
-
disabled: disabled && !focusableWhenDisabled || void 0,
|
|
241
|
-
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
242
|
-
...menuItemDataAttributes(disabled),
|
|
243
331
|
className,
|
|
244
332
|
children,
|
|
245
|
-
ref: elementRef,
|
|
246
333
|
onClick() {
|
|
247
334
|
if (!disabled) setOpen(false);
|
|
248
335
|
}
|
|
@@ -250,6 +337,207 @@ function MenuItem({
|
|
|
250
337
|
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
251
338
|
});
|
|
252
339
|
}
|
|
340
|
+
|
|
341
|
+
// src/menu/MenuCheckboxItem.tsx
|
|
342
|
+
import { useMemo as useMemo2 } from "react";
|
|
343
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
344
|
+
function MenuCheckboxItem({
|
|
345
|
+
checked: checkedProp,
|
|
346
|
+
defaultChecked,
|
|
347
|
+
onCheckedChange,
|
|
348
|
+
closeOnClick = false,
|
|
349
|
+
disabled = false,
|
|
350
|
+
textValue,
|
|
351
|
+
onClick,
|
|
352
|
+
className,
|
|
353
|
+
children,
|
|
354
|
+
render,
|
|
355
|
+
...rest
|
|
356
|
+
}) {
|
|
357
|
+
const { setOpen, itemProps } = useMenuItem("CheckboxItem", { disabled, textValue, children });
|
|
358
|
+
const [checked, setChecked] = useControlled({
|
|
359
|
+
controlled: checkedProp,
|
|
360
|
+
default: defaultChecked ?? false,
|
|
361
|
+
name: "Menu.CheckboxItem",
|
|
362
|
+
state: "checked"
|
|
363
|
+
});
|
|
364
|
+
const state = useMemo2(() => ({ checked, disabled }), [checked, disabled]);
|
|
365
|
+
const element = useRender({
|
|
366
|
+
render,
|
|
367
|
+
defaultTagName: "button",
|
|
368
|
+
props: {
|
|
369
|
+
...itemProps,
|
|
370
|
+
role: "menuitemcheckbox",
|
|
371
|
+
"aria-checked": checked,
|
|
372
|
+
...menuCheckableDataAttributes(state),
|
|
373
|
+
className,
|
|
374
|
+
children,
|
|
375
|
+
onClick() {
|
|
376
|
+
if (disabled) return;
|
|
377
|
+
setChecked(!checked);
|
|
378
|
+
onCheckedChange?.(!checked);
|
|
379
|
+
if (closeOnClick) setOpen(false);
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
383
|
+
});
|
|
384
|
+
return /* @__PURE__ */ jsx2(MenuItemIndicatorContext.Provider, { value: state, children: element });
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/menu/MenuRadioGroup.tsx
|
|
388
|
+
import { createContext as createContext4, useCallback as useCallback4, useContext as useContext4, useMemo as useMemo4 } from "react";
|
|
389
|
+
|
|
390
|
+
// src/menu/MenuGroup.tsx
|
|
391
|
+
import { createContext as createContext3, useCallback as useCallback3, useContext as useContext3, useId as useId2, useMemo as useMemo3, useState as useState2 } from "react";
|
|
392
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
393
|
+
var MenuGroupContext = createContext3(null);
|
|
394
|
+
function useMenuGroupContext() {
|
|
395
|
+
return useContext3(MenuGroupContext);
|
|
396
|
+
}
|
|
397
|
+
function useMenuGroupElement(part, {
|
|
398
|
+
render,
|
|
399
|
+
props,
|
|
400
|
+
consumerProps
|
|
401
|
+
}) {
|
|
402
|
+
useMenuRootContext(part);
|
|
403
|
+
const labelId = `${useId2()}-label`;
|
|
404
|
+
const [hasLabel, setHasLabel] = useState2(false);
|
|
405
|
+
const registerLabel = useCallback3(() => {
|
|
406
|
+
setHasLabel(true);
|
|
407
|
+
return () => setHasLabel(false);
|
|
408
|
+
}, []);
|
|
409
|
+
const context = useMemo3(() => ({ labelId, registerLabel }), [labelId, registerLabel]);
|
|
410
|
+
const element = useRender({
|
|
411
|
+
render,
|
|
412
|
+
defaultTagName: "div",
|
|
413
|
+
props: { role: "group", "aria-labelledby": hasLabel ? labelId : void 0, ...props },
|
|
414
|
+
consumerProps
|
|
415
|
+
});
|
|
416
|
+
return /* @__PURE__ */ jsx3(MenuGroupContext.Provider, { value: context, children: element });
|
|
417
|
+
}
|
|
418
|
+
function MenuGroup({ className, children, render, ...rest }) {
|
|
419
|
+
return useMenuGroupElement("Group", {
|
|
420
|
+
render,
|
|
421
|
+
props: { className, children },
|
|
422
|
+
consumerProps: rest
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/menu/MenuRadioGroup.tsx
|
|
427
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
428
|
+
var MenuRadioGroupContext = createContext4(null);
|
|
429
|
+
function useMenuRadioGroupContext() {
|
|
430
|
+
const context = useContext4(MenuRadioGroupContext);
|
|
431
|
+
if (context === null) {
|
|
432
|
+
throw new Error("<Menu.RadioItem> must be rendered inside <Menu.RadioGroup>.");
|
|
433
|
+
}
|
|
434
|
+
return context;
|
|
435
|
+
}
|
|
436
|
+
function MenuRadioGroup({
|
|
437
|
+
value: valueProp,
|
|
438
|
+
defaultValue,
|
|
439
|
+
onValueChange,
|
|
440
|
+
disabled = false,
|
|
441
|
+
className,
|
|
442
|
+
children,
|
|
443
|
+
render,
|
|
444
|
+
...rest
|
|
445
|
+
}) {
|
|
446
|
+
const [value, setValue] = useControlled({
|
|
447
|
+
controlled: valueProp,
|
|
448
|
+
default: defaultValue ?? null,
|
|
449
|
+
name: "Menu.RadioGroup",
|
|
450
|
+
state: "value"
|
|
451
|
+
});
|
|
452
|
+
const select = useCallback4(
|
|
453
|
+
(next) => {
|
|
454
|
+
if (next === value) return;
|
|
455
|
+
setValue(next);
|
|
456
|
+
onValueChange?.(next);
|
|
457
|
+
},
|
|
458
|
+
[value, setValue, onValueChange]
|
|
459
|
+
);
|
|
460
|
+
const context = useMemo4(() => ({ value, disabled, select }), [value, disabled, select]);
|
|
461
|
+
const element = useMenuGroupElement("RadioGroup", {
|
|
462
|
+
render,
|
|
463
|
+
props: { "data-disabled": disabled ? "" : void 0, className, children },
|
|
464
|
+
consumerProps: rest
|
|
465
|
+
});
|
|
466
|
+
return /* @__PURE__ */ jsx4(MenuRadioGroupContext.Provider, { value: context, children: element });
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/menu/MenuRadioItem.tsx
|
|
470
|
+
import { useMemo as useMemo5 } from "react";
|
|
471
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
472
|
+
function MenuRadioItem({
|
|
473
|
+
value,
|
|
474
|
+
closeOnClick = false,
|
|
475
|
+
disabled: disabledProp = false,
|
|
476
|
+
textValue,
|
|
477
|
+
onClick,
|
|
478
|
+
className,
|
|
479
|
+
children,
|
|
480
|
+
render,
|
|
481
|
+
...rest
|
|
482
|
+
}) {
|
|
483
|
+
const group = useMenuRadioGroupContext();
|
|
484
|
+
const disabled = disabledProp || group.disabled;
|
|
485
|
+
const { setOpen, itemProps } = useMenuItem("RadioItem", { disabled, textValue, children });
|
|
486
|
+
const checked = group.value === value;
|
|
487
|
+
const state = useMemo5(() => ({ checked, disabled }), [checked, disabled]);
|
|
488
|
+
const element = useRender({
|
|
489
|
+
render,
|
|
490
|
+
defaultTagName: "button",
|
|
491
|
+
props: {
|
|
492
|
+
...itemProps,
|
|
493
|
+
role: "menuitemradio",
|
|
494
|
+
"aria-checked": checked,
|
|
495
|
+
...menuCheckableDataAttributes(state),
|
|
496
|
+
className,
|
|
497
|
+
children,
|
|
498
|
+
onClick() {
|
|
499
|
+
if (disabled) return;
|
|
500
|
+
group.select(value);
|
|
501
|
+
if (closeOnClick) setOpen(false);
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
505
|
+
});
|
|
506
|
+
return /* @__PURE__ */ jsx5(MenuItemIndicatorContext.Provider, { value: state, children: element });
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/menu/MenuItemIndicator.tsx
|
|
510
|
+
function MenuItemIndicator({
|
|
511
|
+
className,
|
|
512
|
+
children,
|
|
513
|
+
render,
|
|
514
|
+
...rest
|
|
515
|
+
}) {
|
|
516
|
+
const state = useMenuItemIndicatorContext();
|
|
517
|
+
return useRender({
|
|
518
|
+
render,
|
|
519
|
+
defaultTagName: "span",
|
|
520
|
+
props: { "aria-hidden": true, ...menuCheckableDataAttributes(state), className, children },
|
|
521
|
+
consumerProps: rest
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// src/menu/MenuGroupLabel.tsx
|
|
526
|
+
import { useLayoutEffect as useLayoutEffect2 } from "react";
|
|
527
|
+
function MenuGroupLabel({ className, children, render, ...rest }) {
|
|
528
|
+
const group = useMenuGroupContext();
|
|
529
|
+
if (group === null) {
|
|
530
|
+
throw new Error("<Menu.GroupLabel> must be rendered inside <Menu.Group> or <Menu.RadioGroup>.");
|
|
531
|
+
}
|
|
532
|
+
const { labelId, registerLabel } = group;
|
|
533
|
+
useLayoutEffect2(registerLabel, [registerLabel]);
|
|
534
|
+
return useRender({
|
|
535
|
+
render,
|
|
536
|
+
defaultTagName: "div",
|
|
537
|
+
props: { id: labelId, className, children },
|
|
538
|
+
consumerProps: rest
|
|
539
|
+
});
|
|
540
|
+
}
|
|
253
541
|
export {
|
|
254
542
|
index_parts_exports as Menu
|
|
255
543
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arun-dev/headless",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.15.0",
|
|
4
4
|
"description": "Unstyled React behaviour primitives — render engine, controlled/uncontrolled state, and data-* state projection. Ships no CSS and no class names.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|