@destyler/combobox 0.0.5 → 0.0.7-beta.1

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/index.mjs CHANGED
@@ -1,15 +1,1470 @@
1
- export { ComboboxAnchor, ComboboxArrow, ComboboxCancel, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxItemIndicator, ComboboxLabel, ComboboxPortal, ComboboxRoot, ComboboxSeparator, ComboboxTrigger, ComboboxViewport, comboboxAnchorProps, comboboxArrowProps, comboboxCancelProps, comboboxContentProps, comboboxEmptyProps, comboboxGroupProps, comboboxInputProps, comboboxItemIndicatorProps, comboboxItemProps, comboboxLabelProps, comboboxPortalProps, comboboxRootProps, comboboxSeparatorProps, comboboxTriggerProps, comboboxViewportProps } from './component.mjs';
2
- import 'vue';
3
- import '@destyler/primitive';
4
- import '@destyler/composition';
5
- import '@destyler/popper';
6
- import '@destyler/popper/component';
7
- import '@destyler/shared';
8
- import '@destyler/visually-hidden/component';
9
- import '@destyler/collection/composition';
10
- import '@destyler/collection';
11
- import '@destyler/dismissable-layer';
12
- import '@destyler/dismissable-layer/component';
13
- import '@destyler/directives';
14
- import '@destyler/presence';
15
- import '@destyler/teleport';
1
+ import { createAnatomy } from '@zag-js/anatomy';
2
+ import { ListCollection } from '@zag-js/collection';
3
+ import { ref, createMachine, guards } from '@zag-js/core';
4
+ import { getEventKey, isLeftClick, isContextMenuEvent, clickIfLink } from '@zag-js/dom-event';
5
+ import { createScope, query, dataAttr, ariaAttr, isComposingEvent, isDownloadingEvent, isOpeningInNewTab, observeChildren, raf, observeAttributes, scrollIntoView } from '@zag-js/dom-query';
6
+ import { getPlacementStyles, getPlacement } from '@zag-js/popper';
7
+ import { ariaHidden } from '@zag-js/aria-hidden';
8
+ import { trackDismissableElement } from '@zag-js/dismissable';
9
+ import { compact, isBoolean, match, isArray, isEqual, addOrRemove } from '@zag-js/utils';
10
+
11
+ const anatomy = createAnatomy("combobox").parts(
12
+ "root",
13
+ "clearTrigger",
14
+ "content",
15
+ "control",
16
+ "input",
17
+ "item",
18
+ "itemGroup",
19
+ "itemGroupLabel",
20
+ "itemIndicator",
21
+ "itemText",
22
+ "label",
23
+ "list",
24
+ "positioner",
25
+ "trigger"
26
+ );
27
+ const parts = anatomy.build();
28
+
29
+ function collection(options) {
30
+ return ref(new ListCollection(options));
31
+ }
32
+ collection.empty = () => {
33
+ return ref(new ListCollection({ items: [] }));
34
+ };
35
+
36
+ const dom = createScope({
37
+ getRootId: (ctx) => ctx.ids?.root ?? `combobox:${ctx.id}`,
38
+ getLabelId: (ctx) => ctx.ids?.label ?? `combobox:${ctx.id}:label`,
39
+ getControlId: (ctx) => ctx.ids?.control ?? `combobox:${ctx.id}:control`,
40
+ getInputId: (ctx) => ctx.ids?.input ?? `combobox:${ctx.id}:input`,
41
+ getContentId: (ctx) => ctx.ids?.content ?? `combobox:${ctx.id}:content`,
42
+ getPositionerId: (ctx) => ctx.ids?.positioner ?? `combobox:${ctx.id}:popper`,
43
+ getTriggerId: (ctx) => ctx.ids?.trigger ?? `combobox:${ctx.id}:toggle-btn`,
44
+ getClearTriggerId: (ctx) => ctx.ids?.clearTrigger ?? `combobox:${ctx.id}:clear-btn`,
45
+ getItemGroupId: (ctx, id) => ctx.ids?.itemGroup?.(id) ?? `combobox:${ctx.id}:optgroup:${id}`,
46
+ getItemGroupLabelId: (ctx, id) => ctx.ids?.itemGroupLabel?.(id) ?? `combobox:${ctx.id}:optgroup-label:${id}`,
47
+ getItemId: (ctx, id) => ctx.ids?.item?.(id) ?? `combobox:${ctx.id}:option:${id}`,
48
+ getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
49
+ getInputEl: (ctx) => dom.getById(ctx, dom.getInputId(ctx)),
50
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
51
+ getControlEl: (ctx) => dom.getById(ctx, dom.getControlId(ctx)),
52
+ getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
53
+ getClearTriggerEl: (ctx) => dom.getById(ctx, dom.getClearTriggerId(ctx)),
54
+ getHighlightedItemEl: (ctx) => {
55
+ const value = ctx.highlightedValue;
56
+ if (value == null)
57
+ return;
58
+ const selector = `[role=option][data-value="${CSS.escape(value)}"`;
59
+ return query(dom.getContentEl(ctx), selector);
60
+ },
61
+ focusInputEl: (ctx) => {
62
+ const inputEl = dom.getInputEl(ctx);
63
+ if (dom.isActiveElement(ctx, inputEl))
64
+ return;
65
+ inputEl?.focus({ preventScroll: true });
66
+ },
67
+ focusTriggerEl: (ctx) => {
68
+ const triggerEl = dom.getTriggerEl(ctx);
69
+ if (dom.isActiveElement(ctx, triggerEl))
70
+ return;
71
+ triggerEl?.focus({ preventScroll: true });
72
+ }
73
+ });
74
+
75
+ function connect(state, send, normalize) {
76
+ const translations = state.context.translations;
77
+ const collection = state.context.collection;
78
+ const disabled = state.context.disabled;
79
+ const interactive = state.context.isInteractive;
80
+ const invalid = state.context.invalid;
81
+ const readOnly = state.context.readOnly;
82
+ const open = state.hasTag("open");
83
+ const focused = state.hasTag("focused");
84
+ const composite = state.context.composite;
85
+ const highlightedValue = state.context.highlightedValue;
86
+ const popperStyles = getPlacementStyles({
87
+ ...state.context.positioning,
88
+ placement: state.context.currentPlacement
89
+ });
90
+ function getItemState(props) {
91
+ const disabled2 = collection.getItemDisabled(props.item);
92
+ const value = collection.getItemValue(props.item);
93
+ return {
94
+ value,
95
+ disabled: Boolean(disabled2 || disabled2),
96
+ highlighted: highlightedValue === value,
97
+ selected: state.context.value.includes(value)
98
+ };
99
+ }
100
+ return {
101
+ focused,
102
+ open,
103
+ inputValue: state.context.inputValue,
104
+ highlightedValue,
105
+ highlightedItem: state.context.highlightedItem,
106
+ value: state.context.value,
107
+ valueAsString: state.context.valueAsString,
108
+ hasSelectedItems: state.context.hasSelectedItems,
109
+ selectedItems: state.context.selectedItems,
110
+ collection: state.context.collection,
111
+ multiple: !!state.context.multiple,
112
+ disabled: !!disabled,
113
+ syncSelectedItems() {
114
+ send({ type: "SELECTED_ITEMS.SYNC" });
115
+ },
116
+ reposition(options = {}) {
117
+ send({ type: "POSITIONING.SET", options });
118
+ },
119
+ setCollection(collection2) {
120
+ send({ type: "COLLECTION.SET", value: collection2 });
121
+ },
122
+ setHighlightValue(value) {
123
+ send({ type: "HIGHLIGHTED_VALUE.SET", value });
124
+ },
125
+ selectValue(value) {
126
+ send({ type: "ITEM.SELECT", value });
127
+ },
128
+ setValue(value) {
129
+ send({ type: "VALUE.SET", value });
130
+ },
131
+ setInputValue(value) {
132
+ send({ type: "INPUT_VALUE.SET", value });
133
+ },
134
+ clearValue(value) {
135
+ if (value != null) {
136
+ send({ type: "ITEM.CLEAR", value });
137
+ } else {
138
+ send("VALUE.CLEAR");
139
+ }
140
+ },
141
+ focus() {
142
+ dom.getInputEl(state.context)?.focus();
143
+ },
144
+ setOpen(nextOpen) {
145
+ if (nextOpen === open)
146
+ return;
147
+ send(nextOpen ? "OPEN" : "CLOSE");
148
+ },
149
+ getRootProps() {
150
+ return normalize.element({
151
+ ...parts.root.attrs,
152
+ "dir": state.context.dir,
153
+ "id": dom.getRootId(state.context),
154
+ "data-invalid": dataAttr(invalid),
155
+ "data-readonly": dataAttr(readOnly)
156
+ });
157
+ },
158
+ getLabelProps() {
159
+ return normalize.label({
160
+ ...parts.label.attrs,
161
+ "dir": state.context.dir,
162
+ "htmlFor": dom.getInputId(state.context),
163
+ "id": dom.getLabelId(state.context),
164
+ "data-readonly": dataAttr(readOnly),
165
+ "data-disabled": dataAttr(disabled),
166
+ "data-invalid": dataAttr(invalid),
167
+ "data-focus": dataAttr(focused),
168
+ onClick(event) {
169
+ if (composite)
170
+ return;
171
+ event.preventDefault();
172
+ dom.getTriggerEl(state.context)?.focus({ preventScroll: true });
173
+ }
174
+ });
175
+ },
176
+ getControlProps() {
177
+ return normalize.element({
178
+ ...parts.control.attrs,
179
+ "dir": state.context.dir,
180
+ "id": dom.getControlId(state.context),
181
+ "data-state": open ? "open" : "closed",
182
+ "data-focus": dataAttr(focused),
183
+ "data-disabled": dataAttr(disabled),
184
+ "data-invalid": dataAttr(invalid)
185
+ });
186
+ },
187
+ getPositionerProps() {
188
+ return normalize.element({
189
+ ...parts.positioner.attrs,
190
+ dir: state.context.dir,
191
+ id: dom.getPositionerId(state.context),
192
+ style: popperStyles.floating
193
+ });
194
+ },
195
+ getInputProps() {
196
+ return normalize.input({
197
+ ...parts.input.attrs,
198
+ "dir": state.context.dir,
199
+ "aria-invalid": ariaAttr(invalid),
200
+ "data-invalid": dataAttr(invalid),
201
+ "name": state.context.name,
202
+ "form": state.context.form,
203
+ "disabled": disabled,
204
+ "autoFocus": state.context.autoFocus,
205
+ "required": state.context.required,
206
+ "autoComplete": "off",
207
+ "autoCorrect": "off",
208
+ "autoCapitalize": "none",
209
+ "spellCheck": "false",
210
+ "readOnly": readOnly,
211
+ "placeholder": state.context.placeholder,
212
+ "id": dom.getInputId(state.context),
213
+ "type": "text",
214
+ "role": "combobox",
215
+ "defaultValue": state.context.inputValue,
216
+ "aria-autocomplete": state.context.autoComplete ? "both" : "list",
217
+ "aria-controls": dom.getContentId(state.context),
218
+ "aria-expanded": open,
219
+ "data-state": open ? "open" : "closed",
220
+ "aria-activedescendant": highlightedValue ? dom.getItemId(state.context, highlightedValue) : void 0,
221
+ onClick(event) {
222
+ if (event.defaultPrevented)
223
+ return;
224
+ if (!state.context.openOnClick)
225
+ return;
226
+ if (!interactive)
227
+ return;
228
+ send("INPUT.CLICK");
229
+ },
230
+ onFocus() {
231
+ if (disabled)
232
+ return;
233
+ send("INPUT.FOCUS");
234
+ },
235
+ onBlur() {
236
+ if (disabled)
237
+ return;
238
+ send("INPUT.BLUR");
239
+ },
240
+ onChange(event) {
241
+ send({ type: "INPUT.CHANGE", value: event.currentTarget.value });
242
+ },
243
+ onKeyDown(event) {
244
+ if (event.defaultPrevented)
245
+ return;
246
+ if (!interactive)
247
+ return;
248
+ if (event.ctrlKey || event.shiftKey || isComposingEvent(event))
249
+ return;
250
+ const openOnKeyPress = state.context.openOnKeyPress;
251
+ const isModifierKey = event.ctrlKey || event.metaKey || event.shiftKey;
252
+ const keypress = true;
253
+ const keymap = {
254
+ ArrowDown(event2) {
255
+ if (!openOnKeyPress && !open)
256
+ return;
257
+ send({ type: event2.altKey ? "OPEN" : "INPUT.ARROW_DOWN", keypress });
258
+ event2.preventDefault();
259
+ },
260
+ ArrowUp() {
261
+ if (!openOnKeyPress && !open)
262
+ return;
263
+ send({ type: event.altKey ? "CLOSE" : "INPUT.ARROW_UP", keypress });
264
+ event.preventDefault();
265
+ },
266
+ Home(event2) {
267
+ if (isModifierKey)
268
+ return;
269
+ send({ type: "INPUT.HOME", keypress });
270
+ if (open) {
271
+ event2.preventDefault();
272
+ }
273
+ },
274
+ End(event2) {
275
+ if (isModifierKey)
276
+ return;
277
+ send({ type: "INPUT.END", keypress });
278
+ if (open) {
279
+ event2.preventDefault();
280
+ }
281
+ },
282
+ Enter(event2) {
283
+ send({ type: "INPUT.ENTER", keypress });
284
+ if (open) {
285
+ event2.preventDefault();
286
+ }
287
+ const itemEl = dom.getHighlightedItemEl(state.context);
288
+ clickIfLink(itemEl);
289
+ },
290
+ Escape() {
291
+ send({ type: "INPUT.ESCAPE", keypress });
292
+ event.preventDefault();
293
+ }
294
+ };
295
+ const key = getEventKey(event, state.context);
296
+ const exec = keymap[key];
297
+ exec?.(event);
298
+ }
299
+ });
300
+ },
301
+ getTriggerProps(props = {}) {
302
+ return normalize.button({
303
+ ...parts.trigger.attrs,
304
+ "dir": state.context.dir,
305
+ "id": dom.getTriggerId(state.context),
306
+ "aria-haspopup": composite ? "listbox" : "dialog",
307
+ "type": "button",
308
+ "tabIndex": props.focusable ? void 0 : -1,
309
+ "aria-label": translations.triggerLabel,
310
+ "aria-expanded": open,
311
+ "data-state": open ? "open" : "closed",
312
+ "aria-controls": open ? dom.getContentId(state.context) : void 0,
313
+ disabled,
314
+ "data-invalid": dataAttr(invalid),
315
+ "data-focusable": dataAttr(props.focusable),
316
+ "data-readonly": dataAttr(readOnly),
317
+ "data-disabled": dataAttr(disabled),
318
+ onFocus() {
319
+ if (!props.focusable)
320
+ return;
321
+ send({ type: "INPUT.FOCUS", src: "trigger" });
322
+ },
323
+ onClick(event) {
324
+ if (event.defaultPrevented)
325
+ return;
326
+ if (!interactive)
327
+ return;
328
+ if (!isLeftClick(event))
329
+ return;
330
+ send("TRIGGER.CLICK");
331
+ },
332
+ onPointerDown(event) {
333
+ if (!interactive)
334
+ return;
335
+ if (event.pointerType === "touch")
336
+ return;
337
+ event.preventDefault();
338
+ queueMicrotask(() => {
339
+ dom.getInputEl(state.context)?.focus({ preventScroll: true });
340
+ });
341
+ },
342
+ onKeyDown(event) {
343
+ if (event.defaultPrevented)
344
+ return;
345
+ if (composite)
346
+ return;
347
+ const keyMap = {
348
+ ArrowDown() {
349
+ send({ type: "INPUT.ARROW_DOWN", src: "trigger" });
350
+ },
351
+ ArrowUp() {
352
+ send({ type: "INPUT.ARROW_UP", src: "trigger" });
353
+ }
354
+ };
355
+ const key = getEventKey(event, state.context);
356
+ const exec = keyMap[key];
357
+ if (exec) {
358
+ exec(event);
359
+ event.preventDefault();
360
+ }
361
+ }
362
+ });
363
+ },
364
+ getContentProps() {
365
+ return normalize.element({
366
+ ...parts.content.attrs,
367
+ "dir": state.context.dir,
368
+ "id": dom.getContentId(state.context),
369
+ "role": !composite ? "dialog" : "listbox",
370
+ "tabIndex": -1,
371
+ "hidden": !open,
372
+ "data-state": open ? "open" : "closed",
373
+ "data-placement": state.context.currentPlacement,
374
+ "aria-labelledby": dom.getLabelId(state.context),
375
+ "aria-multiselectable": state.context.multiple && composite ? true : void 0,
376
+ onPointerDown(event) {
377
+ event.preventDefault();
378
+ }
379
+ });
380
+ },
381
+ getListProps() {
382
+ return normalize.element({
383
+ ...parts.list.attrs,
384
+ "role": !composite ? "listbox" : void 0,
385
+ "aria-labelledby": dom.getLabelId(state.context),
386
+ "aria-multiselectable": state.context.multiple && !composite ? true : void 0
387
+ });
388
+ },
389
+ getClearTriggerProps() {
390
+ return normalize.button({
391
+ ...parts.clearTrigger.attrs,
392
+ "dir": state.context.dir,
393
+ "id": dom.getClearTriggerId(state.context),
394
+ "type": "button",
395
+ "tabIndex": -1,
396
+ "disabled": disabled,
397
+ "data-invalid": dataAttr(invalid),
398
+ "aria-label": translations.clearTriggerLabel,
399
+ "aria-controls": dom.getInputId(state.context),
400
+ "hidden": !state.context.value.length,
401
+ onPointerDown(event) {
402
+ event.preventDefault();
403
+ },
404
+ onClick(event) {
405
+ if (event.defaultPrevented)
406
+ return;
407
+ if (!interactive)
408
+ return;
409
+ send({ type: "VALUE.CLEAR", src: "clear-trigger" });
410
+ }
411
+ });
412
+ },
413
+ getItemState,
414
+ getItemProps(props) {
415
+ const itemState = getItemState(props);
416
+ const value = itemState.value;
417
+ return normalize.element({
418
+ ...parts.item.attrs,
419
+ "dir": state.context.dir,
420
+ "id": dom.getItemId(state.context, value),
421
+ "role": "option",
422
+ "tabIndex": -1,
423
+ "data-highlighted": dataAttr(itemState.highlighted),
424
+ "data-state": itemState.selected ? "checked" : "unchecked",
425
+ "aria-selected": ariaAttr(itemState.highlighted),
426
+ "aria-disabled": ariaAttr(itemState.disabled),
427
+ "data-disabled": dataAttr(itemState.disabled),
428
+ "data-value": itemState.value,
429
+ onPointerMove() {
430
+ if (itemState.disabled)
431
+ return;
432
+ if (itemState.highlighted)
433
+ return;
434
+ send({ type: "ITEM.POINTER_MOVE", value });
435
+ },
436
+ onPointerLeave() {
437
+ if (props.persistFocus)
438
+ return;
439
+ if (itemState.disabled)
440
+ return;
441
+ const mouseMoved = state.previousEvent.type.includes("POINTER");
442
+ if (!mouseMoved)
443
+ return;
444
+ send({ type: "ITEM.POINTER_LEAVE", value });
445
+ },
446
+ onClick(event) {
447
+ if (isDownloadingEvent(event))
448
+ return;
449
+ if (isOpeningInNewTab(event))
450
+ return;
451
+ if (isContextMenuEvent(event))
452
+ return;
453
+ if (itemState.disabled)
454
+ return;
455
+ send({ type: "ITEM.CLICK", src: "click", value });
456
+ }
457
+ });
458
+ },
459
+ getItemTextProps(props) {
460
+ const itemState = getItemState(props);
461
+ return normalize.element({
462
+ ...parts.itemText.attrs,
463
+ "dir": state.context.dir,
464
+ "data-state": itemState.selected ? "checked" : "unchecked",
465
+ "data-disabled": dataAttr(itemState.disabled),
466
+ "data-highlighted": dataAttr(itemState.highlighted)
467
+ });
468
+ },
469
+ getItemIndicatorProps(props) {
470
+ const itemState = getItemState(props);
471
+ return normalize.element({
472
+ "aria-hidden": true,
473
+ ...parts.itemIndicator.attrs,
474
+ "dir": state.context.dir,
475
+ "data-state": itemState.selected ? "checked" : "unchecked",
476
+ "hidden": !itemState.selected
477
+ });
478
+ },
479
+ getItemGroupProps(props) {
480
+ const { id } = props;
481
+ return normalize.element({
482
+ ...parts.itemGroup.attrs,
483
+ "dir": state.context.dir,
484
+ "id": dom.getItemGroupId(state.context, id),
485
+ "aria-labelledby": dom.getItemGroupLabelId(state.context, id)
486
+ });
487
+ },
488
+ getItemGroupLabelProps(props) {
489
+ const { htmlFor } = props;
490
+ return normalize.element({
491
+ ...parts.itemGroupLabel.attrs,
492
+ dir: state.context.dir,
493
+ id: dom.getItemGroupLabelId(state.context, htmlFor),
494
+ role: "group"
495
+ });
496
+ }
497
+ };
498
+ }
499
+
500
+ const { and, not } = guards;
501
+ function getInputValue(ctx) {
502
+ return match(ctx.selectionBehavior, {
503
+ preserve: ctx.inputValue,
504
+ replace: ctx.valueAsString,
505
+ clear: ""
506
+ });
507
+ }
508
+ const sync = {
509
+ valueChange: (ctx) => {
510
+ const prevSelectedItems = ctx.selectedItems;
511
+ ctx.selectedItems = ctx.value.map((v) => {
512
+ const foundItem = prevSelectedItems.find((item) => ctx.collection.getItemValue(item) === v);
513
+ if (foundItem)
514
+ return foundItem;
515
+ return ctx.collection.find(v);
516
+ });
517
+ ctx.valueAsString = ctx.collection.stringifyItems(ctx.selectedItems);
518
+ },
519
+ highlightChange: (ctx) => {
520
+ ctx.highlightedItem = ctx.collection.find(ctx.highlightedValue);
521
+ }
522
+ };
523
+ const invoke = {
524
+ valueChange: (ctx) => {
525
+ sync.valueChange(ctx);
526
+ ctx.onValueChange?.({
527
+ value: Array.from(ctx.value),
528
+ items: Array.from(ctx.selectedItems)
529
+ });
530
+ },
531
+ highlightChange: (ctx) => {
532
+ sync.highlightChange(ctx);
533
+ ctx.onHighlightChange?.({
534
+ highlightedValue: ctx.highlightedValue,
535
+ highlightedItem: ctx.highlightedItem
536
+ });
537
+ },
538
+ inputChange: (ctx) => {
539
+ ctx.onInputValueChange?.({ inputValue: ctx.inputValue });
540
+ }
541
+ };
542
+ const set = {
543
+ value: (ctx, value, force = false) => {
544
+ if (isEqual(ctx.value, value))
545
+ return;
546
+ if (value == null && !force)
547
+ return;
548
+ if (value == null && force) {
549
+ ctx.value = [];
550
+ invoke.valueChange(ctx);
551
+ return;
552
+ }
553
+ if (isArray(value)) {
554
+ ctx.value = value;
555
+ } else if (value != null) {
556
+ ctx.value = ctx.multiple ? addOrRemove(ctx.value, value) : [value];
557
+ }
558
+ invoke.valueChange(ctx);
559
+ },
560
+ highlightedValue: (ctx, value, force = false) => {
561
+ if (isEqual(ctx.highlightedValue, value))
562
+ return;
563
+ if (!value && !force)
564
+ return;
565
+ ctx.highlightedValue = value || null;
566
+ invoke.highlightChange(ctx);
567
+ },
568
+ inputValue: (ctx, value) => {
569
+ if (isEqual(ctx.inputValue, value))
570
+ return;
571
+ ctx.inputValue = value;
572
+ invoke.inputChange(ctx);
573
+ }
574
+ };
575
+ function machine(userContext) {
576
+ const ctx = compact(userContext);
577
+ return createMachine(
578
+ {
579
+ id: "combobox",
580
+ initial: ctx.open ? "suggesting" : "idle",
581
+ context: {
582
+ loopFocus: true,
583
+ openOnClick: false,
584
+ value: [],
585
+ highlightedValue: null,
586
+ inputValue: "",
587
+ allowCustomValue: false,
588
+ closeOnSelect: !ctx.multiple,
589
+ inputBehavior: "none",
590
+ selectionBehavior: "replace",
591
+ openOnKeyPress: true,
592
+ openOnChange: true,
593
+ composite: true,
594
+ readOnly: false,
595
+ disabled: false,
596
+ ...ctx,
597
+ highlightedItem: null,
598
+ selectedItems: [],
599
+ valueAsString: "",
600
+ collection: ctx.collection ?? collection.empty(),
601
+ positioning: {
602
+ placement: "bottom",
603
+ sameWidth: true,
604
+ ...ctx.positioning
605
+ },
606
+ translations: {
607
+ triggerLabel: "Toggle suggestions",
608
+ clearTriggerLabel: "Clear value",
609
+ ...ctx.translations
610
+ }
611
+ },
612
+ created: ["syncInitialValues", "syncSelectionBehavior"],
613
+ computed: {
614
+ isInputValueEmpty: (ctx2) => ctx2.inputValue.length === 0,
615
+ isInteractive: (ctx2) => !(ctx2.readOnly || ctx2.disabled),
616
+ autoComplete: (ctx2) => ctx2.inputBehavior === "autocomplete",
617
+ autoHighlight: (ctx2) => ctx2.inputBehavior === "autohighlight",
618
+ hasSelectedItems: (ctx2) => ctx2.value.length > 0
619
+ },
620
+ watch: {
621
+ value: ["syncSelectedItems"],
622
+ inputValue: ["syncInputValue"],
623
+ highlightedValue: ["syncHighlightedItem", "autofillInputValue"],
624
+ multiple: ["syncSelectionBehavior"],
625
+ open: ["toggleVisibility"]
626
+ },
627
+ on: {
628
+ "SELECTED_ITEMS.SYNC": {
629
+ actions: ["syncSelectedItems"]
630
+ },
631
+ "HIGHLIGHTED_VALUE.SET": {
632
+ actions: ["setHighlightedItem"]
633
+ },
634
+ "ITEM.SELECT": {
635
+ actions: ["selectItem"]
636
+ },
637
+ "ITEM.CLEAR": {
638
+ actions: ["clearItem"]
639
+ },
640
+ "VALUE.SET": {
641
+ actions: ["setSelectedItems"]
642
+ },
643
+ "INPUT_VALUE.SET": {
644
+ actions: "setInputValue"
645
+ },
646
+ "COLLECTION.SET": {
647
+ actions: ["setCollection"]
648
+ },
649
+ "POSITIONING.SET": {
650
+ actions: ["reposition"]
651
+ }
652
+ },
653
+ states: {
654
+ idle: {
655
+ tags: ["idle", "closed"],
656
+ entry: ["scrollContentToTop", "clearHighlightedItem"],
657
+ on: {
658
+ "CONTROLLED.OPEN": {
659
+ target: "interacting"
660
+ },
661
+ "TRIGGER.CLICK": [
662
+ {
663
+ guard: "isOpenControlled",
664
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
665
+ },
666
+ {
667
+ target: "interacting",
668
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
669
+ }
670
+ ],
671
+ "INPUT.CLICK": [
672
+ {
673
+ guard: "isOpenControlled",
674
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
675
+ },
676
+ {
677
+ target: "interacting",
678
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
679
+ }
680
+ ],
681
+ "INPUT.FOCUS": {
682
+ target: "focused"
683
+ },
684
+ "OPEN": [
685
+ {
686
+ guard: "isOpenControlled",
687
+ actions: ["invokeOnOpen"]
688
+ },
689
+ {
690
+ target: "interacting",
691
+ actions: ["invokeOnOpen"]
692
+ }
693
+ ],
694
+ "VALUE.CLEAR": {
695
+ target: "focused",
696
+ actions: ["clearInputValue", "clearSelectedItems", "setInitialFocus"]
697
+ }
698
+ }
699
+ },
700
+ focused: {
701
+ tags: ["focused", "closed"],
702
+ entry: ["scrollContentToTop", "clearHighlightedItem"],
703
+ on: {
704
+ "CONTROLLED.OPEN": [
705
+ {
706
+ guard: "isChangeEvent",
707
+ target: "suggesting"
708
+ },
709
+ {
710
+ target: "interacting"
711
+ }
712
+ ],
713
+ "INPUT.CHANGE": [
714
+ {
715
+ guard: and("isOpenControlled", "openOnChange"),
716
+ actions: ["setInputValue", "invokeOnOpen", "highlightFirstItemIfNeeded"]
717
+ },
718
+ {
719
+ guard: "openOnChange",
720
+ target: "suggesting",
721
+ actions: ["setInputValue", "invokeOnOpen", "highlightFirstItemIfNeeded"]
722
+ },
723
+ {
724
+ actions: "setInputValue"
725
+ }
726
+ ],
727
+ "LAYER.INTERACT_OUTSIDE": {
728
+ target: "idle"
729
+ },
730
+ "INPUT.ESCAPE": {
731
+ guard: and("isCustomValue", not("allowCustomValue")),
732
+ actions: "revertInputValue"
733
+ },
734
+ "INPUT.BLUR": {
735
+ target: "idle"
736
+ },
737
+ "INPUT.CLICK": [
738
+ {
739
+ guard: "isOpenControlled",
740
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
741
+ },
742
+ {
743
+ target: "interacting",
744
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
745
+ }
746
+ ],
747
+ "TRIGGER.CLICK": [
748
+ {
749
+ guard: "isOpenControlled",
750
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
751
+ },
752
+ {
753
+ target: "interacting",
754
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
755
+ }
756
+ ],
757
+ "INPUT.ARROW_DOWN": [
758
+ // == group 1 ==
759
+ {
760
+ guard: and("isOpenControlled", "autoComplete"),
761
+ actions: ["invokeOnOpen"]
762
+ },
763
+ {
764
+ guard: "autoComplete",
765
+ target: "interacting",
766
+ actions: ["invokeOnOpen"]
767
+ },
768
+ // == group 2 ==
769
+ {
770
+ guard: "isOpenControlled",
771
+ actions: ["highlightFirstOrSelectedItem", "invokeOnOpen"]
772
+ },
773
+ {
774
+ target: "interacting",
775
+ actions: ["highlightFirstOrSelectedItem", "invokeOnOpen"]
776
+ }
777
+ ],
778
+ "INPUT.ARROW_UP": [
779
+ // == group 1 ==
780
+ {
781
+ guard: "autoComplete",
782
+ target: "interacting",
783
+ actions: "invokeOnOpen"
784
+ },
785
+ {
786
+ guard: "autoComplete",
787
+ target: "interacting",
788
+ actions: "invokeOnOpen"
789
+ },
790
+ // == group 2 ==
791
+ {
792
+ target: "interacting",
793
+ actions: ["highlightLastOrSelectedItem", "invokeOnOpen"]
794
+ },
795
+ {
796
+ target: "interacting",
797
+ actions: ["highlightLastOrSelectedItem", "invokeOnOpen"]
798
+ }
799
+ ],
800
+ "OPEN": [
801
+ {
802
+ guard: "isOpenControlled",
803
+ actions: ["invokeOnOpen"]
804
+ },
805
+ {
806
+ target: "interacting",
807
+ actions: ["invokeOnOpen"]
808
+ }
809
+ ],
810
+ "VALUE.CLEAR": {
811
+ actions: ["clearInputValue", "clearSelectedItems"]
812
+ }
813
+ }
814
+ },
815
+ interacting: {
816
+ tags: ["open", "focused"],
817
+ entry: ["setInitialFocus"],
818
+ activities: ["scrollToHighlightedItem", "trackDismissableLayer", "computePlacement", "hideOtherElements"],
819
+ on: {
820
+ "CONTROLLED.CLOSE": [
821
+ {
822
+ guard: "restoreFocus",
823
+ target: "focused",
824
+ actions: ["setFinalFocus"]
825
+ },
826
+ {
827
+ target: "idle"
828
+ }
829
+ ],
830
+ "INPUT.HOME": {
831
+ actions: ["highlightFirstItem"]
832
+ },
833
+ "INPUT.END": {
834
+ actions: ["highlightLastItem"]
835
+ },
836
+ "INPUT.ARROW_DOWN": [
837
+ {
838
+ guard: and("autoComplete", "isLastItemHighlighted"),
839
+ actions: ["clearHighlightedItem", "scrollContentToTop"]
840
+ },
841
+ {
842
+ actions: ["highlightNextItem"]
843
+ }
844
+ ],
845
+ "INPUT.ARROW_UP": [
846
+ {
847
+ guard: and("autoComplete", "isFirstItemHighlighted"),
848
+ actions: "clearHighlightedItem"
849
+ },
850
+ {
851
+ actions: "highlightPrevItem"
852
+ }
853
+ ],
854
+ "INPUT.ENTER": [
855
+ // == group 1 ==
856
+ {
857
+ guard: and("isOpenControlled", "isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
858
+ actions: ["revertInputValue", "invokeOnClose"]
859
+ },
860
+ {
861
+ guard: and("isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
862
+ target: "focused",
863
+ actions: ["revertInputValue", "invokeOnClose"]
864
+ },
865
+ // == group 2 ==
866
+ {
867
+ guard: and("isOpenControlled", "closeOnSelect"),
868
+ actions: ["selectHighlightedItem", "invokeOnClose"]
869
+ },
870
+ {
871
+ guard: "closeOnSelect",
872
+ target: "focused",
873
+ actions: ["selectHighlightedItem", "invokeOnClose", "setFinalFocus"]
874
+ },
875
+ {
876
+ actions: ["selectHighlightedItem"]
877
+ }
878
+ ],
879
+ "INPUT.CHANGE": [
880
+ {
881
+ guard: "autoComplete",
882
+ target: "suggesting",
883
+ actions: ["setInputValue", "invokeOnOpen"]
884
+ },
885
+ {
886
+ target: "suggesting",
887
+ actions: ["clearHighlightedItem", "setInputValue", "invokeOnOpen"]
888
+ }
889
+ ],
890
+ "ITEM.POINTER_MOVE": {
891
+ actions: ["setHighlightedItem"]
892
+ },
893
+ "ITEM.POINTER_LEAVE": {
894
+ actions: ["clearHighlightedItem"]
895
+ },
896
+ "ITEM.CLICK": [
897
+ {
898
+ guard: and("isOpenControlled", "closeOnSelect"),
899
+ actions: ["selectItem", "invokeOnClose"]
900
+ },
901
+ {
902
+ guard: "closeOnSelect",
903
+ target: "focused",
904
+ actions: ["selectItem", "invokeOnClose", "setFinalFocus"]
905
+ },
906
+ {
907
+ actions: ["selectItem"]
908
+ }
909
+ ],
910
+ "LAYER.ESCAPE": [
911
+ {
912
+ guard: and("isOpenControlled", "autoComplete"),
913
+ actions: ["syncInputValue", "invokeOnClose"]
914
+ },
915
+ {
916
+ guard: "autoComplete",
917
+ target: "focused",
918
+ actions: ["syncInputValue", "invokeOnClose"]
919
+ },
920
+ {
921
+ guard: "isOpenControlled",
922
+ actions: "invokeOnClose"
923
+ },
924
+ {
925
+ target: "focused",
926
+ actions: ["invokeOnClose", "setFinalFocus"]
927
+ }
928
+ ],
929
+ "TRIGGER.CLICK": [
930
+ {
931
+ guard: "isOpenControlled",
932
+ actions: "invokeOnClose"
933
+ },
934
+ {
935
+ target: "focused",
936
+ actions: "invokeOnClose"
937
+ }
938
+ ],
939
+ "LAYER.INTERACT_OUTSIDE": [
940
+ // == group 1 ==
941
+ {
942
+ guard: and("isOpenControlled", "isCustomValue", not("allowCustomValue")),
943
+ actions: ["revertInputValue", "invokeOnClose"]
944
+ },
945
+ {
946
+ guard: and("isCustomValue", not("allowCustomValue")),
947
+ target: "idle",
948
+ actions: ["revertInputValue", "invokeOnClose"]
949
+ },
950
+ // == group 2 ==
951
+ {
952
+ guard: "isOpenControlled",
953
+ actions: "invokeOnClose"
954
+ },
955
+ {
956
+ target: "idle",
957
+ actions: "invokeOnClose"
958
+ }
959
+ ],
960
+ "CLOSE": [
961
+ {
962
+ guard: "isOpenControlled",
963
+ actions: ["invokeOnClose"]
964
+ },
965
+ {
966
+ target: "focused",
967
+ actions: ["invokeOnClose", "setFinalFocus"]
968
+ }
969
+ ],
970
+ "VALUE.CLEAR": [
971
+ {
972
+ guard: "isOpenControlled",
973
+ actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose"]
974
+ },
975
+ {
976
+ target: "focused",
977
+ actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose", "setFinalFocus"]
978
+ }
979
+ ]
980
+ }
981
+ },
982
+ suggesting: {
983
+ tags: ["open", "focused"],
984
+ activities: [
985
+ "trackDismissableLayer",
986
+ "scrollToHighlightedItem",
987
+ "computePlacement",
988
+ "trackChildNodes",
989
+ "hideOtherElements"
990
+ ],
991
+ entry: ["setInitialFocus"],
992
+ on: {
993
+ "CONTROLLED.CLOSE": [
994
+ {
995
+ guard: "restoreFocus",
996
+ target: "focused",
997
+ actions: ["setFinalFocus"]
998
+ },
999
+ {
1000
+ target: "idle"
1001
+ }
1002
+ ],
1003
+ "CHILDREN_CHANGE": {
1004
+ actions: ["highlightFirstItem"]
1005
+ },
1006
+ "INPUT.ARROW_DOWN": {
1007
+ target: "interacting",
1008
+ actions: ["highlightNextItem"]
1009
+ },
1010
+ "INPUT.ARROW_UP": {
1011
+ target: "interacting",
1012
+ actions: ["highlightPrevItem"]
1013
+ },
1014
+ "INPUT.HOME": {
1015
+ target: "interacting",
1016
+ actions: ["highlightFirstItem"]
1017
+ },
1018
+ "INPUT.END": {
1019
+ target: "interacting",
1020
+ actions: ["highlightLastItem"]
1021
+ },
1022
+ "INPUT.ENTER": [
1023
+ // == group 1 ==
1024
+ {
1025
+ guard: and("isOpenControlled", "isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
1026
+ actions: ["revertInputValue", "invokeOnClose"]
1027
+ },
1028
+ {
1029
+ guard: and("isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
1030
+ target: "focused",
1031
+ actions: ["revertInputValue", "invokeOnClose"]
1032
+ },
1033
+ // == group 2 ==
1034
+ {
1035
+ guard: and("isOpenControlled", "closeOnSelect"),
1036
+ actions: ["selectHighlightedItem", "invokeOnClose"]
1037
+ },
1038
+ {
1039
+ guard: "closeOnSelect",
1040
+ target: "focused",
1041
+ actions: ["selectHighlightedItem", "invokeOnClose", "setFinalFocus"]
1042
+ },
1043
+ {
1044
+ actions: ["selectHighlightedItem"]
1045
+ }
1046
+ ],
1047
+ "INPUT.CHANGE": [
1048
+ {
1049
+ guard: "autoHighlight",
1050
+ actions: ["setInputValue"]
1051
+ },
1052
+ {
1053
+ actions: ["setInputValue"]
1054
+ }
1055
+ ],
1056
+ "LAYER.ESCAPE": [
1057
+ {
1058
+ guard: "isOpenControlled",
1059
+ actions: ["invokeOnClose"]
1060
+ },
1061
+ {
1062
+ target: "focused",
1063
+ actions: ["invokeOnClose"]
1064
+ }
1065
+ ],
1066
+ "ITEM.POINTER_MOVE": {
1067
+ target: "interacting",
1068
+ actions: ["setHighlightedItem"]
1069
+ },
1070
+ "ITEM.POINTER_LEAVE": {
1071
+ actions: ["clearHighlightedItem"]
1072
+ },
1073
+ "LAYER.INTERACT_OUTSIDE": [
1074
+ // == group 1 ==
1075
+ {
1076
+ guard: and("isOpenControlled", "isCustomValue", not("allowCustomValue")),
1077
+ actions: ["revertInputValue", "invokeOnClose"]
1078
+ },
1079
+ {
1080
+ guard: and("isCustomValue", not("allowCustomValue")),
1081
+ target: "idle",
1082
+ actions: ["revertInputValue", "invokeOnClose"]
1083
+ },
1084
+ // == group 2 ==
1085
+ {
1086
+ guard: "isOpenControlled",
1087
+ actions: ["invokeOnClose"]
1088
+ },
1089
+ {
1090
+ target: "idle",
1091
+ actions: ["invokeOnClose"]
1092
+ }
1093
+ ],
1094
+ "TRIGGER.CLICK": [
1095
+ {
1096
+ guard: "isOpenControlled",
1097
+ actions: ["invokeOnClose"]
1098
+ },
1099
+ {
1100
+ target: "focused",
1101
+ actions: ["invokeOnClose"]
1102
+ }
1103
+ ],
1104
+ "ITEM.CLICK": [
1105
+ {
1106
+ guard: and("isOpenControlled", "closeOnSelect"),
1107
+ actions: ["selectItem", "invokeOnClose"]
1108
+ },
1109
+ {
1110
+ guard: "closeOnSelect",
1111
+ target: "focused",
1112
+ actions: ["selectItem", "invokeOnClose", "setFinalFocus"]
1113
+ },
1114
+ {
1115
+ actions: ["selectItem"]
1116
+ }
1117
+ ],
1118
+ "CLOSE": [
1119
+ {
1120
+ guard: "isOpenControlled",
1121
+ actions: ["invokeOnClose"]
1122
+ },
1123
+ {
1124
+ target: "focused",
1125
+ actions: ["invokeOnClose", "setFinalFocus"]
1126
+ }
1127
+ ],
1128
+ "VALUE.CLEAR": [
1129
+ {
1130
+ guard: "isOpenControlled",
1131
+ actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose"]
1132
+ },
1133
+ {
1134
+ target: "focused",
1135
+ actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose", "setFinalFocus"]
1136
+ }
1137
+ ]
1138
+ }
1139
+ }
1140
+ }
1141
+ },
1142
+ {
1143
+ guards: {
1144
+ isInputValueEmpty: (ctx2) => ctx2.isInputValueEmpty,
1145
+ autoComplete: (ctx2) => ctx2.autoComplete && !ctx2.multiple,
1146
+ autoHighlight: (ctx2) => ctx2.autoHighlight,
1147
+ isFirstItemHighlighted: (ctx2) => ctx2.collection.firstValue === ctx2.highlightedValue,
1148
+ isLastItemHighlighted: (ctx2) => ctx2.collection.lastValue === ctx2.highlightedValue,
1149
+ isCustomValue: (ctx2) => ctx2.inputValue !== ctx2.valueAsString,
1150
+ allowCustomValue: (ctx2) => !!ctx2.allowCustomValue,
1151
+ hasHighlightedItem: (ctx2) => ctx2.highlightedValue != null,
1152
+ closeOnSelect: (ctx2) => !!ctx2.closeOnSelect,
1153
+ isOpenControlled: (ctx2) => !!ctx2["open.controlled"],
1154
+ openOnChange: (ctx2, evt) => {
1155
+ if (isBoolean(ctx2.openOnChange))
1156
+ return ctx2.openOnChange;
1157
+ return !!ctx2.openOnChange?.({ inputValue: evt.value });
1158
+ },
1159
+ restoreFocus: (_ctx, evt) => evt.restoreFocus == null ? true : !!evt.restoreFocus,
1160
+ isChangeEvent: (_ctx, evt) => evt.previousEvent?.type === "INPUT.CHANGE"
1161
+ },
1162
+ activities: {
1163
+ trackDismissableLayer(ctx2, _evt, { send }) {
1164
+ if (ctx2.disableLayer)
1165
+ return;
1166
+ const contentEl = () => dom.getContentEl(ctx2);
1167
+ return trackDismissableElement(contentEl, {
1168
+ defer: true,
1169
+ exclude: () => [dom.getInputEl(ctx2), dom.getTriggerEl(ctx2), dom.getClearTriggerEl(ctx2)],
1170
+ onFocusOutside: ctx2.onFocusOutside,
1171
+ onPointerDownOutside: ctx2.onPointerDownOutside,
1172
+ onInteractOutside: ctx2.onInteractOutside,
1173
+ onEscapeKeyDown(event) {
1174
+ event.preventDefault();
1175
+ event.stopPropagation();
1176
+ send("LAYER.ESCAPE");
1177
+ },
1178
+ onDismiss() {
1179
+ send({ type: "LAYER.INTERACT_OUTSIDE", restoreFocus: false });
1180
+ }
1181
+ });
1182
+ },
1183
+ hideOtherElements(ctx2) {
1184
+ return ariaHidden([
1185
+ dom.getInputEl(ctx2),
1186
+ dom.getContentEl(ctx2),
1187
+ dom.getTriggerEl(ctx2),
1188
+ dom.getClearTriggerEl(ctx2)
1189
+ ]);
1190
+ },
1191
+ computePlacement(ctx2) {
1192
+ const controlEl = () => dom.getControlEl(ctx2);
1193
+ const positionerEl = () => dom.getPositionerEl(ctx2);
1194
+ ctx2.currentPlacement = ctx2.positioning.placement;
1195
+ return getPlacement(controlEl, positionerEl, {
1196
+ ...ctx2.positioning,
1197
+ defer: true,
1198
+ onComplete(data) {
1199
+ ctx2.currentPlacement = data.placement;
1200
+ }
1201
+ });
1202
+ },
1203
+ // in event the options are fetched (async), we still want to auto-highlight the first option
1204
+ trackChildNodes(ctx2, _evt, { send }) {
1205
+ if (!ctx2.autoHighlight)
1206
+ return;
1207
+ const exec = () => send("CHILDREN_CHANGE");
1208
+ const contentEl = () => dom.getContentEl(ctx2);
1209
+ return observeChildren(contentEl, {
1210
+ callback: exec,
1211
+ defer: true
1212
+ });
1213
+ },
1214
+ scrollToHighlightedItem(ctx2, _evt, { getState }) {
1215
+ const inputEl = dom.getInputEl(ctx2);
1216
+ const cleanups = [];
1217
+ const exec = (immediate) => {
1218
+ const state = getState();
1219
+ const pointer = state.event.type.includes("POINTER");
1220
+ if (pointer || !ctx2.highlightedValue)
1221
+ return;
1222
+ const itemEl = dom.getHighlightedItemEl(ctx2);
1223
+ const contentEl = dom.getContentEl(ctx2);
1224
+ if (ctx2.scrollToIndexFn) {
1225
+ const highlightedIndex = ctx2.collection.indexOf(ctx2.highlightedValue);
1226
+ ctx2.scrollToIndexFn({ index: highlightedIndex, immediate });
1227
+ return;
1228
+ }
1229
+ const rafCleanup2 = raf(() => {
1230
+ scrollIntoView(itemEl, { rootEl: contentEl, block: "nearest" });
1231
+ });
1232
+ cleanups.push(rafCleanup2);
1233
+ };
1234
+ const rafCleanup = raf(() => exec(true));
1235
+ cleanups.push(rafCleanup);
1236
+ const observerCleanup = observeAttributes(inputEl, {
1237
+ attributes: ["aria-activedescendant"],
1238
+ callback: () => exec(false)
1239
+ });
1240
+ cleanups.push(observerCleanup);
1241
+ return () => {
1242
+ cleanups.forEach((cleanup) => cleanup());
1243
+ };
1244
+ }
1245
+ },
1246
+ actions: {
1247
+ reposition(ctx2, evt) {
1248
+ const controlEl = () => dom.getControlEl(ctx2);
1249
+ const positionerEl = () => dom.getPositionerEl(ctx2);
1250
+ getPlacement(controlEl, positionerEl, {
1251
+ ...ctx2.positioning,
1252
+ ...evt.options,
1253
+ defer: true,
1254
+ listeners: false,
1255
+ onComplete(data) {
1256
+ ctx2.currentPlacement = data.placement;
1257
+ }
1258
+ });
1259
+ },
1260
+ setHighlightedItem(ctx2, evt) {
1261
+ if (evt.value == null)
1262
+ return;
1263
+ set.highlightedValue(ctx2, evt.value);
1264
+ },
1265
+ clearHighlightedItem(ctx2) {
1266
+ set.highlightedValue(ctx2, null, true);
1267
+ },
1268
+ selectHighlightedItem(ctx2) {
1269
+ set.value(ctx2, ctx2.highlightedValue);
1270
+ set.inputValue(ctx2, getInputValue(ctx2));
1271
+ },
1272
+ selectItem(ctx2, evt) {
1273
+ if (evt.value == null)
1274
+ return;
1275
+ set.value(ctx2, evt.value);
1276
+ set.inputValue(ctx2, getInputValue(ctx2));
1277
+ },
1278
+ clearItem(ctx2, evt) {
1279
+ if (evt.value == null)
1280
+ return;
1281
+ const value = ctx2.value.filter((v) => v !== evt.value);
1282
+ set.value(ctx2, value);
1283
+ set.inputValue(ctx2, getInputValue(ctx2));
1284
+ },
1285
+ setInitialFocus(ctx2) {
1286
+ raf(() => {
1287
+ dom.focusInputEl(ctx2);
1288
+ });
1289
+ },
1290
+ setFinalFocus(ctx2) {
1291
+ raf(() => {
1292
+ const triggerEl = dom.getTriggerEl(ctx2);
1293
+ if (triggerEl?.dataset.focusable == null) {
1294
+ dom.focusInputEl(ctx2);
1295
+ } else {
1296
+ dom.focusTriggerEl(ctx2);
1297
+ }
1298
+ });
1299
+ },
1300
+ syncInputValue(ctx2) {
1301
+ const inputEl = dom.getInputEl(ctx2);
1302
+ if (!inputEl)
1303
+ return;
1304
+ inputEl.value = ctx2.inputValue;
1305
+ queueMicrotask(() => {
1306
+ const { selectionStart, selectionEnd } = inputEl;
1307
+ if (Math.abs((selectionEnd ?? 0) - (selectionStart ?? 0)) !== 0)
1308
+ return;
1309
+ if (selectionStart !== 0)
1310
+ return;
1311
+ inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length);
1312
+ });
1313
+ },
1314
+ setInputValue(ctx2, evt) {
1315
+ set.inputValue(ctx2, evt.value);
1316
+ },
1317
+ clearInputValue(ctx2) {
1318
+ set.inputValue(ctx2, "");
1319
+ },
1320
+ revertInputValue(ctx2) {
1321
+ const inputValue = match(ctx2.selectionBehavior, {
1322
+ replace: ctx2.hasSelectedItems ? ctx2.valueAsString : "",
1323
+ preserve: ctx2.inputValue,
1324
+ clear: ""
1325
+ });
1326
+ set.inputValue(ctx2, inputValue);
1327
+ },
1328
+ syncInitialValues(ctx2) {
1329
+ const selectedItems = ctx2.collection.findMany(ctx2.value);
1330
+ const valueAsString = ctx2.collection.stringifyMany(ctx2.value);
1331
+ ctx2.highlightedItem = ctx2.collection.find(ctx2.highlightedValue);
1332
+ ctx2.selectedItems = selectedItems;
1333
+ ctx2.valueAsString = valueAsString;
1334
+ if (ctx2.inputValue.trim() || ctx2.multiple)
1335
+ return;
1336
+ ctx2.inputValue = match(ctx2.selectionBehavior, {
1337
+ preserve: ctx2.inputValue || valueAsString,
1338
+ replace: valueAsString,
1339
+ clear: ""
1340
+ });
1341
+ },
1342
+ syncSelectionBehavior(ctx2) {
1343
+ if (ctx2.multiple) {
1344
+ ctx2.selectionBehavior = "clear";
1345
+ }
1346
+ },
1347
+ setSelectedItems(ctx2, evt) {
1348
+ if (!isArray(evt.value))
1349
+ return;
1350
+ set.value(ctx2, evt.value);
1351
+ set.inputValue(ctx2, getInputValue(ctx2));
1352
+ },
1353
+ clearSelectedItems(ctx2) {
1354
+ set.value(ctx2, []);
1355
+ set.inputValue(ctx2, getInputValue(ctx2));
1356
+ },
1357
+ scrollContentToTop(ctx2) {
1358
+ if (ctx2.scrollToIndexFn) {
1359
+ ctx2.scrollToIndexFn({ index: 0, immediate: true });
1360
+ } else {
1361
+ const contentEl = dom.getContentEl(ctx2);
1362
+ if (!contentEl)
1363
+ return;
1364
+ contentEl.scrollTop = 0;
1365
+ }
1366
+ },
1367
+ invokeOnOpen(ctx2) {
1368
+ ctx2.onOpenChange?.({ open: true });
1369
+ },
1370
+ invokeOnClose(ctx2) {
1371
+ ctx2.onOpenChange?.({ open: false });
1372
+ },
1373
+ highlightFirstItem(ctx2) {
1374
+ raf(() => {
1375
+ const value = ctx2.collection.firstValue;
1376
+ set.highlightedValue(ctx2, value, true);
1377
+ });
1378
+ },
1379
+ highlightFirstItemIfNeeded(ctx2) {
1380
+ if (!ctx2.autoHighlight)
1381
+ return;
1382
+ raf(() => {
1383
+ const value = ctx2.collection.firstValue;
1384
+ set.highlightedValue(ctx2, value);
1385
+ });
1386
+ },
1387
+ highlightLastItem(ctx2) {
1388
+ raf(() => {
1389
+ const value = ctx2.collection.lastValue;
1390
+ set.highlightedValue(ctx2, value);
1391
+ });
1392
+ },
1393
+ highlightNextItem(ctx2) {
1394
+ let value = null;
1395
+ if (ctx2.highlightedValue) {
1396
+ value = ctx2.collection.getNextValue(ctx2.highlightedValue);
1397
+ if (!value && ctx2.loopFocus)
1398
+ value = ctx2.collection.firstValue;
1399
+ } else {
1400
+ value = ctx2.collection.firstValue;
1401
+ }
1402
+ set.highlightedValue(ctx2, value);
1403
+ },
1404
+ highlightPrevItem(ctx2) {
1405
+ let value = null;
1406
+ if (ctx2.highlightedValue) {
1407
+ value = ctx2.collection.getPreviousValue(ctx2.highlightedValue);
1408
+ if (!value && ctx2.loopFocus)
1409
+ value = ctx2.collection.lastValue;
1410
+ } else {
1411
+ value = ctx2.collection.lastValue;
1412
+ }
1413
+ set.highlightedValue(ctx2, value);
1414
+ },
1415
+ highlightFirstSelectedItem(ctx2) {
1416
+ raf(() => {
1417
+ const [value] = ctx2.collection.sort(ctx2.value);
1418
+ set.highlightedValue(ctx2, value);
1419
+ });
1420
+ },
1421
+ highlightFirstOrSelectedItem(ctx2) {
1422
+ raf(() => {
1423
+ let value = null;
1424
+ if (ctx2.hasSelectedItems) {
1425
+ value = ctx2.collection.sort(ctx2.value)[0];
1426
+ } else {
1427
+ value = ctx2.collection.firstValue;
1428
+ }
1429
+ set.highlightedValue(ctx2, value);
1430
+ });
1431
+ },
1432
+ highlightLastOrSelectedItem(ctx2) {
1433
+ raf(() => {
1434
+ let value = null;
1435
+ if (ctx2.hasSelectedItems) {
1436
+ value = ctx2.collection.sort(ctx2.value)[0];
1437
+ } else {
1438
+ value = ctx2.collection.lastValue;
1439
+ }
1440
+ set.highlightedValue(ctx2, value);
1441
+ });
1442
+ },
1443
+ autofillInputValue(ctx2, evt) {
1444
+ const inputEl = dom.getInputEl(ctx2);
1445
+ if (!ctx2.autoComplete || !inputEl || !evt.keypress)
1446
+ return;
1447
+ const valueText = ctx2.collection.stringify(ctx2.highlightedValue);
1448
+ raf(() => {
1449
+ inputEl.value = valueText || ctx2.inputValue;
1450
+ });
1451
+ },
1452
+ setCollection(ctx2, evt) {
1453
+ ctx2.collection = evt.value;
1454
+ },
1455
+ syncSelectedItems(ctx2) {
1456
+ sync.valueChange(ctx2);
1457
+ set.inputValue(ctx2, getInputValue(ctx2));
1458
+ },
1459
+ syncHighlightedItem(ctx2) {
1460
+ sync.highlightChange(ctx2);
1461
+ },
1462
+ toggleVisibility(ctx2, evt, { send }) {
1463
+ send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
1464
+ }
1465
+ }
1466
+ }
1467
+ );
1468
+ }
1469
+
1470
+ export { anatomy, collection, connect, machine };