@destyler/dynamic 0.0.7-beta.7 → 0.0.7-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs DELETED
@@ -1,1024 +0,0 @@
1
- import { createAnatomy } from '@zag-js/anatomy';
2
- import { getEventKey, getNativeEvent } from '@zag-js/dom-event';
3
- import { createScope, indexOfId, nextById, prevById, queryAll, dataAttr, isComposingEvent, ariaAttr, raf, contains } from '@zag-js/dom-query';
4
- import { dispatchInputValueEvent, trackFormControl } from '@zag-js/form-utils';
5
- import { autoResizeInput } from '@zag-js/auto-resize';
6
- import { guards, createMachine } from '@zag-js/core';
7
- import { trackInteractOutside } from '@zag-js/interact-outside';
8
- import { createLiveRegion } from '@zag-js/live-region';
9
- import { compact, uniq, warn, removeAt, isEqual, createSplitProps } from '@zag-js/utils';
10
- import { createProps } from '@zag-js/types';
11
-
12
- const anatomy = createAnatomy("dynamic").parts(
13
- "root",
14
- "label",
15
- "control",
16
- "input",
17
- "clearTrigger",
18
- "item",
19
- "itemPreview",
20
- "itemInput",
21
- "itemText",
22
- "itemDeleteTrigger"
23
- );
24
- const parts = anatomy.build();
25
-
26
- const dom = createScope({
27
- getRootId: (ctx) => ctx.ids?.root ?? `dynamic:${ctx.id}`,
28
- getInputId: (ctx) => ctx.ids?.input ?? `dynamic:${ctx.id}:input`,
29
- getClearTriggerId: (ctx) => ctx.ids?.clearBtn ?? `dynamic:${ctx.id}:clear-btn`,
30
- getHiddenInputId: (ctx) => ctx.ids?.hiddenInput ?? `dynamic:${ctx.id}:hidden-input`,
31
- getLabelId: (ctx) => ctx.ids?.label ?? `dynamic:${ctx.id}:label`,
32
- getControlId: (ctx) => ctx.ids?.control ?? `dynamic:${ctx.id}:control`,
33
- getItemId: (ctx, opt) => ctx.ids?.item?.(opt) ?? `dynamic:${ctx.id}:tag:${opt.value}:${opt.index}`,
34
- getItemDeleteTriggerId: (ctx, opt) => ctx.ids?.itemDeleteTrigger?.(opt) ?? `${dom.getItemId(ctx, opt)}:delete-btn`,
35
- getItemInputId: (ctx, opt) => ctx.ids?.itemInput?.(opt) ?? `${dom.getItemId(ctx, opt)}:input`,
36
- getEditInputId: (ctx) => `${ctx.editedTagId}:input`,
37
- getTagInputEl: (ctx, opt) => dom.getById(ctx, dom.getItemInputId(ctx, opt)),
38
- getRootEl: (ctx) => dom.getById(ctx, dom.getRootId(ctx)),
39
- getInputEl: (ctx) => dom.getById(ctx, dom.getInputId(ctx)),
40
- getHiddenInputEl: (ctx) => dom.getById(ctx, dom.getHiddenInputId(ctx)),
41
- getEditInputEl: (ctx) => dom.getById(ctx, dom.getEditInputId(ctx)),
42
- getTagElements: (ctx) => queryAll(dom.getRootEl(ctx), `[data-part=item-preview]:not([data-disabled])`),
43
- getFirstEl: (ctx) => dom.getTagElements(ctx)[0],
44
- getLastEl: (ctx) => dom.getTagElements(ctx)[dom.getTagElements(ctx).length - 1],
45
- getPrevEl: (ctx, id) => prevById(dom.getTagElements(ctx), id, false),
46
- getNextEl: (ctx, id) => nextById(dom.getTagElements(ctx), id, false),
47
- getTagElAtIndex: (ctx, index) => dom.getTagElements(ctx)[index],
48
- getIndexOfId: (ctx, id) => indexOfId(dom.getTagElements(ctx), id),
49
- isInputFocused: (ctx) => dom.getDoc(ctx).activeElement === dom.getInputEl(ctx),
50
- getHighlightedTagValue: (ctx) => {
51
- if (!ctx.highlightedTagId)
52
- return null;
53
- const tagEl = dom.getById(ctx, ctx.highlightedTagId);
54
- return tagEl?.dataset.value ?? null;
55
- },
56
- setHoverIntent: (el) => {
57
- const tagEl = el.closest("[data-part=item-preview]");
58
- if (!tagEl)
59
- return;
60
- tagEl.dataset.deleteIntent = "";
61
- },
62
- clearHoverIntent: (el) => {
63
- const tagEl = el.closest("[data-part=item-preview]");
64
- if (!tagEl)
65
- return;
66
- delete tagEl.dataset.deleteIntent;
67
- },
68
- dispatchInputEvent(ctx) {
69
- const inputEl = dom.getHiddenInputEl(ctx);
70
- if (!inputEl)
71
- return;
72
- dispatchInputValueEvent(inputEl, { value: ctx.valueAsString });
73
- }
74
- });
75
-
76
- function connect(state, send, normalize) {
77
- const interactive = state.context.isInteractive;
78
- const disabled = state.context.disabled;
79
- const readOnly = state.context.readOnly;
80
- const invalid = state.context.invalid || state.context.isOverflowing;
81
- const translations = state.context.translations;
82
- const focused = state.hasTag("focused");
83
- const editingTag = state.matches("editing:tag");
84
- const empty = state.context.count === 0;
85
- function getItemState(options) {
86
- const id = dom.getItemId(state.context, options);
87
- return {
88
- id,
89
- editing: editingTag && state.context.editedTagId === id,
90
- highlighted: id === state.context.highlightedTagId,
91
- disabled: Boolean(options.disabled || disabled)
92
- };
93
- }
94
- return {
95
- empty,
96
- inputValue: state.context.trimmedInputValue,
97
- value: state.context.value,
98
- valueAsString: state.context.valueAsString,
99
- count: state.context.count,
100
- atMax: state.context.isAtMax,
101
- setValue(value) {
102
- send({ type: "SET_VALUE", value });
103
- },
104
- clearValue(id) {
105
- if (id) {
106
- send({ type: "CLEAR_TAG", id });
107
- } else {
108
- send("CLEAR_VALUE");
109
- }
110
- },
111
- addValue(value) {
112
- send({ type: "ADD_TAG", value });
113
- },
114
- setValueAtIndex(index, value) {
115
- send({ type: "SET_VALUE_AT_INDEX", index, value });
116
- },
117
- setInputValue(value) {
118
- send({ type: "SET_INPUT_VALUE", value });
119
- },
120
- clearInputValue() {
121
- send({ type: "SET_INPUT_VALUE", value: "" });
122
- },
123
- focus() {
124
- dom.getInputEl(state.context)?.focus();
125
- },
126
- getItemState,
127
- getRootProps() {
128
- return normalize.element({
129
- "dir": state.context.dir,
130
- ...parts.root.attrs,
131
- "data-invalid": dataAttr(invalid),
132
- "data-readonly": dataAttr(readOnly),
133
- "data-disabled": dataAttr(disabled),
134
- "data-focus": dataAttr(focused),
135
- "data-empty": dataAttr(empty),
136
- "id": dom.getRootId(state.context),
137
- onPointerDown() {
138
- if (!interactive)
139
- return;
140
- send("POINTER_DOWN");
141
- }
142
- });
143
- },
144
- getLabelProps() {
145
- return normalize.label({
146
- ...parts.label.attrs,
147
- "data-disabled": dataAttr(disabled),
148
- "data-invalid": dataAttr(invalid),
149
- "data-readonly": dataAttr(readOnly),
150
- "id": dom.getLabelId(state.context),
151
- "dir": state.context.dir,
152
- "htmlFor": dom.getInputId(state.context)
153
- });
154
- },
155
- getControlProps() {
156
- return normalize.element({
157
- "id": dom.getControlId(state.context),
158
- ...parts.control.attrs,
159
- "dir": state.context.dir,
160
- "tabIndex": readOnly ? 0 : void 0,
161
- "data-disabled": dataAttr(disabled),
162
- "data-readonly": dataAttr(readOnly),
163
- "data-invalid": dataAttr(invalid),
164
- "data-focus": dataAttr(focused)
165
- });
166
- },
167
- getInputProps() {
168
- return normalize.input({
169
- ...parts.input.attrs,
170
- "dir": state.context.dir,
171
- "data-invalid": dataAttr(invalid),
172
- "aria-invalid": ariaAttr(invalid),
173
- "data-readonly": dataAttr(readOnly),
174
- "maxLength": state.context.maxLength,
175
- "id": dom.getInputId(state.context),
176
- "defaultValue": state.context.inputValue,
177
- "autoComplete": "off",
178
- "autoCorrect": "off",
179
- "autoCapitalize": "none",
180
- "disabled": disabled || readOnly,
181
- onChange(event) {
182
- const evt = getNativeEvent(event);
183
- const value = event.currentTarget.value;
184
- if (evt.inputType === "insertFromPaste") {
185
- send({ type: "PASTE", value });
186
- return;
187
- }
188
- if (endsWith(value, state.context.delimiter)) {
189
- send("DELIMITER_KEY");
190
- return;
191
- }
192
- send({ type: "TYPE", value, key: evt.inputType });
193
- },
194
- onFocus() {
195
- send("FOCUS");
196
- },
197
- onKeyDown(event) {
198
- if (event.defaultPrevented)
199
- return;
200
- if (isComposingEvent(event))
201
- return;
202
- const target = event.currentTarget;
203
- const isCombobox = target.getAttribute("role") === "combobox";
204
- const isExpanded = target.ariaExpanded === "true";
205
- const keyMap = {
206
- ArrowDown() {
207
- send("ARROW_DOWN");
208
- },
209
- ArrowLeft() {
210
- if (isCombobox && isExpanded)
211
- return;
212
- send("ARROW_LEFT");
213
- },
214
- ArrowRight(event2) {
215
- if (state.context.highlightedTagId) {
216
- event2.preventDefault();
217
- }
218
- if (isCombobox && isExpanded)
219
- return;
220
- send("ARROW_RIGHT");
221
- },
222
- Escape(event2) {
223
- event2.preventDefault();
224
- send("ESCAPE");
225
- },
226
- Backspace() {
227
- send("BACKSPACE");
228
- },
229
- Delete() {
230
- send("DELETE");
231
- },
232
- Enter(event2) {
233
- if (isCombobox && isExpanded)
234
- return;
235
- send("ENTER");
236
- event2.preventDefault();
237
- }
238
- };
239
- const key = getEventKey(event, state.context);
240
- const exec = keyMap[key];
241
- if (exec) {
242
- exec(event);
243
- }
244
- }
245
- });
246
- },
247
- getHiddenInputProps() {
248
- return normalize.input({
249
- type: "text",
250
- hidden: true,
251
- name: state.context.name,
252
- form: state.context.form,
253
- disabled,
254
- readOnly,
255
- required: state.context.required,
256
- id: dom.getHiddenInputId(state.context),
257
- defaultValue: state.context.valueAsString
258
- });
259
- },
260
- getItemProps(props) {
261
- return normalize.element({
262
- ...parts.item.attrs,
263
- "dir": state.context.dir,
264
- "data-value": props.value,
265
- "data-disabled": dataAttr(disabled)
266
- });
267
- },
268
- getItemPreviewProps(props) {
269
- const itemState = getItemState(props);
270
- return normalize.element({
271
- ...parts.itemPreview.attrs,
272
- "id": itemState.id,
273
- "dir": state.context.dir,
274
- "hidden": itemState.editing,
275
- "data-value": props.value,
276
- "data-disabled": dataAttr(disabled),
277
- "data-highlighted": dataAttr(itemState.highlighted),
278
- onPointerDown(event) {
279
- if (!interactive || itemState.disabled)
280
- return;
281
- event.preventDefault();
282
- send({ type: "POINTER_DOWN_TAG", id: itemState.id });
283
- },
284
- onDoubleClick() {
285
- if (!interactive || itemState.disabled)
286
- return;
287
- send({ type: "DOUBLE_CLICK_TAG", id: itemState.id });
288
- }
289
- });
290
- },
291
- getItemTextProps(props) {
292
- const itemState = getItemState(props);
293
- return normalize.element({
294
- ...parts.itemText.attrs,
295
- "dir": state.context.dir,
296
- "data-disabled": dataAttr(disabled),
297
- "data-highlighted": dataAttr(itemState.highlighted)
298
- });
299
- },
300
- getItemInputProps(props) {
301
- const itemState = getItemState(props);
302
- return normalize.input({
303
- ...parts.itemInput.attrs,
304
- "dir": state.context.dir,
305
- "aria-label": translations.tagEdited(props.value),
306
- "aria-hidden": true,
307
- "disabled": disabled,
308
- "id": dom.getItemInputId(state.context, props),
309
- "tabIndex": -1,
310
- "hidden": !itemState.editing,
311
- "defaultValue": itemState.editing ? state.context.editedTagValue : "",
312
- onChange(event) {
313
- send({ type: "TAG_INPUT_TYPE", value: event.currentTarget.value });
314
- },
315
- onBlur(event) {
316
- send({ type: "TAG_INPUT_BLUR", target: event.relatedTarget, id: itemState.id });
317
- },
318
- onKeyDown(event) {
319
- if (event.defaultPrevented)
320
- return;
321
- if (isComposingEvent(event))
322
- return;
323
- const keyMap = {
324
- Enter() {
325
- send("TAG_INPUT_ENTER");
326
- },
327
- Escape() {
328
- send("TAG_INPUT_ESCAPE");
329
- }
330
- };
331
- const exec = keyMap[event.key];
332
- if (exec) {
333
- event.preventDefault();
334
- exec(event);
335
- }
336
- }
337
- });
338
- },
339
- getItemDeleteTriggerProps(props) {
340
- const id = dom.getItemId(state.context, props);
341
- return normalize.button({
342
- ...parts.itemDeleteTrigger.attrs,
343
- "dir": state.context.dir,
344
- "id": dom.getItemDeleteTriggerId(state.context, props),
345
- "type": "button",
346
- "disabled": disabled,
347
- "aria-label": translations.deleteTagTriggerLabel(props.value),
348
- "tabIndex": -1,
349
- onPointerDown(event) {
350
- if (!interactive) {
351
- event.preventDefault();
352
- }
353
- },
354
- onPointerMove(event) {
355
- if (!interactive)
356
- return;
357
- dom.setHoverIntent(event.currentTarget);
358
- },
359
- onPointerLeave(event) {
360
- if (!interactive)
361
- return;
362
- dom.clearHoverIntent(event.currentTarget);
363
- },
364
- onClick() {
365
- if (!interactive)
366
- return;
367
- send({ type: "CLICK_DELETE_TAG", id });
368
- }
369
- });
370
- },
371
- getClearTriggerProps() {
372
- return normalize.button({
373
- ...parts.clearTrigger.attrs,
374
- "dir": state.context.dir,
375
- "id": dom.getClearTriggerId(state.context),
376
- "type": "button",
377
- "data-readonly": dataAttr(readOnly),
378
- "disabled": disabled,
379
- "aria-label": translations.clearTriggerLabel,
380
- "hidden": empty,
381
- onClick() {
382
- if (!interactive)
383
- return;
384
- send("CLEAR_VALUE");
385
- }
386
- });
387
- }
388
- };
389
- }
390
- function endsWith(str, del) {
391
- if (!del)
392
- return false;
393
- if (typeof del === "string")
394
- return str.endsWith(del);
395
- return new RegExp(`${del.source}$`).test(str);
396
- }
397
-
398
- const { and, not, or } = guards;
399
- const invoke = {
400
- change: (ctx) => {
401
- ctx.onValueChange?.({ value: Array.from(ctx.value) });
402
- dom.dispatchInputEvent(ctx);
403
- },
404
- highlightChange: (ctx) => {
405
- const highlightedValue = dom.getHighlightedTagValue(ctx);
406
- ctx.onHighlightChange?.({ highlightedValue });
407
- },
408
- valueChange: (ctx) => {
409
- ctx.onInputValueChange?.({ inputValue: ctx.inputValue });
410
- }
411
- };
412
- const set = {
413
- value: (ctx, value) => {
414
- if (isEqual(ctx.value, value))
415
- return;
416
- ctx.value = value;
417
- invoke.change(ctx);
418
- },
419
- valueAtIndex: (ctx, index, value) => {
420
- if (isEqual(ctx.value[index], value))
421
- return;
422
- ctx.value[index] = value;
423
- invoke.change(ctx);
424
- },
425
- highlightedId: (ctx, id) => {
426
- if (isEqual(ctx.highlightedTagId, id))
427
- return;
428
- ctx.highlightedTagId = id;
429
- invoke.highlightChange(ctx);
430
- },
431
- inputValue: (ctx, value) => {
432
- if (isEqual(ctx.inputValue, value))
433
- return;
434
- ctx.inputValue = value;
435
- invoke.valueChange(ctx);
436
- }
437
- };
438
- function machine(userContext) {
439
- const ctx = compact(userContext);
440
- return createMachine(
441
- {
442
- id: "dynamic",
443
- initial: ctx.autoFocus ? "focused:input" : "idle",
444
- context: {
445
- inputValue: "",
446
- editedTagValue: "",
447
- editedTagId: null,
448
- highlightedTagId: null,
449
- value: [],
450
- dir: "ltr",
451
- max: Infinity,
452
- blurBehavior: void 0,
453
- addOnPaste: false,
454
- editable: true,
455
- validate: () => true,
456
- delimiter: ",",
457
- disabled: false,
458
- readOnly: false,
459
- ...ctx,
460
- liveRegion: null,
461
- log: { current: null, prev: null },
462
- fieldsetDisabled: false,
463
- translations: {
464
- clearTriggerLabel: "Clear all tags",
465
- deleteTagTriggerLabel: (value) => `Delete tag ${value}`,
466
- tagAdded: (value) => `Added tag ${value}`,
467
- tagsPasted: (values) => `Pasted ${values.length} tags`,
468
- tagEdited: (value) => `Editing tag ${value}. Press enter to save or escape to cancel.`,
469
- tagUpdated: (value) => `Tag update to ${value}`,
470
- tagDeleted: (value) => `Tag ${value} deleted`,
471
- tagSelected: (value) => `Tag ${value} selected. Press enter to edit, delete or backspace to remove.`,
472
- ...ctx.translations
473
- }
474
- },
475
- computed: {
476
- count: (ctx2) => ctx2.value.length,
477
- valueAsString: (ctx2) => JSON.stringify(ctx2.value),
478
- trimmedInputValue: (ctx2) => ctx2.inputValue.trim(),
479
- isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
480
- isInteractive: (ctx2) => !(ctx2.readOnly || ctx2.isDisabled),
481
- isAtMax: (ctx2) => ctx2.count === ctx2.max,
482
- isOverflowing: (ctx2) => ctx2.count > ctx2.max
483
- },
484
- watch: {
485
- highlightedTagId: "logHighlightedTag",
486
- isOverflowing: "invokeOnInvalid",
487
- log: "announceLog",
488
- inputValue: "syncInputValue",
489
- editedTagValue: "syncEditedTagInputValue"
490
- },
491
- activities: ["trackLiveRegion", "trackFormControlState"],
492
- exit: ["clearLog"],
493
- on: {
494
- DOUBLE_CLICK_TAG: {
495
- internal: true,
496
- guard: "isTagEditable",
497
- target: "editing:tag",
498
- actions: ["setEditedId", "initializeEditedTagValue"]
499
- },
500
- POINTER_DOWN_TAG: {
501
- internal: true,
502
- target: "navigating:tag",
503
- actions: ["highlightTag", "focusInput"]
504
- },
505
- CLICK_DELETE_TAG: {
506
- target: "focused:input",
507
- actions: ["deleteTag"]
508
- },
509
- SET_INPUT_VALUE: {
510
- actions: ["setInputValue"]
511
- },
512
- SET_VALUE: {
513
- actions: ["setValue"]
514
- },
515
- CLEAR_TAG: {
516
- actions: ["deleteTag"]
517
- },
518
- SET_VALUE_AT_INDEX: {
519
- actions: ["setValueAtIndex"]
520
- },
521
- CLEAR_VALUE: {
522
- actions: ["clearTags", "clearInputValue", "focusInput"]
523
- },
524
- ADD_TAG: {
525
- actions: ["addTag"]
526
- },
527
- INSERT_TAG: {
528
- // (!isAtMax || allowOverflow) && !inputValueIsEmpty
529
- guard: and(or(not("isAtMax"), "allowOverflow"), not("isInputValueEmpty")),
530
- actions: ["addTag", "clearInputValue"]
531
- },
532
- EXTERNAL_BLUR: [
533
- { guard: "addOnBlur", actions: "raiseInsertTagEvent" },
534
- { guard: "clearOnBlur", actions: "clearInputValue" }
535
- ]
536
- },
537
- states: {
538
- "idle": {
539
- on: {
540
- FOCUS: "focused:input",
541
- POINTER_DOWN: {
542
- guard: not("hasHighlightedTag"),
543
- target: "focused:input"
544
- }
545
- }
546
- },
547
- "focused:input": {
548
- tags: ["focused"],
549
- entry: ["focusInput", "clearHighlightedId"],
550
- activities: ["trackInteractOutside"],
551
- on: {
552
- TYPE: {
553
- actions: "setInputValue"
554
- },
555
- BLUR: [
556
- {
557
- guard: "addOnBlur",
558
- target: "idle",
559
- actions: "raiseInsertTagEvent"
560
- },
561
- {
562
- guard: "clearOnBlur",
563
- target: "idle",
564
- actions: "clearInputValue"
565
- },
566
- { target: "idle" }
567
- ],
568
- ENTER: {
569
- actions: ["raiseInsertTagEvent"]
570
- },
571
- DELIMITER_KEY: {
572
- actions: ["raiseInsertTagEvent"]
573
- },
574
- ARROW_LEFT: {
575
- guard: and("hasTags", "isInputCaretAtStart"),
576
- target: "navigating:tag",
577
- actions: "highlightLastTag"
578
- },
579
- BACKSPACE: {
580
- target: "navigating:tag",
581
- guard: and("hasTags", "isInputCaretAtStart"),
582
- actions: "highlightLastTag"
583
- },
584
- DELETE: {
585
- guard: "hasHighlightedTag",
586
- actions: ["deleteHighlightedTag", "highlightTagAtIndex"]
587
- },
588
- PASTE: [
589
- {
590
- guard: "addOnPaste",
591
- actions: ["setInputValue", "addTagFromPaste"]
592
- },
593
- {
594
- actions: "setInputValue"
595
- }
596
- ]
597
- }
598
- },
599
- "navigating:tag": {
600
- tags: ["focused"],
601
- activities: ["trackInteractOutside"],
602
- on: {
603
- ARROW_RIGHT: [
604
- {
605
- guard: and("hasTags", "isInputCaretAtStart", not("isLastTagHighlighted")),
606
- actions: "highlightNextTag"
607
- },
608
- { target: "focused:input" }
609
- ],
610
- ARROW_LEFT: {
611
- actions: "highlightPrevTag"
612
- },
613
- BLUR: {
614
- target: "idle",
615
- actions: "clearHighlightedId"
616
- },
617
- ENTER: {
618
- guard: and("isTagEditable", "hasHighlightedTag"),
619
- target: "editing:tag",
620
- actions: ["setEditedId", "initializeEditedTagValue", "focusEditedTagInput"]
621
- },
622
- ARROW_DOWN: "focused:input",
623
- ESCAPE: "focused:input",
624
- TYPE: {
625
- target: "focused:input",
626
- actions: "setInputValue"
627
- },
628
- BACKSPACE: [
629
- {
630
- guard: "isFirstTagHighlighted",
631
- actions: ["deleteHighlightedTag", "highlightFirstTag"]
632
- },
633
- {
634
- guard: "hasHighlightedTag",
635
- actions: ["deleteHighlightedTag", "highlightPrevTag"]
636
- },
637
- {
638
- actions: ["highlightLastTag"]
639
- }
640
- ],
641
- DELETE: {
642
- target: "focused:input",
643
- actions: ["deleteHighlightedTag", "highlightTagAtIndex"]
644
- },
645
- PASTE: [
646
- {
647
- guard: "addOnPaste",
648
- target: "focused:input",
649
- actions: ["setInputValue", "addTagFromPaste"]
650
- },
651
- {
652
- target: "focused:input",
653
- actions: "setInputValue"
654
- }
655
- ]
656
- }
657
- },
658
- "editing:tag": {
659
- tags: ["editing", "focused"],
660
- entry: "focusEditedTagInput",
661
- activities: ["autoResize"],
662
- on: {
663
- TAG_INPUT_TYPE: {
664
- actions: "setEditedTagValue"
665
- },
666
- TAG_INPUT_ESCAPE: {
667
- target: "navigating:tag",
668
- actions: ["clearEditedTagValue", "focusInput", "clearEditedId", "highlightTagAtIndex"]
669
- },
670
- TAG_INPUT_BLUR: [
671
- {
672
- guard: "isInputRelatedTarget",
673
- target: "navigating:tag",
674
- actions: ["clearEditedTagValue", "clearHighlightedId", "clearEditedId"]
675
- },
676
- {
677
- target: "idle",
678
- actions: ["clearEditedTagValue", "clearHighlightedId", "clearEditedId", "raiseExternalBlurEvent"]
679
- }
680
- ],
681
- TAG_INPUT_ENTER: [
682
- {
683
- guard: "isEditedTagEmpty",
684
- target: "navigating:tag",
685
- actions: ["deleteHighlightedTag", "focusInput", "clearEditedId", "highlightTagAtIndex"]
686
- },
687
- {
688
- target: "navigating:tag",
689
- actions: ["submitEditedTagValue", "focusInput", "clearEditedId", "highlightTagAtIndex"]
690
- }
691
- ]
692
- }
693
- }
694
- }
695
- },
696
- {
697
- guards: {
698
- isInputRelatedTarget: (ctx2, evt) => evt.relatedTarget === dom.getInputEl(ctx2),
699
- isAtMax: (ctx2) => ctx2.isAtMax,
700
- hasHighlightedTag: (ctx2) => ctx2.highlightedTagId !== null,
701
- isFirstTagHighlighted: (ctx2) => {
702
- const firstItemId = dom.getItemId(ctx2, { value: ctx2.value[0], index: 0 });
703
- return firstItemId === ctx2.highlightedTagId;
704
- },
705
- isEditedTagEmpty: (ctx2) => ctx2.editedTagValue.trim() === "",
706
- isLastTagHighlighted: (ctx2) => {
707
- const lastIndex = ctx2.value.length - 1;
708
- const lastItemId = dom.getItemId(ctx2, { value: ctx2.value[lastIndex], index: lastIndex });
709
- return lastItemId === ctx2.highlightedTagId;
710
- },
711
- isInputValueEmpty: (ctx2) => ctx2.trimmedInputValue.length === 0,
712
- hasTags: (ctx2) => ctx2.value.length > 0,
713
- allowOverflow: (ctx2) => !!ctx2.allowOverflow,
714
- autoFocus: (ctx2) => !!ctx2.autoFocus,
715
- addOnBlur: (ctx2) => ctx2.blurBehavior === "add",
716
- clearOnBlur: (ctx2) => ctx2.blurBehavior === "clear",
717
- addOnPaste: (ctx2) => !!ctx2.addOnPaste,
718
- isTagEditable: (ctx2) => !!ctx2.editable,
719
- isInputCaretAtStart(ctx2) {
720
- const input = dom.getInputEl(ctx2);
721
- if (!input)
722
- return false;
723
- try {
724
- return input.selectionStart === 0 && input.selectionEnd === 0;
725
- } catch {
726
- return input.value === "";
727
- }
728
- }
729
- },
730
- activities: {
731
- trackInteractOutside(ctx2, _evt, { send }) {
732
- return trackInteractOutside(dom.getInputEl(ctx2), {
733
- exclude(target) {
734
- return contains(dom.getRootEl(ctx2), target);
735
- },
736
- onFocusOutside: ctx2.onFocusOutside,
737
- onPointerDownOutside: ctx2.onPointerDownOutside,
738
- onInteractOutside(event) {
739
- ctx2.onInteractOutside?.(event);
740
- if (event.defaultPrevented)
741
- return;
742
- send({ type: "BLUR", src: "interact-outside" });
743
- }
744
- });
745
- },
746
- trackFormControlState(ctx2, _evt, { send, initialContext }) {
747
- return trackFormControl(dom.getHiddenInputEl(ctx2), {
748
- onFieldsetDisabledChange(disabled) {
749
- ctx2.fieldsetDisabled = disabled;
750
- },
751
- onFormReset() {
752
- send({ type: "SET_VALUE", value: initialContext.value, src: "form-reset" });
753
- }
754
- });
755
- },
756
- autoResize(ctx2) {
757
- if (!ctx2.editedTagValue || ctx2.idx == null || !ctx2.editable)
758
- return;
759
- const input = dom.getTagInputEl(ctx2, { value: ctx2.editedTagValue, index: ctx2.idx });
760
- return autoResizeInput(input);
761
- },
762
- trackLiveRegion(ctx2) {
763
- ctx2.liveRegion = createLiveRegion({
764
- level: "assertive",
765
- document: dom.getDoc(ctx2)
766
- });
767
- return () => ctx2.liveRegion?.destroy();
768
- }
769
- },
770
- actions: {
771
- raiseInsertTagEvent(_, __, { self }) {
772
- self.send("INSERT_TAG");
773
- },
774
- raiseExternalBlurEvent(_, evt, { self }) {
775
- self.send({ type: "EXTERNAL_BLUR", id: evt.id });
776
- },
777
- dispatchChangeEvent(ctx2) {
778
- dom.dispatchInputEvent(ctx2);
779
- },
780
- highlightNextTag(ctx2) {
781
- if (ctx2.highlightedTagId == null)
782
- return;
783
- const next = dom.getNextEl(ctx2, ctx2.highlightedTagId);
784
- set.highlightedId(ctx2, next?.id ?? null);
785
- },
786
- highlightFirstTag(ctx2) {
787
- raf(() => {
788
- const first = dom.getFirstEl(ctx2);
789
- set.highlightedId(ctx2, first?.id ?? null);
790
- });
791
- },
792
- highlightLastTag(ctx2) {
793
- const last = dom.getLastEl(ctx2);
794
- set.highlightedId(ctx2, last?.id ?? null);
795
- },
796
- highlightPrevTag(ctx2) {
797
- if (ctx2.highlightedTagId == null)
798
- return;
799
- const prev = dom.getPrevEl(ctx2, ctx2.highlightedTagId);
800
- set.highlightedId(ctx2, prev?.id ?? null);
801
- },
802
- highlightTag(ctx2, evt) {
803
- set.highlightedId(ctx2, evt.id);
804
- },
805
- highlightTagAtIndex(ctx2) {
806
- raf(() => {
807
- if (ctx2.idx == null)
808
- return;
809
- const tagEl = dom.getTagElAtIndex(ctx2, ctx2.idx);
810
- if (tagEl == null)
811
- return;
812
- set.highlightedId(ctx2, tagEl.id);
813
- ctx2.idx = void 0;
814
- });
815
- },
816
- deleteTag(ctx2, evt) {
817
- const index = dom.getIndexOfId(ctx2, evt.id);
818
- const value = ctx2.value[index];
819
- ctx2.log.prev = ctx2.log.current;
820
- ctx2.log.current = { type: "delete", value };
821
- set.value(ctx2, removeAt(ctx2.value, index));
822
- },
823
- deleteHighlightedTag(ctx2) {
824
- if (ctx2.highlightedTagId == null)
825
- return;
826
- const index = dom.getIndexOfId(ctx2, ctx2.highlightedTagId);
827
- ctx2.idx = index;
828
- const value = ctx2.value[index];
829
- ctx2.log.prev = ctx2.log.current;
830
- ctx2.log.current = { type: "delete", value };
831
- set.value(ctx2, removeAt(ctx2.value, index));
832
- },
833
- setEditedId(ctx2, evt) {
834
- ctx2.editedTagId = evt.id ?? ctx2.highlightedTagId;
835
- ctx2.idx = dom.getIndexOfId(ctx2, ctx2.editedTagId);
836
- },
837
- clearEditedId(ctx2) {
838
- ctx2.editedTagId = null;
839
- },
840
- clearEditedTagValue(ctx2) {
841
- ctx2.editedTagValue = "";
842
- },
843
- setEditedTagValue(ctx2, evt) {
844
- ctx2.editedTagValue = evt.value;
845
- },
846
- submitEditedTagValue(ctx2) {
847
- if (!ctx2.editedTagId)
848
- return;
849
- const index = dom.getIndexOfId(ctx2, ctx2.editedTagId);
850
- set.valueAtIndex(ctx2, index, ctx2.editedTagValue ?? "");
851
- ctx2.log.prev = ctx2.log.current;
852
- ctx2.log.current = { type: "update", value: ctx2.editedTagValue };
853
- },
854
- setValueAtIndex(ctx2, evt) {
855
- if (evt.value) {
856
- ctx2.value[evt.index] = evt.value;
857
- ctx2.log.prev = ctx2.log.current;
858
- ctx2.log.current = { type: "update", value: evt.value };
859
- } else {
860
- warn("You need to provide a value for the tag");
861
- }
862
- },
863
- initializeEditedTagValue(ctx2) {
864
- if (!ctx2.editedTagId)
865
- return;
866
- const index = dom.getIndexOfId(ctx2, ctx2.editedTagId);
867
- ctx2.editedTagValue = ctx2.value[index];
868
- },
869
- focusEditedTagInput(ctx2) {
870
- raf(() => {
871
- dom.getEditInputEl(ctx2)?.select();
872
- });
873
- },
874
- setInputValue(ctx2, evt) {
875
- set.inputValue(ctx2, evt.value);
876
- },
877
- clearHighlightedId(ctx2) {
878
- ctx2.highlightedTagId = null;
879
- },
880
- focusInput(ctx2) {
881
- raf(() => {
882
- dom.getInputEl(ctx2)?.focus();
883
- });
884
- },
885
- clearInputValue(ctx2) {
886
- raf(() => {
887
- set.inputValue(ctx2, "");
888
- });
889
- },
890
- syncInputValue(ctx2) {
891
- const inputEl = dom.getInputEl(ctx2);
892
- dom.setValue(inputEl, ctx2.inputValue);
893
- },
894
- syncEditedTagInputValue(ctx2, evt) {
895
- const id = ctx2.editedTagId || ctx2.highlightedTagId || evt.id;
896
- if (id == null)
897
- return;
898
- const editTagInputEl = dom.getById(ctx2, `${id}:input`);
899
- dom.setValue(editTagInputEl, ctx2.editedTagValue);
900
- },
901
- addTag(ctx2, evt) {
902
- const value = evt.value ?? ctx2.trimmedInputValue;
903
- const guard = ctx2.validate?.({ inputValue: value, value: Array.from(ctx2.value) });
904
- if (guard) {
905
- const nextValue = uniq(ctx2.value.concat(value));
906
- set.value(ctx2, nextValue);
907
- ctx2.log.prev = ctx2.log.current;
908
- ctx2.log.current = { type: "add", value };
909
- } else {
910
- ctx2.onValueInvalid?.({ reason: "invalidTag" });
911
- }
912
- },
913
- addTagFromPaste(ctx2) {
914
- raf(() => {
915
- const value = ctx2.trimmedInputValue;
916
- const guard = ctx2.validate?.({ inputValue: value, value: Array.from(ctx2.value) });
917
- if (guard) {
918
- const trimmedValue = ctx2.delimiter ? value.split(ctx2.delimiter).map((v) => v.trim()) : [value];
919
- const nextValue = uniq(ctx2.value.concat(...trimmedValue));
920
- set.value(ctx2, nextValue);
921
- ctx2.log.prev = ctx2.log.current;
922
- ctx2.log.current = { type: "paste", values: trimmedValue };
923
- } else {
924
- ctx2.onValueInvalid?.({ reason: "invalidTag" });
925
- }
926
- set.inputValue(ctx2, "");
927
- });
928
- },
929
- clearTags(ctx2) {
930
- set.value(ctx2, []);
931
- ctx2.log.prev = ctx2.log.current;
932
- ctx2.log.current = { type: "clear" };
933
- },
934
- setValue(ctx2, evt) {
935
- set.value(ctx2, evt.value);
936
- },
937
- invokeOnInvalid(ctx2) {
938
- if (ctx2.isOverflowing) {
939
- ctx2.onValueInvalid?.({ reason: "rangeOverflow" });
940
- }
941
- },
942
- clearLog(ctx2) {
943
- ctx2.log = { prev: null, current: null };
944
- },
945
- logHighlightedTag(ctx2) {
946
- if (ctx2.highlightedTagId == null)
947
- return;
948
- const index = dom.getIndexOfId(ctx2, ctx2.highlightedTagId);
949
- ctx2.log.prev = ctx2.log.current;
950
- ctx2.log.current = { type: "select", value: ctx2.value[index] };
951
- },
952
- // queue logs with screen reader and get it announced
953
- announceLog(ctx2) {
954
- if (!ctx2.log.current || ctx2.liveRegion == null)
955
- return;
956
- const region = ctx2.liveRegion;
957
- const { current, prev } = ctx2.log;
958
- let msg;
959
- switch (current.type) {
960
- case "add":
961
- msg = ctx2.translations.tagAdded(current.value);
962
- break;
963
- case "delete":
964
- msg = ctx2.translations.tagDeleted(current.value);
965
- break;
966
- case "update":
967
- msg = ctx2.translations.tagUpdated(current.value);
968
- break;
969
- case "paste":
970
- msg = ctx2.translations.tagsPasted(current.values);
971
- break;
972
- case "select":
973
- msg = ctx2.translations.tagSelected(current.value);
974
- if (prev?.type === "delete") {
975
- msg = `${ctx2.translations.tagDeleted(prev.value)}. ${msg}`;
976
- } else if (prev?.type === "update") {
977
- msg = `${ctx2.translations.tagUpdated(prev.value)}. ${msg}`;
978
- }
979
- break;
980
- }
981
- if (msg)
982
- region.announce(msg);
983
- }
984
- }
985
- }
986
- );
987
- }
988
-
989
- const props = createProps()([
990
- "addOnPaste",
991
- "allowOverflow",
992
- "autoFocus",
993
- "blurBehavior",
994
- "delimiter",
995
- "dir",
996
- "disabled",
997
- "editable",
998
- "form",
999
- "getRootNode",
1000
- "id",
1001
- "ids",
1002
- "inputValue",
1003
- "invalid",
1004
- "max",
1005
- "maxLength",
1006
- "name",
1007
- "onFocusOutside",
1008
- "onHighlightChange",
1009
- "onInputValueChange",
1010
- "onInteractOutside",
1011
- "onPointerDownOutside",
1012
- "onValueChange",
1013
- "onValueInvalid",
1014
- "required",
1015
- "readOnly",
1016
- "translations",
1017
- "validate",
1018
- "value"
1019
- ]);
1020
- const splitProps = createSplitProps(props);
1021
- const itemProps = createProps()(["index", "disabled", "value"]);
1022
- const splitItemProps = createSplitProps(itemProps);
1023
-
1024
- export { anatomy, connect, itemProps, machine, props, splitItemProps, splitProps };