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