@zag-js/pin-input 1.34.1 → 1.35.1

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,549 +1,39 @@
1
- 'use strict';
2
-
3
- var anatomy$1 = require('@zag-js/anatomy');
4
- var domQuery = require('@zag-js/dom-query');
5
- var utils = require('@zag-js/utils');
6
- var core = require('@zag-js/core');
7
- var types = require('@zag-js/types');
8
-
9
- // src/pin-input.anatomy.ts
10
- var anatomy = anatomy$1.createAnatomy("pinInput").parts("root", "label", "input", "control");
11
- var parts = anatomy.build();
12
- var getRootId = (ctx) => ctx.ids?.root ?? `pin-input:${ctx.id}`;
13
- var getInputId = (ctx, id) => ctx.ids?.input?.(id) ?? `pin-input:${ctx.id}:${id}`;
14
- var getHiddenInputId = (ctx) => ctx.ids?.hiddenInput ?? `pin-input:${ctx.id}:hidden`;
15
- var getLabelId = (ctx) => ctx.ids?.label ?? `pin-input:${ctx.id}:label`;
16
- var getControlId = (ctx) => ctx.ids?.control ?? `pin-input:${ctx.id}:control`;
17
- var getRootEl = (ctx) => ctx.getById(getRootId(ctx));
18
- var getInputEls = (ctx) => {
19
- const ownerId = CSS.escape(getRootId(ctx));
20
- const selector = `input[data-ownedby=${ownerId}]`;
21
- return domQuery.queryAll(getRootEl(ctx), selector);
22
- };
23
- var getInputElAtIndex = (ctx, index) => getInputEls(ctx)[index];
24
- var getFirstInputEl = (ctx) => getInputEls(ctx)[0];
25
- var getHiddenInputEl = (ctx) => ctx.getById(getHiddenInputId(ctx));
26
- var setInputValue = (inputEl, value) => {
27
- inputEl.value = value;
28
- inputEl.setAttribute("value", value);
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 });
29
9
  };
30
-
31
- // src/pin-input.utils.ts
32
- var REGEX = {
33
- numeric: /^[0-9]+$/,
34
- alphabetic: /^[A-Za-z]+$/,
35
- alphanumeric: /^[a-zA-Z0-9]+$/i
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;
36
17
  };
37
- function isValidType(type, value) {
38
- if (!type) return true;
39
- return !!REGEX[type]?.test(value);
40
- }
41
- function isValidValue(value, type, pattern) {
42
- if (!pattern) return isValidType(type, value);
43
- const regex = new RegExp(pattern, "g");
44
- return regex.test(value);
45
- }
18
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
46
20
 
47
- // src/pin-input.connect.ts
48
- function connect(service, normalize) {
49
- const { send, context, computed, prop, scope } = service;
50
- const complete = computed("isValueComplete");
51
- const disabled = !!prop("disabled");
52
- const readOnly = !!prop("readOnly");
53
- const invalid = !!prop("invalid");
54
- const required = !!prop("required");
55
- const translations = prop("translations");
56
- const focusedIndex = context.get("focusedIndex");
57
- function focus() {
58
- getFirstInputEl(scope)?.focus();
59
- }
60
- return {
61
- focus,
62
- count: context.get("count"),
63
- items: Array.from({ length: context.get("count") }).map((_, i) => i),
64
- value: context.get("value"),
65
- valueAsString: computed("valueAsString"),
66
- complete,
67
- setValue(value) {
68
- if (!Array.isArray(value)) {
69
- utils.invariant("[pin-input/setValue] value must be an array");
70
- }
71
- send({ type: "VALUE.SET", value });
72
- },
73
- clearValue() {
74
- send({ type: "VALUE.CLEAR" });
75
- },
76
- setValueAtIndex(index, value) {
77
- send({ type: "VALUE.SET", value, index });
78
- },
79
- getRootProps() {
80
- return normalize.element({
81
- dir: prop("dir"),
82
- ...parts.root.attrs,
83
- id: getRootId(scope),
84
- "data-invalid": domQuery.dataAttr(invalid),
85
- "data-disabled": domQuery.dataAttr(disabled),
86
- "data-complete": domQuery.dataAttr(complete),
87
- "data-readonly": domQuery.dataAttr(readOnly)
88
- });
89
- },
90
- getLabelProps() {
91
- return normalize.label({
92
- ...parts.label.attrs,
93
- dir: prop("dir"),
94
- htmlFor: getHiddenInputId(scope),
95
- id: getLabelId(scope),
96
- "data-invalid": domQuery.dataAttr(invalid),
97
- "data-disabled": domQuery.dataAttr(disabled),
98
- "data-complete": domQuery.dataAttr(complete),
99
- "data-required": domQuery.dataAttr(required),
100
- "data-readonly": domQuery.dataAttr(readOnly),
101
- onClick(event) {
102
- event.preventDefault();
103
- focus();
104
- }
105
- });
106
- },
107
- getHiddenInputProps() {
108
- return normalize.input({
109
- "aria-hidden": true,
110
- type: "text",
111
- tabIndex: -1,
112
- id: getHiddenInputId(scope),
113
- readOnly,
114
- disabled,
115
- required,
116
- name: prop("name"),
117
- form: prop("form"),
118
- style: domQuery.visuallyHiddenStyle,
119
- maxLength: computed("valueLength"),
120
- defaultValue: computed("valueAsString")
121
- });
122
- },
123
- getControlProps() {
124
- return normalize.element({
125
- ...parts.control.attrs,
126
- dir: prop("dir"),
127
- id: getControlId(scope)
128
- });
129
- },
130
- getInputProps(props2) {
131
- const { index } = props2;
132
- const inputType = prop("type") === "numeric" ? "tel" : "text";
133
- return normalize.input({
134
- ...parts.input.attrs,
135
- dir: prop("dir"),
136
- disabled,
137
- "data-disabled": domQuery.dataAttr(disabled),
138
- "data-complete": domQuery.dataAttr(complete),
139
- id: getInputId(scope, index.toString()),
140
- "data-index": index,
141
- "data-ownedby": getRootId(scope),
142
- "aria-label": translations?.inputLabel?.(index, computed("valueLength")),
143
- inputMode: prop("otp") || prop("type") === "numeric" ? "numeric" : "text",
144
- "aria-invalid": domQuery.ariaAttr(invalid),
145
- "data-invalid": domQuery.dataAttr(invalid),
146
- type: prop("mask") ? "password" : inputType,
147
- defaultValue: context.get("value")[index] || "",
148
- readOnly,
149
- autoCapitalize: "none",
150
- autoComplete: prop("otp") ? "one-time-code" : "off",
151
- placeholder: focusedIndex === index ? "" : prop("placeholder"),
152
- onPaste(event) {
153
- const pastedValue = event.clipboardData?.getData("text/plain");
154
- if (!pastedValue) return;
155
- const isValid = isValidValue(pastedValue, prop("type"), prop("pattern"));
156
- if (!isValid) {
157
- send({ type: "VALUE.INVALID", value: pastedValue });
158
- event.preventDefault();
159
- return;
160
- }
161
- event.preventDefault();
162
- send({ type: "INPUT.PASTE", value: pastedValue });
163
- },
164
- onBeforeInput(event) {
165
- try {
166
- const value = domQuery.getBeforeInputValue(event);
167
- const isValid = isValidValue(value, prop("type"), prop("pattern"));
168
- if (!isValid) {
169
- send({ type: "VALUE.INVALID", value });
170
- event.preventDefault();
171
- }
172
- if (value.length > 1) {
173
- event.currentTarget.setSelectionRange(0, 1, "forward");
174
- }
175
- } catch {
176
- }
177
- },
178
- onChange(event) {
179
- const evt = domQuery.getNativeEvent(event);
180
- const { value } = event.currentTarget;
181
- if (evt.inputType === "insertFromPaste") {
182
- event.currentTarget.value = value[0] || "";
183
- return;
184
- }
185
- if (value.length > 2) {
186
- send({ type: "INPUT.PASTE", value });
187
- event.currentTarget.value = value[0];
188
- event.preventDefault();
189
- return;
190
- }
191
- if (evt.inputType === "deleteContentBackward") {
192
- send({ type: "INPUT.BACKSPACE" });
193
- return;
194
- }
195
- send({ type: "INPUT.CHANGE", value, index });
196
- },
197
- onKeyDown(event) {
198
- if (event.defaultPrevented) return;
199
- if (domQuery.isComposingEvent(event)) return;
200
- if (domQuery.isModifierKey(event)) return;
201
- const keyMap = {
202
- Backspace() {
203
- send({ type: "INPUT.BACKSPACE" });
204
- },
205
- Delete() {
206
- send({ type: "INPUT.DELETE" });
207
- },
208
- ArrowLeft() {
209
- send({ type: "INPUT.ARROW_LEFT" });
210
- },
211
- ArrowRight() {
212
- send({ type: "INPUT.ARROW_RIGHT" });
213
- },
214
- Enter() {
215
- send({ type: "INPUT.ENTER" });
216
- }
217
- };
218
- const exec = keyMap[domQuery.getEventKey(event, {
219
- dir: prop("dir"),
220
- orientation: "horizontal"
221
- })];
222
- if (exec) {
223
- exec(event);
224
- event.preventDefault();
225
- }
226
- },
227
- onFocus() {
228
- send({ type: "INPUT.FOCUS", index });
229
- },
230
- onBlur(event) {
231
- const target = event.relatedTarget;
232
- if (domQuery.isHTMLElement(target) && target.dataset.ownedby === getRootId(scope)) return;
233
- send({ type: "INPUT.BLUR", index });
234
- }
235
- });
236
- }
237
- };
238
- }
239
- var { choose, createMachine } = core.setup();
240
- var machine = createMachine({
241
- props({ props: props2 }) {
242
- return {
243
- placeholder: "\u25CB",
244
- otp: false,
245
- type: "numeric",
246
- defaultValue: props2.count ? fill([], props2.count) : [],
247
- ...props2,
248
- translations: {
249
- inputLabel: (index, length) => `pin code ${index + 1} of ${length}`,
250
- ...props2.translations
251
- }
252
- };
253
- },
254
- initialState() {
255
- return "idle";
256
- },
257
- context({ prop, bindable }) {
258
- return {
259
- value: bindable(() => ({
260
- value: prop("value"),
261
- defaultValue: prop("defaultValue"),
262
- isEqual: utils.isEqual,
263
- onChange(value) {
264
- prop("onValueChange")?.({ value, valueAsString: value.join("") });
265
- }
266
- })),
267
- focusedIndex: bindable(() => ({
268
- sync: true,
269
- defaultValue: -1
270
- })),
271
- // TODO: Move this to `props` in next major version
272
- count: bindable(() => ({
273
- defaultValue: prop("count")
274
- }))
275
- };
276
- },
277
- computed: {
278
- _value: ({ context }) => fill(context.get("value"), context.get("count")),
279
- valueLength: ({ computed }) => computed("_value").length,
280
- filledValueLength: ({ computed }) => computed("_value").filter((v) => v?.trim() !== "").length,
281
- isValueComplete: ({ computed }) => computed("valueLength") === computed("filledValueLength"),
282
- valueAsString: ({ computed }) => computed("_value").join(""),
283
- focusedValue: ({ computed, context }) => computed("_value")[context.get("focusedIndex")] || ""
284
- },
285
- entry: choose([
286
- {
287
- guard: "autoFocus",
288
- actions: ["setInputCount", "setFocusIndexToFirst"]
289
- },
290
- { actions: ["setInputCount"] }
291
- ]),
292
- watch({ action, track, context, computed }) {
293
- track([() => context.get("focusedIndex")], () => {
294
- action(["focusInput", "selectInputIfNeeded"]);
295
- });
296
- track([() => context.get("value").join(",")], () => {
297
- action(["syncInputElements", "dispatchInputEvent"]);
298
- });
299
- track([() => computed("isValueComplete")], () => {
300
- action(["invokeOnComplete", "blurFocusedInputIfNeeded"]);
301
- });
302
- },
303
- on: {
304
- "VALUE.SET": [
305
- {
306
- guard: "hasIndex",
307
- actions: ["setValueAtIndex"]
308
- },
309
- { actions: ["setValue"] }
310
- ],
311
- "VALUE.CLEAR": {
312
- actions: ["clearValue", "setFocusIndexToFirst"]
313
- }
314
- },
315
- states: {
316
- idle: {
317
- on: {
318
- "INPUT.FOCUS": {
319
- target: "focused",
320
- actions: ["setFocusedIndex"]
321
- }
322
- }
323
- },
324
- focused: {
325
- on: {
326
- "INPUT.CHANGE": {
327
- actions: ["setFocusedValue", "syncInputValue", "setNextFocusedIndex"]
328
- },
329
- "INPUT.PASTE": {
330
- actions: ["setPastedValue", "setLastValueFocusIndex"]
331
- },
332
- "INPUT.FOCUS": {
333
- actions: ["setFocusedIndex"]
334
- },
335
- "INPUT.BLUR": {
336
- target: "idle",
337
- actions: ["clearFocusedIndex"]
338
- },
339
- "INPUT.DELETE": {
340
- guard: "hasValue",
341
- actions: ["clearFocusedValue"]
342
- },
343
- "INPUT.ARROW_LEFT": {
344
- actions: ["setPrevFocusedIndex"]
345
- },
346
- "INPUT.ARROW_RIGHT": {
347
- actions: ["setNextFocusedIndex"]
348
- },
349
- "INPUT.BACKSPACE": [
350
- {
351
- guard: "hasValue",
352
- actions: ["clearFocusedValue"]
353
- },
354
- {
355
- actions: ["setPrevFocusedIndex", "clearFocusedValue"]
356
- }
357
- ],
358
- "INPUT.ENTER": {
359
- guard: "isValueComplete",
360
- actions: ["requestFormSubmit"]
361
- },
362
- "VALUE.INVALID": {
363
- actions: ["invokeOnInvalid"]
364
- }
365
- }
366
- }
367
- },
368
- implementations: {
369
- guards: {
370
- autoFocus: ({ prop }) => !!prop("autoFocus"),
371
- hasValue: ({ context }) => context.get("value")[context.get("focusedIndex")] !== "",
372
- isValueComplete: ({ computed }) => computed("isValueComplete"),
373
- hasIndex: ({ event }) => event.index !== void 0
374
- },
375
- actions: {
376
- dispatchInputEvent({ computed, scope }) {
377
- const inputEl = getHiddenInputEl(scope);
378
- domQuery.dispatchInputValueEvent(inputEl, { value: computed("valueAsString") });
379
- },
380
- setInputCount({ scope, context, prop }) {
381
- if (prop("count")) return;
382
- const inputEls = getInputEls(scope);
383
- context.set("count", inputEls.length);
384
- },
385
- focusInput({ context, scope }) {
386
- const focusedIndex = context.get("focusedIndex");
387
- if (focusedIndex === -1) return;
388
- getInputElAtIndex(scope, focusedIndex)?.focus({ preventScroll: true });
389
- },
390
- selectInputIfNeeded({ context, prop, scope }) {
391
- const focusedIndex = context.get("focusedIndex");
392
- if (!prop("selectOnFocus") || focusedIndex === -1) return;
393
- domQuery.raf(() => {
394
- getInputElAtIndex(scope, focusedIndex)?.select();
395
- });
396
- },
397
- invokeOnComplete({ computed, prop }) {
398
- if (!computed("isValueComplete")) return;
399
- prop("onValueComplete")?.({
400
- value: computed("_value"),
401
- valueAsString: computed("valueAsString")
402
- });
403
- },
404
- invokeOnInvalid({ context, event, prop }) {
405
- prop("onValueInvalid")?.({
406
- value: event.value,
407
- index: context.get("focusedIndex")
408
- });
409
- },
410
- clearFocusedIndex({ context }) {
411
- context.set("focusedIndex", -1);
412
- },
413
- setFocusedIndex({ context, event }) {
414
- context.set("focusedIndex", event.index);
415
- },
416
- setValue({ context, event }) {
417
- const value = fill(event.value, context.get("count"));
418
- context.set("value", value);
419
- },
420
- setFocusedValue({ context, event, computed, flush }) {
421
- const focusedValue = computed("focusedValue");
422
- const focusedIndex = context.get("focusedIndex");
423
- const value = getNextValue(focusedValue, event.value);
424
- flush(() => {
425
- context.set("value", utils.setValueAtIndex(computed("_value"), focusedIndex, value));
426
- });
427
- },
428
- revertInputValue({ context, computed, scope }) {
429
- const inputEl = getInputElAtIndex(scope, context.get("focusedIndex"));
430
- setInputValue(inputEl, computed("focusedValue"));
431
- },
432
- syncInputValue({ context, event, scope }) {
433
- const value = context.get("value");
434
- const inputEl = getInputElAtIndex(scope, event.index);
435
- setInputValue(inputEl, value[event.index]);
436
- },
437
- syncInputElements({ context, scope }) {
438
- const inputEls = getInputEls(scope);
439
- const value = context.get("value");
440
- inputEls.forEach((inputEl, index) => {
441
- setInputValue(inputEl, value[index]);
442
- });
443
- },
444
- setPastedValue({ context, event, computed, flush }) {
445
- domQuery.raf(() => {
446
- const valueAsString = computed("valueAsString");
447
- const focusedIndex = context.get("focusedIndex");
448
- const valueLength = computed("valueLength");
449
- const filledValueLength = computed("filledValueLength");
450
- const startIndex = Math.min(focusedIndex, filledValueLength);
451
- const left = startIndex > 0 ? valueAsString.substring(0, focusedIndex) : "";
452
- const right = event.value.substring(0, valueLength - startIndex);
453
- const value = fill(`${left}${right}`.split(""), valueLength);
454
- flush(() => {
455
- context.set("value", value);
456
- });
457
- });
458
- },
459
- setValueAtIndex({ context, event, computed }) {
460
- const nextValue = getNextValue(computed("focusedValue"), event.value);
461
- context.set("value", utils.setValueAtIndex(computed("_value"), event.index, nextValue));
462
- },
463
- clearValue({ context }) {
464
- const nextValue = Array.from({ length: context.get("count") }).fill("");
465
- queueMicrotask(() => {
466
- context.set("value", nextValue);
467
- });
468
- },
469
- clearFocusedValue({ context, computed }) {
470
- const focusedIndex = context.get("focusedIndex");
471
- if (focusedIndex === -1) return;
472
- context.set("value", utils.setValueAtIndex(computed("_value"), focusedIndex, ""));
473
- },
474
- setFocusIndexToFirst({ context }) {
475
- context.set("focusedIndex", 0);
476
- },
477
- setNextFocusedIndex({ context, computed }) {
478
- context.set("focusedIndex", Math.min(context.get("focusedIndex") + 1, computed("valueLength") - 1));
479
- },
480
- setPrevFocusedIndex({ context }) {
481
- context.set("focusedIndex", Math.max(context.get("focusedIndex") - 1, 0));
482
- },
483
- setLastValueFocusIndex({ context, computed }) {
484
- domQuery.raf(() => {
485
- context.set("focusedIndex", Math.min(computed("filledValueLength"), computed("valueLength") - 1));
486
- });
487
- },
488
- blurFocusedInputIfNeeded({ context, prop, scope }) {
489
- if (!prop("blurOnComplete")) return;
490
- domQuery.raf(() => {
491
- getInputElAtIndex(scope, context.get("focusedIndex"))?.blur();
492
- });
493
- },
494
- requestFormSubmit({ computed, prop, scope }) {
495
- if (!prop("name") || !computed("isValueComplete")) return;
496
- const inputEl = getHiddenInputEl(scope);
497
- inputEl?.form?.requestSubmit();
498
- }
499
- }
500
- }
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ anatomy: () => import_pin_input.anatomy,
25
+ connect: () => import_pin_input2.connect,
26
+ machine: () => import_pin_input3.machine
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+ var import_pin_input = require("./pin-input.anatomy.cjs");
30
+ var import_pin_input2 = require("./pin-input.connect.cjs");
31
+ var import_pin_input3 = require("./pin-input.machine.cjs");
32
+ __reExport(index_exports, require("./pin-input.props.cjs"), module.exports);
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ anatomy,
36
+ connect,
37
+ machine,
38
+ ...require("./pin-input.props.cjs")
501
39
  });
502
- function getNextValue(current, next) {
503
- let nextValue = next;
504
- if (current[0] === next[0]) {
505
- nextValue = next[1];
506
- } else if (current[0] === next[1]) {
507
- nextValue = next[0];
508
- }
509
- const chars = nextValue.split("");
510
- nextValue = chars[chars.length - 1];
511
- return nextValue ?? "";
512
- }
513
- function fill(value, count) {
514
- return Array.from({ length: count }).fill("").map((v, i) => value[i] || v);
515
- }
516
- var props = types.createProps()([
517
- "autoFocus",
518
- "blurOnComplete",
519
- "count",
520
- "defaultValue",
521
- "dir",
522
- "disabled",
523
- "form",
524
- "getRootNode",
525
- "id",
526
- "ids",
527
- "invalid",
528
- "mask",
529
- "name",
530
- "onValueChange",
531
- "onValueComplete",
532
- "onValueInvalid",
533
- "otp",
534
- "pattern",
535
- "placeholder",
536
- "readOnly",
537
- "required",
538
- "selectOnFocus",
539
- "translations",
540
- "type",
541
- "value"
542
- ]);
543
- var splitProps = utils.createSplitProps(props);
544
-
545
- exports.anatomy = anatomy;
546
- exports.connect = connect;
547
- exports.machine = machine;
548
- exports.props = props;
549
- exports.splitProps = splitProps;