@zag-js/combobox 1.35.2 → 1.36.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.
@@ -4,6 +4,11 @@ import { trackDismissableElement } from "@zag-js/dismissable";
4
4
  import { clickIfLink, nextTick, observeAttributes, raf, scrollIntoView, setCaretToEnd } from "@zag-js/dom-query";
5
5
  import { getInteractionModality, setInteractionModality, trackFocusVisible } from "@zag-js/focus-visible";
6
6
  import { getPlacement } from "@zag-js/popper";
7
+ import {
8
+ createSelectedItemMap,
9
+ deriveSelectionState,
10
+ resolveSelectedItems
11
+ } from "@zag-js/collection";
7
12
  import { addOrRemove, isBoolean, isEqual, match, remove } from "@zag-js/utils";
8
13
  import { collection } from "./combobox.collection.mjs";
9
14
  import * as dom from "./combobox.dom.mjs";
@@ -43,9 +48,11 @@ var machine = createMachine({
43
48
  },
44
49
  initialState({ prop }) {
45
50
  const open = prop("open") || prop("defaultOpen");
46
- return open ? "suggesting" : "idle";
51
+ return open ? "open.suggesting" : "closed.idle";
47
52
  },
48
53
  context({ prop, bindable, getContext, getEvent }) {
54
+ const initialValue = prop("value") ?? prop("defaultValue") ?? [];
55
+ const initialSelectedItems = prop("collection").findMany(initialValue);
49
56
  return {
50
57
  currentPlacement: bindable(() => ({
51
58
  defaultValue: void 0
@@ -59,13 +66,21 @@ var machine = createMachine({
59
66
  },
60
67
  onChange(value) {
61
68
  const context = getContext();
62
- const prevSelectedItems = context.get("selectedItems");
63
69
  const collection2 = prop("collection");
64
- const findItems = (vals) => vals.map((v) => prevSelectedItems.find((item) => collection2.getItemValue(item) === v) || collection2.find(v));
65
- const nextItems = findItems(value);
66
- const effectiveValue = prop("value") || value;
67
- context.set("selectedItems", findItems(effectiveValue));
68
- prop("onValueChange")?.({ value, items: nextItems });
70
+ const selectedItemMap = context.get("selectedItemMap");
71
+ const proposed = deriveSelectionState({
72
+ values: value,
73
+ collection: collection2,
74
+ selectedItemMap
75
+ });
76
+ const effectiveValue = prop("value") ?? value;
77
+ const effective = effectiveValue === value ? proposed : deriveSelectionState({
78
+ values: effectiveValue,
79
+ collection: collection2,
80
+ selectedItemMap: proposed.nextSelectedItemMap
81
+ });
82
+ context.set("selectedItemMap", effective.nextSelectedItemMap);
83
+ prop("onValueChange")?.({ value, items: proposed.selectedItems });
69
84
  }
70
85
  })),
71
86
  highlightedValue: bindable(() => ({
@@ -102,10 +117,13 @@ var machine = createMachine({
102
117
  const highlightedItem = prop("collection").find(highlightedValue);
103
118
  return { defaultValue: highlightedItem };
104
119
  }),
105
- selectedItems: bindable(() => {
106
- const value = prop("value") || prop("defaultValue") || [];
107
- const selectedItems = prop("collection").findMany(value);
108
- return { defaultValue: selectedItems };
120
+ selectedItemMap: bindable(() => {
121
+ return {
122
+ defaultValue: createSelectedItemMap({
123
+ selectedItems: initialSelectedItems,
124
+ collection: prop("collection")
125
+ })
126
+ };
109
127
  })
110
128
  };
111
129
  },
@@ -115,7 +133,12 @@ var machine = createMachine({
115
133
  autoComplete: ({ prop }) => prop("inputBehavior") === "autocomplete",
116
134
  autoHighlight: ({ prop }) => prop("inputBehavior") === "autohighlight",
117
135
  hasSelectedItems: ({ context }) => context.get("value").length > 0,
118
- valueAsString: ({ context, prop }) => prop("collection").stringifyItems(context.get("selectedItems")),
136
+ selectedItems: ({ context, prop }) => resolveSelectedItems({
137
+ values: context.get("value"),
138
+ collection: prop("collection"),
139
+ selectedItemMap: context.get("selectedItemMap")
140
+ }),
141
+ valueAsString: ({ computed, prop }) => prop("collection").stringifyItems(computed("selectedItems")),
119
142
  isCustomValue: ({ context, computed }) => context.get("inputValue") !== computed("valueAsString")
120
143
  },
121
144
  watch({ context, prop, track, action, send }) {
@@ -168,167 +191,173 @@ var machine = createMachine({
168
191
  }
169
192
  ]),
170
193
  states: {
171
- idle: {
172
- tags: ["idle", "closed"],
173
- entry: ["scrollContentToTop", "clearHighlightedValue"],
174
- on: {
175
- "CONTROLLED.OPEN": {
176
- target: "interacting"
177
- },
178
- "TRIGGER.CLICK": [
179
- {
180
- guard: "isOpenControlled",
181
- actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
182
- },
183
- {
184
- target: "interacting",
185
- actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
186
- }
187
- ],
188
- "INPUT.CLICK": [
189
- {
190
- guard: "isOpenControlled",
191
- actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
192
- },
193
- {
194
- target: "interacting",
195
- actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
194
+ closed: {
195
+ tags: ["closed"],
196
+ initial: "idle",
197
+ states: {
198
+ idle: {
199
+ tags: ["idle"],
200
+ entry: ["scrollContentToTop", "clearHighlightedValue"],
201
+ on: {
202
+ "CONTROLLED.OPEN": {
203
+ target: "open.interacting"
204
+ },
205
+ "TRIGGER.CLICK": [
206
+ {
207
+ guard: "isOpenControlled",
208
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
209
+ },
210
+ {
211
+ target: "open.interacting",
212
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
213
+ }
214
+ ],
215
+ "INPUT.CLICK": [
216
+ {
217
+ guard: "isOpenControlled",
218
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
219
+ },
220
+ {
221
+ target: "open.interacting",
222
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
223
+ }
224
+ ],
225
+ "INPUT.FOCUS": {
226
+ target: "focused"
227
+ },
228
+ OPEN: [
229
+ {
230
+ guard: "isOpenControlled",
231
+ actions: ["invokeOnOpen"]
232
+ },
233
+ {
234
+ target: "open.interacting",
235
+ actions: ["invokeOnOpen"]
236
+ }
237
+ ],
238
+ "VALUE.CLEAR": {
239
+ target: "focused",
240
+ actions: ["clearInputValue", "clearSelectedItems", "setInitialFocus"]
241
+ }
196
242
  }
197
- ],
198
- "INPUT.FOCUS": {
199
- target: "focused"
200
243
  },
201
- OPEN: [
202
- {
203
- guard: "isOpenControlled",
204
- actions: ["invokeOnOpen"]
205
- },
206
- {
207
- target: "interacting",
208
- actions: ["invokeOnOpen"]
244
+ focused: {
245
+ tags: ["focused"],
246
+ entry: ["scrollContentToTop", "clearHighlightedValue"],
247
+ on: {
248
+ "CONTROLLED.OPEN": [
249
+ {
250
+ guard: "isChangeEvent",
251
+ target: "open.suggesting"
252
+ },
253
+ {
254
+ target: "open.interacting"
255
+ }
256
+ ],
257
+ "INPUT.CHANGE": [
258
+ {
259
+ guard: and("isOpenControlled", "openOnChange"),
260
+ actions: ["setInputValue", "invokeOnOpen", "highlightFirstItemIfNeeded"]
261
+ },
262
+ {
263
+ guard: "openOnChange",
264
+ target: "open.suggesting",
265
+ actions: ["setInputValue", "invokeOnOpen", "highlightFirstItemIfNeeded"]
266
+ },
267
+ {
268
+ actions: ["setInputValue"]
269
+ }
270
+ ],
271
+ "LAYER.INTERACT_OUTSIDE": {
272
+ target: "idle"
273
+ },
274
+ "INPUT.ESCAPE": {
275
+ guard: and("isCustomValue", not("allowCustomValue")),
276
+ actions: ["revertInputValue"]
277
+ },
278
+ "INPUT.BLUR": {
279
+ target: "idle"
280
+ },
281
+ "INPUT.CLICK": [
282
+ {
283
+ guard: "isOpenControlled",
284
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
285
+ },
286
+ {
287
+ target: "open.interacting",
288
+ actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
289
+ }
290
+ ],
291
+ "TRIGGER.CLICK": [
292
+ {
293
+ guard: "isOpenControlled",
294
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
295
+ },
296
+ {
297
+ target: "open.interacting",
298
+ actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
299
+ }
300
+ ],
301
+ "INPUT.ARROW_DOWN": [
302
+ // == group 1 ==
303
+ {
304
+ guard: and("isOpenControlled", "autoComplete"),
305
+ actions: ["invokeOnOpen"]
306
+ },
307
+ {
308
+ guard: "autoComplete",
309
+ target: "open.interacting",
310
+ actions: ["invokeOnOpen"]
311
+ },
312
+ // == group 2 ==
313
+ {
314
+ guard: "isOpenControlled",
315
+ actions: ["highlightFirstOrSelectedItem", "invokeOnOpen"]
316
+ },
317
+ {
318
+ target: "open.interacting",
319
+ actions: ["highlightFirstOrSelectedItem", "invokeOnOpen"]
320
+ }
321
+ ],
322
+ "INPUT.ARROW_UP": [
323
+ // == group 1 ==
324
+ {
325
+ guard: and("isOpenControlled", "autoComplete"),
326
+ actions: ["invokeOnOpen"]
327
+ },
328
+ {
329
+ guard: "autoComplete",
330
+ target: "open.interacting",
331
+ actions: ["invokeOnOpen"]
332
+ },
333
+ // == group 2 ==
334
+ {
335
+ guard: "isOpenControlled",
336
+ actions: ["highlightLastOrSelectedItem", "invokeOnOpen"]
337
+ },
338
+ {
339
+ target: "open.interacting",
340
+ actions: ["highlightLastOrSelectedItem", "invokeOnOpen"]
341
+ }
342
+ ],
343
+ OPEN: [
344
+ {
345
+ guard: "isOpenControlled",
346
+ actions: ["invokeOnOpen"]
347
+ },
348
+ {
349
+ target: "open.interacting",
350
+ actions: ["invokeOnOpen"]
351
+ }
352
+ ],
353
+ "VALUE.CLEAR": {
354
+ actions: ["clearInputValue", "clearSelectedItems"]
355
+ }
209
356
  }
210
- ],
211
- "VALUE.CLEAR": {
212
- target: "focused",
213
- actions: ["clearInputValue", "clearSelectedItems", "setInitialFocus"]
214
357
  }
215
358
  }
216
359
  },
217
- focused: {
218
- tags: ["focused", "closed"],
219
- entry: ["scrollContentToTop", "clearHighlightedValue"],
220
- on: {
221
- "CONTROLLED.OPEN": [
222
- {
223
- guard: "isChangeEvent",
224
- target: "suggesting"
225
- },
226
- {
227
- target: "interacting"
228
- }
229
- ],
230
- "INPUT.CHANGE": [
231
- {
232
- guard: and("isOpenControlled", "openOnChange"),
233
- actions: ["setInputValue", "invokeOnOpen", "highlightFirstItemIfNeeded"]
234
- },
235
- {
236
- guard: "openOnChange",
237
- target: "suggesting",
238
- actions: ["setInputValue", "invokeOnOpen", "highlightFirstItemIfNeeded"]
239
- },
240
- {
241
- actions: ["setInputValue"]
242
- }
243
- ],
244
- "LAYER.INTERACT_OUTSIDE": {
245
- target: "idle"
246
- },
247
- "INPUT.ESCAPE": {
248
- guard: and("isCustomValue", not("allowCustomValue")),
249
- actions: ["revertInputValue"]
250
- },
251
- "INPUT.BLUR": {
252
- target: "idle"
253
- },
254
- "INPUT.CLICK": [
255
- {
256
- guard: "isOpenControlled",
257
- actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
258
- },
259
- {
260
- target: "interacting",
261
- actions: ["highlightFirstSelectedItem", "invokeOnOpen"]
262
- }
263
- ],
264
- "TRIGGER.CLICK": [
265
- {
266
- guard: "isOpenControlled",
267
- actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
268
- },
269
- {
270
- target: "interacting",
271
- actions: ["setInitialFocus", "highlightFirstSelectedItem", "invokeOnOpen"]
272
- }
273
- ],
274
- "INPUT.ARROW_DOWN": [
275
- // == group 1 ==
276
- {
277
- guard: and("isOpenControlled", "autoComplete"),
278
- actions: ["invokeOnOpen"]
279
- },
280
- {
281
- guard: "autoComplete",
282
- target: "interacting",
283
- actions: ["invokeOnOpen"]
284
- },
285
- // == group 2 ==
286
- {
287
- guard: "isOpenControlled",
288
- actions: ["highlightFirstOrSelectedItem", "invokeOnOpen"]
289
- },
290
- {
291
- target: "interacting",
292
- actions: ["highlightFirstOrSelectedItem", "invokeOnOpen"]
293
- }
294
- ],
295
- "INPUT.ARROW_UP": [
296
- // == group 1 ==
297
- {
298
- guard: and("isOpenControlled", "autoComplete"),
299
- actions: ["invokeOnOpen"]
300
- },
301
- {
302
- guard: "autoComplete",
303
- target: "interacting",
304
- actions: ["invokeOnOpen"]
305
- },
306
- // == group 2 ==
307
- {
308
- guard: "isOpenControlled",
309
- actions: ["highlightLastOrSelectedItem", "invokeOnOpen"]
310
- },
311
- {
312
- target: "interacting",
313
- actions: ["highlightLastOrSelectedItem", "invokeOnOpen"]
314
- }
315
- ],
316
- OPEN: [
317
- {
318
- guard: "isOpenControlled",
319
- actions: ["invokeOnOpen"]
320
- },
321
- {
322
- target: "interacting",
323
- actions: ["invokeOnOpen"]
324
- }
325
- ],
326
- "VALUE.CLEAR": {
327
- actions: ["clearInputValue", "clearSelectedItems"]
328
- }
329
- }
330
- },
331
- interacting: {
360
+ open: {
332
361
  tags: ["open", "focused"],
333
362
  entry: ["setInitialFocus"],
334
363
  effects: ["trackFocusVisible", "scrollToHighlightedItem", "trackDismissableLayer", "trackPlacement"],
@@ -336,44 +365,11 @@ var machine = createMachine({
336
365
  "CONTROLLED.CLOSE": [
337
366
  {
338
367
  guard: "restoreFocus",
339
- target: "focused",
368
+ target: "closed.focused",
340
369
  actions: ["setFinalFocus"]
341
370
  },
342
371
  {
343
- target: "idle"
344
- }
345
- ],
346
- CHILDREN_CHANGE: [
347
- {
348
- guard: "isHighlightedItemRemoved",
349
- actions: ["clearHighlightedValue"]
350
- },
351
- {
352
- actions: ["scrollToHighlightedItem"]
353
- }
354
- ],
355
- "INPUT.HOME": {
356
- actions: ["highlightFirstItem"]
357
- },
358
- "INPUT.END": {
359
- actions: ["highlightLastItem"]
360
- },
361
- "INPUT.ARROW_DOWN": [
362
- {
363
- guard: and("autoComplete", "isLastItemHighlighted"),
364
- actions: ["clearHighlightedValue", "scrollContentToTop"]
365
- },
366
- {
367
- actions: ["highlightNextItem"]
368
- }
369
- ],
370
- "INPUT.ARROW_UP": [
371
- {
372
- guard: and("autoComplete", "isFirstItemHighlighted"),
373
- actions: ["clearHighlightedValue"]
374
- },
375
- {
376
- actions: ["highlightPrevItem"]
372
+ target: "closed.idle"
377
373
  }
378
374
  ],
379
375
  "INPUT.ENTER": [
@@ -384,7 +380,7 @@ var machine = createMachine({
384
380
  },
385
381
  {
386
382
  guard: and("isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
387
- target: "focused",
383
+ target: "closed.focused",
388
384
  actions: ["revertInputValue", "invokeOnClose"]
389
385
  },
390
386
  // == group 2 ==
@@ -394,30 +390,13 @@ var machine = createMachine({
394
390
  },
395
391
  {
396
392
  guard: "closeOnSelect",
397
- target: "focused",
393
+ target: "closed.focused",
398
394
  actions: ["selectHighlightedItem", "invokeOnClose", "setFinalFocus"]
399
395
  },
400
396
  {
401
397
  actions: ["selectHighlightedItem"]
402
398
  }
403
399
  ],
404
- "INPUT.CHANGE": [
405
- {
406
- guard: "autoComplete",
407
- target: "suggesting",
408
- actions: ["setInputValue"]
409
- },
410
- {
411
- target: "suggesting",
412
- actions: ["clearHighlightedValue", "setInputValue"]
413
- }
414
- ],
415
- "ITEM.POINTER_MOVE": {
416
- actions: ["setHighlightedValue"]
417
- },
418
- "ITEM.POINTER_LEAVE": {
419
- actions: ["clearHighlightedValue"]
420
- },
421
400
  "ITEM.CLICK": [
422
401
  {
423
402
  guard: and("isOpenControlled", "closeOnSelect"),
@@ -425,39 +404,20 @@ var machine = createMachine({
425
404
  },
426
405
  {
427
406
  guard: "closeOnSelect",
428
- target: "focused",
407
+ target: "closed.focused",
429
408
  actions: ["selectItem", "invokeOnClose", "setFinalFocus"]
430
409
  },
431
410
  {
432
411
  actions: ["selectItem"]
433
412
  }
434
413
  ],
435
- "LAYER.ESCAPE": [
436
- {
437
- guard: and("isOpenControlled", "autoComplete"),
438
- actions: ["syncInputValue", "invokeOnClose"]
439
- },
440
- {
441
- guard: "autoComplete",
442
- target: "focused",
443
- actions: ["syncInputValue", "invokeOnClose"]
444
- },
445
- {
446
- guard: "isOpenControlled",
447
- actions: ["invokeOnClose"]
448
- },
449
- {
450
- target: "focused",
451
- actions: ["invokeOnClose", "setFinalFocus"]
452
- }
453
- ],
454
414
  "TRIGGER.CLICK": [
455
415
  {
456
416
  guard: "isOpenControlled",
457
417
  actions: ["invokeOnClose"]
458
418
  },
459
419
  {
460
- target: "focused",
420
+ target: "closed.focused",
461
421
  actions: ["invokeOnClose"]
462
422
  }
463
423
  ],
@@ -469,7 +429,7 @@ var machine = createMachine({
469
429
  },
470
430
  {
471
431
  guard: and("isCustomValue", not("allowCustomValue")),
472
- target: "idle",
432
+ target: "closed.idle",
473
433
  actions: ["revertInputValue", "invokeOnClose"]
474
434
  },
475
435
  // == group 2 ==
@@ -478,7 +438,7 @@ var machine = createMachine({
478
438
  actions: ["invokeOnClose"]
479
439
  },
480
440
  {
481
- target: "idle",
441
+ target: "closed.idle",
482
442
  actions: ["invokeOnClose"]
483
443
  }
484
444
  ],
@@ -488,7 +448,7 @@ var machine = createMachine({
488
448
  actions: ["invokeOnClose"]
489
449
  },
490
450
  {
491
- target: "focused",
451
+ target: "closed.focused",
492
452
  actions: ["invokeOnClose", "setFinalFocus"]
493
453
  }
494
454
  ],
@@ -498,167 +458,140 @@ var machine = createMachine({
498
458
  actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose"]
499
459
  },
500
460
  {
501
- target: "focused",
461
+ target: "closed.focused",
502
462
  actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose", "setFinalFocus"]
503
463
  }
504
464
  ]
505
- }
506
- },
507
- suggesting: {
508
- tags: ["open", "focused"],
509
- effects: ["trackFocusVisible", "trackDismissableLayer", "scrollToHighlightedItem", "trackPlacement"],
510
- entry: ["setInitialFocus"],
511
- on: {
512
- "CONTROLLED.CLOSE": [
513
- {
514
- guard: "restoreFocus",
515
- target: "focused",
516
- actions: ["setFinalFocus"]
517
- },
518
- {
519
- target: "idle"
520
- }
521
- ],
522
- CHILDREN_CHANGE: [
523
- {
524
- guard: and("isHighlightedItemRemoved", "hasCollectionItems", "autoHighlight"),
525
- actions: ["clearHighlightedValue", "highlightFirstItem"]
526
- },
527
- {
528
- guard: "isHighlightedItemRemoved",
529
- actions: ["clearHighlightedValue"]
530
- },
531
- {
532
- guard: "autoHighlight",
533
- actions: ["highlightFirstItem"]
534
- }
535
- ],
536
- "INPUT.ARROW_DOWN": {
537
- target: "interacting",
538
- actions: ["highlightNextItem"]
539
- },
540
- "INPUT.ARROW_UP": {
541
- target: "interacting",
542
- actions: ["highlightPrevItem"]
543
- },
544
- "INPUT.HOME": {
545
- target: "interacting",
546
- actions: ["highlightFirstItem"]
547
- },
548
- "INPUT.END": {
549
- target: "interacting",
550
- actions: ["highlightLastItem"]
551
- },
552
- "INPUT.ENTER": [
553
- // == group 1 ==
554
- {
555
- guard: and("isOpenControlled", "isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
556
- actions: ["revertInputValue", "invokeOnClose"]
557
- },
558
- {
559
- guard: and("isCustomValue", not("hasHighlightedItem"), not("allowCustomValue")),
560
- target: "focused",
561
- actions: ["revertInputValue", "invokeOnClose"]
562
- },
563
- // == group 2 ==
564
- {
565
- guard: and("isOpenControlled", "closeOnSelect"),
566
- actions: ["selectHighlightedItem", "invokeOnClose"]
567
- },
568
- {
569
- guard: "closeOnSelect",
570
- target: "focused",
571
- actions: ["selectHighlightedItem", "invokeOnClose", "setFinalFocus"]
572
- },
573
- {
574
- actions: ["selectHighlightedItem"]
465
+ },
466
+ initial: "interacting",
467
+ states: {
468
+ interacting: {
469
+ on: {
470
+ CHILDREN_CHANGE: [
471
+ {
472
+ guard: "isHighlightedItemRemoved",
473
+ actions: ["clearHighlightedValue"]
474
+ },
475
+ {
476
+ actions: ["scrollToHighlightedItem"]
477
+ }
478
+ ],
479
+ "INPUT.HOME": {
480
+ actions: ["highlightFirstItem"]
481
+ },
482
+ "INPUT.END": {
483
+ actions: ["highlightLastItem"]
484
+ },
485
+ "INPUT.ARROW_DOWN": [
486
+ {
487
+ guard: and("autoComplete", "isLastItemHighlighted"),
488
+ actions: ["clearHighlightedValue", "scrollContentToTop"]
489
+ },
490
+ {
491
+ actions: ["highlightNextItem"]
492
+ }
493
+ ],
494
+ "INPUT.ARROW_UP": [
495
+ {
496
+ guard: and("autoComplete", "isFirstItemHighlighted"),
497
+ actions: ["clearHighlightedValue"]
498
+ },
499
+ {
500
+ actions: ["highlightPrevItem"]
501
+ }
502
+ ],
503
+ "INPUT.CHANGE": [
504
+ {
505
+ guard: "autoComplete",
506
+ target: "suggesting",
507
+ actions: ["setInputValue"]
508
+ },
509
+ {
510
+ target: "suggesting",
511
+ actions: ["clearHighlightedValue", "setInputValue"]
512
+ }
513
+ ],
514
+ "ITEM.POINTER_MOVE": {
515
+ actions: ["setHighlightedValue"]
516
+ },
517
+ "ITEM.POINTER_LEAVE": {
518
+ actions: ["clearHighlightedValue"]
519
+ },
520
+ "LAYER.ESCAPE": [
521
+ {
522
+ guard: and("isOpenControlled", "autoComplete"),
523
+ actions: ["syncInputValue", "invokeOnClose"]
524
+ },
525
+ {
526
+ guard: "autoComplete",
527
+ target: "closed.focused",
528
+ actions: ["syncInputValue", "invokeOnClose"]
529
+ },
530
+ {
531
+ guard: "isOpenControlled",
532
+ actions: ["invokeOnClose"]
533
+ },
534
+ {
535
+ target: "closed.focused",
536
+ actions: ["invokeOnClose", "setFinalFocus"]
537
+ }
538
+ ]
575
539
  }
576
- ],
577
- "INPUT.CHANGE": {
578
- actions: ["setInputValue"]
579
540
  },
580
- "LAYER.ESCAPE": [
581
- {
582
- guard: "isOpenControlled",
583
- actions: ["invokeOnClose"]
584
- },
585
- {
586
- target: "focused",
587
- actions: ["invokeOnClose"]
541
+ suggesting: {
542
+ on: {
543
+ CHILDREN_CHANGE: [
544
+ {
545
+ guard: and("isHighlightedItemRemoved", "hasCollectionItems", "autoHighlight"),
546
+ actions: ["clearHighlightedValue", "highlightFirstItem"]
547
+ },
548
+ {
549
+ guard: "isHighlightedItemRemoved",
550
+ actions: ["clearHighlightedValue"]
551
+ },
552
+ {
553
+ guard: "autoHighlight",
554
+ actions: ["highlightFirstItem"]
555
+ }
556
+ ],
557
+ "INPUT.ARROW_DOWN": {
558
+ target: "interacting",
559
+ actions: ["highlightNextItem"]
560
+ },
561
+ "INPUT.ARROW_UP": {
562
+ target: "interacting",
563
+ actions: ["highlightPrevItem"]
564
+ },
565
+ "INPUT.HOME": {
566
+ target: "interacting",
567
+ actions: ["highlightFirstItem"]
568
+ },
569
+ "INPUT.END": {
570
+ target: "interacting",
571
+ actions: ["highlightLastItem"]
572
+ },
573
+ "INPUT.CHANGE": {
574
+ actions: ["setInputValue"]
575
+ },
576
+ "LAYER.ESCAPE": [
577
+ {
578
+ guard: "isOpenControlled",
579
+ actions: ["invokeOnClose"]
580
+ },
581
+ {
582
+ target: "closed.focused",
583
+ actions: ["invokeOnClose"]
584
+ }
585
+ ],
586
+ "ITEM.POINTER_MOVE": {
587
+ target: "interacting",
588
+ actions: ["setHighlightedValue"]
589
+ },
590
+ "ITEM.POINTER_LEAVE": {
591
+ actions: ["clearHighlightedValue"]
592
+ }
588
593
  }
589
- ],
590
- "ITEM.POINTER_MOVE": {
591
- target: "interacting",
592
- actions: ["setHighlightedValue"]
593
- },
594
- "ITEM.POINTER_LEAVE": {
595
- actions: ["clearHighlightedValue"]
596
- },
597
- "LAYER.INTERACT_OUTSIDE": [
598
- // == group 1 ==
599
- {
600
- guard: and("isOpenControlled", "isCustomValue", not("allowCustomValue")),
601
- actions: ["revertInputValue", "invokeOnClose"]
602
- },
603
- {
604
- guard: and("isCustomValue", not("allowCustomValue")),
605
- target: "idle",
606
- actions: ["revertInputValue", "invokeOnClose"]
607
- },
608
- // == group 2 ==
609
- {
610
- guard: "isOpenControlled",
611
- actions: ["invokeOnClose"]
612
- },
613
- {
614
- target: "idle",
615
- actions: ["invokeOnClose"]
616
- }
617
- ],
618
- "TRIGGER.CLICK": [
619
- {
620
- guard: "isOpenControlled",
621
- actions: ["invokeOnClose"]
622
- },
623
- {
624
- target: "focused",
625
- actions: ["invokeOnClose"]
626
- }
627
- ],
628
- "ITEM.CLICK": [
629
- {
630
- guard: and("isOpenControlled", "closeOnSelect"),
631
- actions: ["selectItem", "invokeOnClose"]
632
- },
633
- {
634
- guard: "closeOnSelect",
635
- target: "focused",
636
- actions: ["selectItem", "invokeOnClose", "setFinalFocus"]
637
- },
638
- {
639
- actions: ["selectItem"]
640
- }
641
- ],
642
- CLOSE: [
643
- {
644
- guard: "isOpenControlled",
645
- actions: ["invokeOnClose"]
646
- },
647
- {
648
- target: "focused",
649
- actions: ["invokeOnClose", "setFinalFocus"]
650
- }
651
- ],
652
- "VALUE.CLEAR": [
653
- {
654
- guard: "isOpenControlled",
655
- actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose"]
656
- },
657
- {
658
- target: "focused",
659
- actions: ["clearInputValue", "clearSelectedItems", "invokeOnClose", "setFinalFocus"]
660
- }
661
- ]
594
+ }
662
595
  }
663
596
  }
664
597
  },
@@ -1019,11 +952,9 @@ var machine = createMachine({
1019
952
  const { context, prop } = params;
1020
953
  const collection2 = prop("collection");
1021
954
  const value = context.get("value");
1022
- const selectedItems = value.map((v) => {
1023
- const item = context.get("selectedItems").find((item2) => collection2.getItemValue(item2) === v);
1024
- return item || collection2.find(v);
1025
- });
1026
- context.set("selectedItems", selectedItems);
955
+ const selectedItemMap = context.get("selectedItemMap");
956
+ const next = deriveSelectionState({ values: value, collection: collection2, selectedItemMap });
957
+ context.set("selectedItemMap", next.nextSelectedItemMap);
1027
958
  const inputValue = match(prop("selectionBehavior"), {
1028
959
  preserve: context.get("inputValue"),
1029
960
  replace: collection2.stringifyMany(value),