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