@arun-dev/headless 4.6.0 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1057 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/combobox/index.ts
21
+ var combobox_exports = {};
22
+ __export(combobox_exports, {
23
+ Combobox: () => index_parts_exports,
24
+ defaultFilter: () => defaultFilter
25
+ });
26
+ module.exports = __toCommonJS(combobox_exports);
27
+
28
+ // src/combobox/index.parts.ts
29
+ var index_parts_exports = {};
30
+ __export(index_parts_exports, {
31
+ Chip: () => ComboboxChip,
32
+ ChipRemove: () => ComboboxChipRemove,
33
+ Clear: () => ComboboxClear,
34
+ Empty: () => ComboboxEmpty,
35
+ Input: () => ComboboxInput,
36
+ Item: () => ComboboxItem,
37
+ List: () => ComboboxList,
38
+ Popup: () => ComboboxPopup,
39
+ Root: () => ComboboxRoot,
40
+ Status: () => ComboboxStatus,
41
+ Trigger: () => ComboboxTrigger
42
+ });
43
+
44
+ // src/combobox/ComboboxRoot.tsx
45
+ var import_react3 = require("react");
46
+
47
+ // src/core/anchoring.ts
48
+ function anchorNameFor(id) {
49
+ return `--hl-anchor-${id.replace(/[^a-zA-Z0-9_-]/g, "")}`;
50
+ }
51
+ var POSITION_AREA = {
52
+ bottom: { start: "bottom span-right", center: "bottom", end: "bottom span-left" },
53
+ top: { start: "top span-right", center: "top", end: "top span-left" },
54
+ right: { start: "right span-bottom", center: "right", end: "right span-top" },
55
+ left: { start: "left span-bottom", center: "left", end: "left span-top" }
56
+ };
57
+ function anchoredPopupStyle(anchorName, side, align) {
58
+ return {
59
+ positionAnchor: anchorName,
60
+ positionArea: POSITION_AREA[side][align],
61
+ // Flip across the axis it opens on; the other axis is left alone.
62
+ positionTryFallbacks: side === "top" || side === "bottom" ? "flip-block" : "flip-inline"
63
+ };
64
+ }
65
+ function anchoredDataAttributes(side, align) {
66
+ return { "data-side": side, "data-align": align };
67
+ }
68
+
69
+ // src/core/rovingFocus.ts
70
+ function byDocumentOrder(a, b) {
71
+ const x = a.ref.current;
72
+ const y = b.ref.current;
73
+ if (!x || !y) return 0;
74
+ return x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
75
+ }
76
+ function rovingIndex(key, {
77
+ count,
78
+ current,
79
+ orientation,
80
+ rtl
81
+ }) {
82
+ if (count === 0) return null;
83
+ const [prevKey, nextKey] = orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : rtl ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"];
84
+ switch (key) {
85
+ case nextKey:
86
+ return current < 0 ? 0 : (current + 1) % count;
87
+ case prevKey:
88
+ return current < 0 ? count - 1 : (current - 1 + count) % count;
89
+ case "Home":
90
+ return 0;
91
+ case "End":
92
+ return count - 1;
93
+ default:
94
+ return null;
95
+ }
96
+ }
97
+
98
+ // src/core/useControlled.ts
99
+ var import_react = require("react");
100
+ function useControlled({
101
+ controlled,
102
+ default: defaultValue,
103
+ name = "Component",
104
+ state = "value"
105
+ }) {
106
+ const { current: isControlled } = (0, import_react.useRef)(controlled !== void 0);
107
+ const [uncontrolled, setUncontrolled] = (0, import_react.useState)(defaultValue);
108
+ const defaultRef = (0, import_react.useRef)(defaultValue);
109
+ const value = isControlled ? controlled : uncontrolled;
110
+ if (process.env.NODE_ENV !== "production") {
111
+ if (isControlled !== (controlled !== void 0)) {
112
+ console.error(
113
+ `${name}: cannot switch between controlled and uncontrolled \`${state}\`. Decide which one this component is for the whole of its life.`
114
+ );
115
+ }
116
+ if (!isControlled && defaultRef.current !== defaultValue) {
117
+ console.error(
118
+ `${name}: cannot change the default \`${state}\` after mount. It is only read once, so later changes are silently ignored.`
119
+ );
120
+ }
121
+ }
122
+ const setValue = (0, import_react.useCallback)(
123
+ (next) => {
124
+ if (!isControlled) setUncontrolled(next);
125
+ },
126
+ [isControlled]
127
+ );
128
+ return [value, setValue];
129
+ }
130
+
131
+ // src/combobox/defaultFilter.ts
132
+ function fold(text) {
133
+ return text.normalize("NFD").replace(/\p{M}/gu, "").toLocaleLowerCase();
134
+ }
135
+ function defaultFilter(items, query, itemToString) {
136
+ const needle = fold(query.trim());
137
+ if (needle === "") return [...items];
138
+ return items.filter((item) => fold(itemToString(item)).includes(needle));
139
+ }
140
+
141
+ // src/combobox/ComboboxRootContext.ts
142
+ var import_react2 = require("react");
143
+ function createHighlightStore() {
144
+ let current = { index: -1, reason: "none" };
145
+ const listeners = /* @__PURE__ */ new Set();
146
+ return {
147
+ get: () => current,
148
+ set(next) {
149
+ if (next.index === current.index && next.reason === current.reason) return;
150
+ current = next;
151
+ for (const listener of listeners) listener();
152
+ },
153
+ subscribe(listener) {
154
+ listeners.add(listener);
155
+ return () => listeners.delete(listener);
156
+ }
157
+ };
158
+ }
159
+ var ComboboxRootContext = (0, import_react2.createContext)(null);
160
+ function useComboboxRootContext(part) {
161
+ const context = (0, import_react2.useContext)(ComboboxRootContext);
162
+ if (context === null) {
163
+ throw new Error(`<Combobox.${part}> must be rendered inside <Combobox.Root>.`);
164
+ }
165
+ return context;
166
+ }
167
+
168
+ // src/combobox/ComboboxRoot.tsx
169
+ var import_jsx_runtime = require("react/jsx-runtime");
170
+ function defaultItemToString(item) {
171
+ if (typeof item === "string") return item;
172
+ if (item !== null && typeof item === "object" && "label" in item) return String(item.label);
173
+ return String(item);
174
+ }
175
+ function ComboboxRoot({
176
+ items,
177
+ itemToString: itemToStringProp,
178
+ itemToKey: itemToKeyProp,
179
+ filter,
180
+ multiple: multipleProp,
181
+ value: valueProp,
182
+ defaultValue,
183
+ onValueChange,
184
+ inputValue: inputValueProp,
185
+ defaultInputValue,
186
+ onInputValueChange,
187
+ open: openProp,
188
+ defaultOpen,
189
+ onOpenChange,
190
+ onItemHighlighted,
191
+ onLoadMore,
192
+ loading = false,
193
+ disabled = false,
194
+ name,
195
+ form,
196
+ children
197
+ }) {
198
+ const multiple = multipleProp === true;
199
+ const itemToString = itemToStringProp ?? defaultItemToString;
200
+ const itemToKey = itemToKeyProp ?? itemToString;
201
+ const [value, setValueState] = useControlled({
202
+ controlled: valueProp,
203
+ default: defaultValue ?? (multiple ? [] : null),
204
+ name: "Combobox.Root",
205
+ state: "value"
206
+ });
207
+ const selectedItems = (0, import_react3.useMemo)(
208
+ () => multiple ? value : value == null ? [] : [value],
209
+ [multiple, value]
210
+ );
211
+ const selectedKeys = (0, import_react3.useMemo)(
212
+ () => new Set(selectedItems.map((item) => itemToKey(item))),
213
+ [selectedItems, itemToKey]
214
+ );
215
+ const selectedLabel = !multiple && selectedItems[0] != null ? itemToString(selectedItems[0]) : "";
216
+ const [inputValue, setInputValueState] = useControlled({
217
+ controlled: inputValueProp,
218
+ default: defaultInputValue ?? selectedLabel,
219
+ name: "Combobox.Root",
220
+ state: "inputValue"
221
+ });
222
+ const [open, setOpenState] = useControlled({
223
+ controlled: openProp,
224
+ default: defaultOpen ?? false,
225
+ name: "Combobox.Root",
226
+ state: "open"
227
+ });
228
+ const query = !multiple && inputValue === selectedLabel ? "" : inputValue;
229
+ const deferredQuery = (0, import_react3.useDeferredValue)(query);
230
+ const filteredItems = (0, import_react3.useMemo)(() => {
231
+ if (filter === null) return items;
232
+ const run = filter ?? defaultFilter;
233
+ return run(items, deferredQuery, itemToString);
234
+ }, [items, filter, deferredQuery, itemToString]);
235
+ const indexByKey = (0, import_react3.useMemo)(
236
+ () => new Map(filteredItems.map((item, index) => [itemToKey(item), index])),
237
+ [filteredItems, itemToKey]
238
+ );
239
+ const [highlight] = (0, import_react3.useState)(createHighlightStore);
240
+ const setHighlight = (0, import_react3.useCallback)(
241
+ (index, reason) => {
242
+ if (highlight.get().index === index && highlight.get().reason === reason) return;
243
+ highlight.set({ index, reason });
244
+ onItemHighlighted?.(filteredItems[index], { index, reason });
245
+ },
246
+ [highlight, filteredItems, onItemHighlighted]
247
+ );
248
+ (0, import_react3.useEffect)(() => {
249
+ if (highlight.get().index !== -1) setHighlight(-1, "none");
250
+ }, [filteredItems]);
251
+ const setValue = (0, import_react3.useCallback)(
252
+ (next, reason) => {
253
+ setValueState(next);
254
+ onValueChange?.(next, {
255
+ reason
256
+ });
257
+ },
258
+ [setValueState, onValueChange]
259
+ );
260
+ const setInputValue = (0, import_react3.useCallback)(
261
+ (next, reason) => {
262
+ if (next === inputValue) return;
263
+ setInputValueState(next);
264
+ onInputValueChange?.(next, { reason });
265
+ },
266
+ [inputValue, setInputValueState, onInputValueChange]
267
+ );
268
+ const setOpen = (0, import_react3.useCallback)(
269
+ (next, reason) => {
270
+ if (next === open) return;
271
+ setOpenState(next);
272
+ onOpenChange?.(next, { reason });
273
+ if (!next) setHighlight(-1, "none");
274
+ },
275
+ [open, setOpenState, onOpenChange, setHighlight]
276
+ );
277
+ const close = (0, import_react3.useCallback)(
278
+ (reason) => {
279
+ setOpen(false, reason);
280
+ setInputValue(selectedLabel, reason);
281
+ },
282
+ [setOpen, setInputValue, selectedLabel]
283
+ );
284
+ const select = (0, import_react3.useCallback)(
285
+ (item) => {
286
+ const key = itemToKey(item);
287
+ if (multiple) {
288
+ const current = value;
289
+ setValue(
290
+ selectedKeys.has(key) ? current.filter((i) => itemToKey(i) !== key) : [...current, item],
291
+ "item-press"
292
+ );
293
+ setInputValue("", "item-press");
294
+ } else {
295
+ if (!selectedKeys.has(key)) setValue(item, "item-press");
296
+ setInputValue(itemToString(item), "item-press");
297
+ }
298
+ setOpen(false, "item-press");
299
+ },
300
+ [multiple, value, selectedKeys, itemToKey, itemToString, setValue, setInputValue, setOpen]
301
+ );
302
+ const remove = (0, import_react3.useCallback)(
303
+ (item, reason) => {
304
+ if (!multiple) return;
305
+ const key = itemToKey(item);
306
+ setValue(
307
+ value.filter((i) => itemToKey(i) !== key),
308
+ reason
309
+ );
310
+ },
311
+ [multiple, value, itemToKey, setValue]
312
+ );
313
+ const clearSelection = (0, import_react3.useCallback)(
314
+ (reason) => setValue(multiple ? [] : null, reason),
315
+ [multiple, setValue]
316
+ );
317
+ const clear = (0, import_react3.useCallback)(() => {
318
+ setInputValue("", "clear");
319
+ clearSelection("clear");
320
+ setHighlight(-1, "none");
321
+ }, [setInputValue, clearSelection, setHighlight]);
322
+ const selectedKey = !multiple && selectedItems[0] != null ? itemToKey(selectedItems[0]) : null;
323
+ const lastSelectedKeyRef = (0, import_react3.useRef)(selectedKey);
324
+ (0, import_react3.useEffect)(() => {
325
+ if (lastSelectedKeyRef.current === selectedKey) return;
326
+ lastSelectedKeyRef.current = selectedKey;
327
+ setInputValueState(selectedLabel);
328
+ }, [selectedKey]);
329
+ const [chips, setChips] = (0, import_react3.useState)([]);
330
+ const registerChip = (0, import_react3.useCallback)((entry) => {
331
+ setChips((current) => [...current, entry].sort(byDocumentOrder));
332
+ return () => setChips((current) => current.filter((c) => c !== entry));
333
+ }, []);
334
+ const [disabledKeys] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set());
335
+ const [insideRefs] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set());
336
+ const registerInside = (0, import_react3.useCallback)(
337
+ (ref) => {
338
+ insideRefs.add(ref);
339
+ return () => {
340
+ insideRefs.delete(ref);
341
+ };
342
+ },
343
+ [insideRefs]
344
+ );
345
+ const inputRef = (0, import_react3.useRef)(null);
346
+ const popupRef = (0, import_react3.useRef)(null);
347
+ const { current: initial } = (0, import_react3.useRef)({ value, inputValue });
348
+ (0, import_react3.useEffect)(() => {
349
+ const owner = inputRef.current?.form;
350
+ if (!owner) return;
351
+ function onReset(event) {
352
+ queueMicrotask(() => {
353
+ if (event.defaultPrevented) return;
354
+ if (value !== initial.value) setValue(initial.value, "form-reset");
355
+ setInputValue(initial.inputValue, "form-reset");
356
+ });
357
+ }
358
+ owner.addEventListener("reset", onReset);
359
+ return () => owner.removeEventListener("reset", onReset);
360
+ }, [value, initial, setValue, setInputValue]);
361
+ const isInside = (0, import_react3.useCallback)(
362
+ (node) => [inputRef, popupRef, ...insideRefs, ...chips.map((chip) => chip.ref)].some(
363
+ (ref) => ref.current?.contains(node) ?? false
364
+ ),
365
+ [insideRefs, chips]
366
+ );
367
+ const id = (0, import_react3.useId)();
368
+ const context = (0, import_react3.useMemo)(
369
+ () => ({
370
+ open,
371
+ multiple,
372
+ disabled,
373
+ inputValue,
374
+ loading,
375
+ filteredItems,
376
+ itemToString,
377
+ itemToKey,
378
+ indexByKey,
379
+ selectedKeys,
380
+ selectedItems,
381
+ disabledKeys,
382
+ highlight,
383
+ setHighlight,
384
+ setOpen,
385
+ setInputValue,
386
+ select,
387
+ remove,
388
+ clearSelection,
389
+ clear,
390
+ close,
391
+ registerChip,
392
+ chips,
393
+ registerInside,
394
+ isInside,
395
+ onLoadMore,
396
+ inputId: `${id}-input`,
397
+ listId: `${id}-list`,
398
+ optionId: (index) => `${id}-option-${index}`,
399
+ anchorName: anchorNameFor(id),
400
+ inputRef,
401
+ popupRef
402
+ }),
403
+ [
404
+ open,
405
+ multiple,
406
+ disabled,
407
+ inputValue,
408
+ loading,
409
+ filteredItems,
410
+ itemToString,
411
+ itemToKey,
412
+ indexByKey,
413
+ selectedKeys,
414
+ selectedItems,
415
+ disabledKeys,
416
+ highlight,
417
+ setHighlight,
418
+ setOpen,
419
+ setInputValue,
420
+ select,
421
+ remove,
422
+ clearSelection,
423
+ clear,
424
+ close,
425
+ registerChip,
426
+ chips,
427
+ registerInside,
428
+ isInside,
429
+ onLoadMore,
430
+ id
431
+ ]
432
+ );
433
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ComboboxRootContext.Provider, { value: context, children: [
434
+ children,
435
+ name !== void 0 && (multiple ? selectedItems : [selectedItems[0] ?? null]).map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
436
+ "input",
437
+ {
438
+ type: "hidden",
439
+ name,
440
+ form,
441
+ disabled,
442
+ value: item === null ? "" : itemToKey(item)
443
+ },
444
+ item === null ? index : itemToKey(item)
445
+ ))
446
+ ] });
447
+ }
448
+
449
+ // src/combobox/ComboboxInput.tsx
450
+ var import_react5 = require("react");
451
+
452
+ // src/core/useRender.ts
453
+ var import_react4 = require("react");
454
+
455
+ // src/core/mergeProps.ts
456
+ function isEventHandler(key) {
457
+ return key.length > 2 && key.startsWith("on") && key[2] === key[2]?.toUpperCase();
458
+ }
459
+ function mergeRefs(...refs) {
460
+ return (node) => {
461
+ const cleanups = refs.map((ref) => {
462
+ if (typeof ref === "function") {
463
+ const result = ref(node);
464
+ return typeof result === "function" ? result : () => ref(null);
465
+ }
466
+ if (ref && typeof ref === "object") {
467
+ ref.current = node;
468
+ return () => {
469
+ ref.current = null;
470
+ };
471
+ }
472
+ return void 0;
473
+ });
474
+ return () => {
475
+ cleanups.forEach((cleanup) => {
476
+ if (typeof cleanup === "function") cleanup();
477
+ });
478
+ };
479
+ };
480
+ }
481
+ function isSyntheticEvent(event) {
482
+ return typeof event === "object" && event !== null && "nativeEvent" in event;
483
+ }
484
+ function makeEventPreventable(event) {
485
+ if (Object.prototype.hasOwnProperty.call(event, "preventComponentHandler")) return;
486
+ const target = event;
487
+ target.preventComponentHandler = () => {
488
+ target.componentHandlerPrevented = true;
489
+ };
490
+ }
491
+ function isComponentHandlerPrevented(event) {
492
+ return typeof event === "object" && event !== null && event.componentHandlerPrevented === true;
493
+ }
494
+ function chainHandlers(earlier, value) {
495
+ return (...args) => {
496
+ const event = args[0];
497
+ if (isSyntheticEvent(event)) makeEventPreventable(event);
498
+ value(...args);
499
+ if (isComponentHandlerPrevented(event)) return;
500
+ earlier(...args);
501
+ };
502
+ }
503
+ function mergeProps(...objects) {
504
+ const merged = {};
505
+ for (const props of objects) {
506
+ if (!props) continue;
507
+ for (const key of Object.keys(props)) {
508
+ const value = props[key];
509
+ if (value === void 0) continue;
510
+ if (isEventHandler(key) && typeof value === "function") {
511
+ const earlier = merged[key];
512
+ merged[key] = typeof earlier === "function" ? chainHandlers(earlier, value) : value;
513
+ } else if (key === "className") {
514
+ merged.className = merged.className ? `${String(merged.className)} ${String(value)}` : value;
515
+ } else if (key === "style") {
516
+ merged.style = { ...merged.style, ...value };
517
+ } else if (key === "ref") {
518
+ merged.ref = merged.ref ? mergeRefs(merged.ref, value) : value;
519
+ } else {
520
+ merged[key] = value;
521
+ }
522
+ }
523
+ }
524
+ return merged;
525
+ }
526
+
527
+ // src/core/useRender.ts
528
+ function useRender({
529
+ render,
530
+ defaultTagName,
531
+ props,
532
+ consumerProps
533
+ }) {
534
+ const merged = mergeProps(props, consumerProps);
535
+ if ((0, import_react4.isValidElement)(render)) {
536
+ return (0, import_react4.cloneElement)(render, mergeProps(merged, render.props));
537
+ }
538
+ return (0, import_react4.createElement)(defaultTagName, merged);
539
+ }
540
+
541
+ // src/combobox/comboboxDataAttributes.ts
542
+ function comboboxDataAttributes({ open, disabled }) {
543
+ return {
544
+ "data-open": open ? "" : void 0,
545
+ "data-closed": open ? void 0 : "",
546
+ "data-disabled": disabled ? "" : void 0
547
+ };
548
+ }
549
+ function comboboxItemDataAttributes({
550
+ selected,
551
+ highlighted,
552
+ disabled
553
+ }) {
554
+ return {
555
+ "data-selected": selected ? "" : void 0,
556
+ "data-highlighted": highlighted ? "" : void 0,
557
+ "data-disabled": disabled ? "" : void 0
558
+ };
559
+ }
560
+ function comboboxClearDataAttributes(visible) {
561
+ return { "data-visible": visible ? "" : void 0 };
562
+ }
563
+
564
+ // src/combobox/ComboboxInput.tsx
565
+ function ComboboxInput({ className, render, ...rest }) {
566
+ const {
567
+ open,
568
+ multiple,
569
+ disabled,
570
+ inputValue,
571
+ filteredItems,
572
+ itemToKey,
573
+ selectedItems,
574
+ selectedKeys,
575
+ disabledKeys,
576
+ highlight,
577
+ setHighlight,
578
+ setOpen,
579
+ setInputValue,
580
+ select,
581
+ remove,
582
+ clearSelection,
583
+ close,
584
+ chips,
585
+ inputId,
586
+ listId,
587
+ optionId,
588
+ anchorName,
589
+ inputRef,
590
+ popupRef
591
+ } = useComboboxRootContext("Input");
592
+ const highlighted = (0, import_react5.useSyncExternalStore)(
593
+ highlight.subscribe,
594
+ () => highlight.get().index,
595
+ () => -1
596
+ );
597
+ function enabledIndices() {
598
+ const indices = [];
599
+ filteredItems.forEach((item, index) => {
600
+ if (!disabledKeys.has(itemToKey(item))) indices.push(index);
601
+ });
602
+ return indices;
603
+ }
604
+ function openingIndex(key, enabled) {
605
+ if (!multiple && selectedItems[0] != null) {
606
+ const selected = enabled.find((i) => selectedKeys.has(itemToKey(filteredItems[i])));
607
+ if (selected !== void 0) return selected;
608
+ }
609
+ return (key === "ArrowDown" ? enabled[0] : enabled.at(-1)) ?? -1;
610
+ }
611
+ function moveHighlight(key) {
612
+ const enabled = enabledIndices();
613
+ const next = rovingIndex(key, {
614
+ count: enabled.length,
615
+ current: enabled.indexOf(highlighted),
616
+ orientation: "vertical",
617
+ rtl: false
618
+ });
619
+ if (next !== null) setHighlight(enabled[next] ?? -1, "keyboard");
620
+ }
621
+ return useRender({
622
+ render,
623
+ defaultTagName: "input",
624
+ props: {
625
+ id: inputId,
626
+ type: "text",
627
+ role: "combobox",
628
+ autoComplete: "off",
629
+ "aria-autocomplete": "list",
630
+ "aria-expanded": open,
631
+ "aria-controls": listId,
632
+ "aria-activedescendant": open && highlighted >= 0 ? optionId(highlighted) : void 0,
633
+ disabled: disabled || void 0,
634
+ value: inputValue,
635
+ ...comboboxDataAttributes({ open, multiple, disabled }),
636
+ style: { anchorName },
637
+ className,
638
+ ref: inputRef,
639
+ onChange(event) {
640
+ const text = event.target.value;
641
+ setInputValue(text, "input");
642
+ if (!multiple && text === "" && selectedItems.length > 0) clearSelection("input");
643
+ setOpen(true, "input");
644
+ },
645
+ onClick() {
646
+ if (!disabled) setOpen(true, "input-press");
647
+ },
648
+ onKeyDown(event) {
649
+ const { key } = event;
650
+ if (key === "ArrowDown" || key === "ArrowUp") {
651
+ event.preventDefault();
652
+ if (!open) {
653
+ setOpen(true, "keyboard");
654
+ if (!event.altKey) setHighlight(openingIndex(key, enabledIndices()), "keyboard");
655
+ return;
656
+ }
657
+ moveHighlight(key);
658
+ return;
659
+ }
660
+ if ((key === "Home" || key === "End") && open) {
661
+ event.preventDefault();
662
+ moveHighlight(key);
663
+ return;
664
+ }
665
+ if (key === "Enter") {
666
+ if (!open || highlighted < 0) return;
667
+ event.preventDefault();
668
+ const item = filteredItems[highlighted];
669
+ if (!disabledKeys.has(itemToKey(item))) select(item);
670
+ return;
671
+ }
672
+ if (key === "Escape") {
673
+ if (!open) return;
674
+ event.preventDefault();
675
+ close("escape");
676
+ return;
677
+ }
678
+ if (!multiple) return;
679
+ if (key === "Backspace" && inputValue === "" && selectedItems.length > 0) {
680
+ remove(selectedItems.at(-1), "chip-remove");
681
+ return;
682
+ }
683
+ const input = event.currentTarget;
684
+ if (key === "ArrowLeft" && chips.length > 0 && input.selectionStart === 0 && input.selectionEnd === 0) {
685
+ event.preventDefault();
686
+ chips.at(-1)?.ref.current?.focus();
687
+ }
688
+ },
689
+ onBlur(event) {
690
+ const next = event.relatedTarget;
691
+ if (next && popupRef.current?.contains(next)) return;
692
+ if (next && chips.some((chip) => chip.ref.current === next)) {
693
+ setOpen(false, "blur");
694
+ return;
695
+ }
696
+ close("blur");
697
+ }
698
+ },
699
+ consumerProps: rest
700
+ });
701
+ }
702
+
703
+ // src/combobox/ComboboxTrigger.tsx
704
+ var import_react6 = require("react");
705
+ function ComboboxTrigger({ className, children, render, ...rest }) {
706
+ const { open, multiple, disabled, setOpen, close, listId, inputRef, registerInside } = useComboboxRootContext("Trigger");
707
+ const elementRef = (0, import_react6.useRef)(null);
708
+ (0, import_react6.useLayoutEffect)(() => registerInside(elementRef), [registerInside]);
709
+ return useRender({
710
+ render,
711
+ defaultTagName: "button",
712
+ props: {
713
+ type: "button",
714
+ tabIndex: -1,
715
+ "aria-expanded": open,
716
+ "aria-controls": listId,
717
+ disabled: disabled || void 0,
718
+ ...comboboxDataAttributes({ open, multiple, disabled }),
719
+ className,
720
+ children,
721
+ ref: elementRef,
722
+ onMouseDown(event) {
723
+ event.preventDefault();
724
+ },
725
+ onClick() {
726
+ if (open) close("trigger-press");
727
+ else setOpen(true, "trigger-press");
728
+ inputRef.current?.focus();
729
+ }
730
+ },
731
+ consumerProps: rest
732
+ });
733
+ }
734
+
735
+ // src/combobox/ComboboxClear.tsx
736
+ var import_react7 = require("react");
737
+ function ComboboxClear({ className, children, render, ...rest }) {
738
+ const { disabled, selectedItems, clear, inputRef, registerInside } = useComboboxRootContext("Clear");
739
+ const elementRef = (0, import_react7.useRef)(null);
740
+ (0, import_react7.useLayoutEffect)(() => registerInside(elementRef), [registerInside]);
741
+ return useRender({
742
+ render,
743
+ defaultTagName: "button",
744
+ props: {
745
+ type: "button",
746
+ tabIndex: -1,
747
+ disabled: disabled || void 0,
748
+ ...comboboxClearDataAttributes(selectedItems.length > 0),
749
+ className,
750
+ children,
751
+ ref: elementRef,
752
+ onMouseDown(event) {
753
+ event.preventDefault();
754
+ },
755
+ onClick() {
756
+ if (disabled) return;
757
+ clear();
758
+ inputRef.current?.focus();
759
+ }
760
+ },
761
+ consumerProps: rest
762
+ });
763
+ }
764
+
765
+ // src/combobox/ComboboxPopup.tsx
766
+ var import_react8 = require("react");
767
+ function ComboboxPopup({
768
+ side = "bottom",
769
+ align = "start",
770
+ className,
771
+ children,
772
+ render,
773
+ ...rest
774
+ }) {
775
+ const { open, multiple, disabled, setOpen, close, isInside, anchorName, inputRef, popupRef } = useComboboxRootContext("Popup");
776
+ (0, import_react8.useEffect)(() => {
777
+ if (!open) return;
778
+ function onPointerDown(event) {
779
+ if (event.target instanceof Node && isInside(event.target)) return;
780
+ close("outside-press");
781
+ }
782
+ document.addEventListener("pointerdown", onPointerDown, true);
783
+ return () => document.removeEventListener("pointerdown", onPointerDown, true);
784
+ }, [open, isInside, close]);
785
+ const [, resync] = (0, import_react8.useReducer)((n) => n + 1, 0);
786
+ (0, import_react8.useEffect)(() => {
787
+ const popup = popupRef.current;
788
+ if (!popup || typeof popup.showPopover !== "function") return;
789
+ const shown = popup.matches(":popover-open");
790
+ if (open && !shown) {
791
+ popup.showPopover({ source: inputRef.current ?? void 0 });
792
+ if (!popup.matches(":popover-open")) setOpen(false, "outside-press");
793
+ } else if (!open && shown) {
794
+ popup.hidePopover();
795
+ }
796
+ });
797
+ return useRender({
798
+ render,
799
+ defaultTagName: "div",
800
+ props: {
801
+ popover: "manual",
802
+ ...anchoredDataAttributes(side, align),
803
+ ...comboboxDataAttributes({ open, multiple, disabled }),
804
+ style: anchoredPopupStyle(anchorName, side, align),
805
+ className,
806
+ children,
807
+ ref: popupRef,
808
+ onMouseDown(event) {
809
+ event.preventDefault();
810
+ },
811
+ onToggle(event) {
812
+ if (event.target !== event.currentTarget) return;
813
+ if (event.nativeEvent.newState !== "closed") return;
814
+ close("outside-press");
815
+ resync();
816
+ }
817
+ },
818
+ consumerProps: rest
819
+ });
820
+ }
821
+
822
+ // src/combobox/ComboboxList.tsx
823
+ var import_react9 = require("react");
824
+ var import_jsx_runtime2 = require("react/jsx-runtime");
825
+ function ComboboxList({
826
+ className,
827
+ children,
828
+ render,
829
+ ...rest
830
+ }) {
831
+ const { multiple, loading, filteredItems, onLoadMore, listId } = useComboboxRootContext("List");
832
+ const content = typeof children === "function" ? filteredItems.map((item, index) => children(item, index)) : children;
833
+ return useRender({
834
+ render,
835
+ defaultTagName: "div",
836
+ props: {
837
+ id: listId,
838
+ role: "listbox",
839
+ "aria-multiselectable": multiple || void 0,
840
+ "aria-busy": loading || void 0,
841
+ className,
842
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
843
+ content,
844
+ onLoadMore && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LoadMoreSentinel, {})
845
+ ] })
846
+ },
847
+ consumerProps: rest
848
+ });
849
+ }
850
+ function LoadMoreSentinel() {
851
+ const { open, loading, filteredItems, onLoadMore } = useComboboxRootContext("List");
852
+ const ref = (0, import_react9.useRef)(null);
853
+ const onLoadMoreRef = (0, import_react9.useRef)(onLoadMore);
854
+ onLoadMoreRef.current = onLoadMore;
855
+ (0, import_react9.useEffect)(() => {
856
+ const element = ref.current;
857
+ if (!element || !open || loading || typeof IntersectionObserver === "undefined") return;
858
+ const observer = new IntersectionObserver((entries) => {
859
+ if (entries.some((entry) => entry.isIntersecting)) onLoadMoreRef.current?.();
860
+ });
861
+ observer.observe(element);
862
+ return () => observer.disconnect();
863
+ }, [open, loading, filteredItems.length]);
864
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, "aria-hidden": "true", "data-load-more": "", style: { blockSize: 1 } });
865
+ }
866
+
867
+ // src/combobox/ComboboxItem.tsx
868
+ var import_react10 = require("react");
869
+ function ComboboxItem({
870
+ value,
871
+ disabled = false,
872
+ className,
873
+ children,
874
+ render,
875
+ ...rest
876
+ }) {
877
+ const {
878
+ itemToKey,
879
+ indexByKey,
880
+ selectedKeys,
881
+ disabledKeys,
882
+ highlight,
883
+ setHighlight,
884
+ select,
885
+ optionId
886
+ } = useComboboxRootContext("Item");
887
+ const key = itemToKey(value);
888
+ const index = indexByKey.get(key) ?? -1;
889
+ const selected = selectedKeys.has(key);
890
+ const highlighted = (0, import_react10.useSyncExternalStore)(
891
+ highlight.subscribe,
892
+ () => index >= 0 && highlight.get().index === index,
893
+ () => false
894
+ );
895
+ const elementRef = (0, import_react10.useRef)(null);
896
+ (0, import_react10.useLayoutEffect)(() => {
897
+ if (!disabled) return;
898
+ disabledKeys.add(key);
899
+ return () => {
900
+ disabledKeys.delete(key);
901
+ };
902
+ }, [disabled, disabledKeys, key]);
903
+ (0, import_react10.useEffect)(() => {
904
+ if (highlighted && highlight.get().reason === "keyboard") {
905
+ elementRef.current?.scrollIntoView?.({ block: "nearest" });
906
+ }
907
+ }, [highlighted, highlight]);
908
+ return useRender({
909
+ render,
910
+ defaultTagName: "div",
911
+ props: {
912
+ id: index >= 0 ? optionId(index) : void 0,
913
+ role: "option",
914
+ "aria-selected": selected,
915
+ "aria-disabled": disabled || void 0,
916
+ ...comboboxItemDataAttributes({ selected, highlighted, disabled }),
917
+ className,
918
+ children,
919
+ ref: elementRef,
920
+ onMouseDown(event) {
921
+ event.preventDefault();
922
+ },
923
+ onPointerMove() {
924
+ if (!disabled && !highlighted && index >= 0) setHighlight(index, "pointer");
925
+ },
926
+ onClick() {
927
+ if (!disabled) select(value);
928
+ }
929
+ },
930
+ consumerProps: rest
931
+ });
932
+ }
933
+
934
+ // src/combobox/ComboboxEmpty.tsx
935
+ function ComboboxEmpty({ className, children, render, ...rest }) {
936
+ const { filteredItems, loading } = useComboboxRootContext("Empty");
937
+ const element = useRender({
938
+ render,
939
+ defaultTagName: "div",
940
+ props: { className, children },
941
+ consumerProps: rest
942
+ });
943
+ return filteredItems.length === 0 && !loading ? element : null;
944
+ }
945
+
946
+ // src/combobox/ComboboxStatus.tsx
947
+ function ComboboxStatus({ className, children, render, ...rest }) {
948
+ useComboboxRootContext("Status");
949
+ return useRender({
950
+ render,
951
+ defaultTagName: "div",
952
+ props: { role: "status", "aria-live": "polite", "aria-atomic": true, className, children },
953
+ consumerProps: rest
954
+ });
955
+ }
956
+
957
+ // src/combobox/ComboboxChip.tsx
958
+ var import_react11 = require("react");
959
+ var import_jsx_runtime3 = require("react/jsx-runtime");
960
+ var ComboboxChipContext = (0, import_react11.createContext)(null);
961
+ function useComboboxChipContext() {
962
+ const context = (0, import_react11.useContext)(ComboboxChipContext);
963
+ if (context === null) {
964
+ throw new Error("<Combobox.ChipRemove> must be rendered inside <Combobox.Chip>.");
965
+ }
966
+ return context;
967
+ }
968
+ function ComboboxChip({
969
+ value,
970
+ className,
971
+ children,
972
+ render,
973
+ ...rest
974
+ }) {
975
+ const { disabled, itemToKey, remove, registerChip, chips, inputRef } = useComboboxRootContext("Chip");
976
+ const key = itemToKey(value);
977
+ const elementRef = (0, import_react11.useRef)(null);
978
+ (0, import_react11.useLayoutEffect)(() => registerChip({ key, ref: elementRef }), [registerChip, key]);
979
+ const chipContext = (0, import_react11.useMemo)(() => ({ value }), [value]);
980
+ function focusAt(index) {
981
+ const chip = chips[index];
982
+ if (chip) chip.ref.current?.focus();
983
+ else inputRef.current?.focus();
984
+ }
985
+ const element = useRender({
986
+ render,
987
+ defaultTagName: "div",
988
+ props: {
989
+ tabIndex: -1,
990
+ "data-disabled": disabled ? "" : void 0,
991
+ className,
992
+ children,
993
+ ref: elementRef,
994
+ onKeyDown(event) {
995
+ const index = chips.findIndex((chip) => chip.ref.current === elementRef.current);
996
+ switch (event.key) {
997
+ case "ArrowLeft":
998
+ event.preventDefault();
999
+ if (index > 0) focusAt(index - 1);
1000
+ return;
1001
+ case "ArrowRight":
1002
+ event.preventDefault();
1003
+ focusAt(index + 1);
1004
+ return;
1005
+ case "Backspace":
1006
+ case "Delete":
1007
+ event.preventDefault();
1008
+ if (disabled) return;
1009
+ remove(value, "chip-remove");
1010
+ focusAt(index + 1 < chips.length ? index + 1 : chips.length);
1011
+ return;
1012
+ case "Escape":
1013
+ inputRef.current?.focus();
1014
+ return;
1015
+ }
1016
+ }
1017
+ },
1018
+ consumerProps: rest
1019
+ });
1020
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ComboboxChipContext.Provider, { value: chipContext, children: element });
1021
+ }
1022
+
1023
+ // src/combobox/ComboboxChipRemove.tsx
1024
+ function ComboboxChipRemove({
1025
+ className,
1026
+ children,
1027
+ render,
1028
+ ...rest
1029
+ }) {
1030
+ const { disabled, remove, inputRef } = useComboboxRootContext("ChipRemove");
1031
+ const { value } = useComboboxChipContext();
1032
+ return useRender({
1033
+ render,
1034
+ defaultTagName: "button",
1035
+ props: {
1036
+ type: "button",
1037
+ tabIndex: -1,
1038
+ disabled: disabled || void 0,
1039
+ className,
1040
+ children,
1041
+ onMouseDown(event) {
1042
+ event.preventDefault();
1043
+ },
1044
+ onClick() {
1045
+ if (disabled) return;
1046
+ remove(value, "chip-remove");
1047
+ inputRef.current?.focus();
1048
+ }
1049
+ },
1050
+ consumerProps: rest
1051
+ });
1052
+ }
1053
+ // Annotate the CommonJS export names for ESM import in node:
1054
+ 0 && (module.exports = {
1055
+ Combobox,
1056
+ defaultFilter
1057
+ });