@zag-js/pin-input 0.70.0 → 0.71.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
@@ -1,44 +1,16 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
19
2
 
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- anatomy: () => anatomy,
24
- connect: () => connect,
25
- machine: () => machine
26
- });
27
- module.exports = __toCommonJS(src_exports);
3
+ var anatomy$1 = require('@zag-js/anatomy');
4
+ var domEvent = require('@zag-js/dom-event');
5
+ var domQuery = require('@zag-js/dom-query');
6
+ var utils = require('@zag-js/utils');
7
+ var core = require('@zag-js/core');
8
+ var formUtils = require('@zag-js/form-utils');
28
9
 
29
10
  // src/pin-input.anatomy.ts
30
- var import_anatomy = require("@zag-js/anatomy");
31
- var anatomy = (0, import_anatomy.createAnatomy)("pinInput").parts("root", "label", "input", "control");
11
+ var anatomy = anatomy$1.createAnatomy("pinInput").parts("root", "label", "input", "control");
32
12
  var parts = anatomy.build();
33
-
34
- // src/pin-input.connect.ts
35
- var import_dom_event = require("@zag-js/dom-event");
36
- var import_dom_query2 = require("@zag-js/dom-query");
37
- var import_utils = require("@zag-js/utils");
38
-
39
- // src/pin-input.dom.ts
40
- var import_dom_query = require("@zag-js/dom-query");
41
- var dom = (0, import_dom_query.createScope)({
13
+ var dom = domQuery.createScope({
42
14
  getRootId: (ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`,
43
15
  getInputId: (ctx, id) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`,
44
16
  getHiddenInputId: (ctx) => ctx.ids?.hiddenInput ?? `pin-input:${ctx.id}:hidden`,
@@ -48,7 +20,7 @@ var dom = (0, import_dom_query.createScope)({
48
20
  getInputEls: (ctx) => {
49
21
  const ownerId = CSS.escape(dom.getRootId(ctx));
50
22
  const selector = `input[data-ownedby=${ownerId}]`;
51
- return (0, import_dom_query.queryAll)(dom.getRootEl(ctx), selector);
23
+ return domQuery.queryAll(dom.getRootEl(ctx), selector);
52
24
  },
53
25
  getInputEl: (ctx, id) => dom.getById(ctx, dom.getInputId(ctx, id)),
54
26
  getFocusedInputEl: (ctx) => dom.getInputEls(ctx)[ctx.focusedIndex],
@@ -88,7 +60,7 @@ function connect(state, send, normalize) {
88
60
  complete,
89
61
  setValue(value) {
90
62
  if (!Array.isArray(value)) {
91
- (0, import_utils.invariant)("[pin-input/setValue] value must be an array");
63
+ utils.invariant("[pin-input/setValue] value must be an array");
92
64
  }
93
65
  send({ type: "VALUE.SET", value });
94
66
  },
@@ -103,10 +75,10 @@ function connect(state, send, normalize) {
103
75
  dir: state.context.dir,
104
76
  ...parts.root.attrs,
105
77
  id: dom.getRootId(state.context),
106
- "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
107
- "data-disabled": (0, import_dom_query2.dataAttr)(state.context.disabled),
108
- "data-complete": (0, import_dom_query2.dataAttr)(complete),
109
- "data-readonly": (0, import_dom_query2.dataAttr)(state.context.readOnly)
78
+ "data-invalid": domQuery.dataAttr(invalid),
79
+ "data-disabled": domQuery.dataAttr(state.context.disabled),
80
+ "data-complete": domQuery.dataAttr(complete),
81
+ "data-readonly": domQuery.dataAttr(state.context.readOnly)
110
82
  });
111
83
  },
112
84
  getLabelProps() {
@@ -115,10 +87,10 @@ function connect(state, send, normalize) {
115
87
  dir: state.context.dir,
116
88
  htmlFor: dom.getHiddenInputId(state.context),
117
89
  id: dom.getLabelId(state.context),
118
- "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
119
- "data-disabled": (0, import_dom_query2.dataAttr)(state.context.disabled),
120
- "data-complete": (0, import_dom_query2.dataAttr)(complete),
121
- "data-readonly": (0, import_dom_query2.dataAttr)(state.context.readOnly),
90
+ "data-invalid": domQuery.dataAttr(invalid),
91
+ "data-disabled": domQuery.dataAttr(state.context.disabled),
92
+ "data-complete": domQuery.dataAttr(complete),
93
+ "data-readonly": domQuery.dataAttr(state.context.readOnly),
122
94
  onClick(event) {
123
95
  event.preventDefault();
124
96
  focus();
@@ -136,7 +108,7 @@ function connect(state, send, normalize) {
136
108
  required: state.context.required,
137
109
  name: state.context.name,
138
110
  form: state.context.form,
139
- style: import_dom_query2.visuallyHiddenStyle,
111
+ style: domQuery.visuallyHiddenStyle,
140
112
  maxLength: state.context.valueLength,
141
113
  defaultValue: state.context.valueAsString
142
114
  });
@@ -155,14 +127,14 @@ function connect(state, send, normalize) {
155
127
  ...parts.input.attrs,
156
128
  dir: state.context.dir,
157
129
  disabled: state.context.disabled,
158
- "data-disabled": (0, import_dom_query2.dataAttr)(state.context.disabled),
159
- "data-complete": (0, import_dom_query2.dataAttr)(complete),
130
+ "data-disabled": domQuery.dataAttr(state.context.disabled),
131
+ "data-complete": domQuery.dataAttr(complete),
160
132
  id: dom.getInputId(state.context, index.toString()),
161
133
  "data-ownedby": dom.getRootId(state.context),
162
134
  "aria-label": translations.inputLabel(index, state.context.valueLength),
163
135
  inputMode: state.context.otp || state.context.type === "numeric" ? "numeric" : "text",
164
- "aria-invalid": (0, import_dom_query2.ariaAttr)(invalid),
165
- "data-invalid": (0, import_dom_query2.dataAttr)(invalid),
136
+ "aria-invalid": domQuery.ariaAttr(invalid),
137
+ "data-invalid": domQuery.dataAttr(invalid),
166
138
  type: state.context.mask ? "password" : inputType,
167
139
  defaultValue: state.context.value[index] || "",
168
140
  readOnly: state.context.readOnly,
@@ -171,7 +143,7 @@ function connect(state, send, normalize) {
171
143
  placeholder: focusedIndex === index ? "" : state.context.placeholder,
172
144
  onBeforeInput(event) {
173
145
  try {
174
- const value = (0, import_dom_query2.getBeforeInputValue)(event);
146
+ const value = domQuery.getBeforeInputValue(event);
175
147
  const isValid = isValidValue(state.context, value);
176
148
  if (!isValid) {
177
149
  send({ type: "VALUE.INVALID", value });
@@ -184,7 +156,7 @@ function connect(state, send, normalize) {
184
156
  }
185
157
  },
186
158
  onChange(event) {
187
- const evt = (0, import_dom_event.getNativeEvent)(event);
159
+ const evt = domEvent.getNativeEvent(event);
188
160
  const { value } = event.currentTarget;
189
161
  if (evt.inputType === "insertFromPaste" || value.length > 2) {
190
162
  send({ type: "INPUT.PASTE", value });
@@ -200,8 +172,8 @@ function connect(state, send, normalize) {
200
172
  },
201
173
  onKeyDown(event) {
202
174
  if (event.defaultPrevented) return;
203
- if ((0, import_dom_query2.isComposingEvent)(event)) return;
204
- if ((0, import_dom_event.isModifierKey)(event)) return;
175
+ if (domQuery.isComposingEvent(event)) return;
176
+ if (domEvent.isModifierKey(event)) return;
205
177
  const keyMap = {
206
178
  Backspace() {
207
179
  send("INPUT.BACKSPACE");
@@ -219,7 +191,7 @@ function connect(state, send, normalize) {
219
191
  send("INPUT.ENTER");
220
192
  }
221
193
  };
222
- const exec = keyMap[(0, import_dom_event.getEventKey)(event, state.context)];
194
+ const exec = keyMap[domEvent.getEventKey(event, state.context)];
223
195
  if (exec) {
224
196
  exec(event);
225
197
  event.preventDefault();
@@ -235,15 +207,9 @@ function connect(state, send, normalize) {
235
207
  }
236
208
  };
237
209
  }
238
-
239
- // src/pin-input.machine.ts
240
- var import_core = require("@zag-js/core");
241
- var import_dom_query3 = require("@zag-js/dom-query");
242
- var import_form_utils = require("@zag-js/form-utils");
243
- var import_utils2 = require("@zag-js/utils");
244
210
  function machine(userContext) {
245
- const ctx = (0, import_utils2.compact)(userContext);
246
- return (0, import_core.createMachine)(
211
+ const ctx = utils.compact(userContext);
212
+ return core.createMachine(
247
213
  {
248
214
  id: "pin-input",
249
215
  initial: "idle",
@@ -266,7 +232,7 @@ function machine(userContext) {
266
232
  valueAsString: (ctx2) => ctx2.value.join(""),
267
233
  focusedValue: (ctx2) => ctx2.value[ctx2.focusedIndex] || ""
268
234
  },
269
- entry: (0, import_core.choose)([
235
+ entry: core.choose([
270
236
  {
271
237
  guard: "autoFocus",
272
238
  actions: ["setupValue", "setFocusIndexToFirst"]
@@ -370,7 +336,7 @@ function machine(userContext) {
370
336
  },
371
337
  selectInputIfNeeded(ctx2) {
372
338
  if (!ctx2.selectOnFocus || ctx2.focusedIndex === -1) return;
373
- (0, import_dom_query3.raf)(() => {
339
+ domQuery.raf(() => {
374
340
  dom.getFocusedInputEl(ctx2)?.select();
375
341
  });
376
342
  },
@@ -415,7 +381,7 @@ function machine(userContext) {
415
381
  });
416
382
  },
417
383
  setPastedValue(ctx2, evt) {
418
- (0, import_dom_query3.raf)(() => {
384
+ domQuery.raf(() => {
419
385
  const startIndex = Math.min(ctx2.focusedIndex, ctx2.filledValueLength);
420
386
  const left = startIndex > 0 ? ctx2.valueAsString.substring(0, ctx2.focusedIndex) : "";
421
387
  const right = evt.value.substring(0, ctx2.valueLength - startIndex);
@@ -444,13 +410,13 @@ function machine(userContext) {
444
410
  ctx2.focusedIndex = Math.max(ctx2.focusedIndex - 1, 0);
445
411
  },
446
412
  setLastValueFocusIndex(ctx2) {
447
- (0, import_dom_query3.raf)(() => {
413
+ domQuery.raf(() => {
448
414
  ctx2.focusedIndex = Math.min(ctx2.filledValueLength, ctx2.valueLength - 1);
449
415
  });
450
416
  },
451
417
  blurFocusedInputIfNeeded(ctx2) {
452
418
  if (!ctx2.blurOnComplete) return;
453
- (0, import_dom_query3.raf)(() => {
419
+ domQuery.raf(() => {
454
420
  dom.getFocusedInputEl(ctx2)?.blur();
455
421
  });
456
422
  },
@@ -482,25 +448,22 @@ var invoke = {
482
448
  valueAsString: ctx.valueAsString
483
449
  });
484
450
  const inputEl = dom.getHiddenInputEl(ctx);
485
- (0, import_form_utils.dispatchInputValueEvent)(inputEl, { value: ctx.valueAsString });
451
+ formUtils.dispatchInputValueEvent(inputEl, { value: ctx.valueAsString });
486
452
  }
487
453
  };
488
454
  var set = {
489
455
  value(ctx, value) {
490
- if ((0, import_utils2.isEqual)(ctx.value, value)) return;
456
+ if (utils.isEqual(ctx.value, value)) return;
491
457
  assignValue(ctx, value);
492
458
  invoke.change(ctx);
493
459
  },
494
460
  valueAtIndex(ctx, index, value) {
495
- if ((0, import_utils2.isEqual)(ctx.value[index], value)) return;
461
+ if (utils.isEqual(ctx.value[index], value)) return;
496
462
  ctx.value[index] = value;
497
463
  invoke.change(ctx);
498
464
  }
499
465
  };
500
- // Annotate the CommonJS export names for ESM import in node:
501
- 0 && (module.exports = {
502
- anatomy,
503
- connect,
504
- machine
505
- });
506
- //# sourceMappingURL=index.js.map
466
+
467
+ exports.anatomy = anatomy;
468
+ exports.connect = connect;
469
+ exports.machine = machine;
package/dist/index.mjs CHANGED
@@ -1,15 +1,13 @@
1
+ import { createAnatomy } from '@zag-js/anatomy';
2
+ import { getNativeEvent, isModifierKey, getEventKey } from '@zag-js/dom-event';
3
+ import { createScope, queryAll, dataAttr, visuallyHiddenStyle, ariaAttr, getBeforeInputValue, isComposingEvent, raf } from '@zag-js/dom-query';
4
+ import { invariant, compact, isEqual } from '@zag-js/utils';
5
+ import { createMachine, choose } from '@zag-js/core';
6
+ import { dispatchInputValueEvent } from '@zag-js/form-utils';
7
+
1
8
  // src/pin-input.anatomy.ts
2
- import { createAnatomy } from "@zag-js/anatomy";
3
9
  var anatomy = createAnatomy("pinInput").parts("root", "label", "input", "control");
4
10
  var parts = anatomy.build();
5
-
6
- // src/pin-input.connect.ts
7
- import { getEventKey, getNativeEvent, isModifierKey } from "@zag-js/dom-event";
8
- import { ariaAttr, dataAttr, getBeforeInputValue, isComposingEvent, visuallyHiddenStyle } from "@zag-js/dom-query";
9
- import { invariant } from "@zag-js/utils";
10
-
11
- // src/pin-input.dom.ts
12
- import { createScope, queryAll } from "@zag-js/dom-query";
13
11
  var dom = createScope({
14
12
  getRootId: (ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`,
15
13
  getInputId: (ctx, id) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`,
@@ -207,12 +205,6 @@ function connect(state, send, normalize) {
207
205
  }
208
206
  };
209
207
  }
210
-
211
- // src/pin-input.machine.ts
212
- import { choose, createMachine } from "@zag-js/core";
213
- import { raf } from "@zag-js/dom-query";
214
- import { dispatchInputValueEvent } from "@zag-js/form-utils";
215
- import { compact, isEqual } from "@zag-js/utils";
216
208
  function machine(userContext) {
217
209
  const ctx = compact(userContext);
218
210
  return createMachine(
@@ -469,9 +461,5 @@ var set = {
469
461
  invoke.change(ctx);
470
462
  }
471
463
  };
472
- export {
473
- anatomy,
474
- connect,
475
- machine
476
- };
477
- //# sourceMappingURL=index.mjs.map
464
+
465
+ export { anatomy, connect, machine };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/pin-input",
3
- "version": "0.70.0",
3
+ "version": "0.71.0",
4
4
  "description": "Core logic for the pin-input widget implemented as a state machine",
5
5
  "keywords": [
6
6
  "js",
@@ -17,8 +17,7 @@
17
17
  "repository": "https://github.com/chakra-ui/zag/tree/main/packages/pin-input",
18
18
  "sideEffects": false,
19
19
  "files": [
20
- "dist",
21
- "src"
20
+ "dist"
22
21
  ],
23
22
  "publishConfig": {
24
23
  "access": "public"
@@ -27,13 +26,13 @@
27
26
  "url": "https://github.com/chakra-ui/zag/issues"
28
27
  },
29
28
  "dependencies": {
30
- "@zag-js/anatomy": "0.70.0",
31
- "@zag-js/dom-query": "0.70.0",
32
- "@zag-js/dom-event": "0.70.0",
33
- "@zag-js/form-utils": "0.70.0",
34
- "@zag-js/utils": "0.70.0",
35
- "@zag-js/core": "0.70.0",
36
- "@zag-js/types": "0.70.0"
29
+ "@zag-js/anatomy": "0.71.0",
30
+ "@zag-js/dom-query": "0.71.0",
31
+ "@zag-js/dom-event": "0.71.0",
32
+ "@zag-js/form-utils": "0.71.0",
33
+ "@zag-js/utils": "0.71.0",
34
+ "@zag-js/core": "0.71.0",
35
+ "@zag-js/types": "0.71.0"
37
36
  },
38
37
  "devDependencies": {
39
38
  "clean-package": "2.2.0"
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../src/pin-input.anatomy.ts","../src/pin-input.connect.ts","../src/pin-input.dom.ts","../src/pin-input.utils.ts","../src/pin-input.machine.ts"],"sourcesContent":["export { anatomy } from \"./pin-input.anatomy\"\nexport { connect } from \"./pin-input.connect\"\nexport { machine } from \"./pin-input.machine\"\nexport type {\n MachineApi as Api,\n UserDefinedContext as Context,\n ElementIds,\n InputProps,\n IntlTranslations,\n ValueChangeDetails,\n ValueInvalidDetails,\n} from \"./pin-input.types\"\n","import { createAnatomy } from \"@zag-js/anatomy\"\n\nexport const anatomy = createAnatomy(\"pinInput\").parts(\"root\", \"label\", \"input\", \"control\")\nexport const parts = anatomy.build()\n","import { getEventKey, getNativeEvent, isModifierKey, type EventKeyMap } from \"@zag-js/dom-event\"\nimport { ariaAttr, dataAttr, getBeforeInputValue, isComposingEvent, visuallyHiddenStyle } from \"@zag-js/dom-query\"\nimport type { NormalizeProps, PropTypes } from \"@zag-js/types\"\nimport { invariant } from \"@zag-js/utils\"\nimport { parts } from \"./pin-input.anatomy\"\nimport { dom } from \"./pin-input.dom\"\nimport type { MachineApi, Send, State } from \"./pin-input.types\"\nimport { isValidValue } from \"./pin-input.utils\"\n\nexport function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T> {\n const complete = state.context.isValueComplete\n const invalid = state.context.invalid\n const focusedIndex = state.context.focusedIndex\n const translations = state.context.translations\n\n function focus() {\n dom.getFirstInputEl(state.context)?.focus()\n }\n\n return {\n focus,\n value: state.context.value,\n valueAsString: state.context.valueAsString,\n complete: complete,\n setValue(value) {\n if (!Array.isArray(value)) {\n invariant(\"[pin-input/setValue] value must be an array\")\n }\n send({ type: \"VALUE.SET\", value })\n },\n clearValue() {\n send({ type: \"VALUE.CLEAR\" })\n },\n setValueAtIndex(index, value) {\n send({ type: \"VALUE.SET\", value, index })\n },\n\n getRootProps() {\n return normalize.element({\n dir: state.context.dir,\n ...parts.root.attrs,\n id: dom.getRootId(state.context),\n \"data-invalid\": dataAttr(invalid),\n \"data-disabled\": dataAttr(state.context.disabled),\n \"data-complete\": dataAttr(complete),\n \"data-readonly\": dataAttr(state.context.readOnly),\n })\n },\n\n getLabelProps() {\n return normalize.label({\n ...parts.label.attrs,\n dir: state.context.dir,\n htmlFor: dom.getHiddenInputId(state.context),\n id: dom.getLabelId(state.context),\n \"data-invalid\": dataAttr(invalid),\n \"data-disabled\": dataAttr(state.context.disabled),\n \"data-complete\": dataAttr(complete),\n \"data-readonly\": dataAttr(state.context.readOnly),\n onClick(event) {\n event.preventDefault()\n focus()\n },\n })\n },\n\n getHiddenInputProps() {\n return normalize.input({\n \"aria-hidden\": true,\n type: \"text\",\n tabIndex: -1,\n id: dom.getHiddenInputId(state.context),\n readOnly: state.context.readOnly,\n disabled: state.context.disabled,\n required: state.context.required,\n name: state.context.name,\n form: state.context.form,\n style: visuallyHiddenStyle,\n maxLength: state.context.valueLength,\n defaultValue: state.context.valueAsString,\n })\n },\n\n getControlProps() {\n return normalize.element({\n ...parts.control.attrs,\n dir: state.context.dir,\n id: dom.getControlId(state.context),\n })\n },\n\n getInputProps(props) {\n const { index } = props\n const inputType = state.context.type === \"numeric\" ? \"tel\" : \"text\"\n return normalize.input({\n ...parts.input.attrs,\n dir: state.context.dir,\n disabled: state.context.disabled,\n \"data-disabled\": dataAttr(state.context.disabled),\n \"data-complete\": dataAttr(complete),\n id: dom.getInputId(state.context, index.toString()),\n \"data-ownedby\": dom.getRootId(state.context),\n \"aria-label\": translations.inputLabel(index, state.context.valueLength),\n inputMode: state.context.otp || state.context.type === \"numeric\" ? \"numeric\" : \"text\",\n \"aria-invalid\": ariaAttr(invalid),\n \"data-invalid\": dataAttr(invalid),\n type: state.context.mask ? \"password\" : inputType,\n defaultValue: state.context.value[index] || \"\",\n readOnly: state.context.readOnly,\n autoCapitalize: \"none\",\n autoComplete: state.context.otp ? \"one-time-code\" : \"off\",\n placeholder: focusedIndex === index ? \"\" : state.context.placeholder,\n onBeforeInput(event) {\n try {\n const value = getBeforeInputValue(event)\n const isValid = isValidValue(state.context, value)\n if (!isValid) {\n send({ type: \"VALUE.INVALID\", value })\n event.preventDefault()\n }\n\n // select the text so paste always replaces the\n // current input's value regardless of cursor position\n if (value.length > 2) {\n event.currentTarget.setSelectionRange(0, 1, \"forward\")\n }\n } catch {\n // noop\n }\n },\n onChange(event) {\n const evt = getNativeEvent(event)\n const { value } = event.currentTarget\n\n if (evt.inputType === \"insertFromPaste\" || value.length > 2) {\n send({ type: \"INPUT.PASTE\", value })\n // prevent multiple characters being pasted\n // into a single input\n event.target.value = value[0]\n\n event.preventDefault()\n return\n }\n\n if (evt.inputType === \"deleteContentBackward\") {\n send(\"INPUT.BACKSPACE\")\n return\n }\n\n send({ type: \"INPUT.CHANGE\", value, index })\n },\n onKeyDown(event) {\n if (event.defaultPrevented) return\n\n if (isComposingEvent(event)) return\n if (isModifierKey(event)) return\n\n const keyMap: EventKeyMap = {\n Backspace() {\n send(\"INPUT.BACKSPACE\")\n },\n Delete() {\n send(\"INPUT.DELETE\")\n },\n ArrowLeft() {\n send(\"INPUT.ARROW_LEFT\")\n },\n ArrowRight() {\n send(\"INPUT.ARROW_RIGHT\")\n },\n Enter() {\n send(\"INPUT.ENTER\")\n },\n }\n\n const exec = keyMap[getEventKey(event, state.context)]\n\n if (exec) {\n exec(event)\n event.preventDefault()\n }\n },\n onFocus() {\n send({ type: \"INPUT.FOCUS\", index })\n },\n onBlur() {\n send({ type: \"INPUT.BLUR\", index })\n },\n })\n },\n }\n}\n","import { createScope, queryAll } from \"@zag-js/dom-query\"\nimport type { MachineContext as Ctx } from \"./pin-input.types\"\n\nexport const dom = createScope({\n getRootId: (ctx: Ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`,\n getInputId: (ctx: Ctx, id: string) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`,\n getHiddenInputId: (ctx: Ctx) => ctx.ids?.hiddenInput ?? `pin-input:${ctx.id}:hidden`,\n getLabelId: (ctx: Ctx) => ctx.ids?.label ?? `pin-input:${ctx.id}:label`,\n getControlId: (ctx: Ctx) => ctx.ids?.control ?? `pin-input:${ctx.id}:control`,\n\n getRootEl: (ctx: Ctx) => dom.getById(ctx, dom.getRootId(ctx)),\n getInputEls: (ctx: Ctx) => {\n const ownerId = CSS.escape(dom.getRootId(ctx))\n const selector = `input[data-ownedby=${ownerId}]`\n return queryAll<HTMLInputElement>(dom.getRootEl(ctx), selector)\n },\n getInputEl: (ctx: Ctx, id: string) => dom.getById<HTMLInputElement>(ctx, dom.getInputId(ctx, id)),\n getFocusedInputEl: (ctx: Ctx) => dom.getInputEls(ctx)[ctx.focusedIndex],\n getFirstInputEl: (ctx: Ctx) => dom.getInputEls(ctx)[0],\n getHiddenInputEl: (ctx: Ctx) => dom.getById<HTMLInputElement>(ctx, dom.getHiddenInputId(ctx)),\n})\n","import type { MachineContext } from \"./pin-input.types\"\n\nconst REGEX = {\n numeric: /^[0-9]+$/,\n alphabetic: /^[A-Za-z]+$/,\n alphanumeric: /^[a-zA-Z0-9]+$/i,\n}\n\nexport function isValidType(ctx: MachineContext, value: string) {\n if (!ctx.type) return true\n return !!REGEX[ctx.type]?.test(value)\n}\n\nexport function isValidValue(ctx: MachineContext, value: string) {\n if (!ctx.pattern) return isValidType(ctx, value)\n const regex = new RegExp(ctx.pattern, \"g\")\n return regex.test(value)\n}\n","import { choose, createMachine } from \"@zag-js/core\"\nimport { raf } from \"@zag-js/dom-query\"\nimport { dispatchInputValueEvent } from \"@zag-js/form-utils\"\nimport { compact, isEqual } from \"@zag-js/utils\"\nimport { dom } from \"./pin-input.dom\"\nimport type { MachineContext, MachineState, UserDefinedContext } from \"./pin-input.types\"\n\nexport function machine(userContext: UserDefinedContext) {\n const ctx = compact(userContext)\n return createMachine<MachineContext, MachineState>(\n {\n id: \"pin-input\",\n initial: \"idle\",\n context: {\n value: [],\n placeholder: \"○\",\n otp: false,\n type: \"numeric\",\n ...ctx,\n focusedIndex: -1,\n translations: {\n inputLabel: (index, length) => `pin code ${index + 1} of ${length}`,\n ...ctx.translations,\n },\n },\n\n computed: {\n valueLength: (ctx) => ctx.value.length,\n filledValueLength: (ctx) => ctx.value.filter((v) => v?.trim() !== \"\").length,\n isValueComplete: (ctx) => ctx.valueLength === ctx.filledValueLength,\n valueAsString: (ctx) => ctx.value.join(\"\"),\n focusedValue: (ctx) => ctx.value[ctx.focusedIndex] || \"\",\n },\n\n entry: choose([\n {\n guard: \"autoFocus\",\n actions: [\"setupValue\", \"setFocusIndexToFirst\"],\n },\n { actions: [\"setupValue\"] },\n ]),\n\n watch: {\n focusedIndex: [\"focusInput\", \"selectInputIfNeeded\"],\n value: [\"syncInputElements\"],\n isValueComplete: [\"invokeOnComplete\", \"blurFocusedInputIfNeeded\"],\n },\n\n on: {\n \"VALUE.SET\": [\n {\n guard: \"hasIndex\",\n actions: [\"setValueAtIndex\"],\n },\n { actions: [\"setValue\"] },\n ],\n \"VALUE.CLEAR\": {\n actions: [\"clearValue\", \"setFocusIndexToFirst\"],\n },\n },\n\n states: {\n idle: {\n on: {\n \"INPUT.FOCUS\": {\n target: \"focused\",\n actions: \"setFocusedIndex\",\n },\n },\n },\n focused: {\n on: {\n \"INPUT.CHANGE\": [\n {\n guard: \"isFinalValue\",\n actions: [\"setFocusedValue\", \"syncInputValue\"],\n },\n {\n actions: [\"setFocusedValue\", \"setNextFocusedIndex\", \"syncInputValue\"],\n },\n ],\n \"INPUT.PASTE\": {\n actions: [\"setPastedValue\", \"setLastValueFocusIndex\"],\n },\n \"INPUT.BLUR\": {\n target: \"idle\",\n actions: \"clearFocusedIndex\",\n },\n \"INPUT.DELETE\": {\n guard: \"hasValue\",\n actions: \"clearFocusedValue\",\n },\n \"INPUT.ARROW_LEFT\": {\n actions: \"setPrevFocusedIndex\",\n },\n \"INPUT.ARROW_RIGHT\": {\n actions: \"setNextFocusedIndex\",\n },\n \"INPUT.BACKSPACE\": [\n {\n guard: \"hasValue\",\n actions: [\"clearFocusedValue\"],\n },\n {\n actions: [\"setPrevFocusedIndex\", \"clearFocusedValue\"],\n },\n ],\n \"INPUT.ENTER\": {\n guard: \"isValueComplete\",\n actions: \"requestFormSubmit\",\n },\n \"VALUE.INVALID\": {\n actions: \"invokeOnInvalid\",\n },\n },\n },\n },\n },\n {\n guards: {\n autoFocus: (ctx) => !!ctx.autoFocus,\n isValueEmpty: (_ctx, evt) => evt.value === \"\",\n hasValue: (ctx) => ctx.value[ctx.focusedIndex] !== \"\",\n isValueComplete: (ctx) => ctx.isValueComplete,\n isFinalValue: (ctx) =>\n ctx.filledValueLength + 1 === ctx.valueLength &&\n ctx.value.findIndex((v) => v.trim() === \"\") === ctx.focusedIndex,\n hasIndex: (_ctx, evt) => evt.index !== undefined,\n isDisabled: (ctx) => !!ctx.disabled,\n },\n actions: {\n setupValue(ctx) {\n if (ctx.value.length) return\n const inputEls = dom.getInputEls(ctx)\n const emptyValues = Array.from<string>({ length: inputEls.length }).fill(\"\")\n assignValue(ctx, emptyValues)\n },\n focusInput(ctx) {\n if (ctx.focusedIndex === -1) return\n dom.getFocusedInputEl(ctx)?.focus({ preventScroll: true })\n },\n selectInputIfNeeded(ctx) {\n if (!ctx.selectOnFocus || ctx.focusedIndex === -1) return\n raf(() => {\n dom.getFocusedInputEl(ctx)?.select()\n })\n },\n invokeOnComplete(ctx) {\n if (!ctx.isValueComplete) return\n ctx.onValueComplete?.({\n value: Array.from(ctx.value),\n valueAsString: ctx.valueAsString,\n })\n },\n invokeOnInvalid(ctx, evt) {\n ctx.onValueInvalid?.({\n value: evt.value,\n index: ctx.focusedIndex,\n })\n },\n clearFocusedIndex(ctx) {\n ctx.focusedIndex = -1\n },\n setFocusedIndex(ctx, evt) {\n ctx.focusedIndex = evt.index\n },\n setValue(ctx, evt) {\n set.value(ctx, evt.value)\n },\n setFocusedValue(ctx, evt) {\n const nextValue = getNextValue(ctx.focusedValue, evt.value)\n set.valueAtIndex(ctx, ctx.focusedIndex, nextValue)\n },\n revertInputValue(ctx) {\n const inputEl = dom.getFocusedInputEl(ctx)\n dom.setValue(inputEl, ctx.focusedValue)\n },\n syncInputValue(ctx, evt) {\n const inputEl = dom.getInputEl(ctx, evt.index.toString())\n dom.setValue(inputEl, ctx.value[evt.index])\n },\n syncInputElements(ctx) {\n const inputEls = dom.getInputEls(ctx)\n inputEls.forEach((inputEl, index) => {\n dom.setValue(inputEl, ctx.value[index])\n })\n },\n setPastedValue(ctx, evt) {\n raf(() => {\n const startIndex = Math.min(ctx.focusedIndex, ctx.filledValueLength)\n\n // keep value left of cursor\n // replace value from curor to end with pasted text\n const left = startIndex > 0 ? ctx.valueAsString.substring(0, ctx.focusedIndex) : \"\"\n const right = evt.value.substring(0, ctx.valueLength - startIndex)\n\n const value = left + right\n\n set.value(ctx, value.split(\"\"))\n })\n },\n setValueAtIndex(ctx, evt) {\n const nextValue = getNextValue(ctx.focusedValue, evt.value)\n set.valueAtIndex(ctx, evt.index, nextValue)\n },\n clearValue(ctx) {\n const nextValue = Array.from<string>({ length: ctx.valueLength }).fill(\"\")\n set.value(ctx, nextValue)\n },\n clearFocusedValue(ctx) {\n set.valueAtIndex(ctx, ctx.focusedIndex, \"\")\n },\n setFocusIndexToFirst(ctx) {\n ctx.focusedIndex = 0\n },\n setNextFocusedIndex(ctx) {\n ctx.focusedIndex = Math.min(ctx.focusedIndex + 1, ctx.valueLength - 1)\n },\n setPrevFocusedIndex(ctx) {\n ctx.focusedIndex = Math.max(ctx.focusedIndex - 1, 0)\n },\n setLastValueFocusIndex(ctx) {\n raf(() => {\n ctx.focusedIndex = Math.min(ctx.filledValueLength, ctx.valueLength - 1)\n })\n },\n blurFocusedInputIfNeeded(ctx) {\n if (!ctx.blurOnComplete) return\n raf(() => {\n dom.getFocusedInputEl(ctx)?.blur()\n })\n },\n requestFormSubmit(ctx) {\n if (!ctx.name || !ctx.isValueComplete) return\n const inputEl = dom.getHiddenInputEl(ctx)\n inputEl?.form?.requestSubmit()\n },\n },\n },\n )\n}\n\nfunction assignValue(ctx: MachineContext, value: string | string[]) {\n const arr = Array.isArray(value) ? value : value.split(\"\").filter(Boolean)\n arr.forEach((value, index) => {\n ctx.value[index] = value\n })\n}\n\nfunction getNextValue(current: string, next: string) {\n let nextValue = next\n if (current[0] === next[0]) nextValue = next[1]\n else if (current[0] === next[1]) nextValue = next[0]\n return nextValue.split(\"\")[nextValue.length - 1]\n}\n\nconst invoke = {\n change(ctx: MachineContext) {\n // callback\n ctx.onValueChange?.({\n value: Array.from(ctx.value),\n valueAsString: ctx.valueAsString,\n })\n\n // form event\n const inputEl = dom.getHiddenInputEl(ctx)\n dispatchInputValueEvent(inputEl, { value: ctx.valueAsString })\n },\n}\n\nconst set = {\n value(ctx: MachineContext, value: string[]) {\n if (isEqual(ctx.value, value)) return\n assignValue(ctx, value)\n invoke.change(ctx)\n },\n valueAtIndex(ctx: MachineContext, index: number, value: string) {\n if (isEqual(ctx.value[index], value)) return\n ctx.value[index] = value\n invoke.change(ctx)\n },\n}\n"],"mappings":"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","names":["import_dom_query","import_dom_query","import_utils","ctx","value"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/pin-input.anatomy.ts","../src/pin-input.connect.ts","../src/pin-input.dom.ts","../src/pin-input.utils.ts","../src/pin-input.machine.ts"],"sourcesContent":["import { createAnatomy } from \"@zag-js/anatomy\"\n\nexport const anatomy = createAnatomy(\"pinInput\").parts(\"root\", \"label\", \"input\", \"control\")\nexport const parts = anatomy.build()\n","import { getEventKey, getNativeEvent, isModifierKey, type EventKeyMap } from \"@zag-js/dom-event\"\nimport { ariaAttr, dataAttr, getBeforeInputValue, isComposingEvent, visuallyHiddenStyle } from \"@zag-js/dom-query\"\nimport type { NormalizeProps, PropTypes } from \"@zag-js/types\"\nimport { invariant } from \"@zag-js/utils\"\nimport { parts } from \"./pin-input.anatomy\"\nimport { dom } from \"./pin-input.dom\"\nimport type { MachineApi, Send, State } from \"./pin-input.types\"\nimport { isValidValue } from \"./pin-input.utils\"\n\nexport function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T> {\n const complete = state.context.isValueComplete\n const invalid = state.context.invalid\n const focusedIndex = state.context.focusedIndex\n const translations = state.context.translations\n\n function focus() {\n dom.getFirstInputEl(state.context)?.focus()\n }\n\n return {\n focus,\n value: state.context.value,\n valueAsString: state.context.valueAsString,\n complete: complete,\n setValue(value) {\n if (!Array.isArray(value)) {\n invariant(\"[pin-input/setValue] value must be an array\")\n }\n send({ type: \"VALUE.SET\", value })\n },\n clearValue() {\n send({ type: \"VALUE.CLEAR\" })\n },\n setValueAtIndex(index, value) {\n send({ type: \"VALUE.SET\", value, index })\n },\n\n getRootProps() {\n return normalize.element({\n dir: state.context.dir,\n ...parts.root.attrs,\n id: dom.getRootId(state.context),\n \"data-invalid\": dataAttr(invalid),\n \"data-disabled\": dataAttr(state.context.disabled),\n \"data-complete\": dataAttr(complete),\n \"data-readonly\": dataAttr(state.context.readOnly),\n })\n },\n\n getLabelProps() {\n return normalize.label({\n ...parts.label.attrs,\n dir: state.context.dir,\n htmlFor: dom.getHiddenInputId(state.context),\n id: dom.getLabelId(state.context),\n \"data-invalid\": dataAttr(invalid),\n \"data-disabled\": dataAttr(state.context.disabled),\n \"data-complete\": dataAttr(complete),\n \"data-readonly\": dataAttr(state.context.readOnly),\n onClick(event) {\n event.preventDefault()\n focus()\n },\n })\n },\n\n getHiddenInputProps() {\n return normalize.input({\n \"aria-hidden\": true,\n type: \"text\",\n tabIndex: -1,\n id: dom.getHiddenInputId(state.context),\n readOnly: state.context.readOnly,\n disabled: state.context.disabled,\n required: state.context.required,\n name: state.context.name,\n form: state.context.form,\n style: visuallyHiddenStyle,\n maxLength: state.context.valueLength,\n defaultValue: state.context.valueAsString,\n })\n },\n\n getControlProps() {\n return normalize.element({\n ...parts.control.attrs,\n dir: state.context.dir,\n id: dom.getControlId(state.context),\n })\n },\n\n getInputProps(props) {\n const { index } = props\n const inputType = state.context.type === \"numeric\" ? \"tel\" : \"text\"\n return normalize.input({\n ...parts.input.attrs,\n dir: state.context.dir,\n disabled: state.context.disabled,\n \"data-disabled\": dataAttr(state.context.disabled),\n \"data-complete\": dataAttr(complete),\n id: dom.getInputId(state.context, index.toString()),\n \"data-ownedby\": dom.getRootId(state.context),\n \"aria-label\": translations.inputLabel(index, state.context.valueLength),\n inputMode: state.context.otp || state.context.type === \"numeric\" ? \"numeric\" : \"text\",\n \"aria-invalid\": ariaAttr(invalid),\n \"data-invalid\": dataAttr(invalid),\n type: state.context.mask ? \"password\" : inputType,\n defaultValue: state.context.value[index] || \"\",\n readOnly: state.context.readOnly,\n autoCapitalize: \"none\",\n autoComplete: state.context.otp ? \"one-time-code\" : \"off\",\n placeholder: focusedIndex === index ? \"\" : state.context.placeholder,\n onBeforeInput(event) {\n try {\n const value = getBeforeInputValue(event)\n const isValid = isValidValue(state.context, value)\n if (!isValid) {\n send({ type: \"VALUE.INVALID\", value })\n event.preventDefault()\n }\n\n // select the text so paste always replaces the\n // current input's value regardless of cursor position\n if (value.length > 2) {\n event.currentTarget.setSelectionRange(0, 1, \"forward\")\n }\n } catch {\n // noop\n }\n },\n onChange(event) {\n const evt = getNativeEvent(event)\n const { value } = event.currentTarget\n\n if (evt.inputType === \"insertFromPaste\" || value.length > 2) {\n send({ type: \"INPUT.PASTE\", value })\n // prevent multiple characters being pasted\n // into a single input\n event.target.value = value[0]\n\n event.preventDefault()\n return\n }\n\n if (evt.inputType === \"deleteContentBackward\") {\n send(\"INPUT.BACKSPACE\")\n return\n }\n\n send({ type: \"INPUT.CHANGE\", value, index })\n },\n onKeyDown(event) {\n if (event.defaultPrevented) return\n\n if (isComposingEvent(event)) return\n if (isModifierKey(event)) return\n\n const keyMap: EventKeyMap = {\n Backspace() {\n send(\"INPUT.BACKSPACE\")\n },\n Delete() {\n send(\"INPUT.DELETE\")\n },\n ArrowLeft() {\n send(\"INPUT.ARROW_LEFT\")\n },\n ArrowRight() {\n send(\"INPUT.ARROW_RIGHT\")\n },\n Enter() {\n send(\"INPUT.ENTER\")\n },\n }\n\n const exec = keyMap[getEventKey(event, state.context)]\n\n if (exec) {\n exec(event)\n event.preventDefault()\n }\n },\n onFocus() {\n send({ type: \"INPUT.FOCUS\", index })\n },\n onBlur() {\n send({ type: \"INPUT.BLUR\", index })\n },\n })\n },\n }\n}\n","import { createScope, queryAll } from \"@zag-js/dom-query\"\nimport type { MachineContext as Ctx } from \"./pin-input.types\"\n\nexport const dom = createScope({\n getRootId: (ctx: Ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`,\n getInputId: (ctx: Ctx, id: string) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`,\n getHiddenInputId: (ctx: Ctx) => ctx.ids?.hiddenInput ?? `pin-input:${ctx.id}:hidden`,\n getLabelId: (ctx: Ctx) => ctx.ids?.label ?? `pin-input:${ctx.id}:label`,\n getControlId: (ctx: Ctx) => ctx.ids?.control ?? `pin-input:${ctx.id}:control`,\n\n getRootEl: (ctx: Ctx) => dom.getById(ctx, dom.getRootId(ctx)),\n getInputEls: (ctx: Ctx) => {\n const ownerId = CSS.escape(dom.getRootId(ctx))\n const selector = `input[data-ownedby=${ownerId}]`\n return queryAll<HTMLInputElement>(dom.getRootEl(ctx), selector)\n },\n getInputEl: (ctx: Ctx, id: string) => dom.getById<HTMLInputElement>(ctx, dom.getInputId(ctx, id)),\n getFocusedInputEl: (ctx: Ctx) => dom.getInputEls(ctx)[ctx.focusedIndex],\n getFirstInputEl: (ctx: Ctx) => dom.getInputEls(ctx)[0],\n getHiddenInputEl: (ctx: Ctx) => dom.getById<HTMLInputElement>(ctx, dom.getHiddenInputId(ctx)),\n})\n","import type { MachineContext } from \"./pin-input.types\"\n\nconst REGEX = {\n numeric: /^[0-9]+$/,\n alphabetic: /^[A-Za-z]+$/,\n alphanumeric: /^[a-zA-Z0-9]+$/i,\n}\n\nexport function isValidType(ctx: MachineContext, value: string) {\n if (!ctx.type) return true\n return !!REGEX[ctx.type]?.test(value)\n}\n\nexport function isValidValue(ctx: MachineContext, value: string) {\n if (!ctx.pattern) return isValidType(ctx, value)\n const regex = new RegExp(ctx.pattern, \"g\")\n return regex.test(value)\n}\n","import { choose, createMachine } from \"@zag-js/core\"\nimport { raf } from \"@zag-js/dom-query\"\nimport { dispatchInputValueEvent } from \"@zag-js/form-utils\"\nimport { compact, isEqual } from \"@zag-js/utils\"\nimport { dom } from \"./pin-input.dom\"\nimport type { MachineContext, MachineState, UserDefinedContext } from \"./pin-input.types\"\n\nexport function machine(userContext: UserDefinedContext) {\n const ctx = compact(userContext)\n return createMachine<MachineContext, MachineState>(\n {\n id: \"pin-input\",\n initial: \"idle\",\n context: {\n value: [],\n placeholder: \"○\",\n otp: false,\n type: \"numeric\",\n ...ctx,\n focusedIndex: -1,\n translations: {\n inputLabel: (index, length) => `pin code ${index + 1} of ${length}`,\n ...ctx.translations,\n },\n },\n\n computed: {\n valueLength: (ctx) => ctx.value.length,\n filledValueLength: (ctx) => ctx.value.filter((v) => v?.trim() !== \"\").length,\n isValueComplete: (ctx) => ctx.valueLength === ctx.filledValueLength,\n valueAsString: (ctx) => ctx.value.join(\"\"),\n focusedValue: (ctx) => ctx.value[ctx.focusedIndex] || \"\",\n },\n\n entry: choose([\n {\n guard: \"autoFocus\",\n actions: [\"setupValue\", \"setFocusIndexToFirst\"],\n },\n { actions: [\"setupValue\"] },\n ]),\n\n watch: {\n focusedIndex: [\"focusInput\", \"selectInputIfNeeded\"],\n value: [\"syncInputElements\"],\n isValueComplete: [\"invokeOnComplete\", \"blurFocusedInputIfNeeded\"],\n },\n\n on: {\n \"VALUE.SET\": [\n {\n guard: \"hasIndex\",\n actions: [\"setValueAtIndex\"],\n },\n { actions: [\"setValue\"] },\n ],\n \"VALUE.CLEAR\": {\n actions: [\"clearValue\", \"setFocusIndexToFirst\"],\n },\n },\n\n states: {\n idle: {\n on: {\n \"INPUT.FOCUS\": {\n target: \"focused\",\n actions: \"setFocusedIndex\",\n },\n },\n },\n focused: {\n on: {\n \"INPUT.CHANGE\": [\n {\n guard: \"isFinalValue\",\n actions: [\"setFocusedValue\", \"syncInputValue\"],\n },\n {\n actions: [\"setFocusedValue\", \"setNextFocusedIndex\", \"syncInputValue\"],\n },\n ],\n \"INPUT.PASTE\": {\n actions: [\"setPastedValue\", \"setLastValueFocusIndex\"],\n },\n \"INPUT.BLUR\": {\n target: \"idle\",\n actions: \"clearFocusedIndex\",\n },\n \"INPUT.DELETE\": {\n guard: \"hasValue\",\n actions: \"clearFocusedValue\",\n },\n \"INPUT.ARROW_LEFT\": {\n actions: \"setPrevFocusedIndex\",\n },\n \"INPUT.ARROW_RIGHT\": {\n actions: \"setNextFocusedIndex\",\n },\n \"INPUT.BACKSPACE\": [\n {\n guard: \"hasValue\",\n actions: [\"clearFocusedValue\"],\n },\n {\n actions: [\"setPrevFocusedIndex\", \"clearFocusedValue\"],\n },\n ],\n \"INPUT.ENTER\": {\n guard: \"isValueComplete\",\n actions: \"requestFormSubmit\",\n },\n \"VALUE.INVALID\": {\n actions: \"invokeOnInvalid\",\n },\n },\n },\n },\n },\n {\n guards: {\n autoFocus: (ctx) => !!ctx.autoFocus,\n isValueEmpty: (_ctx, evt) => evt.value === \"\",\n hasValue: (ctx) => ctx.value[ctx.focusedIndex] !== \"\",\n isValueComplete: (ctx) => ctx.isValueComplete,\n isFinalValue: (ctx) =>\n ctx.filledValueLength + 1 === ctx.valueLength &&\n ctx.value.findIndex((v) => v.trim() === \"\") === ctx.focusedIndex,\n hasIndex: (_ctx, evt) => evt.index !== undefined,\n isDisabled: (ctx) => !!ctx.disabled,\n },\n actions: {\n setupValue(ctx) {\n if (ctx.value.length) return\n const inputEls = dom.getInputEls(ctx)\n const emptyValues = Array.from<string>({ length: inputEls.length }).fill(\"\")\n assignValue(ctx, emptyValues)\n },\n focusInput(ctx) {\n if (ctx.focusedIndex === -1) return\n dom.getFocusedInputEl(ctx)?.focus({ preventScroll: true })\n },\n selectInputIfNeeded(ctx) {\n if (!ctx.selectOnFocus || ctx.focusedIndex === -1) return\n raf(() => {\n dom.getFocusedInputEl(ctx)?.select()\n })\n },\n invokeOnComplete(ctx) {\n if (!ctx.isValueComplete) return\n ctx.onValueComplete?.({\n value: Array.from(ctx.value),\n valueAsString: ctx.valueAsString,\n })\n },\n invokeOnInvalid(ctx, evt) {\n ctx.onValueInvalid?.({\n value: evt.value,\n index: ctx.focusedIndex,\n })\n },\n clearFocusedIndex(ctx) {\n ctx.focusedIndex = -1\n },\n setFocusedIndex(ctx, evt) {\n ctx.focusedIndex = evt.index\n },\n setValue(ctx, evt) {\n set.value(ctx, evt.value)\n },\n setFocusedValue(ctx, evt) {\n const nextValue = getNextValue(ctx.focusedValue, evt.value)\n set.valueAtIndex(ctx, ctx.focusedIndex, nextValue)\n },\n revertInputValue(ctx) {\n const inputEl = dom.getFocusedInputEl(ctx)\n dom.setValue(inputEl, ctx.focusedValue)\n },\n syncInputValue(ctx, evt) {\n const inputEl = dom.getInputEl(ctx, evt.index.toString())\n dom.setValue(inputEl, ctx.value[evt.index])\n },\n syncInputElements(ctx) {\n const inputEls = dom.getInputEls(ctx)\n inputEls.forEach((inputEl, index) => {\n dom.setValue(inputEl, ctx.value[index])\n })\n },\n setPastedValue(ctx, evt) {\n raf(() => {\n const startIndex = Math.min(ctx.focusedIndex, ctx.filledValueLength)\n\n // keep value left of cursor\n // replace value from curor to end with pasted text\n const left = startIndex > 0 ? ctx.valueAsString.substring(0, ctx.focusedIndex) : \"\"\n const right = evt.value.substring(0, ctx.valueLength - startIndex)\n\n const value = left + right\n\n set.value(ctx, value.split(\"\"))\n })\n },\n setValueAtIndex(ctx, evt) {\n const nextValue = getNextValue(ctx.focusedValue, evt.value)\n set.valueAtIndex(ctx, evt.index, nextValue)\n },\n clearValue(ctx) {\n const nextValue = Array.from<string>({ length: ctx.valueLength }).fill(\"\")\n set.value(ctx, nextValue)\n },\n clearFocusedValue(ctx) {\n set.valueAtIndex(ctx, ctx.focusedIndex, \"\")\n },\n setFocusIndexToFirst(ctx) {\n ctx.focusedIndex = 0\n },\n setNextFocusedIndex(ctx) {\n ctx.focusedIndex = Math.min(ctx.focusedIndex + 1, ctx.valueLength - 1)\n },\n setPrevFocusedIndex(ctx) {\n ctx.focusedIndex = Math.max(ctx.focusedIndex - 1, 0)\n },\n setLastValueFocusIndex(ctx) {\n raf(() => {\n ctx.focusedIndex = Math.min(ctx.filledValueLength, ctx.valueLength - 1)\n })\n },\n blurFocusedInputIfNeeded(ctx) {\n if (!ctx.blurOnComplete) return\n raf(() => {\n dom.getFocusedInputEl(ctx)?.blur()\n })\n },\n requestFormSubmit(ctx) {\n if (!ctx.name || !ctx.isValueComplete) return\n const inputEl = dom.getHiddenInputEl(ctx)\n inputEl?.form?.requestSubmit()\n },\n },\n },\n )\n}\n\nfunction assignValue(ctx: MachineContext, value: string | string[]) {\n const arr = Array.isArray(value) ? value : value.split(\"\").filter(Boolean)\n arr.forEach((value, index) => {\n ctx.value[index] = value\n })\n}\n\nfunction getNextValue(current: string, next: string) {\n let nextValue = next\n if (current[0] === next[0]) nextValue = next[1]\n else if (current[0] === next[1]) nextValue = next[0]\n return nextValue.split(\"\")[nextValue.length - 1]\n}\n\nconst invoke = {\n change(ctx: MachineContext) {\n // callback\n ctx.onValueChange?.({\n value: Array.from(ctx.value),\n valueAsString: ctx.valueAsString,\n })\n\n // form event\n const inputEl = dom.getHiddenInputEl(ctx)\n dispatchInputValueEvent(inputEl, { value: ctx.valueAsString })\n },\n}\n\nconst set = {\n value(ctx: MachineContext, value: string[]) {\n if (isEqual(ctx.value, value)) return\n assignValue(ctx, value)\n invoke.change(ctx)\n },\n valueAtIndex(ctx: MachineContext, index: number, value: string) {\n if (isEqual(ctx.value[index], value)) return\n ctx.value[index] = value\n invoke.change(ctx)\n },\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAEvB,IAAM,UAAU,cAAc,UAAU,EAAE,MAAM,QAAQ,SAAS,SAAS,SAAS;AACnF,IAAM,QAAQ,QAAQ,MAAM;;;ACHnC,SAAS,aAAa,gBAAgB,qBAAuC;AAC7E,SAAS,UAAU,UAAU,qBAAqB,kBAAkB,2BAA2B;AAE/F,SAAS,iBAAiB;;;ACH1B,SAAS,aAAa,gBAAgB;AAG/B,IAAM,MAAM,YAAY;AAAA,EAC7B,WAAW,CAAC,QAAa,IAAI,KAAK,QAAQ,aAAa,IAAI,EAAE;AAAA,EAC7D,YAAY,CAAC,KAAU,OAAe,IAAI,KAAK,QAAQ,EAAE,KAAK,aAAa,IAAI,EAAE,IAAI,EAAE;AAAA,EACvF,kBAAkB,CAAC,QAAa,IAAI,KAAK,eAAe,aAAa,IAAI,EAAE;AAAA,EAC3E,YAAY,CAAC,QAAa,IAAI,KAAK,SAAS,aAAa,IAAI,EAAE;AAAA,EAC/D,cAAc,CAAC,QAAa,IAAI,KAAK,WAAW,aAAa,IAAI,EAAE;AAAA,EAEnE,WAAW,CAAC,QAAa,IAAI,QAAQ,KAAK,IAAI,UAAU,GAAG,CAAC;AAAA,EAC5D,aAAa,CAAC,QAAa;AACzB,UAAM,UAAU,IAAI,OAAO,IAAI,UAAU,GAAG,CAAC;AAC7C,UAAM,WAAW,sBAAsB,OAAO;AAC9C,WAAO,SAA2B,IAAI,UAAU,GAAG,GAAG,QAAQ;AAAA,EAChE;AAAA,EACA,YAAY,CAAC,KAAU,OAAe,IAAI,QAA0B,KAAK,IAAI,WAAW,KAAK,EAAE,CAAC;AAAA,EAChG,mBAAmB,CAAC,QAAa,IAAI,YAAY,GAAG,EAAE,IAAI,YAAY;AAAA,EACtE,iBAAiB,CAAC,QAAa,IAAI,YAAY,GAAG,EAAE,CAAC;AAAA,EACrD,kBAAkB,CAAC,QAAa,IAAI,QAA0B,KAAK,IAAI,iBAAiB,GAAG,CAAC;AAC9F,CAAC;;;AClBD,IAAM,QAAQ;AAAA,EACZ,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,cAAc;AAChB;AAEO,SAAS,YAAY,KAAqB,OAAe;AAC9D,MAAI,CAAC,IAAI,KAAM,QAAO;AACtB,SAAO,CAAC,CAAC,MAAM,IAAI,IAAI,GAAG,KAAK,KAAK;AACtC;AAEO,SAAS,aAAa,KAAqB,OAAe;AAC/D,MAAI,CAAC,IAAI,QAAS,QAAO,YAAY,KAAK,KAAK;AAC/C,QAAM,QAAQ,IAAI,OAAO,IAAI,SAAS,GAAG;AACzC,SAAO,MAAM,KAAK,KAAK;AACzB;;;AFRO,SAAS,QAA6B,OAAc,MAAY,WAA6C;AAClH,QAAM,WAAW,MAAM,QAAQ;AAC/B,QAAM,UAAU,MAAM,QAAQ;AAC9B,QAAM,eAAe,MAAM,QAAQ;AACnC,QAAM,eAAe,MAAM,QAAQ;AAEnC,WAAS,QAAQ;AACf,QAAI,gBAAgB,MAAM,OAAO,GAAG,MAAM;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL;AAAA,IACA,OAAO,MAAM,QAAQ;AAAA,IACrB,eAAe,MAAM,QAAQ;AAAA,IAC7B;AAAA,IACA,SAAS,OAAO;AACd,UAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,kBAAU,6CAA6C;AAAA,MACzD;AACA,WAAK,EAAE,MAAM,aAAa,MAAM,CAAC;AAAA,IACnC;AAAA,IACA,aAAa;AACX,WAAK,EAAE,MAAM,cAAc,CAAC;AAAA,IAC9B;AAAA,IACA,gBAAgB,OAAO,OAAO;AAC5B,WAAK,EAAE,MAAM,aAAa,OAAO,MAAM,CAAC;AAAA,IAC1C;AAAA,IAEA,eAAe;AACb,aAAO,UAAU,QAAQ;AAAA,QACvB,KAAK,MAAM,QAAQ;AAAA,QACnB,GAAG,MAAM,KAAK;AAAA,QACd,IAAI,IAAI,UAAU,MAAM,OAAO;AAAA,QAC/B,gBAAgB,SAAS,OAAO;AAAA,QAChC,iBAAiB,SAAS,MAAM,QAAQ,QAAQ;AAAA,QAChD,iBAAiB,SAAS,QAAQ;AAAA,QAClC,iBAAiB,SAAS,MAAM,QAAQ,QAAQ;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,IAEA,gBAAgB;AACd,aAAO,UAAU,MAAM;AAAA,QACrB,GAAG,MAAM,MAAM;AAAA,QACf,KAAK,MAAM,QAAQ;AAAA,QACnB,SAAS,IAAI,iBAAiB,MAAM,OAAO;AAAA,QAC3C,IAAI,IAAI,WAAW,MAAM,OAAO;AAAA,QAChC,gBAAgB,SAAS,OAAO;AAAA,QAChC,iBAAiB,SAAS,MAAM,QAAQ,QAAQ;AAAA,QAChD,iBAAiB,SAAS,QAAQ;AAAA,QAClC,iBAAiB,SAAS,MAAM,QAAQ,QAAQ;AAAA,QAChD,QAAQ,OAAO;AACb,gBAAM,eAAe;AACrB,gBAAM;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,sBAAsB;AACpB,aAAO,UAAU,MAAM;AAAA,QACrB,eAAe;AAAA,QACf,MAAM;AAAA,QACN,UAAU;AAAA,QACV,IAAI,IAAI,iBAAiB,MAAM,OAAO;AAAA,QACtC,UAAU,MAAM,QAAQ;AAAA,QACxB,UAAU,MAAM,QAAQ;AAAA,QACxB,UAAU,MAAM,QAAQ;AAAA,QACxB,MAAM,MAAM,QAAQ;AAAA,QACpB,MAAM,MAAM,QAAQ;AAAA,QACpB,OAAO;AAAA,QACP,WAAW,MAAM,QAAQ;AAAA,QACzB,cAAc,MAAM,QAAQ;AAAA,MAC9B,CAAC;AAAA,IACH;AAAA,IAEA,kBAAkB;AAChB,aAAO,UAAU,QAAQ;AAAA,QACvB,GAAG,MAAM,QAAQ;AAAA,QACjB,KAAK,MAAM,QAAQ;AAAA,QACnB,IAAI,IAAI,aAAa,MAAM,OAAO;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,IAEA,cAAc,OAAO;AACnB,YAAM,EAAE,MAAM,IAAI;AAClB,YAAM,YAAY,MAAM,QAAQ,SAAS,YAAY,QAAQ;AAC7D,aAAO,UAAU,MAAM;AAAA,QACrB,GAAG,MAAM,MAAM;AAAA,QACf,KAAK,MAAM,QAAQ;AAAA,QACnB,UAAU,MAAM,QAAQ;AAAA,QACxB,iBAAiB,SAAS,MAAM,QAAQ,QAAQ;AAAA,QAChD,iBAAiB,SAAS,QAAQ;AAAA,QAClC,IAAI,IAAI,WAAW,MAAM,SAAS,MAAM,SAAS,CAAC;AAAA,QAClD,gBAAgB,IAAI,UAAU,MAAM,OAAO;AAAA,QAC3C,cAAc,aAAa,WAAW,OAAO,MAAM,QAAQ,WAAW;AAAA,QACtE,WAAW,MAAM,QAAQ,OAAO,MAAM,QAAQ,SAAS,YAAY,YAAY;AAAA,QAC/E,gBAAgB,SAAS,OAAO;AAAA,QAChC,gBAAgB,SAAS,OAAO;AAAA,QAChC,MAAM,MAAM,QAAQ,OAAO,aAAa;AAAA,QACxC,cAAc,MAAM,QAAQ,MAAM,KAAK,KAAK;AAAA,QAC5C,UAAU,MAAM,QAAQ;AAAA,QACxB,gBAAgB;AAAA,QAChB,cAAc,MAAM,QAAQ,MAAM,kBAAkB;AAAA,QACpD,aAAa,iBAAiB,QAAQ,KAAK,MAAM,QAAQ;AAAA,QACzD,cAAc,OAAO;AACnB,cAAI;AACF,kBAAM,QAAQ,oBAAoB,KAAK;AACvC,kBAAM,UAAU,aAAa,MAAM,SAAS,KAAK;AACjD,gBAAI,CAAC,SAAS;AACZ,mBAAK,EAAE,MAAM,iBAAiB,MAAM,CAAC;AACrC,oBAAM,eAAe;AAAA,YACvB;AAIA,gBAAI,MAAM,SAAS,GAAG;AACpB,oBAAM,cAAc,kBAAkB,GAAG,GAAG,SAAS;AAAA,YACvD;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,QACA,SAAS,OAAO;AACd,gBAAM,MAAM,eAAe,KAAK;AAChC,gBAAM,EAAE,MAAM,IAAI,MAAM;AAExB,cAAI,IAAI,cAAc,qBAAqB,MAAM,SAAS,GAAG;AAC3D,iBAAK,EAAE,MAAM,eAAe,MAAM,CAAC;AAGnC,kBAAM,OAAO,QAAQ,MAAM,CAAC;AAE5B,kBAAM,eAAe;AACrB;AAAA,UACF;AAEA,cAAI,IAAI,cAAc,yBAAyB;AAC7C,iBAAK,iBAAiB;AACtB;AAAA,UACF;AAEA,eAAK,EAAE,MAAM,gBAAgB,OAAO,MAAM,CAAC;AAAA,QAC7C;AAAA,QACA,UAAU,OAAO;AACf,cAAI,MAAM,iBAAkB;AAE5B,cAAI,iBAAiB,KAAK,EAAG;AAC7B,cAAI,cAAc,KAAK,EAAG;AAE1B,gBAAM,SAAsB;AAAA,YAC1B,YAAY;AACV,mBAAK,iBAAiB;AAAA,YACxB;AAAA,YACA,SAAS;AACP,mBAAK,cAAc;AAAA,YACrB;AAAA,YACA,YAAY;AACV,mBAAK,kBAAkB;AAAA,YACzB;AAAA,YACA,aAAa;AACX,mBAAK,mBAAmB;AAAA,YAC1B;AAAA,YACA,QAAQ;AACN,mBAAK,aAAa;AAAA,YACpB;AAAA,UACF;AAEA,gBAAM,OAAO,OAAO,YAAY,OAAO,MAAM,OAAO,CAAC;AAErD,cAAI,MAAM;AACR,iBAAK,KAAK;AACV,kBAAM,eAAe;AAAA,UACvB;AAAA,QACF;AAAA,QACA,UAAU;AACR,eAAK,EAAE,MAAM,eAAe,MAAM,CAAC;AAAA,QACrC;AAAA,QACA,SAAS;AACP,eAAK,EAAE,MAAM,cAAc,MAAM,CAAC;AAAA,QACpC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AG/LA,SAAS,QAAQ,qBAAqB;AACtC,SAAS,WAAW;AACpB,SAAS,+BAA+B;AACxC,SAAS,SAAS,eAAe;AAI1B,SAAS,QAAQ,aAAiC;AACvD,QAAM,MAAM,QAAQ,WAAW;AAC/B,SAAO;AAAA,IACL;AAAA,MACE,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,SAAS;AAAA,QACP,OAAO,CAAC;AAAA,QACR,aAAa;AAAA,QACb,KAAK;AAAA,QACL,MAAM;AAAA,QACN,GAAG;AAAA,QACH,cAAc;AAAA,QACd,cAAc;AAAA,UACZ,YAAY,CAAC,OAAO,WAAW,YAAY,QAAQ,CAAC,OAAO,MAAM;AAAA,UACjE,GAAG,IAAI;AAAA,QACT;AAAA,MACF;AAAA,MAEA,UAAU;AAAA,QACR,aAAa,CAACA,SAAQA,KAAI,MAAM;AAAA,QAChC,mBAAmB,CAACA,SAAQA,KAAI,MAAM,OAAO,CAAC,MAAM,GAAG,KAAK,MAAM,EAAE,EAAE;AAAA,QACtE,iBAAiB,CAACA,SAAQA,KAAI,gBAAgBA,KAAI;AAAA,QAClD,eAAe,CAACA,SAAQA,KAAI,MAAM,KAAK,EAAE;AAAA,QACzC,cAAc,CAACA,SAAQA,KAAI,MAAMA,KAAI,YAAY,KAAK;AAAA,MACxD;AAAA,MAEA,OAAO,OAAO;AAAA,QACZ;AAAA,UACE,OAAO;AAAA,UACP,SAAS,CAAC,cAAc,sBAAsB;AAAA,QAChD;AAAA,QACA,EAAE,SAAS,CAAC,YAAY,EAAE;AAAA,MAC5B,CAAC;AAAA,MAED,OAAO;AAAA,QACL,cAAc,CAAC,cAAc,qBAAqB;AAAA,QAClD,OAAO,CAAC,mBAAmB;AAAA,QAC3B,iBAAiB,CAAC,oBAAoB,0BAA0B;AAAA,MAClE;AAAA,MAEA,IAAI;AAAA,QACF,aAAa;AAAA,UACX;AAAA,YACE,OAAO;AAAA,YACP,SAAS,CAAC,iBAAiB;AAAA,UAC7B;AAAA,UACA,EAAE,SAAS,CAAC,UAAU,EAAE;AAAA,QAC1B;AAAA,QACA,eAAe;AAAA,UACb,SAAS,CAAC,cAAc,sBAAsB;AAAA,QAChD;AAAA,MACF;AAAA,MAEA,QAAQ;AAAA,QACN,MAAM;AAAA,UACJ,IAAI;AAAA,YACF,eAAe;AAAA,cACb,QAAQ;AAAA,cACR,SAAS;AAAA,YACX;AAAA,UACF;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP,IAAI;AAAA,YACF,gBAAgB;AAAA,cACd;AAAA,gBACE,OAAO;AAAA,gBACP,SAAS,CAAC,mBAAmB,gBAAgB;AAAA,cAC/C;AAAA,cACA;AAAA,gBACE,SAAS,CAAC,mBAAmB,uBAAuB,gBAAgB;AAAA,cACtE;AAAA,YACF;AAAA,YACA,eAAe;AAAA,cACb,SAAS,CAAC,kBAAkB,wBAAwB;AAAA,YACtD;AAAA,YACA,cAAc;AAAA,cACZ,QAAQ;AAAA,cACR,SAAS;AAAA,YACX;AAAA,YACA,gBAAgB;AAAA,cACd,OAAO;AAAA,cACP,SAAS;AAAA,YACX;AAAA,YACA,oBAAoB;AAAA,cAClB,SAAS;AAAA,YACX;AAAA,YACA,qBAAqB;AAAA,cACnB,SAAS;AAAA,YACX;AAAA,YACA,mBAAmB;AAAA,cACjB;AAAA,gBACE,OAAO;AAAA,gBACP,SAAS,CAAC,mBAAmB;AAAA,cAC/B;AAAA,cACA;AAAA,gBACE,SAAS,CAAC,uBAAuB,mBAAmB;AAAA,cACtD;AAAA,YACF;AAAA,YACA,eAAe;AAAA,cACb,OAAO;AAAA,cACP,SAAS;AAAA,YACX;AAAA,YACA,iBAAiB;AAAA,cACf,SAAS;AAAA,YACX;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,QACN,WAAW,CAACA,SAAQ,CAAC,CAACA,KAAI;AAAA,QAC1B,cAAc,CAAC,MAAM,QAAQ,IAAI,UAAU;AAAA,QAC3C,UAAU,CAACA,SAAQA,KAAI,MAAMA,KAAI,YAAY,MAAM;AAAA,QACnD,iBAAiB,CAACA,SAAQA,KAAI;AAAA,QAC9B,cAAc,CAACA,SACbA,KAAI,oBAAoB,MAAMA,KAAI,eAClCA,KAAI,MAAM,UAAU,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE,MAAMA,KAAI;AAAA,QACtD,UAAU,CAAC,MAAM,QAAQ,IAAI,UAAU;AAAA,QACvC,YAAY,CAACA,SAAQ,CAAC,CAACA,KAAI;AAAA,MAC7B;AAAA,MACA,SAAS;AAAA,QACP,WAAWA,MAAK;AACd,cAAIA,KAAI,MAAM,OAAQ;AACtB,gBAAM,WAAW,IAAI,YAAYA,IAAG;AACpC,gBAAM,cAAc,MAAM,KAAa,EAAE,QAAQ,SAAS,OAAO,CAAC,EAAE,KAAK,EAAE;AAC3E,sBAAYA,MAAK,WAAW;AAAA,QAC9B;AAAA,QACA,WAAWA,MAAK;AACd,cAAIA,KAAI,iBAAiB,GAAI;AAC7B,cAAI,kBAAkBA,IAAG,GAAG,MAAM,EAAE,eAAe,KAAK,CAAC;AAAA,QAC3D;AAAA,QACA,oBAAoBA,MAAK;AACvB,cAAI,CAACA,KAAI,iBAAiBA,KAAI,iBAAiB,GAAI;AACnD,cAAI,MAAM;AACR,gBAAI,kBAAkBA,IAAG,GAAG,OAAO;AAAA,UACrC,CAAC;AAAA,QACH;AAAA,QACA,iBAAiBA,MAAK;AACpB,cAAI,CAACA,KAAI,gBAAiB;AAC1B,UAAAA,KAAI,kBAAkB;AAAA,YACpB,OAAO,MAAM,KAAKA,KAAI,KAAK;AAAA,YAC3B,eAAeA,KAAI;AAAA,UACrB,CAAC;AAAA,QACH;AAAA,QACA,gBAAgBA,MAAK,KAAK;AACxB,UAAAA,KAAI,iBAAiB;AAAA,YACnB,OAAO,IAAI;AAAA,YACX,OAAOA,KAAI;AAAA,UACb,CAAC;AAAA,QACH;AAAA,QACA,kBAAkBA,MAAK;AACrB,UAAAA,KAAI,eAAe;AAAA,QACrB;AAAA,QACA,gBAAgBA,MAAK,KAAK;AACxB,UAAAA,KAAI,eAAe,IAAI;AAAA,QACzB;AAAA,QACA,SAASA,MAAK,KAAK;AACjB,cAAI,MAAMA,MAAK,IAAI,KAAK;AAAA,QAC1B;AAAA,QACA,gBAAgBA,MAAK,KAAK;AACxB,gBAAM,YAAY,aAAaA,KAAI,cAAc,IAAI,KAAK;AAC1D,cAAI,aAAaA,MAAKA,KAAI,cAAc,SAAS;AAAA,QACnD;AAAA,QACA,iBAAiBA,MAAK;AACpB,gBAAM,UAAU,IAAI,kBAAkBA,IAAG;AACzC,cAAI,SAAS,SAASA,KAAI,YAAY;AAAA,QACxC;AAAA,QACA,eAAeA,MAAK,KAAK;AACvB,gBAAM,UAAU,IAAI,WAAWA,MAAK,IAAI,MAAM,SAAS,CAAC;AACxD,cAAI,SAAS,SAASA,KAAI,MAAM,IAAI,KAAK,CAAC;AAAA,QAC5C;AAAA,QACA,kBAAkBA,MAAK;AACrB,gBAAM,WAAW,IAAI,YAAYA,IAAG;AACpC,mBAAS,QAAQ,CAAC,SAAS,UAAU;AACnC,gBAAI,SAAS,SAASA,KAAI,MAAM,KAAK,CAAC;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,QACA,eAAeA,MAAK,KAAK;AACvB,cAAI,MAAM;AACR,kBAAM,aAAa,KAAK,IAAIA,KAAI,cAAcA,KAAI,iBAAiB;AAInE,kBAAM,OAAO,aAAa,IAAIA,KAAI,cAAc,UAAU,GAAGA,KAAI,YAAY,IAAI;AACjF,kBAAM,QAAQ,IAAI,MAAM,UAAU,GAAGA,KAAI,cAAc,UAAU;AAEjE,kBAAM,QAAQ,OAAO;AAErB,gBAAI,MAAMA,MAAK,MAAM,MAAM,EAAE,CAAC;AAAA,UAChC,CAAC;AAAA,QACH;AAAA,QACA,gBAAgBA,MAAK,KAAK;AACxB,gBAAM,YAAY,aAAaA,KAAI,cAAc,IAAI,KAAK;AAC1D,cAAI,aAAaA,MAAK,IAAI,OAAO,SAAS;AAAA,QAC5C;AAAA,QACA,WAAWA,MAAK;AACd,gBAAM,YAAY,MAAM,KAAa,EAAE,QAAQA,KAAI,YAAY,CAAC,EAAE,KAAK,EAAE;AACzE,cAAI,MAAMA,MAAK,SAAS;AAAA,QAC1B;AAAA,QACA,kBAAkBA,MAAK;AACrB,cAAI,aAAaA,MAAKA,KAAI,cAAc,EAAE;AAAA,QAC5C;AAAA,QACA,qBAAqBA,MAAK;AACxB,UAAAA,KAAI,eAAe;AAAA,QACrB;AAAA,QACA,oBAAoBA,MAAK;AACvB,UAAAA,KAAI,eAAe,KAAK,IAAIA,KAAI,eAAe,GAAGA,KAAI,cAAc,CAAC;AAAA,QACvE;AAAA,QACA,oBAAoBA,MAAK;AACvB,UAAAA,KAAI,eAAe,KAAK,IAAIA,KAAI,eAAe,GAAG,CAAC;AAAA,QACrD;AAAA,QACA,uBAAuBA,MAAK;AAC1B,cAAI,MAAM;AACR,YAAAA,KAAI,eAAe,KAAK,IAAIA,KAAI,mBAAmBA,KAAI,cAAc,CAAC;AAAA,UACxE,CAAC;AAAA,QACH;AAAA,QACA,yBAAyBA,MAAK;AAC5B,cAAI,CAACA,KAAI,eAAgB;AACzB,cAAI,MAAM;AACR,gBAAI,kBAAkBA,IAAG,GAAG,KAAK;AAAA,UACnC,CAAC;AAAA,QACH;AAAA,QACA,kBAAkBA,MAAK;AACrB,cAAI,CAACA,KAAI,QAAQ,CAACA,KAAI,gBAAiB;AACvC,gBAAM,UAAU,IAAI,iBAAiBA,IAAG;AACxC,mBAAS,MAAM,cAAc;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,YAAY,KAAqB,OAA0B;AAClE,QAAM,MAAM,MAAM,QAAQ,KAAK,IAAI,QAAQ,MAAM,MAAM,EAAE,EAAE,OAAO,OAAO;AACzE,MAAI,QAAQ,CAACC,QAAO,UAAU;AAC5B,QAAI,MAAM,KAAK,IAAIA;AAAA,EACrB,CAAC;AACH;AAEA,SAAS,aAAa,SAAiB,MAAc;AACnD,MAAI,YAAY;AAChB,MAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAG,aAAY,KAAK,CAAC;AAAA,WACrC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAG,aAAY,KAAK,CAAC;AACnD,SAAO,UAAU,MAAM,EAAE,EAAE,UAAU,SAAS,CAAC;AACjD;AAEA,IAAM,SAAS;AAAA,EACb,OAAO,KAAqB;AAE1B,QAAI,gBAAgB;AAAA,MAClB,OAAO,MAAM,KAAK,IAAI,KAAK;AAAA,MAC3B,eAAe,IAAI;AAAA,IACrB,CAAC;AAGD,UAAM,UAAU,IAAI,iBAAiB,GAAG;AACxC,4BAAwB,SAAS,EAAE,OAAO,IAAI,cAAc,CAAC;AAAA,EAC/D;AACF;AAEA,IAAM,MAAM;AAAA,EACV,MAAM,KAAqB,OAAiB;AAC1C,QAAI,QAAQ,IAAI,OAAO,KAAK,EAAG;AAC/B,gBAAY,KAAK,KAAK;AACtB,WAAO,OAAO,GAAG;AAAA,EACnB;AAAA,EACA,aAAa,KAAqB,OAAe,OAAe;AAC9D,QAAI,QAAQ,IAAI,MAAM,KAAK,GAAG,KAAK,EAAG;AACtC,QAAI,MAAM,KAAK,IAAI;AACnB,WAAO,OAAO,GAAG;AAAA,EACnB;AACF;","names":["ctx","value"]}
package/src/index.ts DELETED
@@ -1,12 +0,0 @@
1
- export { anatomy } from "./pin-input.anatomy"
2
- export { connect } from "./pin-input.connect"
3
- export { machine } from "./pin-input.machine"
4
- export type {
5
- MachineApi as Api,
6
- UserDefinedContext as Context,
7
- ElementIds,
8
- InputProps,
9
- IntlTranslations,
10
- ValueChangeDetails,
11
- ValueInvalidDetails,
12
- } from "./pin-input.types"
@@ -1,4 +0,0 @@
1
- import { createAnatomy } from "@zag-js/anatomy"
2
-
3
- export const anatomy = createAnatomy("pinInput").parts("root", "label", "input", "control")
4
- export const parts = anatomy.build()
@@ -1,192 +0,0 @@
1
- import { getEventKey, getNativeEvent, isModifierKey, type EventKeyMap } from "@zag-js/dom-event"
2
- import { ariaAttr, dataAttr, getBeforeInputValue, isComposingEvent, visuallyHiddenStyle } from "@zag-js/dom-query"
3
- import type { NormalizeProps, PropTypes } from "@zag-js/types"
4
- import { invariant } from "@zag-js/utils"
5
- import { parts } from "./pin-input.anatomy"
6
- import { dom } from "./pin-input.dom"
7
- import type { MachineApi, Send, State } from "./pin-input.types"
8
- import { isValidValue } from "./pin-input.utils"
9
-
10
- export function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): MachineApi<T> {
11
- const complete = state.context.isValueComplete
12
- const invalid = state.context.invalid
13
- const focusedIndex = state.context.focusedIndex
14
- const translations = state.context.translations
15
-
16
- function focus() {
17
- dom.getFirstInputEl(state.context)?.focus()
18
- }
19
-
20
- return {
21
- focus,
22
- value: state.context.value,
23
- valueAsString: state.context.valueAsString,
24
- complete: complete,
25
- setValue(value) {
26
- if (!Array.isArray(value)) {
27
- invariant("[pin-input/setValue] value must be an array")
28
- }
29
- send({ type: "VALUE.SET", value })
30
- },
31
- clearValue() {
32
- send({ type: "VALUE.CLEAR" })
33
- },
34
- setValueAtIndex(index, value) {
35
- send({ type: "VALUE.SET", value, index })
36
- },
37
-
38
- getRootProps() {
39
- return normalize.element({
40
- dir: state.context.dir,
41
- ...parts.root.attrs,
42
- id: dom.getRootId(state.context),
43
- "data-invalid": dataAttr(invalid),
44
- "data-disabled": dataAttr(state.context.disabled),
45
- "data-complete": dataAttr(complete),
46
- "data-readonly": dataAttr(state.context.readOnly),
47
- })
48
- },
49
-
50
- getLabelProps() {
51
- return normalize.label({
52
- ...parts.label.attrs,
53
- dir: state.context.dir,
54
- htmlFor: dom.getHiddenInputId(state.context),
55
- id: dom.getLabelId(state.context),
56
- "data-invalid": dataAttr(invalid),
57
- "data-disabled": dataAttr(state.context.disabled),
58
- "data-complete": dataAttr(complete),
59
- "data-readonly": dataAttr(state.context.readOnly),
60
- onClick(event) {
61
- event.preventDefault()
62
- focus()
63
- },
64
- })
65
- },
66
-
67
- getHiddenInputProps() {
68
- return normalize.input({
69
- "aria-hidden": true,
70
- type: "text",
71
- tabIndex: -1,
72
- id: dom.getHiddenInputId(state.context),
73
- readOnly: state.context.readOnly,
74
- disabled: state.context.disabled,
75
- required: state.context.required,
76
- name: state.context.name,
77
- form: state.context.form,
78
- style: visuallyHiddenStyle,
79
- maxLength: state.context.valueLength,
80
- defaultValue: state.context.valueAsString,
81
- })
82
- },
83
-
84
- getControlProps() {
85
- return normalize.element({
86
- ...parts.control.attrs,
87
- dir: state.context.dir,
88
- id: dom.getControlId(state.context),
89
- })
90
- },
91
-
92
- getInputProps(props) {
93
- const { index } = props
94
- const inputType = state.context.type === "numeric" ? "tel" : "text"
95
- return normalize.input({
96
- ...parts.input.attrs,
97
- dir: state.context.dir,
98
- disabled: state.context.disabled,
99
- "data-disabled": dataAttr(state.context.disabled),
100
- "data-complete": dataAttr(complete),
101
- id: dom.getInputId(state.context, index.toString()),
102
- "data-ownedby": dom.getRootId(state.context),
103
- "aria-label": translations.inputLabel(index, state.context.valueLength),
104
- inputMode: state.context.otp || state.context.type === "numeric" ? "numeric" : "text",
105
- "aria-invalid": ariaAttr(invalid),
106
- "data-invalid": dataAttr(invalid),
107
- type: state.context.mask ? "password" : inputType,
108
- defaultValue: state.context.value[index] || "",
109
- readOnly: state.context.readOnly,
110
- autoCapitalize: "none",
111
- autoComplete: state.context.otp ? "one-time-code" : "off",
112
- placeholder: focusedIndex === index ? "" : state.context.placeholder,
113
- onBeforeInput(event) {
114
- try {
115
- const value = getBeforeInputValue(event)
116
- const isValid = isValidValue(state.context, value)
117
- if (!isValid) {
118
- send({ type: "VALUE.INVALID", value })
119
- event.preventDefault()
120
- }
121
-
122
- // select the text so paste always replaces the
123
- // current input's value regardless of cursor position
124
- if (value.length > 2) {
125
- event.currentTarget.setSelectionRange(0, 1, "forward")
126
- }
127
- } catch {
128
- // noop
129
- }
130
- },
131
- onChange(event) {
132
- const evt = getNativeEvent(event)
133
- const { value } = event.currentTarget
134
-
135
- if (evt.inputType === "insertFromPaste" || value.length > 2) {
136
- send({ type: "INPUT.PASTE", value })
137
- // prevent multiple characters being pasted
138
- // into a single input
139
- event.target.value = value[0]
140
-
141
- event.preventDefault()
142
- return
143
- }
144
-
145
- if (evt.inputType === "deleteContentBackward") {
146
- send("INPUT.BACKSPACE")
147
- return
148
- }
149
-
150
- send({ type: "INPUT.CHANGE", value, index })
151
- },
152
- onKeyDown(event) {
153
- if (event.defaultPrevented) return
154
-
155
- if (isComposingEvent(event)) return
156
- if (isModifierKey(event)) return
157
-
158
- const keyMap: EventKeyMap = {
159
- Backspace() {
160
- send("INPUT.BACKSPACE")
161
- },
162
- Delete() {
163
- send("INPUT.DELETE")
164
- },
165
- ArrowLeft() {
166
- send("INPUT.ARROW_LEFT")
167
- },
168
- ArrowRight() {
169
- send("INPUT.ARROW_RIGHT")
170
- },
171
- Enter() {
172
- send("INPUT.ENTER")
173
- },
174
- }
175
-
176
- const exec = keyMap[getEventKey(event, state.context)]
177
-
178
- if (exec) {
179
- exec(event)
180
- event.preventDefault()
181
- }
182
- },
183
- onFocus() {
184
- send({ type: "INPUT.FOCUS", index })
185
- },
186
- onBlur() {
187
- send({ type: "INPUT.BLUR", index })
188
- },
189
- })
190
- },
191
- }
192
- }
@@ -1,21 +0,0 @@
1
- import { createScope, queryAll } from "@zag-js/dom-query"
2
- import type { MachineContext as Ctx } from "./pin-input.types"
3
-
4
- export const dom = createScope({
5
- getRootId: (ctx: Ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`,
6
- getInputId: (ctx: Ctx, id: string) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`,
7
- getHiddenInputId: (ctx: Ctx) => ctx.ids?.hiddenInput ?? `pin-input:${ctx.id}:hidden`,
8
- getLabelId: (ctx: Ctx) => ctx.ids?.label ?? `pin-input:${ctx.id}:label`,
9
- getControlId: (ctx: Ctx) => ctx.ids?.control ?? `pin-input:${ctx.id}:control`,
10
-
11
- getRootEl: (ctx: Ctx) => dom.getById(ctx, dom.getRootId(ctx)),
12
- getInputEls: (ctx: Ctx) => {
13
- const ownerId = CSS.escape(dom.getRootId(ctx))
14
- const selector = `input[data-ownedby=${ownerId}]`
15
- return queryAll<HTMLInputElement>(dom.getRootEl(ctx), selector)
16
- },
17
- getInputEl: (ctx: Ctx, id: string) => dom.getById<HTMLInputElement>(ctx, dom.getInputId(ctx, id)),
18
- getFocusedInputEl: (ctx: Ctx) => dom.getInputEls(ctx)[ctx.focusedIndex],
19
- getFirstInputEl: (ctx: Ctx) => dom.getInputEls(ctx)[0],
20
- getHiddenInputEl: (ctx: Ctx) => dom.getById<HTMLInputElement>(ctx, dom.getHiddenInputId(ctx)),
21
- })
@@ -1,282 +0,0 @@
1
- import { choose, createMachine } from "@zag-js/core"
2
- import { raf } from "@zag-js/dom-query"
3
- import { dispatchInputValueEvent } from "@zag-js/form-utils"
4
- import { compact, isEqual } from "@zag-js/utils"
5
- import { dom } from "./pin-input.dom"
6
- import type { MachineContext, MachineState, UserDefinedContext } from "./pin-input.types"
7
-
8
- export function machine(userContext: UserDefinedContext) {
9
- const ctx = compact(userContext)
10
- return createMachine<MachineContext, MachineState>(
11
- {
12
- id: "pin-input",
13
- initial: "idle",
14
- context: {
15
- value: [],
16
- placeholder: "○",
17
- otp: false,
18
- type: "numeric",
19
- ...ctx,
20
- focusedIndex: -1,
21
- translations: {
22
- inputLabel: (index, length) => `pin code ${index + 1} of ${length}`,
23
- ...ctx.translations,
24
- },
25
- },
26
-
27
- computed: {
28
- valueLength: (ctx) => ctx.value.length,
29
- filledValueLength: (ctx) => ctx.value.filter((v) => v?.trim() !== "").length,
30
- isValueComplete: (ctx) => ctx.valueLength === ctx.filledValueLength,
31
- valueAsString: (ctx) => ctx.value.join(""),
32
- focusedValue: (ctx) => ctx.value[ctx.focusedIndex] || "",
33
- },
34
-
35
- entry: choose([
36
- {
37
- guard: "autoFocus",
38
- actions: ["setupValue", "setFocusIndexToFirst"],
39
- },
40
- { actions: ["setupValue"] },
41
- ]),
42
-
43
- watch: {
44
- focusedIndex: ["focusInput", "selectInputIfNeeded"],
45
- value: ["syncInputElements"],
46
- isValueComplete: ["invokeOnComplete", "blurFocusedInputIfNeeded"],
47
- },
48
-
49
- on: {
50
- "VALUE.SET": [
51
- {
52
- guard: "hasIndex",
53
- actions: ["setValueAtIndex"],
54
- },
55
- { actions: ["setValue"] },
56
- ],
57
- "VALUE.CLEAR": {
58
- actions: ["clearValue", "setFocusIndexToFirst"],
59
- },
60
- },
61
-
62
- states: {
63
- idle: {
64
- on: {
65
- "INPUT.FOCUS": {
66
- target: "focused",
67
- actions: "setFocusedIndex",
68
- },
69
- },
70
- },
71
- focused: {
72
- on: {
73
- "INPUT.CHANGE": [
74
- {
75
- guard: "isFinalValue",
76
- actions: ["setFocusedValue", "syncInputValue"],
77
- },
78
- {
79
- actions: ["setFocusedValue", "setNextFocusedIndex", "syncInputValue"],
80
- },
81
- ],
82
- "INPUT.PASTE": {
83
- actions: ["setPastedValue", "setLastValueFocusIndex"],
84
- },
85
- "INPUT.BLUR": {
86
- target: "idle",
87
- actions: "clearFocusedIndex",
88
- },
89
- "INPUT.DELETE": {
90
- guard: "hasValue",
91
- actions: "clearFocusedValue",
92
- },
93
- "INPUT.ARROW_LEFT": {
94
- actions: "setPrevFocusedIndex",
95
- },
96
- "INPUT.ARROW_RIGHT": {
97
- actions: "setNextFocusedIndex",
98
- },
99
- "INPUT.BACKSPACE": [
100
- {
101
- guard: "hasValue",
102
- actions: ["clearFocusedValue"],
103
- },
104
- {
105
- actions: ["setPrevFocusedIndex", "clearFocusedValue"],
106
- },
107
- ],
108
- "INPUT.ENTER": {
109
- guard: "isValueComplete",
110
- actions: "requestFormSubmit",
111
- },
112
- "VALUE.INVALID": {
113
- actions: "invokeOnInvalid",
114
- },
115
- },
116
- },
117
- },
118
- },
119
- {
120
- guards: {
121
- autoFocus: (ctx) => !!ctx.autoFocus,
122
- isValueEmpty: (_ctx, evt) => evt.value === "",
123
- hasValue: (ctx) => ctx.value[ctx.focusedIndex] !== "",
124
- isValueComplete: (ctx) => ctx.isValueComplete,
125
- isFinalValue: (ctx) =>
126
- ctx.filledValueLength + 1 === ctx.valueLength &&
127
- ctx.value.findIndex((v) => v.trim() === "") === ctx.focusedIndex,
128
- hasIndex: (_ctx, evt) => evt.index !== undefined,
129
- isDisabled: (ctx) => !!ctx.disabled,
130
- },
131
- actions: {
132
- setupValue(ctx) {
133
- if (ctx.value.length) return
134
- const inputEls = dom.getInputEls(ctx)
135
- const emptyValues = Array.from<string>({ length: inputEls.length }).fill("")
136
- assignValue(ctx, emptyValues)
137
- },
138
- focusInput(ctx) {
139
- if (ctx.focusedIndex === -1) return
140
- dom.getFocusedInputEl(ctx)?.focus({ preventScroll: true })
141
- },
142
- selectInputIfNeeded(ctx) {
143
- if (!ctx.selectOnFocus || ctx.focusedIndex === -1) return
144
- raf(() => {
145
- dom.getFocusedInputEl(ctx)?.select()
146
- })
147
- },
148
- invokeOnComplete(ctx) {
149
- if (!ctx.isValueComplete) return
150
- ctx.onValueComplete?.({
151
- value: Array.from(ctx.value),
152
- valueAsString: ctx.valueAsString,
153
- })
154
- },
155
- invokeOnInvalid(ctx, evt) {
156
- ctx.onValueInvalid?.({
157
- value: evt.value,
158
- index: ctx.focusedIndex,
159
- })
160
- },
161
- clearFocusedIndex(ctx) {
162
- ctx.focusedIndex = -1
163
- },
164
- setFocusedIndex(ctx, evt) {
165
- ctx.focusedIndex = evt.index
166
- },
167
- setValue(ctx, evt) {
168
- set.value(ctx, evt.value)
169
- },
170
- setFocusedValue(ctx, evt) {
171
- const nextValue = getNextValue(ctx.focusedValue, evt.value)
172
- set.valueAtIndex(ctx, ctx.focusedIndex, nextValue)
173
- },
174
- revertInputValue(ctx) {
175
- const inputEl = dom.getFocusedInputEl(ctx)
176
- dom.setValue(inputEl, ctx.focusedValue)
177
- },
178
- syncInputValue(ctx, evt) {
179
- const inputEl = dom.getInputEl(ctx, evt.index.toString())
180
- dom.setValue(inputEl, ctx.value[evt.index])
181
- },
182
- syncInputElements(ctx) {
183
- const inputEls = dom.getInputEls(ctx)
184
- inputEls.forEach((inputEl, index) => {
185
- dom.setValue(inputEl, ctx.value[index])
186
- })
187
- },
188
- setPastedValue(ctx, evt) {
189
- raf(() => {
190
- const startIndex = Math.min(ctx.focusedIndex, ctx.filledValueLength)
191
-
192
- // keep value left of cursor
193
- // replace value from curor to end with pasted text
194
- const left = startIndex > 0 ? ctx.valueAsString.substring(0, ctx.focusedIndex) : ""
195
- const right = evt.value.substring(0, ctx.valueLength - startIndex)
196
-
197
- const value = left + right
198
-
199
- set.value(ctx, value.split(""))
200
- })
201
- },
202
- setValueAtIndex(ctx, evt) {
203
- const nextValue = getNextValue(ctx.focusedValue, evt.value)
204
- set.valueAtIndex(ctx, evt.index, nextValue)
205
- },
206
- clearValue(ctx) {
207
- const nextValue = Array.from<string>({ length: ctx.valueLength }).fill("")
208
- set.value(ctx, nextValue)
209
- },
210
- clearFocusedValue(ctx) {
211
- set.valueAtIndex(ctx, ctx.focusedIndex, "")
212
- },
213
- setFocusIndexToFirst(ctx) {
214
- ctx.focusedIndex = 0
215
- },
216
- setNextFocusedIndex(ctx) {
217
- ctx.focusedIndex = Math.min(ctx.focusedIndex + 1, ctx.valueLength - 1)
218
- },
219
- setPrevFocusedIndex(ctx) {
220
- ctx.focusedIndex = Math.max(ctx.focusedIndex - 1, 0)
221
- },
222
- setLastValueFocusIndex(ctx) {
223
- raf(() => {
224
- ctx.focusedIndex = Math.min(ctx.filledValueLength, ctx.valueLength - 1)
225
- })
226
- },
227
- blurFocusedInputIfNeeded(ctx) {
228
- if (!ctx.blurOnComplete) return
229
- raf(() => {
230
- dom.getFocusedInputEl(ctx)?.blur()
231
- })
232
- },
233
- requestFormSubmit(ctx) {
234
- if (!ctx.name || !ctx.isValueComplete) return
235
- const inputEl = dom.getHiddenInputEl(ctx)
236
- inputEl?.form?.requestSubmit()
237
- },
238
- },
239
- },
240
- )
241
- }
242
-
243
- function assignValue(ctx: MachineContext, value: string | string[]) {
244
- const arr = Array.isArray(value) ? value : value.split("").filter(Boolean)
245
- arr.forEach((value, index) => {
246
- ctx.value[index] = value
247
- })
248
- }
249
-
250
- function getNextValue(current: string, next: string) {
251
- let nextValue = next
252
- if (current[0] === next[0]) nextValue = next[1]
253
- else if (current[0] === next[1]) nextValue = next[0]
254
- return nextValue.split("")[nextValue.length - 1]
255
- }
256
-
257
- const invoke = {
258
- change(ctx: MachineContext) {
259
- // callback
260
- ctx.onValueChange?.({
261
- value: Array.from(ctx.value),
262
- valueAsString: ctx.valueAsString,
263
- })
264
-
265
- // form event
266
- const inputEl = dom.getHiddenInputEl(ctx)
267
- dispatchInputValueEvent(inputEl, { value: ctx.valueAsString })
268
- },
269
- }
270
-
271
- const set = {
272
- value(ctx: MachineContext, value: string[]) {
273
- if (isEqual(ctx.value, value)) return
274
- assignValue(ctx, value)
275
- invoke.change(ctx)
276
- },
277
- valueAtIndex(ctx: MachineContext, index: number, value: string) {
278
- if (isEqual(ctx.value[index], value)) return
279
- ctx.value[index] = value
280
- invoke.change(ctx)
281
- },
282
- }
@@ -1,31 +0,0 @@
1
- import { createProps } from "@zag-js/types"
2
- import { createSplitProps } from "@zag-js/utils"
3
- import type { UserDefinedContext } from "./pin-input.types"
4
-
5
- export const props = createProps<UserDefinedContext>()([
6
- "autoFocus",
7
- "blurOnComplete",
8
- "dir",
9
- "disabled",
10
- "form",
11
- "getRootNode",
12
- "id",
13
- "ids",
14
- "invalid",
15
- "mask",
16
- "name",
17
- "onValueChange",
18
- "onValueComplete",
19
- "onValueInvalid",
20
- "otp",
21
- "readOnly",
22
- "pattern",
23
- "placeholder",
24
- "required",
25
- "selectOnFocus",
26
- "translations",
27
- "type",
28
- "value",
29
- ])
30
-
31
- export const splitProps = createSplitProps<Partial<UserDefinedContext>>(props)
@@ -1,210 +0,0 @@
1
- import type { StateMachine as S } from "@zag-js/core"
2
- import type { CommonProperties, DirectionProperty, PropTypes, RequiredBy } from "@zag-js/types"
3
-
4
- /* -----------------------------------------------------------------------------
5
- * Callback details
6
- * -----------------------------------------------------------------------------*/
7
-
8
- export interface ValueChangeDetails {
9
- value: string[]
10
- valueAsString: string
11
- }
12
-
13
- export interface ValueInvalidDetails {
14
- value: string
15
- index: number
16
- }
17
-
18
- /* -----------------------------------------------------------------------------
19
- * Machine context
20
- * -----------------------------------------------------------------------------*/
21
-
22
- export type IntlTranslations = {
23
- inputLabel: (index: number, length: number) => string
24
- }
25
-
26
- export type ElementIds = Partial<{
27
- root: string
28
- hiddenInput: string
29
- label: string
30
- control: string
31
- input(id: string): string
32
- }>
33
-
34
- interface PublicContext extends DirectionProperty, CommonProperties {
35
- /**
36
- * The name of the input element. Useful for form submission.
37
- */
38
- name?: string
39
- /**
40
- * The associate form of the underlying input element.
41
- */
42
- form?: string
43
- /**
44
- * The regular expression that the user-entered input value is checked against.
45
- */
46
- pattern?: string
47
- /**
48
- * The ids of the elements in the pin input. Useful for composition.
49
- */
50
- ids?: ElementIds
51
- /**
52
- * Whether the inputs are disabled
53
- */
54
- disabled?: boolean
55
- /**
56
- * The placeholder text for the input
57
- * @default "○"
58
- */
59
- placeholder?: string
60
- /**
61
- * Whether to auto-focus the first input.
62
- */
63
- autoFocus?: boolean
64
- /**
65
- * Whether the pin input is in the invalid state
66
- */
67
- invalid?: boolean
68
- /**
69
- * Whether the pin input is required
70
- */
71
- required?: boolean
72
- /**
73
- * Whether the pin input is in the valid state
74
- */
75
- readOnly?: boolean
76
- /**
77
- * If `true`, the pin input component signals to its fields that they should
78
- * use `autocomplete="one-time-code"`.
79
- */
80
- otp?: boolean
81
- /**
82
- * The value of the the pin input.
83
- */
84
- value: string[]
85
- /**
86
- * The type of value the pin-input should allow
87
- * @default "numeric"
88
- */
89
- type?: "alphanumeric" | "numeric" | "alphabetic"
90
- /**
91
- * Function called when all inputs have valid values
92
- */
93
- onValueComplete?: (details: ValueChangeDetails) => void
94
- /**
95
- * Function called on input change
96
- */
97
- onValueChange?: (details: ValueChangeDetails) => void
98
- /**
99
- * Function called when an invalid value is entered
100
- */
101
- onValueInvalid?: (details: ValueInvalidDetails) => void
102
- /**
103
- * If `true`, the input's value will be masked just like `type=password`
104
- */
105
- mask?: boolean
106
- /**
107
- * Whether to blur the input when the value is complete
108
- */
109
- blurOnComplete?: boolean
110
- /**
111
- * Whether to select input value when input is focused
112
- */
113
- selectOnFocus?: boolean
114
- /**
115
- * Specifies the localized strings that identifies the accessibility elements and their states
116
- */
117
- translations: IntlTranslations
118
- }
119
-
120
- export type UserDefinedContext = RequiredBy<PublicContext, "id">
121
-
122
- type ComputedContext = Readonly<{
123
- /**
124
- * @computed
125
- * The number of inputs
126
- */
127
- valueLength: number
128
- /**
129
- * @computed
130
- * The number of inputs that are not empty
131
- */
132
- filledValueLength: number
133
- /**
134
- * @computed
135
- * Whether all input values are valid
136
- */
137
- isValueComplete: boolean
138
- /**
139
- * @computed
140
- * The string representation of the input values
141
- */
142
- valueAsString: string
143
- /**
144
- * @computed
145
- * The value at focused index
146
- */
147
- focusedValue: string
148
- }>
149
-
150
- interface PrivateContext {
151
- /**
152
- * @internal
153
- * The index of the input field that has focus
154
- */
155
- focusedIndex: number
156
- }
157
-
158
- export interface MachineContext extends PublicContext, PrivateContext, ComputedContext {}
159
-
160
- export interface MachineState {
161
- value: "idle" | "focused"
162
- }
163
-
164
- export type State = S.State<MachineContext, MachineState>
165
-
166
- export type Send = S.Send<S.AnyEventObject>
167
-
168
- /* -----------------------------------------------------------------------------
169
- * Component API
170
- * -----------------------------------------------------------------------------*/
171
-
172
- export interface InputProps {
173
- index: number
174
- }
175
-
176
- export interface MachineApi<T extends PropTypes = PropTypes> {
177
- /**
178
- * The value of the input as an array of strings.
179
- */
180
- value: string[]
181
- /**
182
- * The value of the input as a string.
183
- */
184
- valueAsString: string
185
- /**
186
- * Whether all inputs are filled.
187
- */
188
- complete: boolean
189
- /**
190
- * Function to set the value of the inputs.
191
- */
192
- setValue(value: string[]): void
193
- /**
194
- * Function to clear the value of the inputs.
195
- */
196
- clearValue(): void
197
- /**
198
- * Function to set the value of the input at a specific index.
199
- */
200
- setValueAtIndex(index: number, value: string): void
201
- /**
202
- * Function to focus the pin-input. This will focus the first input.
203
- */
204
- focus: () => void
205
- getRootProps(): T["element"]
206
- getLabelProps(): T["label"]
207
- getHiddenInputProps(): T["input"]
208
- getControlProps(): T["element"]
209
- getInputProps(props: InputProps): T["input"]
210
- }
@@ -1,18 +0,0 @@
1
- import type { MachineContext } from "./pin-input.types"
2
-
3
- const REGEX = {
4
- numeric: /^[0-9]+$/,
5
- alphabetic: /^[A-Za-z]+$/,
6
- alphanumeric: /^[a-zA-Z0-9]+$/i,
7
- }
8
-
9
- export function isValidType(ctx: MachineContext, value: string) {
10
- if (!ctx.type) return true
11
- return !!REGEX[ctx.type]?.test(value)
12
- }
13
-
14
- export function isValidValue(ctx: MachineContext, value: string) {
15
- if (!ctx.pattern) return isValidType(ctx, value)
16
- const regex = new RegExp(ctx.pattern, "g")
17
- return regex.test(value)
18
- }