@zag-js/pin-input 0.2.11 → 0.2.13

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
@@ -31,127 +31,15 @@ var import_anatomy = require("@zag-js/anatomy");
31
31
  var anatomy = (0, import_anatomy.createAnatomy)("pinInput").parts("root", "label", "hiddenInput", "input", "control");
32
32
  var parts = anatomy.build();
33
33
 
34
- // ../../utilities/dom/src/attrs.ts
35
- var dataAttr = (guard) => {
36
- return guard ? "" : void 0;
37
- };
38
- var ariaAttr = (guard) => {
39
- return guard ? "true" : void 0;
40
- };
41
-
42
- // ../../utilities/core/src/guard.ts
43
- var isArray = (v) => Array.isArray(v);
44
- var isObject = (v) => !(v == null || typeof v !== "object" || isArray(v));
45
-
46
- // ../../utilities/core/src/object.ts
47
- function compact(obj) {
48
- if (obj === void 0)
49
- return obj;
50
- return Object.fromEntries(
51
- Object.entries(obj).filter(([, value]) => value !== void 0).map(([key, value]) => [key, isObject(value) ? compact(value) : value])
52
- );
53
- }
54
-
55
- // ../../utilities/core/src/warning.ts
56
- function invariant(...a) {
57
- const m = a.length === 1 ? a[0] : a[1];
58
- const c = a.length === 2 ? a[0] : true;
59
- if (c && process.env.NODE_ENV !== "production") {
60
- throw new Error(m);
61
- }
62
- }
63
-
64
- // ../../utilities/dom/src/query.ts
65
- function isDocument(el) {
66
- return el.nodeType === Node.DOCUMENT_NODE;
67
- }
68
- function isWindow(value) {
69
- return value?.toString() === "[object Window]";
70
- }
71
- function getDocument(el) {
72
- if (isWindow(el))
73
- return el.document;
74
- if (isDocument(el))
75
- return el;
76
- return el?.ownerDocument ?? document;
77
- }
78
- function getWindow(el) {
79
- return el?.ownerDocument.defaultView ?? window;
80
- }
81
- function defineDomHelpers(helpers) {
82
- const dom2 = {
83
- getRootNode: (ctx) => ctx.getRootNode?.() ?? document,
84
- getDoc: (ctx) => getDocument(dom2.getRootNode(ctx)),
85
- getWin: (ctx) => dom2.getDoc(ctx).defaultView ?? window,
86
- getActiveElement: (ctx) => dom2.getDoc(ctx).activeElement,
87
- getById: (ctx, id) => dom2.getRootNode(ctx).getElementById(id)
88
- };
89
- return {
90
- ...dom2,
91
- ...helpers
92
- };
93
- }
94
-
95
- // ../../utilities/dom/src/event.ts
96
- function getNativeEvent(e) {
97
- return e.nativeEvent ?? e;
98
- }
99
- var isModifiedEvent = (v) => v.ctrlKey || v.altKey || v.metaKey;
100
-
101
- // ../../utilities/dom/src/keyboard-event.ts
102
- var rtlKeyMap = {
103
- ArrowLeft: "ArrowRight",
104
- ArrowRight: "ArrowLeft"
105
- };
106
- var sameKeyMap = {
107
- Up: "ArrowUp",
108
- Down: "ArrowDown",
109
- Esc: "Escape",
110
- " ": "Space",
111
- ",": "Comma",
112
- Left: "ArrowLeft",
113
- Right: "ArrowRight"
114
- };
115
- function getEventKey(event, options = {}) {
116
- const { dir = "ltr", orientation = "horizontal" } = options;
117
- let { key } = event;
118
- key = sameKeyMap[key] ?? key;
119
- const isRtl = dir === "rtl" && orientation === "horizontal";
120
- if (isRtl && key in rtlKeyMap) {
121
- key = rtlKeyMap[key];
122
- }
123
- return key;
124
- }
125
-
126
- // ../../utilities/dom/src/next-tick.ts
127
- function raf(fn) {
128
- const id = globalThis.requestAnimationFrame(fn);
129
- return function cleanup() {
130
- globalThis.cancelAnimationFrame(id);
131
- };
132
- }
133
-
134
- // ../../utilities/dom/src/nodelist.ts
135
- function queryAll(root, selector) {
136
- return Array.from(root?.querySelectorAll(selector) ?? []);
137
- }
138
-
139
- // ../../utilities/dom/src/visually-hidden.ts
140
- var visuallyHiddenStyle = {
141
- border: "0",
142
- clip: "rect(0 0 0 0)",
143
- height: "1px",
144
- margin: "-1px",
145
- overflow: "hidden",
146
- padding: "0",
147
- position: "absolute",
148
- width: "1px",
149
- whiteSpace: "nowrap",
150
- wordWrap: "normal"
151
- };
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
+ var import_visually_hidden = require("@zag-js/visually-hidden");
152
39
 
153
40
  // src/pin-input.dom.ts
154
- var dom = defineDomHelpers({
41
+ var import_dom_query = require("@zag-js/dom-query");
42
+ var dom = (0, import_dom_query.createScope)({
155
43
  getRootId: (ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`,
156
44
  getInputId: (ctx, id) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`,
157
45
  getHiddenInputId: (ctx) => ctx.ids?.hiddenInput ?? `pin-input:${ctx.id}:hidden`,
@@ -161,9 +49,10 @@ var dom = defineDomHelpers({
161
49
  getElements: (ctx) => {
162
50
  const ownerId = CSS.escape(dom.getRootId(ctx));
163
51
  const selector = `input[data-ownedby=${ownerId}]`;
164
- return queryAll(dom.getRootEl(ctx), selector);
52
+ return (0, import_dom_query.queryAll)(dom.getRootEl(ctx), selector);
165
53
  },
166
- getFocusedEl: (ctx) => dom.getElements(ctx)[ctx.focusedIndex],
54
+ getInputEl: (ctx, id) => dom.getById(ctx, dom.getInputId(ctx, id)),
55
+ getFocusedInputEl: (ctx) => dom.getElements(ctx)[ctx.focusedIndex],
167
56
  getFirstInputEl: (ctx) => dom.getElements(ctx)[0],
168
57
  getHiddenInputEl: (ctx) => dom.getById(ctx, dom.getHiddenInputId(ctx))
169
58
  });
@@ -178,37 +67,58 @@ function connect(state, send, normalize) {
178
67
  dom.getFirstInputEl(state.context)?.focus();
179
68
  }
180
69
  return {
70
+ /**
71
+ * The value of the input as an array of strings.
72
+ */
181
73
  value: state.context.value,
74
+ /**
75
+ * The value of the input as a string.
76
+ */
182
77
  valueAsString: state.context.valueAsString,
78
+ /**
79
+ * Whether all inputs are filled.
80
+ */
183
81
  isValueComplete,
82
+ /**
83
+ * Function to set the value of the inputs.
84
+ */
184
85
  setValue(value) {
185
86
  if (!Array.isArray(value)) {
186
- invariant("[pin-input/setValue] value must be an array");
87
+ (0, import_utils.invariant)("[pin-input/setValue] value must be an array");
187
88
  }
188
89
  send({ type: "SET_VALUE", value });
189
90
  },
91
+ /**
92
+ * Function to clear the value of the inputs.
93
+ */
190
94
  clearValue() {
191
95
  send({ type: "CLEAR_VALUE" });
192
96
  },
97
+ /**
98
+ * Function to set the value of the input at a specific index.
99
+ */
193
100
  setValueAtIndex(index, value) {
194
101
  send({ type: "SET_VALUE", value, index });
195
102
  },
103
+ /**
104
+ * Function to focus the pin-input. This will focus the first input.
105
+ */
196
106
  focus,
197
107
  rootProps: normalize.element({
198
108
  dir: state.context.dir,
199
109
  ...parts.root.attrs,
200
110
  id: dom.getRootId(state.context),
201
- "data-invalid": dataAttr(isInvalid),
202
- "data-disabled": dataAttr(state.context.disabled),
203
- "data-complete": dataAttr(isValueComplete)
111
+ "data-invalid": (0, import_dom_query2.dataAttr)(isInvalid),
112
+ "data-disabled": (0, import_dom_query2.dataAttr)(state.context.disabled),
113
+ "data-complete": (0, import_dom_query2.dataAttr)(isValueComplete)
204
114
  }),
205
115
  labelProps: normalize.label({
206
116
  ...parts.label.attrs,
207
117
  htmlFor: dom.getHiddenInputId(state.context),
208
118
  id: dom.getLabelId(state.context),
209
- "data-invalid": dataAttr(isInvalid),
210
- "data-disabled": dataAttr(state.context.disabled),
211
- "data-complete": dataAttr(isValueComplete),
119
+ "data-invalid": (0, import_dom_query2.dataAttr)(isInvalid),
120
+ "data-disabled": (0, import_dom_query2.dataAttr)(state.context.disabled),
121
+ "data-complete": (0, import_dom_query2.dataAttr)(isValueComplete),
212
122
  onClick: (event) => {
213
123
  event.preventDefault();
214
124
  focus();
@@ -222,7 +132,7 @@ function connect(state, send, normalize) {
222
132
  id: dom.getHiddenInputId(state.context),
223
133
  name: state.context.name,
224
134
  form: state.context.form,
225
- style: visuallyHiddenStyle,
135
+ style: import_visually_hidden.visuallyHiddenStyle,
226
136
  maxLength: state.context.valueLength,
227
137
  defaultValue: state.context.valueAsString
228
138
  }),
@@ -235,21 +145,21 @@ function connect(state, send, normalize) {
235
145
  return normalize.input({
236
146
  ...parts.input.attrs,
237
147
  disabled: state.context.disabled,
238
- "data-disabled": dataAttr(state.context.disabled),
239
- "data-complete": dataAttr(isValueComplete),
148
+ "data-disabled": (0, import_dom_query2.dataAttr)(state.context.disabled),
149
+ "data-complete": (0, import_dom_query2.dataAttr)(isValueComplete),
240
150
  id: dom.getInputId(state.context, index.toString()),
241
151
  "data-ownedby": dom.getRootId(state.context),
242
152
  "aria-label": translations.inputLabel(index, state.context.valueLength),
243
153
  inputMode: state.context.otp || state.context.type === "numeric" ? "numeric" : "text",
244
- "aria-invalid": ariaAttr(isInvalid),
245
- "data-invalid": dataAttr(isInvalid),
154
+ "aria-invalid": (0, import_dom_query2.ariaAttr)(isInvalid),
155
+ "data-invalid": (0, import_dom_query2.dataAttr)(isInvalid),
246
156
  type: state.context.mask ? "password" : inputType,
247
157
  defaultValue: state.context.value[index] || "",
248
158
  autoCapitalize: "none",
249
159
  autoComplete: state.context.otp ? "one-time-code" : "off",
250
160
  placeholder: focusedIndex === index ? "" : state.context.placeholder,
251
161
  onChange(event) {
252
- const evt = getNativeEvent(event);
162
+ const evt = (0, import_dom_event.getNativeEvent)(event);
253
163
  const { value } = event.currentTarget;
254
164
  if (evt.inputType === "insertFromPaste" || value.length > 2) {
255
165
  send({ type: "PASTE", value });
@@ -260,11 +170,11 @@ function connect(state, send, normalize) {
260
170
  send("BACKSPACE");
261
171
  return;
262
172
  }
263
- send({ type: "INPUT", value });
173
+ send({ type: "INPUT", value, index });
264
174
  },
265
175
  onKeyDown(event) {
266
- const evt = getNativeEvent(event);
267
- if (evt.isComposing || isModifiedEvent(evt))
176
+ const evt = (0, import_dom_event.getNativeEvent)(event);
177
+ if (evt.isComposing || (0, import_dom_event.isModifiedEvent)(evt))
268
178
  return;
269
179
  const keyMap = {
270
180
  Backspace() {
@@ -283,7 +193,7 @@ function connect(state, send, normalize) {
283
193
  send("ENTER");
284
194
  }
285
195
  };
286
- const key = getEventKey(event, { dir: state.context.dir });
196
+ const key = (0, import_dom_event.getEventKey)(event, { dir: state.context.dir });
287
197
  const exec = keyMap[key];
288
198
  if (exec) {
289
199
  exec(event);
@@ -307,29 +217,12 @@ function connect(state, send, normalize) {
307
217
 
308
218
  // src/pin-input.machine.ts
309
219
  var import_core = require("@zag-js/core");
310
-
311
- // ../../utilities/form-utils/src/input-event.ts
312
- function getDescriptor(el, options) {
313
- const { type, property = "value" } = options;
314
- const proto = getWindow(el)[type].prototype;
315
- return Object.getOwnPropertyDescriptor(proto, property) ?? {};
316
- }
317
- function dispatchInputValueEvent(el, value) {
318
- if (!el)
319
- return;
320
- const win = getWindow(el);
321
- if (!(el instanceof win.HTMLInputElement))
322
- return;
323
- const desc = getDescriptor(el, { type: "HTMLInputElement", property: "value" });
324
- desc.set?.call(el, value);
325
- const event = new win.Event("input", { bubbles: true });
326
- el.dispatchEvent(event);
327
- }
328
-
329
- // src/pin-input.machine.ts
220
+ var import_dom_query3 = require("@zag-js/dom-query");
221
+ var import_form_utils = require("@zag-js/form-utils");
222
+ var import_utils2 = require("@zag-js/utils");
330
223
  var { and, not } = import_core.guards;
331
224
  function machine(userContext) {
332
- const ctx = compact(userContext);
225
+ const ctx = (0, import_utils2.compact)(userContext);
333
226
  return (0, import_core.createMachine)(
334
227
  {
335
228
  id: "pin-input",
@@ -355,7 +248,7 @@ function machine(userContext) {
355
248
  },
356
249
  watch: {
357
250
  focusedIndex: ["focusInput", "setInputSelection"],
358
- value: ["dispatchInputEvent"],
251
+ value: ["dispatchInputEvent", "syncInputElements"],
359
252
  isValueComplete: ["invokeOnComplete", "blurFocusedInputIfNeeded"]
360
253
  },
361
254
  entry: ctx.autoFocus ? ["setupValue", "setFocusIndexToFirst"] : ["setupValue"],
@@ -466,17 +359,17 @@ function machine(userContext) {
466
359
  assign(ctx2, emptyValues);
467
360
  },
468
361
  focusInput: (ctx2) => {
469
- raf(() => {
362
+ (0, import_dom_query3.raf)(() => {
470
363
  if (ctx2.focusedIndex === -1)
471
364
  return;
472
- dom.getFocusedEl(ctx2)?.focus();
365
+ dom.getFocusedInputEl(ctx2)?.focus();
473
366
  });
474
367
  },
475
368
  setInputSelection: (ctx2) => {
476
- raf(() => {
369
+ (0, import_dom_query3.raf)(() => {
477
370
  if (ctx2.focusedIndex === -1)
478
371
  return;
479
- const input = dom.getFocusedEl(ctx2);
372
+ const input = dom.getFocusedInputEl(ctx2);
480
373
  const length = input.value.length;
481
374
  input.selectionStart = ctx2.selectOnFocus ? 0 : length;
482
375
  input.selectionEnd = length;
@@ -487,20 +380,11 @@ function machine(userContext) {
487
380
  return;
488
381
  ctx2.onComplete?.({ value: Array.from(ctx2.value), valueAsString: ctx2.valueAsString });
489
382
  },
490
- invokeOnChange: (ctx2, evt) => {
491
- if (evt.type === "SETUP")
492
- return;
383
+ invokeOnChange: (ctx2) => {
493
384
  ctx2.onChange?.({ value: Array.from(ctx2.value) });
494
385
  },
495
- dispatchInputEvent: (ctx2, evt) => {
496
- if (evt.type === "SETUP")
497
- return;
498
- dispatchInputValueEvent(dom.getHiddenInputEl(ctx2), ctx2.valueAsString);
499
- const inputs = dom.getElements(ctx2);
500
- ctx2.value.forEach((val, index) => {
501
- const input = inputs[index];
502
- input.value = val || "";
503
- });
386
+ dispatchInputEvent: (ctx2) => {
387
+ (0, import_form_utils.dispatchInputValueEvent)(dom.getHiddenInputEl(ctx2), ctx2.valueAsString);
504
388
  },
505
389
  invokeOnInvalid: (ctx2, evt) => {
506
390
  ctx2.onInvalid?.({ value: evt.value, index: ctx2.focusedIndex });
@@ -517,17 +401,20 @@ function machine(userContext) {
517
401
  setFocusedValue: (ctx2, evt) => {
518
402
  ctx2.value[ctx2.focusedIndex] = getNextValue(ctx2.focusedValue, evt.value);
519
403
  },
520
- syncInputValue: (ctx2, evt) => {
521
- const nextValue = getNextValue(ctx2.focusedValue, evt.value);
522
- const changed = nextValue !== ctx2.focusedValue;
523
- if (evt.value.length <= 1 || changed)
404
+ syncInputValue(ctx2, evt) {
405
+ const input = dom.getInputEl(ctx2, evt.index.toString());
406
+ if (!input)
524
407
  return;
408
+ input.value = ctx2.value[evt.index];
409
+ },
410
+ syncInputElements(ctx2) {
525
411
  const inputs = dom.getElements(ctx2);
526
- const input = inputs[ctx2.focusedIndex];
527
- input.value = nextValue;
412
+ inputs.forEach((input, index) => {
413
+ input.value = ctx2.value[index];
414
+ });
528
415
  },
529
416
  setPastedValue(ctx2, evt) {
530
- raf(() => {
417
+ (0, import_dom_query3.raf)(() => {
531
418
  const startIndex = ctx2.focusedValue ? 1 : 0;
532
419
  const value = evt.value.substring(startIndex, startIndex + ctx2.valueLength);
533
420
  assign(ctx2, value);
@@ -544,7 +431,7 @@ function machine(userContext) {
544
431
  ctx2.value[ctx2.focusedIndex] = "";
545
432
  },
546
433
  resetFocusedValue: (ctx2) => {
547
- const input = dom.getFocusedEl(ctx2);
434
+ const input = dom.getFocusedInputEl(ctx2);
548
435
  input.value = ctx2.focusedValue;
549
436
  },
550
437
  setFocusIndexToFirst: (ctx2) => {
@@ -557,7 +444,7 @@ function machine(userContext) {
557
444
  ctx2.focusedIndex = Math.max(ctx2.focusedIndex - 1, 0);
558
445
  },
559
446
  setLastValueFocusIndex: (ctx2) => {
560
- raf(() => {
447
+ (0, import_dom_query3.raf)(() => {
561
448
  ctx2.focusedIndex = Math.min(ctx2.filledValueLength, ctx2.valueLength - 1);
562
449
  });
563
450
  },
@@ -567,8 +454,8 @@ function machine(userContext) {
567
454
  blurFocusedInputIfNeeded(ctx2) {
568
455
  if (!ctx2.blurOnComplete)
569
456
  return;
570
- raf(() => {
571
- dom.getFocusedEl(ctx2)?.blur();
457
+ (0, import_dom_query3.raf)(() => {
458
+ dom.getFocusedInputEl(ctx2)?.blur();
572
459
  });
573
460
  },
574
461
  requestFormSubmit(ctx2) {
package/dist/index.mjs CHANGED
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  connect
3
- } from "./chunk-QVOI2QEW.mjs";
3
+ } from "./chunk-KLVAQVBX.mjs";
4
4
  import {
5
5
  anatomy
6
6
  } from "./chunk-BJXKBZJG.mjs";
7
7
  import {
8
8
  machine
9
- } from "./chunk-6TEZTVFI.mjs";
10
- import "./chunk-NT4W6JYX.mjs";
11
- import "./chunk-T5OKDF74.mjs";
9
+ } from "./chunk-H5AVP4J4.mjs";
10
+ import "./chunk-CPXMEVTH.mjs";
12
11
  export {
13
12
  anatomy,
14
13
  connect,
@@ -1,6 +1,6 @@
1
1
  import * as _zag_js_anatomy from '@zag-js/anatomy';
2
2
 
3
- declare const anatomy: _zag_js_anatomy.AnatomyInstance<"root" | "label" | "hiddenInput" | "input" | "control">;
4
- declare const parts: Record<"root" | "label" | "hiddenInput" | "input" | "control", _zag_js_anatomy.AnatomyPart>;
3
+ declare const anatomy: _zag_js_anatomy.AnatomyInstance<"root" | "hiddenInput" | "label" | "control" | "input">;
4
+ declare const parts: Record<"root" | "hiddenInput" | "label" | "control" | "input", _zag_js_anatomy.AnatomyPart>;
5
5
 
6
6
  export { anatomy, parts };
@@ -3,12 +3,33 @@ import { State, Send } from './pin-input.types.js';
3
3
  import '@zag-js/core';
4
4
 
5
5
  declare function connect<T extends PropTypes>(state: State, send: Send, normalize: NormalizeProps<T>): {
6
+ /**
7
+ * The value of the input as an array of strings.
8
+ */
6
9
  value: string[];
10
+ /**
11
+ * The value of the input as a string.
12
+ */
7
13
  valueAsString: string;
14
+ /**
15
+ * Whether all inputs are filled.
16
+ */
8
17
  isValueComplete: boolean;
18
+ /**
19
+ * Function to set the value of the inputs.
20
+ */
9
21
  setValue(value: string[]): void;
22
+ /**
23
+ * Function to clear the value of the inputs.
24
+ */
10
25
  clearValue(): void;
26
+ /**
27
+ * Function to set the value of the input at a specific index.
28
+ */
11
29
  setValueAtIndex(index: number, value: string): void;
30
+ /**
31
+ * Function to focus the pin-input. This will focus the first input.
32
+ */
12
33
  focus: () => void;
13
34
  rootProps: T["element"];
14
35
  labelProps: T["label"];