@arun-dev/headless 4.9.0 → 4.11.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/combobox/index.cjs +146 -23
- package/dist/combobox/index.d.cts +85 -11
- package/dist/combobox/index.d.ts +85 -11
- package/dist/combobox/index.js +159 -36
- package/package.json +1 -1
package/dist/combobox/index.cjs
CHANGED
|
@@ -32,12 +32,15 @@ __export(index_parts_exports, {
|
|
|
32
32
|
ChipRemove: () => ComboboxChipRemove,
|
|
33
33
|
Clear: () => ComboboxClear,
|
|
34
34
|
Empty: () => ComboboxEmpty,
|
|
35
|
+
Group: () => ComboboxGroup,
|
|
36
|
+
GroupLabel: () => ComboboxGroupLabel,
|
|
35
37
|
Input: () => ComboboxInput,
|
|
36
38
|
InputGroup: () => ComboboxInputGroup,
|
|
37
39
|
Item: () => ComboboxItem,
|
|
38
40
|
List: () => ComboboxList,
|
|
39
41
|
Popup: () => ComboboxPopup,
|
|
40
42
|
Root: () => ComboboxRoot,
|
|
43
|
+
Separator: () => ComboboxSeparator,
|
|
41
44
|
Status: () => ComboboxStatus,
|
|
42
45
|
Trigger: () => ComboboxTrigger,
|
|
43
46
|
Value: () => ComboboxValue
|
|
@@ -169,6 +172,11 @@ function useComboboxRootContext(part) {
|
|
|
169
172
|
|
|
170
173
|
// src/combobox/ComboboxRoot.tsx
|
|
171
174
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
175
|
+
function isGroupList(items) {
|
|
176
|
+
return items.length > 0 && items.every(
|
|
177
|
+
(entry) => entry !== null && typeof entry === "object" && Array.isArray(entry.items)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
172
180
|
function defaultItemToString(item) {
|
|
173
181
|
if (typeof item === "string") return item;
|
|
174
182
|
if (item !== null && typeof item === "object" && "label" in item) return String(item.label);
|
|
@@ -193,6 +201,7 @@ function ComboboxRoot({
|
|
|
193
201
|
onLoadMore,
|
|
194
202
|
loading = false,
|
|
195
203
|
disabled = false,
|
|
204
|
+
required = false,
|
|
196
205
|
name,
|
|
197
206
|
form,
|
|
198
207
|
children
|
|
@@ -229,10 +238,17 @@ function ComboboxRoot({
|
|
|
229
238
|
});
|
|
230
239
|
const query = !multiple && inputValue === selectedLabel ? "" : inputValue;
|
|
231
240
|
const deferredQuery = (0, import_react3.useDeferredValue)(query);
|
|
232
|
-
const filteredItems = (0, import_react3.useMemo)(() => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
241
|
+
const { filteredItems, filteredGroups } = (0, import_react3.useMemo)(() => {
|
|
242
|
+
const run = filter === null ? (list) => list : (list) => (filter ?? defaultFilter)(
|
|
243
|
+
list,
|
|
244
|
+
deferredQuery,
|
|
245
|
+
itemToString
|
|
246
|
+
);
|
|
247
|
+
if (!isGroupList(items)) {
|
|
248
|
+
return { filteredItems: run(items), filteredGroups: null };
|
|
249
|
+
}
|
|
250
|
+
const groups = items.map((group) => ({ ...group, items: run(group.items) })).filter((group) => group.items.length > 0);
|
|
251
|
+
return { filteredItems: groups.flatMap((group) => group.items), filteredGroups: groups };
|
|
236
252
|
}, [items, filter, deferredQuery, itemToString]);
|
|
237
253
|
const indexByKey = (0, import_react3.useMemo)(
|
|
238
254
|
() => new Map(filteredItems.map((item, index) => [itemToKey(item), index])),
|
|
@@ -326,7 +342,7 @@ function ComboboxRoot({
|
|
|
326
342
|
(0, import_react3.useEffect)(() => {
|
|
327
343
|
if (lastSelectedKeyRef.current === selectedKey) return;
|
|
328
344
|
lastSelectedKeyRef.current = selectedKey;
|
|
329
|
-
|
|
345
|
+
setInputValue(selectedLabel, "value-change");
|
|
330
346
|
}, [selectedKey]);
|
|
331
347
|
const [chips, setChips] = (0, import_react3.useState)([]);
|
|
332
348
|
const registerChip = (0, import_react3.useCallback)((entry) => {
|
|
@@ -377,9 +393,11 @@ function ComboboxRoot({
|
|
|
377
393
|
open,
|
|
378
394
|
multiple,
|
|
379
395
|
disabled,
|
|
396
|
+
required,
|
|
380
397
|
inputValue,
|
|
381
398
|
loading,
|
|
382
399
|
filteredItems,
|
|
400
|
+
filteredGroups,
|
|
383
401
|
itemToString,
|
|
384
402
|
itemToKey,
|
|
385
403
|
indexByKey,
|
|
@@ -413,9 +431,11 @@ function ComboboxRoot({
|
|
|
413
431
|
open,
|
|
414
432
|
multiple,
|
|
415
433
|
disabled,
|
|
434
|
+
required,
|
|
416
435
|
inputValue,
|
|
417
436
|
loading,
|
|
418
437
|
filteredItems,
|
|
438
|
+
filteredGroups,
|
|
419
439
|
itemToString,
|
|
420
440
|
itemToKey,
|
|
421
441
|
indexByKey,
|
|
@@ -578,6 +598,7 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
578
598
|
open,
|
|
579
599
|
multiple,
|
|
580
600
|
disabled,
|
|
601
|
+
required,
|
|
581
602
|
inputValue,
|
|
582
603
|
filteredItems,
|
|
583
604
|
itemToKey,
|
|
@@ -606,6 +627,20 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
606
627
|
() => highlight.get().index,
|
|
607
628
|
() => -1
|
|
608
629
|
);
|
|
630
|
+
const missing = required && selectedItems.length === 0;
|
|
631
|
+
const textOnly = missing && inputValue !== "";
|
|
632
|
+
const customValidityRef = (0, import_react5.useRef)(false);
|
|
633
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
634
|
+
const input = inputRef.current;
|
|
635
|
+
if (!input || typeof input.setCustomValidity !== "function") return;
|
|
636
|
+
if (textOnly) {
|
|
637
|
+
input.setCustomValidity(valueMissingMessage());
|
|
638
|
+
customValidityRef.current = true;
|
|
639
|
+
} else if (customValidityRef.current) {
|
|
640
|
+
input.setCustomValidity("");
|
|
641
|
+
customValidityRef.current = false;
|
|
642
|
+
}
|
|
643
|
+
}, [textOnly, inputRef]);
|
|
609
644
|
function enabledIndices() {
|
|
610
645
|
const indices = [];
|
|
611
646
|
filteredItems.forEach((item, index) => {
|
|
@@ -643,6 +678,9 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
643
678
|
"aria-controls": listId,
|
|
644
679
|
"aria-activedescendant": open && highlighted >= 0 ? optionId(highlighted) : void 0,
|
|
645
680
|
disabled: disabled || void 0,
|
|
681
|
+
required: missing || void 0,
|
|
682
|
+
// Stays when a selection lifts `required`: the field is still required.
|
|
683
|
+
"aria-required": required || void 0,
|
|
646
684
|
value: inputValue,
|
|
647
685
|
...comboboxDataAttributes({ open, multiple, disabled }),
|
|
648
686
|
// The anchor, unless an InputGroup around it is.
|
|
@@ -712,6 +750,11 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
712
750
|
consumerProps: rest
|
|
713
751
|
});
|
|
714
752
|
}
|
|
753
|
+
function valueMissingMessage() {
|
|
754
|
+
const probe = document.createElement("input");
|
|
755
|
+
probe.required = true;
|
|
756
|
+
return probe.validationMessage || "Please select an item in the list.";
|
|
757
|
+
}
|
|
715
758
|
|
|
716
759
|
// src/combobox/ComboboxInputGroup.tsx
|
|
717
760
|
var import_react6 = require("react");
|
|
@@ -789,7 +832,8 @@ function ComboboxClear({ className, children, render, ...rest }) {
|
|
|
789
832
|
type: "button",
|
|
790
833
|
tabIndex: -1,
|
|
791
834
|
disabled: disabled || void 0,
|
|
792
|
-
|
|
835
|
+
// Nothing to clear while disabled: a disabled field hides it, as it has no effect.
|
|
836
|
+
...comboboxClearDataAttributes(!disabled && selectedItems.length > 0),
|
|
793
837
|
className,
|
|
794
838
|
children,
|
|
795
839
|
ref: elementRef,
|
|
@@ -872,8 +916,10 @@ function ComboboxList({
|
|
|
872
916
|
render,
|
|
873
917
|
...rest
|
|
874
918
|
}) {
|
|
875
|
-
const { multiple, loading, filteredItems, onLoadMore, listId } = useComboboxRootContext("List");
|
|
876
|
-
const content = typeof children === "function" ? filteredItems.map(
|
|
919
|
+
const { multiple, loading, filteredItems, filteredGroups, onLoadMore, listId } = useComboboxRootContext("List");
|
|
920
|
+
const content = typeof children === "function" ? (filteredGroups ?? filteredItems).map(
|
|
921
|
+
(entry, index) => children(entry, index)
|
|
922
|
+
) : children;
|
|
877
923
|
return useRender({
|
|
878
924
|
render,
|
|
879
925
|
defaultTagName: "div",
|
|
@@ -909,10 +955,52 @@ function LoadMoreSentinel() {
|
|
|
909
955
|
}
|
|
910
956
|
|
|
911
957
|
// src/combobox/ComboboxItem.tsx
|
|
958
|
+
var import_react12 = require("react");
|
|
959
|
+
|
|
960
|
+
// src/combobox/ComboboxGroup.tsx
|
|
912
961
|
var import_react11 = require("react");
|
|
962
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
963
|
+
var ComboboxGroupContext = (0, import_react11.createContext)(null);
|
|
964
|
+
function useComboboxGroupContext() {
|
|
965
|
+
return (0, import_react11.useContext)(ComboboxGroupContext);
|
|
966
|
+
}
|
|
967
|
+
function ComboboxGroup({
|
|
968
|
+
disabled = false,
|
|
969
|
+
className,
|
|
970
|
+
children,
|
|
971
|
+
render,
|
|
972
|
+
...rest
|
|
973
|
+
}) {
|
|
974
|
+
useComboboxRootContext("Group");
|
|
975
|
+
const labelId = `${(0, import_react11.useId)()}-label`;
|
|
976
|
+
const [hasLabel, setHasLabel] = (0, import_react11.useState)(false);
|
|
977
|
+
const registerLabel = (0, import_react11.useCallback)(() => {
|
|
978
|
+
setHasLabel(true);
|
|
979
|
+
return () => setHasLabel(false);
|
|
980
|
+
}, []);
|
|
981
|
+
const context = (0, import_react11.useMemo)(
|
|
982
|
+
() => ({ disabled, labelId, registerLabel }),
|
|
983
|
+
[disabled, labelId, registerLabel]
|
|
984
|
+
);
|
|
985
|
+
const element = useRender({
|
|
986
|
+
render,
|
|
987
|
+
defaultTagName: "div",
|
|
988
|
+
props: {
|
|
989
|
+
role: "group",
|
|
990
|
+
"aria-labelledby": hasLabel ? labelId : void 0,
|
|
991
|
+
"data-disabled": disabled ? "" : void 0,
|
|
992
|
+
className,
|
|
993
|
+
children
|
|
994
|
+
},
|
|
995
|
+
consumerProps: rest
|
|
996
|
+
});
|
|
997
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ComboboxGroupContext.Provider, { value: context, children: element });
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// src/combobox/ComboboxItem.tsx
|
|
913
1001
|
function ComboboxItem({
|
|
914
1002
|
value,
|
|
915
|
-
disabled = false,
|
|
1003
|
+
disabled: disabledProp = false,
|
|
916
1004
|
className,
|
|
917
1005
|
children,
|
|
918
1006
|
render,
|
|
@@ -928,23 +1016,25 @@ function ComboboxItem({
|
|
|
928
1016
|
select,
|
|
929
1017
|
optionId
|
|
930
1018
|
} = useComboboxRootContext("Item");
|
|
1019
|
+
const group = useComboboxGroupContext();
|
|
1020
|
+
const disabled = disabledProp || (group?.disabled ?? false);
|
|
931
1021
|
const key = itemToKey(value);
|
|
932
1022
|
const index = indexByKey.get(key) ?? -1;
|
|
933
1023
|
const selected = selectedKeys.has(key);
|
|
934
|
-
const highlighted = (0,
|
|
1024
|
+
const highlighted = (0, import_react12.useSyncExternalStore)(
|
|
935
1025
|
highlight.subscribe,
|
|
936
1026
|
() => index >= 0 && highlight.get().index === index,
|
|
937
1027
|
() => false
|
|
938
1028
|
);
|
|
939
|
-
const elementRef = (0,
|
|
940
|
-
(0,
|
|
1029
|
+
const elementRef = (0, import_react12.useRef)(null);
|
|
1030
|
+
(0, import_react12.useLayoutEffect)(() => {
|
|
941
1031
|
if (!disabled) return;
|
|
942
1032
|
disabledKeys.add(key);
|
|
943
1033
|
return () => {
|
|
944
1034
|
disabledKeys.delete(key);
|
|
945
1035
|
};
|
|
946
1036
|
}, [disabled, disabledKeys, key]);
|
|
947
|
-
(0,
|
|
1037
|
+
(0, import_react12.useEffect)(() => {
|
|
948
1038
|
if (highlighted && highlight.get().reason === "keyboard") {
|
|
949
1039
|
elementRef.current?.scrollIntoView?.({ block: "nearest" });
|
|
950
1040
|
}
|
|
@@ -975,6 +1065,39 @@ function ComboboxItem({
|
|
|
975
1065
|
});
|
|
976
1066
|
}
|
|
977
1067
|
|
|
1068
|
+
// src/combobox/ComboboxGroupLabel.tsx
|
|
1069
|
+
var import_react13 = require("react");
|
|
1070
|
+
function ComboboxGroupLabel({
|
|
1071
|
+
className,
|
|
1072
|
+
children,
|
|
1073
|
+
render,
|
|
1074
|
+
...rest
|
|
1075
|
+
}) {
|
|
1076
|
+
const group = useComboboxGroupContext();
|
|
1077
|
+
if (group === null) {
|
|
1078
|
+
throw new Error("<Combobox.GroupLabel> must be rendered inside <Combobox.Group>.");
|
|
1079
|
+
}
|
|
1080
|
+
const { labelId, registerLabel } = group;
|
|
1081
|
+
(0, import_react13.useLayoutEffect)(registerLabel, [registerLabel]);
|
|
1082
|
+
return useRender({
|
|
1083
|
+
render,
|
|
1084
|
+
defaultTagName: "div",
|
|
1085
|
+
props: { id: labelId, className, children },
|
|
1086
|
+
consumerProps: rest
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
// src/combobox/ComboboxSeparator.tsx
|
|
1091
|
+
function ComboboxSeparator({ className, render, ...rest }) {
|
|
1092
|
+
useComboboxRootContext("Separator");
|
|
1093
|
+
return useRender({
|
|
1094
|
+
render,
|
|
1095
|
+
defaultTagName: "div",
|
|
1096
|
+
props: { "aria-hidden": true, className },
|
|
1097
|
+
consumerProps: rest
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
|
|
978
1101
|
// src/combobox/ComboboxEmpty.tsx
|
|
979
1102
|
function ComboboxEmpty({ className, children, render, ...rest }) {
|
|
980
1103
|
const { filteredItems, loading } = useComboboxRootContext("Empty");
|
|
@@ -999,11 +1122,11 @@ function ComboboxStatus({ className, children, render, ...rest }) {
|
|
|
999
1122
|
}
|
|
1000
1123
|
|
|
1001
1124
|
// src/combobox/ComboboxChip.tsx
|
|
1002
|
-
var
|
|
1003
|
-
var
|
|
1004
|
-
var ComboboxChipContext = (0,
|
|
1125
|
+
var import_react14 = require("react");
|
|
1126
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1127
|
+
var ComboboxChipContext = (0, import_react14.createContext)(null);
|
|
1005
1128
|
function useComboboxChipContext() {
|
|
1006
|
-
const context = (0,
|
|
1129
|
+
const context = (0, import_react14.useContext)(ComboboxChipContext);
|
|
1007
1130
|
if (context === null) {
|
|
1008
1131
|
throw new Error("<Combobox.ChipRemove> must be rendered inside <Combobox.Chip>.");
|
|
1009
1132
|
}
|
|
@@ -1018,9 +1141,9 @@ function ComboboxChip({
|
|
|
1018
1141
|
}) {
|
|
1019
1142
|
const { disabled, itemToKey, remove, registerChip, chips, inputRef } = useComboboxRootContext("Chip");
|
|
1020
1143
|
const key = itemToKey(value);
|
|
1021
|
-
const elementRef = (0,
|
|
1022
|
-
(0,
|
|
1023
|
-
const chipContext = (0,
|
|
1144
|
+
const elementRef = (0, import_react14.useRef)(null);
|
|
1145
|
+
(0, import_react14.useLayoutEffect)(() => registerChip({ key, ref: elementRef }), [registerChip, key]);
|
|
1146
|
+
const chipContext = (0, import_react14.useMemo)(() => ({ value }), [value]);
|
|
1024
1147
|
function focusAt(index) {
|
|
1025
1148
|
const chip = chips[index];
|
|
1026
1149
|
if (chip) chip.ref.current?.focus();
|
|
@@ -1061,7 +1184,7 @@ function ComboboxChip({
|
|
|
1061
1184
|
},
|
|
1062
1185
|
consumerProps: rest
|
|
1063
1186
|
});
|
|
1064
|
-
return /* @__PURE__ */ (0,
|
|
1187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ComboboxChipContext.Provider, { value: chipContext, children: element });
|
|
1065
1188
|
}
|
|
1066
1189
|
|
|
1067
1190
|
// src/combobox/ComboboxChipRemove.tsx
|
|
@@ -1096,11 +1219,11 @@ function ComboboxChipRemove({
|
|
|
1096
1219
|
}
|
|
1097
1220
|
|
|
1098
1221
|
// src/combobox/ComboboxValue.tsx
|
|
1099
|
-
var
|
|
1222
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1100
1223
|
function ComboboxValue({ children }) {
|
|
1101
1224
|
const { multiple, selectedItems, itemToString } = useComboboxRootContext("Value");
|
|
1102
1225
|
const value = multiple ? selectedItems : selectedItems[0] ?? null;
|
|
1103
|
-
return /* @__PURE__ */ (0,
|
|
1226
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children: children(value, { itemToString }) });
|
|
1104
1227
|
}
|
|
1105
1228
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1106
1229
|
0 && (module.exports = {
|
|
@@ -3,7 +3,9 @@ import { ReactNode, ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
|
3
3
|
import { A as AnchorSide, a as AnchorAlign } from '../anchoring-Btxi0QwC.cjs';
|
|
4
4
|
|
|
5
5
|
/** Why a value, the input's text or the open state changed — the second callback argument. */
|
|
6
|
-
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
6
|
+
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
7
|
+
/** The input's text followed a change of `value` — the parent's, not the user's. */
|
|
8
|
+
| 'value-change';
|
|
7
9
|
type ComboboxChangeDetails = {
|
|
8
10
|
reason: ComboboxChangeReason;
|
|
9
11
|
};
|
|
@@ -24,9 +26,20 @@ type ComboboxState = {
|
|
|
24
26
|
type ComboboxValue$1<T, Multiple extends boolean> = Multiple extends true ? T[] : T | null;
|
|
25
27
|
/** Takes the whole list, so a filter can rank as well as narrow — a fuzzy search, say. */
|
|
26
28
|
type ComboboxFilter<T> = (items: readonly T[], query: string, itemToString: (item: T) => string) => T[];
|
|
29
|
+
/**
|
|
30
|
+
* Items under a label, as an `<optgroup>`: any object with an `items` array — the rest, a
|
|
31
|
+
* label or an id, is yours to render.
|
|
32
|
+
*/
|
|
33
|
+
type ComboboxGroup$1<T> = {
|
|
34
|
+
readonly items: readonly T[];
|
|
35
|
+
};
|
|
27
36
|
type ComboboxRootProps<T, Multiple extends boolean = false> = {
|
|
28
|
-
/**
|
|
29
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Every item the list can show. With server search, the current results. Or groups of
|
|
39
|
+
* them: each an object with an `items` array, which the filter searches and `List` renders
|
|
40
|
+
* one by one, leaving out the groups with no match.
|
|
41
|
+
*/
|
|
42
|
+
items: readonly T[] | readonly ComboboxGroup$1<T>[];
|
|
30
43
|
/**
|
|
31
44
|
* An item's label: what the input shows once it is picked, and what the default filter
|
|
32
45
|
* matches. Defaults to the item itself for strings, else its `label` property.
|
|
@@ -78,6 +91,11 @@ type ComboboxRootProps<T, Multiple extends boolean = false> = {
|
|
|
78
91
|
loading?: boolean;
|
|
79
92
|
/** Disables the input and every button. */
|
|
80
93
|
disabled?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Something must be selected before the form submits. The input is `required` while the
|
|
96
|
+
* selection is empty, so the browser's own validation reports it.
|
|
97
|
+
*/
|
|
98
|
+
required?: boolean;
|
|
81
99
|
/** Submits each selected item's key under this name, from hidden inputs. */
|
|
82
100
|
name?: string;
|
|
83
101
|
/** Associates the hidden inputs with a `<form>` by id, when rendered outside it. */
|
|
@@ -96,7 +114,7 @@ type ComboboxRootProps<T, Multiple extends boolean = false> = {
|
|
|
96
114
|
*
|
|
97
115
|
* Focus stays in the input; the highlighted option is its `aria-activedescendant`.
|
|
98
116
|
*/
|
|
99
|
-
declare function ComboboxRoot<T, Multiple extends boolean = false>({ items, itemToString: itemToStringProp, itemToKey: itemToKeyProp, filter, multiple: multipleProp, value: valueProp, defaultValue, onValueChange, inputValue: inputValueProp, defaultInputValue, onInputValueChange, open: openProp, defaultOpen, onOpenChange, onItemHighlighted, onLoadMore, loading, disabled, name, form, children, }: ComboboxRootProps<T, Multiple>): react.JSX.Element;
|
|
117
|
+
declare function ComboboxRoot<T, Multiple extends boolean = false>({ items, itemToString: itemToStringProp, itemToKey: itemToKeyProp, filter, multiple: multipleProp, value: valueProp, defaultValue, onValueChange, inputValue: inputValueProp, defaultInputValue, onInputValueChange, open: openProp, defaultOpen, onOpenChange, onItemHighlighted, onLoadMore, loading, disabled, required, name, form, children, }: ComboboxRootProps<T, Multiple>): react.JSX.Element;
|
|
100
118
|
|
|
101
119
|
type ComboboxInputOwnProps = {
|
|
102
120
|
/** Element to render instead of the default `<input>`. Props and ref are merged onto it. */
|
|
@@ -114,6 +132,11 @@ type ComboboxInputProps = ComboboxInputOwnProps & Omit<ComponentPropsWithRef<'in
|
|
|
114
132
|
* Enter picks the highlighted item; Esc closes. With `multiple`, Backspace in an empty input
|
|
115
133
|
* removes the last selected item, and Left at the start of the text moves into the chips.
|
|
116
134
|
*
|
|
135
|
+
* With the Root's `required`, the input is `required` while nothing is selected, so the
|
|
136
|
+
* browser's validation reports it, `:invalid` matches it, and `form.checkValidity()` fails.
|
|
137
|
+
* Text typed but not picked is still nothing selected: the input reports `valueMissing`'s
|
|
138
|
+
* message then, through `setCustomValidity`.
|
|
139
|
+
*
|
|
117
140
|
* Leaving the input closes the list and puts the text back: the selected label, or empty
|
|
118
141
|
* with `multiple`.
|
|
119
142
|
*/
|
|
@@ -161,7 +184,8 @@ type ComboboxClearProps = ComboboxClearOwnProps & Omit<ComponentPropsWithRef<'bu
|
|
|
161
184
|
* Empties the input and the selection — every selected item, with `multiple`. Give it an
|
|
162
185
|
* `aria-label`.
|
|
163
186
|
*
|
|
164
|
-
* `data-visible` is present while there is a selection to clear
|
|
187
|
+
* `data-visible` is present while there is a selection to clear and the Root is not disabled;
|
|
188
|
+
* style it hidden otherwise.
|
|
165
189
|
* Out of the tab order, and a press keeps focus in the input.
|
|
166
190
|
*/
|
|
167
191
|
declare function ComboboxClear({ className, children, render, ...rest }: ComboboxClearProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
@@ -194,7 +218,8 @@ declare function ComboboxPopup({ side, align, className, children, render, ...re
|
|
|
194
218
|
type ComboboxListOwnProps<T> = {
|
|
195
219
|
/**
|
|
196
220
|
* A function rendering one `Combobox.Item` per filtered item, or any nodes. With a
|
|
197
|
-
* virtualizer, render only the rows it asks for.
|
|
221
|
+
* virtualizer, render only the rows it asks for. With groups, it is called once per group
|
|
222
|
+
* the filter left an item in, with that group, and renders a `Combobox.Group`.
|
|
198
223
|
*/
|
|
199
224
|
children?: ReactNode | ((item: T, index: number) => ReactNode);
|
|
200
225
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
@@ -204,7 +229,8 @@ type ComboboxListOwnProps<T> = {
|
|
|
204
229
|
};
|
|
205
230
|
type ComboboxListProps<T = unknown> = ComboboxListOwnProps<T> & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxListOwnProps<T>>;
|
|
206
231
|
/**
|
|
207
|
-
* The `role="listbox"`. Given a function, renders it once per item the filter left
|
|
232
|
+
* The `role="listbox"`. Given a function, renders it once per item the filter left — or, when
|
|
233
|
+
* the Root's `items` are groups, once per group.
|
|
208
234
|
*
|
|
209
235
|
* With the Root's `onLoadMore`, an invisible sentinel follows the items; when it scrolls into
|
|
210
236
|
* view and nothing is `loading`, `onLoadMore` is called. The list is `aria-busy` meanwhile.
|
|
@@ -214,7 +240,7 @@ declare function ComboboxList<T = unknown>({ className, children, render, ...res
|
|
|
214
240
|
type ComboboxItemOwnProps<T> = {
|
|
215
241
|
/** The item this option stands for — one of the Root's `items`. */
|
|
216
242
|
value: T;
|
|
217
|
-
/** Cannot be picked, and the arrow keys skip it. */
|
|
243
|
+
/** Cannot be picked, and the arrow keys skip it. A disabled Group disables it too. */
|
|
218
244
|
disabled?: boolean;
|
|
219
245
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
220
246
|
render?: ReactElement;
|
|
@@ -229,7 +255,55 @@ type ComboboxItemProps<T = unknown> = ComboboxItemOwnProps<T> & Omit<ComponentPr
|
|
|
229
255
|
* `data-selected` and `aria-selected` follow the Root's `value`; `data-highlighted` follows
|
|
230
256
|
* the arrow keys and the pointer. Only the items whose highlight changes re-render.
|
|
231
257
|
*/
|
|
232
|
-
declare function ComboboxItem<T = unknown>({ value, disabled, className, children, render, ...rest }: ComboboxItemProps<T>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
258
|
+
declare function ComboboxItem<T = unknown>({ value, disabled: disabledProp, className, children, render, ...rest }: ComboboxItemProps<T>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
259
|
+
|
|
260
|
+
type ComboboxGroupOwnProps = {
|
|
261
|
+
/** Disables every Item inside, as `disabled` on an `<optgroup>` does. */
|
|
262
|
+
disabled?: boolean;
|
|
263
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
264
|
+
render?: ReactElement;
|
|
265
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
266
|
+
ref?: Ref<HTMLElement>;
|
|
267
|
+
};
|
|
268
|
+
type ComboboxGroupProps = ComboboxGroupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxGroupOwnProps>;
|
|
269
|
+
/**
|
|
270
|
+
* Items under a label, as an `<optgroup>`: `role="group"`, named by its GroupLabel. Render one
|
|
271
|
+
* from the List's function for each group of the Root's `items`, with an Item for each of the
|
|
272
|
+
* group's `items` — the filter has already narrowed them, and left out a group with none.
|
|
273
|
+
*
|
|
274
|
+
* The arrow keys run through every group's items as one list, past the labels.
|
|
275
|
+
*/
|
|
276
|
+
declare function ComboboxGroup({ disabled, className, children, render, ...rest }: ComboboxGroupProps): react.JSX.Element;
|
|
277
|
+
|
|
278
|
+
type ComboboxGroupLabelOwnProps = {
|
|
279
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
280
|
+
render?: ReactElement;
|
|
281
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
282
|
+
ref?: Ref<HTMLElement>;
|
|
283
|
+
};
|
|
284
|
+
type ComboboxGroupLabelProps = ComboboxGroupLabelOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxGroupLabelOwnProps>;
|
|
285
|
+
/**
|
|
286
|
+
* Names its Group, as an `<optgroup>`'s `label` does. Shown in the list, but not an option:
|
|
287
|
+
* it cannot be picked, and the arrow keys pass it.
|
|
288
|
+
*/
|
|
289
|
+
declare function ComboboxGroupLabel({ className, children, render, ...rest }: ComboboxGroupLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
290
|
+
|
|
291
|
+
type ComboboxSeparatorOwnProps = {
|
|
292
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
293
|
+
render?: ReactElement;
|
|
294
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
295
|
+
ref?: Ref<HTMLElement>;
|
|
296
|
+
};
|
|
297
|
+
type ComboboxSeparatorProps = ComboboxSeparatorOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxSeparatorOwnProps>;
|
|
298
|
+
/**
|
|
299
|
+
* A line between items or groups in the List, as an `<hr>` in a `<select>`. The arrow keys pass
|
|
300
|
+
* it.
|
|
301
|
+
*
|
|
302
|
+
* Visual only: `aria-hidden`, with no `role="separator"`. A listbox may own only options and
|
|
303
|
+
* groups, so a separator role inside one fails `aria-required-children`; a Group, named by its
|
|
304
|
+
* label, is what tells a screen reader where one set ends.
|
|
305
|
+
*/
|
|
306
|
+
declare function ComboboxSeparator({ className, render, ...rest }: ComboboxSeparatorProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
233
307
|
|
|
234
308
|
type ComboboxEmptyOwnProps = {
|
|
235
309
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
@@ -308,7 +382,7 @@ type ComboboxValueProps<T = unknown> = {
|
|
|
308
382
|
declare function ComboboxValue<T = unknown>({ children }: ComboboxValueProps<T>): react.JSX.Element;
|
|
309
383
|
|
|
310
384
|
declare namespace index_parts {
|
|
311
|
-
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
385
|
+
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxSeparator as Separator, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
312
386
|
}
|
|
313
387
|
|
|
314
388
|
/**
|
|
@@ -319,4 +393,4 @@ declare namespace index_parts {
|
|
|
319
393
|
*/
|
|
320
394
|
declare function defaultFilter<T>(items: readonly T[], query: string, itemToString: (item: T) => string): T[];
|
|
321
395
|
|
|
322
|
-
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
|
396
|
+
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxGroup$1 as ComboboxGroup, type ComboboxGroupLabelProps, type ComboboxGroupProps, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSeparatorProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
package/dist/combobox/index.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { ReactNode, ReactElement, Ref, ComponentPropsWithRef } from 'react';
|
|
|
3
3
|
import { A as AnchorSide, a as AnchorAlign } from '../anchoring-Btxi0QwC.js';
|
|
4
4
|
|
|
5
5
|
/** Why a value, the input's text or the open state changed — the second callback argument. */
|
|
6
|
-
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
6
|
+
type ComboboxChangeReason = 'input' | 'input-press' | 'trigger-press' | 'item-press' | 'keyboard' | 'clear' | 'chip-remove' | 'escape' | 'outside-press' | 'blur' | 'form-reset'
|
|
7
|
+
/** The input's text followed a change of `value` — the parent's, not the user's. */
|
|
8
|
+
| 'value-change';
|
|
7
9
|
type ComboboxChangeDetails = {
|
|
8
10
|
reason: ComboboxChangeReason;
|
|
9
11
|
};
|
|
@@ -24,9 +26,20 @@ type ComboboxState = {
|
|
|
24
26
|
type ComboboxValue$1<T, Multiple extends boolean> = Multiple extends true ? T[] : T | null;
|
|
25
27
|
/** Takes the whole list, so a filter can rank as well as narrow — a fuzzy search, say. */
|
|
26
28
|
type ComboboxFilter<T> = (items: readonly T[], query: string, itemToString: (item: T) => string) => T[];
|
|
29
|
+
/**
|
|
30
|
+
* Items under a label, as an `<optgroup>`: any object with an `items` array — the rest, a
|
|
31
|
+
* label or an id, is yours to render.
|
|
32
|
+
*/
|
|
33
|
+
type ComboboxGroup$1<T> = {
|
|
34
|
+
readonly items: readonly T[];
|
|
35
|
+
};
|
|
27
36
|
type ComboboxRootProps<T, Multiple extends boolean = false> = {
|
|
28
|
-
/**
|
|
29
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Every item the list can show. With server search, the current results. Or groups of
|
|
39
|
+
* them: each an object with an `items` array, which the filter searches and `List` renders
|
|
40
|
+
* one by one, leaving out the groups with no match.
|
|
41
|
+
*/
|
|
42
|
+
items: readonly T[] | readonly ComboboxGroup$1<T>[];
|
|
30
43
|
/**
|
|
31
44
|
* An item's label: what the input shows once it is picked, and what the default filter
|
|
32
45
|
* matches. Defaults to the item itself for strings, else its `label` property.
|
|
@@ -78,6 +91,11 @@ type ComboboxRootProps<T, Multiple extends boolean = false> = {
|
|
|
78
91
|
loading?: boolean;
|
|
79
92
|
/** Disables the input and every button. */
|
|
80
93
|
disabled?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Something must be selected before the form submits. The input is `required` while the
|
|
96
|
+
* selection is empty, so the browser's own validation reports it.
|
|
97
|
+
*/
|
|
98
|
+
required?: boolean;
|
|
81
99
|
/** Submits each selected item's key under this name, from hidden inputs. */
|
|
82
100
|
name?: string;
|
|
83
101
|
/** Associates the hidden inputs with a `<form>` by id, when rendered outside it. */
|
|
@@ -96,7 +114,7 @@ type ComboboxRootProps<T, Multiple extends boolean = false> = {
|
|
|
96
114
|
*
|
|
97
115
|
* Focus stays in the input; the highlighted option is its `aria-activedescendant`.
|
|
98
116
|
*/
|
|
99
|
-
declare function ComboboxRoot<T, Multiple extends boolean = false>({ items, itemToString: itemToStringProp, itemToKey: itemToKeyProp, filter, multiple: multipleProp, value: valueProp, defaultValue, onValueChange, inputValue: inputValueProp, defaultInputValue, onInputValueChange, open: openProp, defaultOpen, onOpenChange, onItemHighlighted, onLoadMore, loading, disabled, name, form, children, }: ComboboxRootProps<T, Multiple>): react.JSX.Element;
|
|
117
|
+
declare function ComboboxRoot<T, Multiple extends boolean = false>({ items, itemToString: itemToStringProp, itemToKey: itemToKeyProp, filter, multiple: multipleProp, value: valueProp, defaultValue, onValueChange, inputValue: inputValueProp, defaultInputValue, onInputValueChange, open: openProp, defaultOpen, onOpenChange, onItemHighlighted, onLoadMore, loading, disabled, required, name, form, children, }: ComboboxRootProps<T, Multiple>): react.JSX.Element;
|
|
100
118
|
|
|
101
119
|
type ComboboxInputOwnProps = {
|
|
102
120
|
/** Element to render instead of the default `<input>`. Props and ref are merged onto it. */
|
|
@@ -114,6 +132,11 @@ type ComboboxInputProps = ComboboxInputOwnProps & Omit<ComponentPropsWithRef<'in
|
|
|
114
132
|
* Enter picks the highlighted item; Esc closes. With `multiple`, Backspace in an empty input
|
|
115
133
|
* removes the last selected item, and Left at the start of the text moves into the chips.
|
|
116
134
|
*
|
|
135
|
+
* With the Root's `required`, the input is `required` while nothing is selected, so the
|
|
136
|
+
* browser's validation reports it, `:invalid` matches it, and `form.checkValidity()` fails.
|
|
137
|
+
* Text typed but not picked is still nothing selected: the input reports `valueMissing`'s
|
|
138
|
+
* message then, through `setCustomValidity`.
|
|
139
|
+
*
|
|
117
140
|
* Leaving the input closes the list and puts the text back: the selected label, or empty
|
|
118
141
|
* with `multiple`.
|
|
119
142
|
*/
|
|
@@ -161,7 +184,8 @@ type ComboboxClearProps = ComboboxClearOwnProps & Omit<ComponentPropsWithRef<'bu
|
|
|
161
184
|
* Empties the input and the selection — every selected item, with `multiple`. Give it an
|
|
162
185
|
* `aria-label`.
|
|
163
186
|
*
|
|
164
|
-
* `data-visible` is present while there is a selection to clear
|
|
187
|
+
* `data-visible` is present while there is a selection to clear and the Root is not disabled;
|
|
188
|
+
* style it hidden otherwise.
|
|
165
189
|
* Out of the tab order, and a press keeps focus in the input.
|
|
166
190
|
*/
|
|
167
191
|
declare function ComboboxClear({ className, children, render, ...rest }: ComboboxClearProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
@@ -194,7 +218,8 @@ declare function ComboboxPopup({ side, align, className, children, render, ...re
|
|
|
194
218
|
type ComboboxListOwnProps<T> = {
|
|
195
219
|
/**
|
|
196
220
|
* A function rendering one `Combobox.Item` per filtered item, or any nodes. With a
|
|
197
|
-
* virtualizer, render only the rows it asks for.
|
|
221
|
+
* virtualizer, render only the rows it asks for. With groups, it is called once per group
|
|
222
|
+
* the filter left an item in, with that group, and renders a `Combobox.Group`.
|
|
198
223
|
*/
|
|
199
224
|
children?: ReactNode | ((item: T, index: number) => ReactNode);
|
|
200
225
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
@@ -204,7 +229,8 @@ type ComboboxListOwnProps<T> = {
|
|
|
204
229
|
};
|
|
205
230
|
type ComboboxListProps<T = unknown> = ComboboxListOwnProps<T> & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxListOwnProps<T>>;
|
|
206
231
|
/**
|
|
207
|
-
* The `role="listbox"`. Given a function, renders it once per item the filter left
|
|
232
|
+
* The `role="listbox"`. Given a function, renders it once per item the filter left — or, when
|
|
233
|
+
* the Root's `items` are groups, once per group.
|
|
208
234
|
*
|
|
209
235
|
* With the Root's `onLoadMore`, an invisible sentinel follows the items; when it scrolls into
|
|
210
236
|
* view and nothing is `loading`, `onLoadMore` is called. The list is `aria-busy` meanwhile.
|
|
@@ -214,7 +240,7 @@ declare function ComboboxList<T = unknown>({ className, children, render, ...res
|
|
|
214
240
|
type ComboboxItemOwnProps<T> = {
|
|
215
241
|
/** The item this option stands for — one of the Root's `items`. */
|
|
216
242
|
value: T;
|
|
217
|
-
/** Cannot be picked, and the arrow keys skip it. */
|
|
243
|
+
/** Cannot be picked, and the arrow keys skip it. A disabled Group disables it too. */
|
|
218
244
|
disabled?: boolean;
|
|
219
245
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
220
246
|
render?: ReactElement;
|
|
@@ -229,7 +255,55 @@ type ComboboxItemProps<T = unknown> = ComboboxItemOwnProps<T> & Omit<ComponentPr
|
|
|
229
255
|
* `data-selected` and `aria-selected` follow the Root's `value`; `data-highlighted` follows
|
|
230
256
|
* the arrow keys and the pointer. Only the items whose highlight changes re-render.
|
|
231
257
|
*/
|
|
232
|
-
declare function ComboboxItem<T = unknown>({ value, disabled, className, children, render, ...rest }: ComboboxItemProps<T>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
258
|
+
declare function ComboboxItem<T = unknown>({ value, disabled: disabledProp, className, children, render, ...rest }: ComboboxItemProps<T>): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
259
|
+
|
|
260
|
+
type ComboboxGroupOwnProps = {
|
|
261
|
+
/** Disables every Item inside, as `disabled` on an `<optgroup>` does. */
|
|
262
|
+
disabled?: boolean;
|
|
263
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
264
|
+
render?: ReactElement;
|
|
265
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
266
|
+
ref?: Ref<HTMLElement>;
|
|
267
|
+
};
|
|
268
|
+
type ComboboxGroupProps = ComboboxGroupOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxGroupOwnProps>;
|
|
269
|
+
/**
|
|
270
|
+
* Items under a label, as an `<optgroup>`: `role="group"`, named by its GroupLabel. Render one
|
|
271
|
+
* from the List's function for each group of the Root's `items`, with an Item for each of the
|
|
272
|
+
* group's `items` — the filter has already narrowed them, and left out a group with none.
|
|
273
|
+
*
|
|
274
|
+
* The arrow keys run through every group's items as one list, past the labels.
|
|
275
|
+
*/
|
|
276
|
+
declare function ComboboxGroup({ disabled, className, children, render, ...rest }: ComboboxGroupProps): react.JSX.Element;
|
|
277
|
+
|
|
278
|
+
type ComboboxGroupLabelOwnProps = {
|
|
279
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
280
|
+
render?: ReactElement;
|
|
281
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
282
|
+
ref?: Ref<HTMLElement>;
|
|
283
|
+
};
|
|
284
|
+
type ComboboxGroupLabelProps = ComboboxGroupLabelOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxGroupLabelOwnProps>;
|
|
285
|
+
/**
|
|
286
|
+
* Names its Group, as an `<optgroup>`'s `label` does. Shown in the list, but not an option:
|
|
287
|
+
* it cannot be picked, and the arrow keys pass it.
|
|
288
|
+
*/
|
|
289
|
+
declare function ComboboxGroupLabel({ className, children, render, ...rest }: ComboboxGroupLabelProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
290
|
+
|
|
291
|
+
type ComboboxSeparatorOwnProps = {
|
|
292
|
+
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
293
|
+
render?: ReactElement;
|
|
294
|
+
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
295
|
+
ref?: Ref<HTMLElement>;
|
|
296
|
+
};
|
|
297
|
+
type ComboboxSeparatorProps = ComboboxSeparatorOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof ComboboxSeparatorOwnProps>;
|
|
298
|
+
/**
|
|
299
|
+
* A line between items or groups in the List, as an `<hr>` in a `<select>`. The arrow keys pass
|
|
300
|
+
* it.
|
|
301
|
+
*
|
|
302
|
+
* Visual only: `aria-hidden`, with no `role="separator"`. A listbox may own only options and
|
|
303
|
+
* groups, so a separator role inside one fails `aria-required-children`; a Group, named by its
|
|
304
|
+
* label, is what tells a screen reader where one set ends.
|
|
305
|
+
*/
|
|
306
|
+
declare function ComboboxSeparator({ className, render, ...rest }: ComboboxSeparatorProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
233
307
|
|
|
234
308
|
type ComboboxEmptyOwnProps = {
|
|
235
309
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
@@ -308,7 +382,7 @@ type ComboboxValueProps<T = unknown> = {
|
|
|
308
382
|
declare function ComboboxValue<T = unknown>({ children }: ComboboxValueProps<T>): react.JSX.Element;
|
|
309
383
|
|
|
310
384
|
declare namespace index_parts {
|
|
311
|
-
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
385
|
+
export { ComboboxChip as Chip, ComboboxChipRemove as ChipRemove, ComboboxClear as Clear, ComboboxEmpty as Empty, ComboboxGroup as Group, ComboboxGroupLabel as GroupLabel, ComboboxInput as Input, ComboboxInputGroup as InputGroup, ComboboxItem as Item, ComboboxList as List, ComboboxPopup as Popup, ComboboxRoot as Root, ComboboxSeparator as Separator, ComboboxStatus as Status, ComboboxTrigger as Trigger, ComboboxValue as Value };
|
|
312
386
|
}
|
|
313
387
|
|
|
314
388
|
/**
|
|
@@ -319,4 +393,4 @@ declare namespace index_parts {
|
|
|
319
393
|
*/
|
|
320
394
|
declare function defaultFilter<T>(items: readonly T[], query: string, itemToString: (item: T) => string): T[];
|
|
321
395
|
|
|
322
|
-
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
|
396
|
+
export { index_parts as Combobox, type ComboboxAlign, type ComboboxChangeDetails, type ComboboxChangeReason, type ComboboxChipProps, type ComboboxChipRemoveProps, type ComboboxClearProps, type ComboboxEmptyProps, type ComboboxFilter, type ComboboxGroup$1 as ComboboxGroup, type ComboboxGroupLabelProps, type ComboboxGroupProps, type ComboboxHighlightDetails, type ComboboxHighlightReason, type ComboboxInputGroupProps, type ComboboxInputProps, type ComboboxItemProps, type ComboboxListProps, type ComboboxPopupProps, type ComboboxRootProps, type ComboboxSeparatorProps, type ComboboxSide, type ComboboxState, type ComboboxStatusProps, type ComboboxTriggerProps, type ComboboxValue$1 as ComboboxValue, type ComboboxValueProps, defaultFilter };
|
package/dist/combobox/index.js
CHANGED
|
@@ -22,12 +22,15 @@ __export(index_parts_exports, {
|
|
|
22
22
|
ChipRemove: () => ComboboxChipRemove,
|
|
23
23
|
Clear: () => ComboboxClear,
|
|
24
24
|
Empty: () => ComboboxEmpty,
|
|
25
|
+
Group: () => ComboboxGroup,
|
|
26
|
+
GroupLabel: () => ComboboxGroupLabel,
|
|
25
27
|
Input: () => ComboboxInput,
|
|
26
28
|
InputGroup: () => ComboboxInputGroup,
|
|
27
29
|
Item: () => ComboboxItem,
|
|
28
30
|
List: () => ComboboxList,
|
|
29
31
|
Popup: () => ComboboxPopup,
|
|
30
32
|
Root: () => ComboboxRoot,
|
|
33
|
+
Separator: () => ComboboxSeparator,
|
|
31
34
|
Status: () => ComboboxStatus,
|
|
32
35
|
Trigger: () => ComboboxTrigger,
|
|
33
36
|
Value: () => ComboboxValue
|
|
@@ -75,6 +78,11 @@ function useComboboxRootContext(part) {
|
|
|
75
78
|
|
|
76
79
|
// src/combobox/ComboboxRoot.tsx
|
|
77
80
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
81
|
+
function isGroupList(items) {
|
|
82
|
+
return items.length > 0 && items.every(
|
|
83
|
+
(entry) => entry !== null && typeof entry === "object" && Array.isArray(entry.items)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
78
86
|
function defaultItemToString(item) {
|
|
79
87
|
if (typeof item === "string") return item;
|
|
80
88
|
if (item !== null && typeof item === "object" && "label" in item) return String(item.label);
|
|
@@ -99,6 +107,7 @@ function ComboboxRoot({
|
|
|
99
107
|
onLoadMore,
|
|
100
108
|
loading = false,
|
|
101
109
|
disabled = false,
|
|
110
|
+
required = false,
|
|
102
111
|
name,
|
|
103
112
|
form,
|
|
104
113
|
children
|
|
@@ -135,10 +144,17 @@ function ComboboxRoot({
|
|
|
135
144
|
});
|
|
136
145
|
const query = !multiple && inputValue === selectedLabel ? "" : inputValue;
|
|
137
146
|
const deferredQuery = useDeferredValue(query);
|
|
138
|
-
const filteredItems = useMemo(() => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
147
|
+
const { filteredItems, filteredGroups } = useMemo(() => {
|
|
148
|
+
const run = filter === null ? (list) => list : (list) => (filter ?? defaultFilter)(
|
|
149
|
+
list,
|
|
150
|
+
deferredQuery,
|
|
151
|
+
itemToString
|
|
152
|
+
);
|
|
153
|
+
if (!isGroupList(items)) {
|
|
154
|
+
return { filteredItems: run(items), filteredGroups: null };
|
|
155
|
+
}
|
|
156
|
+
const groups = items.map((group) => ({ ...group, items: run(group.items) })).filter((group) => group.items.length > 0);
|
|
157
|
+
return { filteredItems: groups.flatMap((group) => group.items), filteredGroups: groups };
|
|
142
158
|
}, [items, filter, deferredQuery, itemToString]);
|
|
143
159
|
const indexByKey = useMemo(
|
|
144
160
|
() => new Map(filteredItems.map((item, index) => [itemToKey(item), index])),
|
|
@@ -232,7 +248,7 @@ function ComboboxRoot({
|
|
|
232
248
|
useEffect(() => {
|
|
233
249
|
if (lastSelectedKeyRef.current === selectedKey) return;
|
|
234
250
|
lastSelectedKeyRef.current = selectedKey;
|
|
235
|
-
|
|
251
|
+
setInputValue(selectedLabel, "value-change");
|
|
236
252
|
}, [selectedKey]);
|
|
237
253
|
const [chips, setChips] = useState([]);
|
|
238
254
|
const registerChip = useCallback((entry) => {
|
|
@@ -283,9 +299,11 @@ function ComboboxRoot({
|
|
|
283
299
|
open,
|
|
284
300
|
multiple,
|
|
285
301
|
disabled,
|
|
302
|
+
required,
|
|
286
303
|
inputValue,
|
|
287
304
|
loading,
|
|
288
305
|
filteredItems,
|
|
306
|
+
filteredGroups,
|
|
289
307
|
itemToString,
|
|
290
308
|
itemToKey,
|
|
291
309
|
indexByKey,
|
|
@@ -319,9 +337,11 @@ function ComboboxRoot({
|
|
|
319
337
|
open,
|
|
320
338
|
multiple,
|
|
321
339
|
disabled,
|
|
340
|
+
required,
|
|
322
341
|
inputValue,
|
|
323
342
|
loading,
|
|
324
343
|
filteredItems,
|
|
344
|
+
filteredGroups,
|
|
325
345
|
itemToString,
|
|
326
346
|
itemToKey,
|
|
327
347
|
indexByKey,
|
|
@@ -364,7 +384,7 @@ function ComboboxRoot({
|
|
|
364
384
|
}
|
|
365
385
|
|
|
366
386
|
// src/combobox/ComboboxInput.tsx
|
|
367
|
-
import { useSyncExternalStore } from "react";
|
|
387
|
+
import { useLayoutEffect, useRef as useRef2, useSyncExternalStore } from "react";
|
|
368
388
|
|
|
369
389
|
// src/combobox/comboboxDataAttributes.ts
|
|
370
390
|
function comboboxDataAttributes({ open, disabled }) {
|
|
@@ -395,6 +415,7 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
395
415
|
open,
|
|
396
416
|
multiple,
|
|
397
417
|
disabled,
|
|
418
|
+
required,
|
|
398
419
|
inputValue,
|
|
399
420
|
filteredItems,
|
|
400
421
|
itemToKey,
|
|
@@ -423,6 +444,20 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
423
444
|
() => highlight.get().index,
|
|
424
445
|
() => -1
|
|
425
446
|
);
|
|
447
|
+
const missing = required && selectedItems.length === 0;
|
|
448
|
+
const textOnly = missing && inputValue !== "";
|
|
449
|
+
const customValidityRef = useRef2(false);
|
|
450
|
+
useLayoutEffect(() => {
|
|
451
|
+
const input = inputRef.current;
|
|
452
|
+
if (!input || typeof input.setCustomValidity !== "function") return;
|
|
453
|
+
if (textOnly) {
|
|
454
|
+
input.setCustomValidity(valueMissingMessage());
|
|
455
|
+
customValidityRef.current = true;
|
|
456
|
+
} else if (customValidityRef.current) {
|
|
457
|
+
input.setCustomValidity("");
|
|
458
|
+
customValidityRef.current = false;
|
|
459
|
+
}
|
|
460
|
+
}, [textOnly, inputRef]);
|
|
426
461
|
function enabledIndices() {
|
|
427
462
|
const indices = [];
|
|
428
463
|
filteredItems.forEach((item, index) => {
|
|
@@ -460,6 +495,9 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
460
495
|
"aria-controls": listId,
|
|
461
496
|
"aria-activedescendant": open && highlighted >= 0 ? optionId(highlighted) : void 0,
|
|
462
497
|
disabled: disabled || void 0,
|
|
498
|
+
required: missing || void 0,
|
|
499
|
+
// Stays when a selection lifts `required`: the field is still required.
|
|
500
|
+
"aria-required": required || void 0,
|
|
463
501
|
value: inputValue,
|
|
464
502
|
...comboboxDataAttributes({ open, multiple, disabled }),
|
|
465
503
|
// The anchor, unless an InputGroup around it is.
|
|
@@ -529,9 +567,14 @@ function ComboboxInput({ className, render, ...rest }) {
|
|
|
529
567
|
consumerProps: rest
|
|
530
568
|
});
|
|
531
569
|
}
|
|
570
|
+
function valueMissingMessage() {
|
|
571
|
+
const probe = document.createElement("input");
|
|
572
|
+
probe.required = true;
|
|
573
|
+
return probe.validationMessage || "Please select an item in the list.";
|
|
574
|
+
}
|
|
532
575
|
|
|
533
576
|
// src/combobox/ComboboxInputGroup.tsx
|
|
534
|
-
import { useLayoutEffect, useRef as
|
|
577
|
+
import { useLayoutEffect as useLayoutEffect2, useRef as useRef3 } from "react";
|
|
535
578
|
function ComboboxInputGroup({
|
|
536
579
|
className,
|
|
537
580
|
children,
|
|
@@ -539,9 +582,9 @@ function ComboboxInputGroup({
|
|
|
539
582
|
...rest
|
|
540
583
|
}) {
|
|
541
584
|
const { open, multiple, disabled, anchorName, registerGroup, registerInside, inputRef } = useComboboxRootContext("InputGroup");
|
|
542
|
-
const elementRef =
|
|
543
|
-
|
|
544
|
-
|
|
585
|
+
const elementRef = useRef3(null);
|
|
586
|
+
useLayoutEffect2(() => registerGroup(), [registerGroup]);
|
|
587
|
+
useLayoutEffect2(() => registerInside(elementRef), [registerInside]);
|
|
545
588
|
return useRender({
|
|
546
589
|
render,
|
|
547
590
|
defaultTagName: "div",
|
|
@@ -562,11 +605,11 @@ function ComboboxInputGroup({
|
|
|
562
605
|
}
|
|
563
606
|
|
|
564
607
|
// src/combobox/ComboboxTrigger.tsx
|
|
565
|
-
import { useLayoutEffect as
|
|
608
|
+
import { useLayoutEffect as useLayoutEffect3, useRef as useRef4 } from "react";
|
|
566
609
|
function ComboboxTrigger({ className, children, render, ...rest }) {
|
|
567
610
|
const { open, multiple, disabled, setOpen, close, listId, inputRef, registerInside } = useComboboxRootContext("Trigger");
|
|
568
|
-
const elementRef =
|
|
569
|
-
|
|
611
|
+
const elementRef = useRef4(null);
|
|
612
|
+
useLayoutEffect3(() => registerInside(elementRef), [registerInside]);
|
|
570
613
|
return useRender({
|
|
571
614
|
render,
|
|
572
615
|
defaultTagName: "button",
|
|
@@ -594,11 +637,11 @@ function ComboboxTrigger({ className, children, render, ...rest }) {
|
|
|
594
637
|
}
|
|
595
638
|
|
|
596
639
|
// src/combobox/ComboboxClear.tsx
|
|
597
|
-
import { useLayoutEffect as
|
|
640
|
+
import { useLayoutEffect as useLayoutEffect4, useRef as useRef5 } from "react";
|
|
598
641
|
function ComboboxClear({ className, children, render, ...rest }) {
|
|
599
642
|
const { disabled, selectedItems, clear, inputRef, registerInside } = useComboboxRootContext("Clear");
|
|
600
|
-
const elementRef =
|
|
601
|
-
|
|
643
|
+
const elementRef = useRef5(null);
|
|
644
|
+
useLayoutEffect4(() => registerInside(elementRef), [registerInside]);
|
|
602
645
|
return useRender({
|
|
603
646
|
render,
|
|
604
647
|
defaultTagName: "button",
|
|
@@ -606,7 +649,8 @@ function ComboboxClear({ className, children, render, ...rest }) {
|
|
|
606
649
|
type: "button",
|
|
607
650
|
tabIndex: -1,
|
|
608
651
|
disabled: disabled || void 0,
|
|
609
|
-
|
|
652
|
+
// Nothing to clear while disabled: a disabled field hides it, as it has no effect.
|
|
653
|
+
...comboboxClearDataAttributes(!disabled && selectedItems.length > 0),
|
|
610
654
|
className,
|
|
611
655
|
children,
|
|
612
656
|
ref: elementRef,
|
|
@@ -681,7 +725,7 @@ function ComboboxPopup({
|
|
|
681
725
|
}
|
|
682
726
|
|
|
683
727
|
// src/combobox/ComboboxList.tsx
|
|
684
|
-
import { useEffect as useEffect3, useRef as
|
|
728
|
+
import { useEffect as useEffect3, useRef as useRef6 } from "react";
|
|
685
729
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
686
730
|
function ComboboxList({
|
|
687
731
|
className,
|
|
@@ -689,8 +733,10 @@ function ComboboxList({
|
|
|
689
733
|
render,
|
|
690
734
|
...rest
|
|
691
735
|
}) {
|
|
692
|
-
const { multiple, loading, filteredItems, onLoadMore, listId } = useComboboxRootContext("List");
|
|
693
|
-
const content = typeof children === "function" ? filteredItems.map(
|
|
736
|
+
const { multiple, loading, filteredItems, filteredGroups, onLoadMore, listId } = useComboboxRootContext("List");
|
|
737
|
+
const content = typeof children === "function" ? (filteredGroups ?? filteredItems).map(
|
|
738
|
+
(entry, index) => children(entry, index)
|
|
739
|
+
) : children;
|
|
694
740
|
return useRender({
|
|
695
741
|
render,
|
|
696
742
|
defaultTagName: "div",
|
|
@@ -710,8 +756,8 @@ function ComboboxList({
|
|
|
710
756
|
}
|
|
711
757
|
function LoadMoreSentinel() {
|
|
712
758
|
const { open, loading, filteredItems, onLoadMore } = useComboboxRootContext("List");
|
|
713
|
-
const ref =
|
|
714
|
-
const onLoadMoreRef =
|
|
759
|
+
const ref = useRef6(null);
|
|
760
|
+
const onLoadMoreRef = useRef6(onLoadMore);
|
|
715
761
|
onLoadMoreRef.current = onLoadMore;
|
|
716
762
|
useEffect3(() => {
|
|
717
763
|
const element = ref.current;
|
|
@@ -726,10 +772,52 @@ function LoadMoreSentinel() {
|
|
|
726
772
|
}
|
|
727
773
|
|
|
728
774
|
// src/combobox/ComboboxItem.tsx
|
|
729
|
-
import { useEffect as useEffect4, useLayoutEffect as
|
|
775
|
+
import { useEffect as useEffect4, useLayoutEffect as useLayoutEffect5, useRef as useRef7, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
776
|
+
|
|
777
|
+
// src/combobox/ComboboxGroup.tsx
|
|
778
|
+
import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useId as useId2, useMemo as useMemo2, useState as useState2 } from "react";
|
|
779
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
780
|
+
var ComboboxGroupContext = createContext2(null);
|
|
781
|
+
function useComboboxGroupContext() {
|
|
782
|
+
return useContext2(ComboboxGroupContext);
|
|
783
|
+
}
|
|
784
|
+
function ComboboxGroup({
|
|
785
|
+
disabled = false,
|
|
786
|
+
className,
|
|
787
|
+
children,
|
|
788
|
+
render,
|
|
789
|
+
...rest
|
|
790
|
+
}) {
|
|
791
|
+
useComboboxRootContext("Group");
|
|
792
|
+
const labelId = `${useId2()}-label`;
|
|
793
|
+
const [hasLabel, setHasLabel] = useState2(false);
|
|
794
|
+
const registerLabel = useCallback2(() => {
|
|
795
|
+
setHasLabel(true);
|
|
796
|
+
return () => setHasLabel(false);
|
|
797
|
+
}, []);
|
|
798
|
+
const context = useMemo2(
|
|
799
|
+
() => ({ disabled, labelId, registerLabel }),
|
|
800
|
+
[disabled, labelId, registerLabel]
|
|
801
|
+
);
|
|
802
|
+
const element = useRender({
|
|
803
|
+
render,
|
|
804
|
+
defaultTagName: "div",
|
|
805
|
+
props: {
|
|
806
|
+
role: "group",
|
|
807
|
+
"aria-labelledby": hasLabel ? labelId : void 0,
|
|
808
|
+
"data-disabled": disabled ? "" : void 0,
|
|
809
|
+
className,
|
|
810
|
+
children
|
|
811
|
+
},
|
|
812
|
+
consumerProps: rest
|
|
813
|
+
});
|
|
814
|
+
return /* @__PURE__ */ jsx3(ComboboxGroupContext.Provider, { value: context, children: element });
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/combobox/ComboboxItem.tsx
|
|
730
818
|
function ComboboxItem({
|
|
731
819
|
value,
|
|
732
|
-
disabled = false,
|
|
820
|
+
disabled: disabledProp = false,
|
|
733
821
|
className,
|
|
734
822
|
children,
|
|
735
823
|
render,
|
|
@@ -745,6 +833,8 @@ function ComboboxItem({
|
|
|
745
833
|
select,
|
|
746
834
|
optionId
|
|
747
835
|
} = useComboboxRootContext("Item");
|
|
836
|
+
const group = useComboboxGroupContext();
|
|
837
|
+
const disabled = disabledProp || (group?.disabled ?? false);
|
|
748
838
|
const key = itemToKey(value);
|
|
749
839
|
const index = indexByKey.get(key) ?? -1;
|
|
750
840
|
const selected = selectedKeys.has(key);
|
|
@@ -753,8 +843,8 @@ function ComboboxItem({
|
|
|
753
843
|
() => index >= 0 && highlight.get().index === index,
|
|
754
844
|
() => false
|
|
755
845
|
);
|
|
756
|
-
const elementRef =
|
|
757
|
-
|
|
846
|
+
const elementRef = useRef7(null);
|
|
847
|
+
useLayoutEffect5(() => {
|
|
758
848
|
if (!disabled) return;
|
|
759
849
|
disabledKeys.add(key);
|
|
760
850
|
return () => {
|
|
@@ -792,6 +882,39 @@ function ComboboxItem({
|
|
|
792
882
|
});
|
|
793
883
|
}
|
|
794
884
|
|
|
885
|
+
// src/combobox/ComboboxGroupLabel.tsx
|
|
886
|
+
import { useLayoutEffect as useLayoutEffect6 } from "react";
|
|
887
|
+
function ComboboxGroupLabel({
|
|
888
|
+
className,
|
|
889
|
+
children,
|
|
890
|
+
render,
|
|
891
|
+
...rest
|
|
892
|
+
}) {
|
|
893
|
+
const group = useComboboxGroupContext();
|
|
894
|
+
if (group === null) {
|
|
895
|
+
throw new Error("<Combobox.GroupLabel> must be rendered inside <Combobox.Group>.");
|
|
896
|
+
}
|
|
897
|
+
const { labelId, registerLabel } = group;
|
|
898
|
+
useLayoutEffect6(registerLabel, [registerLabel]);
|
|
899
|
+
return useRender({
|
|
900
|
+
render,
|
|
901
|
+
defaultTagName: "div",
|
|
902
|
+
props: { id: labelId, className, children },
|
|
903
|
+
consumerProps: rest
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// src/combobox/ComboboxSeparator.tsx
|
|
908
|
+
function ComboboxSeparator({ className, render, ...rest }) {
|
|
909
|
+
useComboboxRootContext("Separator");
|
|
910
|
+
return useRender({
|
|
911
|
+
render,
|
|
912
|
+
defaultTagName: "div",
|
|
913
|
+
props: { "aria-hidden": true, className },
|
|
914
|
+
consumerProps: rest
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
|
|
795
918
|
// src/combobox/ComboboxEmpty.tsx
|
|
796
919
|
function ComboboxEmpty({ className, children, render, ...rest }) {
|
|
797
920
|
const { filteredItems, loading } = useComboboxRootContext("Empty");
|
|
@@ -816,11 +939,11 @@ function ComboboxStatus({ className, children, render, ...rest }) {
|
|
|
816
939
|
}
|
|
817
940
|
|
|
818
941
|
// src/combobox/ComboboxChip.tsx
|
|
819
|
-
import { createContext as
|
|
820
|
-
import { jsx as
|
|
821
|
-
var ComboboxChipContext =
|
|
942
|
+
import { createContext as createContext3, useContext as useContext3, useLayoutEffect as useLayoutEffect7, useMemo as useMemo3, useRef as useRef8 } from "react";
|
|
943
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
944
|
+
var ComboboxChipContext = createContext3(null);
|
|
822
945
|
function useComboboxChipContext() {
|
|
823
|
-
const context =
|
|
946
|
+
const context = useContext3(ComboboxChipContext);
|
|
824
947
|
if (context === null) {
|
|
825
948
|
throw new Error("<Combobox.ChipRemove> must be rendered inside <Combobox.Chip>.");
|
|
826
949
|
}
|
|
@@ -835,9 +958,9 @@ function ComboboxChip({
|
|
|
835
958
|
}) {
|
|
836
959
|
const { disabled, itemToKey, remove, registerChip, chips, inputRef } = useComboboxRootContext("Chip");
|
|
837
960
|
const key = itemToKey(value);
|
|
838
|
-
const elementRef =
|
|
839
|
-
|
|
840
|
-
const chipContext =
|
|
961
|
+
const elementRef = useRef8(null);
|
|
962
|
+
useLayoutEffect7(() => registerChip({ key, ref: elementRef }), [registerChip, key]);
|
|
963
|
+
const chipContext = useMemo3(() => ({ value }), [value]);
|
|
841
964
|
function focusAt(index) {
|
|
842
965
|
const chip = chips[index];
|
|
843
966
|
if (chip) chip.ref.current?.focus();
|
|
@@ -878,7 +1001,7 @@ function ComboboxChip({
|
|
|
878
1001
|
},
|
|
879
1002
|
consumerProps: rest
|
|
880
1003
|
});
|
|
881
|
-
return /* @__PURE__ */
|
|
1004
|
+
return /* @__PURE__ */ jsx4(ComboboxChipContext.Provider, { value: chipContext, children: element });
|
|
882
1005
|
}
|
|
883
1006
|
|
|
884
1007
|
// src/combobox/ComboboxChipRemove.tsx
|
|
@@ -913,11 +1036,11 @@ function ComboboxChipRemove({
|
|
|
913
1036
|
}
|
|
914
1037
|
|
|
915
1038
|
// src/combobox/ComboboxValue.tsx
|
|
916
|
-
import { Fragment as Fragment2, jsx as
|
|
1039
|
+
import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
|
|
917
1040
|
function ComboboxValue({ children }) {
|
|
918
1041
|
const { multiple, selectedItems, itemToString } = useComboboxRootContext("Value");
|
|
919
1042
|
const value = multiple ? selectedItems : selectedItems[0] ?? null;
|
|
920
|
-
return /* @__PURE__ */
|
|
1043
|
+
return /* @__PURE__ */ jsx5(Fragment2, { children: children(value, { itemToString }) });
|
|
921
1044
|
}
|
|
922
1045
|
export {
|
|
923
1046
|
index_parts_exports as Combobox,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arun-dev/headless",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.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",
|