@zag-js/pin-input 0.10.4 → 0.11.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.
@@ -1,287 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
-
5
- const core = require('@zag-js/core');
6
- const domQuery = require('@zag-js/dom-query');
7
- const formUtils = require('@zag-js/form-utils');
8
- const utils = require('@zag-js/utils');
9
- const pinInput_dom = require('./pin-input.dom.js');
10
-
11
- const { and, not } = core.guards;
12
- function machine(userContext) {
13
- const ctx = utils.compact(userContext);
14
- return core.createMachine(
15
- {
16
- id: "pin-input",
17
- initial: ctx.autoFocus ? "focused" : "idle",
18
- context: {
19
- value: [],
20
- focusedIndex: -1,
21
- placeholder: "○",
22
- otp: false,
23
- type: "numeric",
24
- ...ctx,
25
- translations: {
26
- inputLabel: (index, length) => `pin code ${index + 1} of ${length}`,
27
- ...ctx.translations
28
- }
29
- },
30
- computed: {
31
- valueLength: (ctx2) => ctx2.value.length,
32
- filledValueLength: (ctx2) => ctx2.value.filter((v) => v?.trim() !== "").length,
33
- isValueComplete: (ctx2) => ctx2.valueLength === ctx2.filledValueLength,
34
- valueAsString: (ctx2) => ctx2.value.join(""),
35
- focusedValue: (ctx2) => ctx2.value[ctx2.focusedIndex]
36
- },
37
- watch: {
38
- focusedIndex: ["focusInput", "setInputSelection"],
39
- value: ["dispatchInputEvent", "syncInputElements"],
40
- isValueComplete: ["invokeOnComplete", "blurFocusedInputIfNeeded"]
41
- },
42
- entry: ctx.autoFocus ? ["setupValue", "setFocusIndexToFirst"] : ["setupValue"],
43
- on: {
44
- SET_VALUE: [
45
- {
46
- guard: "hasIndex",
47
- actions: ["setValueAtIndex", "invokeOnChange"]
48
- },
49
- { actions: ["setValue", "invokeOnChange"] }
50
- ],
51
- CLEAR_VALUE: [
52
- {
53
- guard: "isDisabled",
54
- actions: ["clearValue", "invokeOnChange"]
55
- },
56
- {
57
- actions: ["clearValue", "invokeOnChange", "setFocusIndexToFirst"]
58
- }
59
- ]
60
- },
61
- states: {
62
- idle: {
63
- on: {
64
- FOCUS: {
65
- target: "focused",
66
- actions: "setFocusedIndex"
67
- }
68
- }
69
- },
70
- focused: {
71
- on: {
72
- INPUT: [
73
- {
74
- guard: and("isFinalValue", "isValidValue"),
75
- actions: ["setFocusedValue", "invokeOnChange", "syncInputValue"]
76
- },
77
- {
78
- guard: "isValidValue",
79
- actions: ["setFocusedValue", "invokeOnChange", "setNextFocusedIndex", "syncInputValue"]
80
- }
81
- ],
82
- PASTE: [
83
- {
84
- guard: "isValidValue",
85
- actions: ["setPastedValue", "invokeOnChange", "setLastValueFocusIndex"]
86
- },
87
- { actions: ["resetFocusedValue", "invokeOnChange"] }
88
- ],
89
- BLUR: {
90
- target: "idle",
91
- actions: "clearFocusedIndex"
92
- },
93
- DELETE: {
94
- guard: "hasValue",
95
- actions: ["clearFocusedValue", "invokeOnChange"]
96
- },
97
- ARROW_LEFT: {
98
- actions: "setPrevFocusedIndex"
99
- },
100
- ARROW_RIGHT: {
101
- actions: "setNextFocusedIndex"
102
- },
103
- BACKSPACE: [
104
- {
105
- guard: "hasValue",
106
- actions: ["clearFocusedValue", "invokeOnChange"]
107
- },
108
- {
109
- actions: ["setPrevFocusedIndex", "clearFocusedValue", "invokeOnChange"]
110
- }
111
- ],
112
- ENTER: {
113
- guard: "isValueComplete",
114
- actions: "requestFormSubmit"
115
- },
116
- KEY_DOWN: {
117
- guard: not("isValidValue"),
118
- actions: ["preventDefault", "invokeOnInvalid"]
119
- }
120
- }
121
- }
122
- }
123
- },
124
- {
125
- guards: {
126
- autoFocus: (ctx2) => !!ctx2.autoFocus,
127
- isValueEmpty: (_ctx, evt) => evt.value === "",
128
- hasValue: (ctx2) => ctx2.value[ctx2.focusedIndex] !== "",
129
- isValueComplete: (ctx2) => ctx2.isValueComplete,
130
- isValidValue: (ctx2, evt) => {
131
- if (!ctx2.pattern)
132
- return isValidType(evt.value, ctx2.type);
133
- const regex = new RegExp(ctx2.pattern, "g");
134
- return regex.test(evt.value);
135
- },
136
- isFinalValue: (ctx2) => {
137
- return ctx2.filledValueLength + 1 === ctx2.valueLength && ctx2.value.findIndex((v) => v.trim() === "") === ctx2.focusedIndex;
138
- },
139
- isLastInputFocused: (ctx2) => ctx2.focusedIndex === ctx2.valueLength - 1,
140
- hasIndex: (_ctx, evt) => evt.index !== void 0,
141
- isDisabled: (ctx2) => !!ctx2.disabled
142
- },
143
- actions: {
144
- setupValue: (ctx2) => {
145
- if (ctx2.value.length)
146
- return;
147
- const inputs = pinInput_dom.dom.getElements(ctx2);
148
- const emptyValues = Array.from({ length: inputs.length }).fill("");
149
- assign(ctx2, emptyValues);
150
- },
151
- focusInput: (ctx2) => {
152
- domQuery.raf(() => {
153
- if (ctx2.focusedIndex === -1)
154
- return;
155
- pinInput_dom.dom.getFocusedInputEl(ctx2)?.focus();
156
- });
157
- },
158
- setInputSelection: (ctx2) => {
159
- domQuery.raf(() => {
160
- if (ctx2.focusedIndex === -1)
161
- return;
162
- const input = pinInput_dom.dom.getFocusedInputEl(ctx2);
163
- const length = input.value.length;
164
- input.selectionStart = ctx2.selectOnFocus ? 0 : length;
165
- input.selectionEnd = length;
166
- });
167
- },
168
- invokeOnComplete: (ctx2) => {
169
- if (!ctx2.isValueComplete)
170
- return;
171
- ctx2.onComplete?.({ value: Array.from(ctx2.value), valueAsString: ctx2.valueAsString });
172
- },
173
- invokeOnChange: (ctx2) => {
174
- ctx2.onChange?.({ value: Array.from(ctx2.value) });
175
- },
176
- dispatchInputEvent: (ctx2) => {
177
- const inputEl = pinInput_dom.dom.getHiddenInputEl(ctx2);
178
- formUtils.dispatchInputValueEvent(inputEl, { value: ctx2.valueAsString });
179
- },
180
- invokeOnInvalid: (ctx2, evt) => {
181
- ctx2.onInvalid?.({ value: evt.value, index: ctx2.focusedIndex });
182
- },
183
- clearFocusedIndex: (ctx2) => {
184
- ctx2.focusedIndex = -1;
185
- },
186
- setValue: (ctx2, evt) => {
187
- assign(ctx2, evt.value);
188
- },
189
- setFocusedIndex: (ctx2, evt) => {
190
- ctx2.focusedIndex = evt.index;
191
- },
192
- setFocusedValue: (ctx2, evt) => {
193
- ctx2.value[ctx2.focusedIndex] = getNextValue(ctx2.focusedValue, evt.value);
194
- },
195
- syncInputValue(ctx2, evt) {
196
- const input = pinInput_dom.dom.getInputEl(ctx2, evt.index.toString());
197
- if (!input)
198
- return;
199
- input.value = ctx2.value[evt.index];
200
- },
201
- syncInputElements(ctx2) {
202
- const inputs = pinInput_dom.dom.getElements(ctx2);
203
- inputs.forEach((input, index) => {
204
- input.value = ctx2.value[index];
205
- });
206
- },
207
- setPastedValue(ctx2, evt) {
208
- domQuery.raf(() => {
209
- const startIndex = ctx2.focusedValue ? 1 : 0;
210
- const value = evt.value.substring(startIndex, startIndex + ctx2.valueLength);
211
- assign(ctx2, value);
212
- });
213
- },
214
- setValueAtIndex: (ctx2, evt) => {
215
- ctx2.value[evt.index] = getNextValue(ctx2.focusedValue, evt.value);
216
- },
217
- clearValue: (ctx2) => {
218
- const nextValue = Array.from({ length: ctx2.valueLength }).fill("");
219
- assign(ctx2, nextValue);
220
- },
221
- clearFocusedValue: (ctx2) => {
222
- ctx2.value[ctx2.focusedIndex] = "";
223
- },
224
- resetFocusedValue: (ctx2) => {
225
- const input = pinInput_dom.dom.getFocusedInputEl(ctx2);
226
- input.value = ctx2.focusedValue;
227
- },
228
- setFocusIndexToFirst: (ctx2) => {
229
- ctx2.focusedIndex = 0;
230
- },
231
- setNextFocusedIndex: (ctx2) => {
232
- ctx2.focusedIndex = Math.min(ctx2.focusedIndex + 1, ctx2.valueLength - 1);
233
- },
234
- setPrevFocusedIndex: (ctx2) => {
235
- ctx2.focusedIndex = Math.max(ctx2.focusedIndex - 1, 0);
236
- },
237
- setLastValueFocusIndex: (ctx2) => {
238
- domQuery.raf(() => {
239
- ctx2.focusedIndex = Math.min(ctx2.filledValueLength, ctx2.valueLength - 1);
240
- });
241
- },
242
- preventDefault(_, evt) {
243
- evt.preventDefault();
244
- },
245
- blurFocusedInputIfNeeded(ctx2) {
246
- if (!ctx2.blurOnComplete)
247
- return;
248
- domQuery.raf(() => {
249
- pinInput_dom.dom.getFocusedInputEl(ctx2)?.blur();
250
- });
251
- },
252
- requestFormSubmit(ctx2) {
253
- if (!ctx2.name || !ctx2.isValueComplete)
254
- return;
255
- const input = pinInput_dom.dom.getHiddenInputEl(ctx2);
256
- input?.form?.requestSubmit();
257
- }
258
- }
259
- }
260
- );
261
- }
262
- const REGEX = {
263
- numeric: /^[0-9]+$/,
264
- alphabetic: /^[A-Za-z]+$/,
265
- alphanumeric: /^[a-zA-Z0-9]+$/i
266
- };
267
- function isValidType(value, type) {
268
- if (!type)
269
- return true;
270
- return !!REGEX[type]?.test(value);
271
- }
272
- function assign(ctx, value) {
273
- const arr = Array.isArray(value) ? value : value.split("").filter(Boolean);
274
- arr.forEach((value2, index) => {
275
- ctx.value[index] = value2;
276
- });
277
- }
278
- function getNextValue(current, next) {
279
- let nextValue = next;
280
- if (current[0] === next[0])
281
- nextValue = next[1];
282
- else if (current[0] === next[1])
283
- nextValue = next[0];
284
- return nextValue;
285
- }
286
-
287
- exports.machine = machine;
@@ -1,283 +0,0 @@
1
- import { createMachine, guards } from '@zag-js/core';
2
- import { raf } from '@zag-js/dom-query';
3
- import { dispatchInputValueEvent } from '@zag-js/form-utils';
4
- import { compact } from '@zag-js/utils';
5
- import { dom } from './pin-input.dom.mjs';
6
-
7
- const { and, not } = guards;
8
- function machine(userContext) {
9
- const ctx = compact(userContext);
10
- return createMachine(
11
- {
12
- id: "pin-input",
13
- initial: ctx.autoFocus ? "focused" : "idle",
14
- context: {
15
- value: [],
16
- focusedIndex: -1,
17
- placeholder: "○",
18
- otp: false,
19
- type: "numeric",
20
- ...ctx,
21
- translations: {
22
- inputLabel: (index, length) => `pin code ${index + 1} of ${length}`,
23
- ...ctx.translations
24
- }
25
- },
26
- computed: {
27
- valueLength: (ctx2) => ctx2.value.length,
28
- filledValueLength: (ctx2) => ctx2.value.filter((v) => v?.trim() !== "").length,
29
- isValueComplete: (ctx2) => ctx2.valueLength === ctx2.filledValueLength,
30
- valueAsString: (ctx2) => ctx2.value.join(""),
31
- focusedValue: (ctx2) => ctx2.value[ctx2.focusedIndex]
32
- },
33
- watch: {
34
- focusedIndex: ["focusInput", "setInputSelection"],
35
- value: ["dispatchInputEvent", "syncInputElements"],
36
- isValueComplete: ["invokeOnComplete", "blurFocusedInputIfNeeded"]
37
- },
38
- entry: ctx.autoFocus ? ["setupValue", "setFocusIndexToFirst"] : ["setupValue"],
39
- on: {
40
- SET_VALUE: [
41
- {
42
- guard: "hasIndex",
43
- actions: ["setValueAtIndex", "invokeOnChange"]
44
- },
45
- { actions: ["setValue", "invokeOnChange"] }
46
- ],
47
- CLEAR_VALUE: [
48
- {
49
- guard: "isDisabled",
50
- actions: ["clearValue", "invokeOnChange"]
51
- },
52
- {
53
- actions: ["clearValue", "invokeOnChange", "setFocusIndexToFirst"]
54
- }
55
- ]
56
- },
57
- states: {
58
- idle: {
59
- on: {
60
- FOCUS: {
61
- target: "focused",
62
- actions: "setFocusedIndex"
63
- }
64
- }
65
- },
66
- focused: {
67
- on: {
68
- INPUT: [
69
- {
70
- guard: and("isFinalValue", "isValidValue"),
71
- actions: ["setFocusedValue", "invokeOnChange", "syncInputValue"]
72
- },
73
- {
74
- guard: "isValidValue",
75
- actions: ["setFocusedValue", "invokeOnChange", "setNextFocusedIndex", "syncInputValue"]
76
- }
77
- ],
78
- PASTE: [
79
- {
80
- guard: "isValidValue",
81
- actions: ["setPastedValue", "invokeOnChange", "setLastValueFocusIndex"]
82
- },
83
- { actions: ["resetFocusedValue", "invokeOnChange"] }
84
- ],
85
- BLUR: {
86
- target: "idle",
87
- actions: "clearFocusedIndex"
88
- },
89
- DELETE: {
90
- guard: "hasValue",
91
- actions: ["clearFocusedValue", "invokeOnChange"]
92
- },
93
- ARROW_LEFT: {
94
- actions: "setPrevFocusedIndex"
95
- },
96
- ARROW_RIGHT: {
97
- actions: "setNextFocusedIndex"
98
- },
99
- BACKSPACE: [
100
- {
101
- guard: "hasValue",
102
- actions: ["clearFocusedValue", "invokeOnChange"]
103
- },
104
- {
105
- actions: ["setPrevFocusedIndex", "clearFocusedValue", "invokeOnChange"]
106
- }
107
- ],
108
- ENTER: {
109
- guard: "isValueComplete",
110
- actions: "requestFormSubmit"
111
- },
112
- KEY_DOWN: {
113
- guard: not("isValidValue"),
114
- actions: ["preventDefault", "invokeOnInvalid"]
115
- }
116
- }
117
- }
118
- }
119
- },
120
- {
121
- guards: {
122
- autoFocus: (ctx2) => !!ctx2.autoFocus,
123
- isValueEmpty: (_ctx, evt) => evt.value === "",
124
- hasValue: (ctx2) => ctx2.value[ctx2.focusedIndex] !== "",
125
- isValueComplete: (ctx2) => ctx2.isValueComplete,
126
- isValidValue: (ctx2, evt) => {
127
- if (!ctx2.pattern)
128
- return isValidType(evt.value, ctx2.type);
129
- const regex = new RegExp(ctx2.pattern, "g");
130
- return regex.test(evt.value);
131
- },
132
- isFinalValue: (ctx2) => {
133
- return ctx2.filledValueLength + 1 === ctx2.valueLength && ctx2.value.findIndex((v) => v.trim() === "") === ctx2.focusedIndex;
134
- },
135
- isLastInputFocused: (ctx2) => ctx2.focusedIndex === ctx2.valueLength - 1,
136
- hasIndex: (_ctx, evt) => evt.index !== void 0,
137
- isDisabled: (ctx2) => !!ctx2.disabled
138
- },
139
- actions: {
140
- setupValue: (ctx2) => {
141
- if (ctx2.value.length)
142
- return;
143
- const inputs = dom.getElements(ctx2);
144
- const emptyValues = Array.from({ length: inputs.length }).fill("");
145
- assign(ctx2, emptyValues);
146
- },
147
- focusInput: (ctx2) => {
148
- raf(() => {
149
- if (ctx2.focusedIndex === -1)
150
- return;
151
- dom.getFocusedInputEl(ctx2)?.focus();
152
- });
153
- },
154
- setInputSelection: (ctx2) => {
155
- raf(() => {
156
- if (ctx2.focusedIndex === -1)
157
- return;
158
- const input = dom.getFocusedInputEl(ctx2);
159
- const length = input.value.length;
160
- input.selectionStart = ctx2.selectOnFocus ? 0 : length;
161
- input.selectionEnd = length;
162
- });
163
- },
164
- invokeOnComplete: (ctx2) => {
165
- if (!ctx2.isValueComplete)
166
- return;
167
- ctx2.onComplete?.({ value: Array.from(ctx2.value), valueAsString: ctx2.valueAsString });
168
- },
169
- invokeOnChange: (ctx2) => {
170
- ctx2.onChange?.({ value: Array.from(ctx2.value) });
171
- },
172
- dispatchInputEvent: (ctx2) => {
173
- const inputEl = dom.getHiddenInputEl(ctx2);
174
- dispatchInputValueEvent(inputEl, { value: ctx2.valueAsString });
175
- },
176
- invokeOnInvalid: (ctx2, evt) => {
177
- ctx2.onInvalid?.({ value: evt.value, index: ctx2.focusedIndex });
178
- },
179
- clearFocusedIndex: (ctx2) => {
180
- ctx2.focusedIndex = -1;
181
- },
182
- setValue: (ctx2, evt) => {
183
- assign(ctx2, evt.value);
184
- },
185
- setFocusedIndex: (ctx2, evt) => {
186
- ctx2.focusedIndex = evt.index;
187
- },
188
- setFocusedValue: (ctx2, evt) => {
189
- ctx2.value[ctx2.focusedIndex] = getNextValue(ctx2.focusedValue, evt.value);
190
- },
191
- syncInputValue(ctx2, evt) {
192
- const input = dom.getInputEl(ctx2, evt.index.toString());
193
- if (!input)
194
- return;
195
- input.value = ctx2.value[evt.index];
196
- },
197
- syncInputElements(ctx2) {
198
- const inputs = dom.getElements(ctx2);
199
- inputs.forEach((input, index) => {
200
- input.value = ctx2.value[index];
201
- });
202
- },
203
- setPastedValue(ctx2, evt) {
204
- raf(() => {
205
- const startIndex = ctx2.focusedValue ? 1 : 0;
206
- const value = evt.value.substring(startIndex, startIndex + ctx2.valueLength);
207
- assign(ctx2, value);
208
- });
209
- },
210
- setValueAtIndex: (ctx2, evt) => {
211
- ctx2.value[evt.index] = getNextValue(ctx2.focusedValue, evt.value);
212
- },
213
- clearValue: (ctx2) => {
214
- const nextValue = Array.from({ length: ctx2.valueLength }).fill("");
215
- assign(ctx2, nextValue);
216
- },
217
- clearFocusedValue: (ctx2) => {
218
- ctx2.value[ctx2.focusedIndex] = "";
219
- },
220
- resetFocusedValue: (ctx2) => {
221
- const input = dom.getFocusedInputEl(ctx2);
222
- input.value = ctx2.focusedValue;
223
- },
224
- setFocusIndexToFirst: (ctx2) => {
225
- ctx2.focusedIndex = 0;
226
- },
227
- setNextFocusedIndex: (ctx2) => {
228
- ctx2.focusedIndex = Math.min(ctx2.focusedIndex + 1, ctx2.valueLength - 1);
229
- },
230
- setPrevFocusedIndex: (ctx2) => {
231
- ctx2.focusedIndex = Math.max(ctx2.focusedIndex - 1, 0);
232
- },
233
- setLastValueFocusIndex: (ctx2) => {
234
- raf(() => {
235
- ctx2.focusedIndex = Math.min(ctx2.filledValueLength, ctx2.valueLength - 1);
236
- });
237
- },
238
- preventDefault(_, evt) {
239
- evt.preventDefault();
240
- },
241
- blurFocusedInputIfNeeded(ctx2) {
242
- if (!ctx2.blurOnComplete)
243
- return;
244
- raf(() => {
245
- dom.getFocusedInputEl(ctx2)?.blur();
246
- });
247
- },
248
- requestFormSubmit(ctx2) {
249
- if (!ctx2.name || !ctx2.isValueComplete)
250
- return;
251
- const input = dom.getHiddenInputEl(ctx2);
252
- input?.form?.requestSubmit();
253
- }
254
- }
255
- }
256
- );
257
- }
258
- const REGEX = {
259
- numeric: /^[0-9]+$/,
260
- alphabetic: /^[A-Za-z]+$/,
261
- alphanumeric: /^[a-zA-Z0-9]+$/i
262
- };
263
- function isValidType(value, type) {
264
- if (!type)
265
- return true;
266
- return !!REGEX[type]?.test(value);
267
- }
268
- function assign(ctx, value) {
269
- const arr = Array.isArray(value) ? value : value.split("").filter(Boolean);
270
- arr.forEach((value2, index) => {
271
- ctx.value[index] = value2;
272
- });
273
- }
274
- function getNextValue(current, next) {
275
- let nextValue = next;
276
- if (current[0] === next[0])
277
- nextValue = next[1];
278
- else if (current[0] === next[1])
279
- nextValue = next[0];
280
- return nextValue;
281
- }
282
-
283
- export { machine };