@arun-dev/headless 4.18.0 → 4.19.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/otp-input/index.cjs +67 -16
- package/dist/otp-input/index.d.cts +17 -3
- package/dist/otp-input/index.d.ts +17 -3
- package/dist/otp-input/index.js +65 -14
- package/package.json +1 -1
package/dist/otp-input/index.cjs
CHANGED
|
@@ -167,12 +167,20 @@ function useOtpInputRootContext(part) {
|
|
|
167
167
|
}
|
|
168
168
|
return context;
|
|
169
169
|
}
|
|
170
|
+
var GAP = " ";
|
|
170
171
|
function sanitize(text, validationType) {
|
|
171
172
|
return validationType === "numeric" ? text.replace(/\D/g, "") : text.replace(/[^A-Za-z0-9]/g, "");
|
|
172
173
|
}
|
|
174
|
+
function normalize(text, validationType, length) {
|
|
175
|
+
const allowed = validationType === "numeric" ? /[^\d ]/g : /[^A-Za-z0-9 ]/g;
|
|
176
|
+
return text.replace(allowed, "").slice(0, length).trimEnd();
|
|
177
|
+
}
|
|
178
|
+
function isComplete(value, length) {
|
|
179
|
+
return value.length === length && !value.includes(GAP);
|
|
180
|
+
}
|
|
173
181
|
function otpInputDataAttributes({ value, length, disabled }) {
|
|
174
182
|
return {
|
|
175
|
-
"data-complete": value
|
|
183
|
+
"data-complete": isComplete(value, length) ? "" : void 0,
|
|
176
184
|
"data-disabled": disabled ? "" : void 0
|
|
177
185
|
};
|
|
178
186
|
}
|
|
@@ -183,6 +191,7 @@ function OtpInputRoot({
|
|
|
183
191
|
value: valueProp,
|
|
184
192
|
defaultValue,
|
|
185
193
|
onValueChange,
|
|
194
|
+
onComplete,
|
|
186
195
|
length = 6,
|
|
187
196
|
validationType = "numeric",
|
|
188
197
|
disabled = false,
|
|
@@ -199,12 +208,13 @@ function OtpInputRoot({
|
|
|
199
208
|
});
|
|
200
209
|
const commit = (0, import_react4.useCallback)(
|
|
201
210
|
(next) => {
|
|
202
|
-
const clean =
|
|
211
|
+
const clean = normalize(next, validationType, length);
|
|
203
212
|
if (clean === value) return;
|
|
204
213
|
setValue(clean);
|
|
205
214
|
onValueChange?.(clean);
|
|
215
|
+
if (isComplete(clean, length)) onComplete?.(clean);
|
|
206
216
|
},
|
|
207
|
-
[validationType, length, value, setValue, onValueChange]
|
|
217
|
+
[validationType, length, value, setValue, onValueChange, onComplete]
|
|
208
218
|
);
|
|
209
219
|
const [selection, setSelection] = (0, import_react4.useState)(null);
|
|
210
220
|
const inputRef = (0, import_react4.useRef)(null);
|
|
@@ -267,6 +277,7 @@ function OtpInputRoot({
|
|
|
267
277
|
}
|
|
268
278
|
|
|
269
279
|
// src/otp-input/OtpInputInput.tsx
|
|
280
|
+
var import_react5 = require("react");
|
|
270
281
|
function OtpInputInput({ render, ...rest }) {
|
|
271
282
|
const { value, length, disabled, validationType, setSelection, commit, inputRef, slotAt } = useOtpInputRootContext("Input");
|
|
272
283
|
function select(input, index) {
|
|
@@ -279,6 +290,48 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
279
290
|
function report(input) {
|
|
280
291
|
setSelection({ start: input.selectionStart ?? 0, end: input.selectionEnd ?? 0 });
|
|
281
292
|
}
|
|
293
|
+
const pendingCaret = (0, import_react5.useRef)(null);
|
|
294
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
295
|
+
const input = inputRef.current;
|
|
296
|
+
const at = pendingCaret.current;
|
|
297
|
+
pendingCaret.current = null;
|
|
298
|
+
if (input && at !== null && input.ownerDocument.activeElement === input) select(input, at);
|
|
299
|
+
});
|
|
300
|
+
function edit(next, caret) {
|
|
301
|
+
pendingCaret.current = caret;
|
|
302
|
+
commit(next);
|
|
303
|
+
}
|
|
304
|
+
const cleared = (index) => value.slice(0, index) + GAP + value.slice(index + 1);
|
|
305
|
+
function onDelete(event, input) {
|
|
306
|
+
const start = input.selectionStart ?? 0;
|
|
307
|
+
const end = input.selectionEnd ?? start;
|
|
308
|
+
event.preventDefault();
|
|
309
|
+
if (end > start + 1) {
|
|
310
|
+
edit(value.slice(0, start) + GAP.repeat(end - start) + value.slice(end), start);
|
|
311
|
+
} else if (end === start + 1 && value.charAt(start) !== GAP) {
|
|
312
|
+
edit(cleared(start), start);
|
|
313
|
+
} else if (event.inputType.includes("Backward") && start > 0) {
|
|
314
|
+
edit(cleared(start - 1), start - 1);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
const beforeInput = (0, import_react5.useRef)(() => {
|
|
318
|
+
});
|
|
319
|
+
beforeInput.current = (event) => {
|
|
320
|
+
const input = event.currentTarget;
|
|
321
|
+
if (event.inputType.startsWith("delete") && event.inputType !== "deleteByCut") {
|
|
322
|
+
onDelete(event, input);
|
|
323
|
+
} else if (event.inputType === "insertText") {
|
|
324
|
+
const typed = event.data ?? "";
|
|
325
|
+
if (typed.length > 0 && sanitize(typed, validationType) !== typed) event.preventDefault();
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
(0, import_react5.useEffect)(() => {
|
|
329
|
+
const input = inputRef.current;
|
|
330
|
+
if (!input) return;
|
|
331
|
+
const listener = (event) => beforeInput.current(event);
|
|
332
|
+
input.addEventListener("beforeinput", listener);
|
|
333
|
+
return () => input.removeEventListener("beforeinput", listener);
|
|
334
|
+
}, [inputRef]);
|
|
282
335
|
function syncSelection(event) {
|
|
283
336
|
const input = event.currentTarget;
|
|
284
337
|
const start = input.selectionStart ?? 0;
|
|
@@ -301,12 +354,6 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
301
354
|
maxLength: length,
|
|
302
355
|
pattern: validationType === "numeric" ? `\\d{${length}}` : `[A-Za-z0-9]{${length}}`,
|
|
303
356
|
disabled: disabled || void 0,
|
|
304
|
-
onBeforeInput(event) {
|
|
305
|
-
const typed = event.data;
|
|
306
|
-
if (typed && typed.length === 1 && !sanitize(typed, validationType)) {
|
|
307
|
-
event.preventDefault();
|
|
308
|
-
}
|
|
309
|
-
},
|
|
310
357
|
onChange(event) {
|
|
311
358
|
commit(event.currentTarget.value);
|
|
312
359
|
syncSelection(event);
|
|
@@ -317,12 +364,16 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
317
364
|
if (!pasted) return;
|
|
318
365
|
const input = event.currentTarget;
|
|
319
366
|
if (pasted.length >= length) {
|
|
320
|
-
|
|
367
|
+
edit(pasted, length);
|
|
321
368
|
return;
|
|
322
369
|
}
|
|
323
370
|
const start = input.selectionStart ?? value.length;
|
|
324
371
|
const end = input.selectionEnd ?? start;
|
|
325
|
-
|
|
372
|
+
const reach = start + pasted.length;
|
|
373
|
+
edit(
|
|
374
|
+
value.slice(0, start) + pasted + GAP.repeat(Math.max(0, end - reach)) + value.slice(Math.max(end, reach)),
|
|
375
|
+
reach
|
|
376
|
+
);
|
|
326
377
|
},
|
|
327
378
|
onKeyDown(event) {
|
|
328
379
|
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
@@ -333,13 +384,13 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
333
384
|
select(input, event.key === "ArrowLeft" ? at - 1 : at + 1);
|
|
334
385
|
},
|
|
335
386
|
onClick(event) {
|
|
336
|
-
if (event.detail > 1) return;
|
|
337
387
|
const index = slotAt(event.clientX);
|
|
338
388
|
if (index !== null) select(event.currentTarget, index);
|
|
339
389
|
},
|
|
340
390
|
onSelect: syncSelection,
|
|
341
391
|
onFocus(event) {
|
|
342
|
-
|
|
392
|
+
const gap = value.indexOf(GAP);
|
|
393
|
+
select(event.currentTarget, gap === -1 ? value.length : gap);
|
|
343
394
|
},
|
|
344
395
|
onBlur() {
|
|
345
396
|
setSelection(null);
|
|
@@ -350,15 +401,15 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
350
401
|
}
|
|
351
402
|
|
|
352
403
|
// src/otp-input/OtpInputSlot.tsx
|
|
353
|
-
var
|
|
404
|
+
var import_react6 = require("react");
|
|
354
405
|
function OtpInputSlot({ index, className, children, render, ...rest }) {
|
|
355
406
|
const { value, length, disabled, selection, registerSlot } = useOtpInputRootContext("Slot");
|
|
356
|
-
const char = value.charAt(index);
|
|
407
|
+
const char = value.charAt(index) === GAP ? "" : value.charAt(index);
|
|
357
408
|
let active = false;
|
|
358
409
|
if (selection) {
|
|
359
410
|
active = selection.start === selection.end ? index === Math.min(selection.start, length - 1) : index >= selection.start && index < selection.end;
|
|
360
411
|
}
|
|
361
|
-
const ref = (0,
|
|
412
|
+
const ref = (0, import_react6.useCallback)(
|
|
362
413
|
(element) => registerSlot(index, element),
|
|
363
414
|
[registerSlot, index]
|
|
364
415
|
);
|
|
@@ -20,8 +20,18 @@ type OtpInputRootOwnProps = {
|
|
|
20
20
|
value?: string;
|
|
21
21
|
/** Initial value when uncontrolled. Read once, at mount. */
|
|
22
22
|
defaultValue?: string;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Called with the code after every change, partial or complete. A box emptied before the end
|
|
25
|
+
* is a space — `"123 56"` — so check completeness with a pattern such as `/^\d{6}$/`, not
|
|
26
|
+
* the length alone.
|
|
27
|
+
*/
|
|
24
28
|
onValueChange?: (value: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Called with the code after a change that leaves it complete: every slot filled, no gap.
|
|
31
|
+
* Typing the last digit, pasting a whole code and filling an emptied slot all count; a change
|
|
32
|
+
* that leaves a slot empty does not. Use it to verify as soon as the code is in.
|
|
33
|
+
*/
|
|
34
|
+
onComplete?: (value: string) => void;
|
|
25
35
|
/** How many characters the code has, and so how many slots it shows. Defaults to 6. */
|
|
26
36
|
length?: number;
|
|
27
37
|
/**
|
|
@@ -48,7 +58,7 @@ type OtpInputRootProps = OtpInputRootOwnProps & Omit<ComponentPropsWithRef<'div'
|
|
|
48
58
|
* Holds the value through `useControlled`. The input reports changes, and the Root keeps only
|
|
49
59
|
* the characters `validationType` allows, up to `length`.
|
|
50
60
|
*/
|
|
51
|
-
declare function OtpInputRoot({ value: valueProp, defaultValue, onValueChange, length, validationType, disabled, className, children, render, ...rest }: OtpInputRootProps): react.JSX.Element;
|
|
61
|
+
declare function OtpInputRoot({ value: valueProp, defaultValue, onValueChange, onComplete, length, validationType, disabled, className, children, render, ...rest }: OtpInputRootProps): react.JSX.Element;
|
|
52
62
|
|
|
53
63
|
type OtpInputInputOwnProps = {
|
|
54
64
|
/** Element to render instead of the default `<input>`. Props and ref are merged onto it. */
|
|
@@ -66,7 +76,11 @@ type OtpInputInputProps = OtpInputInputOwnProps & Omit<ComponentPropsWithRef<'in
|
|
|
66
76
|
*
|
|
67
77
|
* The caret always covers one character, so typing replaces the character in the active slot
|
|
68
78
|
* and moves on, and the last slot of a full code is replaced rather than refused. Left and
|
|
69
|
-
* Right move one slot
|
|
79
|
+
* Right move one slot.
|
|
80
|
+
*
|
|
81
|
+
* Delete and Backspace empty a slot in place: the characters after it keep their slots, and
|
|
82
|
+
* the caret stays, so the next character fills the same slot. Backspace on an empty slot
|
|
83
|
+
* empties the one before it; Delete on an empty slot does nothing.
|
|
70
84
|
*
|
|
71
85
|
* Carries `maxLength` and a `pattern` of exactly `length` allowed characters, so the browser's
|
|
72
86
|
* own validation reports a code that is too short. Both can be overridden.
|
|
@@ -20,8 +20,18 @@ type OtpInputRootOwnProps = {
|
|
|
20
20
|
value?: string;
|
|
21
21
|
/** Initial value when uncontrolled. Read once, at mount. */
|
|
22
22
|
defaultValue?: string;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Called with the code after every change, partial or complete. A box emptied before the end
|
|
25
|
+
* is a space — `"123 56"` — so check completeness with a pattern such as `/^\d{6}$/`, not
|
|
26
|
+
* the length alone.
|
|
27
|
+
*/
|
|
24
28
|
onValueChange?: (value: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Called with the code after a change that leaves it complete: every slot filled, no gap.
|
|
31
|
+
* Typing the last digit, pasting a whole code and filling an emptied slot all count; a change
|
|
32
|
+
* that leaves a slot empty does not. Use it to verify as soon as the code is in.
|
|
33
|
+
*/
|
|
34
|
+
onComplete?: (value: string) => void;
|
|
25
35
|
/** How many characters the code has, and so how many slots it shows. Defaults to 6. */
|
|
26
36
|
length?: number;
|
|
27
37
|
/**
|
|
@@ -48,7 +58,7 @@ type OtpInputRootProps = OtpInputRootOwnProps & Omit<ComponentPropsWithRef<'div'
|
|
|
48
58
|
* Holds the value through `useControlled`. The input reports changes, and the Root keeps only
|
|
49
59
|
* the characters `validationType` allows, up to `length`.
|
|
50
60
|
*/
|
|
51
|
-
declare function OtpInputRoot({ value: valueProp, defaultValue, onValueChange, length, validationType, disabled, className, children, render, ...rest }: OtpInputRootProps): react.JSX.Element;
|
|
61
|
+
declare function OtpInputRoot({ value: valueProp, defaultValue, onValueChange, onComplete, length, validationType, disabled, className, children, render, ...rest }: OtpInputRootProps): react.JSX.Element;
|
|
52
62
|
|
|
53
63
|
type OtpInputInputOwnProps = {
|
|
54
64
|
/** Element to render instead of the default `<input>`. Props and ref are merged onto it. */
|
|
@@ -66,7 +76,11 @@ type OtpInputInputProps = OtpInputInputOwnProps & Omit<ComponentPropsWithRef<'in
|
|
|
66
76
|
*
|
|
67
77
|
* The caret always covers one character, so typing replaces the character in the active slot
|
|
68
78
|
* and moves on, and the last slot of a full code is replaced rather than refused. Left and
|
|
69
|
-
* Right move one slot
|
|
79
|
+
* Right move one slot.
|
|
80
|
+
*
|
|
81
|
+
* Delete and Backspace empty a slot in place: the characters after it keep their slots, and
|
|
82
|
+
* the caret stays, so the next character fills the same slot. Backspace on an empty slot
|
|
83
|
+
* empties the one before it; Delete on an empty slot does nothing.
|
|
70
84
|
*
|
|
71
85
|
* Carries `maxLength` and a `pattern` of exactly `length` allowed characters, so the browser's
|
|
72
86
|
* own validation reports a code that is too short. Both can be overridden.
|
package/dist/otp-input/index.js
CHANGED
|
@@ -27,12 +27,20 @@ function useOtpInputRootContext(part) {
|
|
|
27
27
|
}
|
|
28
28
|
return context;
|
|
29
29
|
}
|
|
30
|
+
var GAP = " ";
|
|
30
31
|
function sanitize(text, validationType) {
|
|
31
32
|
return validationType === "numeric" ? text.replace(/\D/g, "") : text.replace(/[^A-Za-z0-9]/g, "");
|
|
32
33
|
}
|
|
34
|
+
function normalize(text, validationType, length) {
|
|
35
|
+
const allowed = validationType === "numeric" ? /[^\d ]/g : /[^A-Za-z0-9 ]/g;
|
|
36
|
+
return text.replace(allowed, "").slice(0, length).trimEnd();
|
|
37
|
+
}
|
|
38
|
+
function isComplete(value, length) {
|
|
39
|
+
return value.length === length && !value.includes(GAP);
|
|
40
|
+
}
|
|
33
41
|
function otpInputDataAttributes({ value, length, disabled }) {
|
|
34
42
|
return {
|
|
35
|
-
"data-complete": value
|
|
43
|
+
"data-complete": isComplete(value, length) ? "" : void 0,
|
|
36
44
|
"data-disabled": disabled ? "" : void 0
|
|
37
45
|
};
|
|
38
46
|
}
|
|
@@ -43,6 +51,7 @@ function OtpInputRoot({
|
|
|
43
51
|
value: valueProp,
|
|
44
52
|
defaultValue,
|
|
45
53
|
onValueChange,
|
|
54
|
+
onComplete,
|
|
46
55
|
length = 6,
|
|
47
56
|
validationType = "numeric",
|
|
48
57
|
disabled = false,
|
|
@@ -59,12 +68,13 @@ function OtpInputRoot({
|
|
|
59
68
|
});
|
|
60
69
|
const commit = useCallback(
|
|
61
70
|
(next) => {
|
|
62
|
-
const clean =
|
|
71
|
+
const clean = normalize(next, validationType, length);
|
|
63
72
|
if (clean === value) return;
|
|
64
73
|
setValue(clean);
|
|
65
74
|
onValueChange?.(clean);
|
|
75
|
+
if (isComplete(clean, length)) onComplete?.(clean);
|
|
66
76
|
},
|
|
67
|
-
[validationType, length, value, setValue, onValueChange]
|
|
77
|
+
[validationType, length, value, setValue, onValueChange, onComplete]
|
|
68
78
|
);
|
|
69
79
|
const [selection, setSelection] = useState(null);
|
|
70
80
|
const inputRef = useRef(null);
|
|
@@ -127,6 +137,7 @@ function OtpInputRoot({
|
|
|
127
137
|
}
|
|
128
138
|
|
|
129
139
|
// src/otp-input/OtpInputInput.tsx
|
|
140
|
+
import { useEffect as useEffect2, useLayoutEffect, useRef as useRef2 } from "react";
|
|
130
141
|
function OtpInputInput({ render, ...rest }) {
|
|
131
142
|
const { value, length, disabled, validationType, setSelection, commit, inputRef, slotAt } = useOtpInputRootContext("Input");
|
|
132
143
|
function select(input, index) {
|
|
@@ -139,6 +150,48 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
139
150
|
function report(input) {
|
|
140
151
|
setSelection({ start: input.selectionStart ?? 0, end: input.selectionEnd ?? 0 });
|
|
141
152
|
}
|
|
153
|
+
const pendingCaret = useRef2(null);
|
|
154
|
+
useLayoutEffect(() => {
|
|
155
|
+
const input = inputRef.current;
|
|
156
|
+
const at = pendingCaret.current;
|
|
157
|
+
pendingCaret.current = null;
|
|
158
|
+
if (input && at !== null && input.ownerDocument.activeElement === input) select(input, at);
|
|
159
|
+
});
|
|
160
|
+
function edit(next, caret) {
|
|
161
|
+
pendingCaret.current = caret;
|
|
162
|
+
commit(next);
|
|
163
|
+
}
|
|
164
|
+
const cleared = (index) => value.slice(0, index) + GAP + value.slice(index + 1);
|
|
165
|
+
function onDelete(event, input) {
|
|
166
|
+
const start = input.selectionStart ?? 0;
|
|
167
|
+
const end = input.selectionEnd ?? start;
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
if (end > start + 1) {
|
|
170
|
+
edit(value.slice(0, start) + GAP.repeat(end - start) + value.slice(end), start);
|
|
171
|
+
} else if (end === start + 1 && value.charAt(start) !== GAP) {
|
|
172
|
+
edit(cleared(start), start);
|
|
173
|
+
} else if (event.inputType.includes("Backward") && start > 0) {
|
|
174
|
+
edit(cleared(start - 1), start - 1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const beforeInput = useRef2(() => {
|
|
178
|
+
});
|
|
179
|
+
beforeInput.current = (event) => {
|
|
180
|
+
const input = event.currentTarget;
|
|
181
|
+
if (event.inputType.startsWith("delete") && event.inputType !== "deleteByCut") {
|
|
182
|
+
onDelete(event, input);
|
|
183
|
+
} else if (event.inputType === "insertText") {
|
|
184
|
+
const typed = event.data ?? "";
|
|
185
|
+
if (typed.length > 0 && sanitize(typed, validationType) !== typed) event.preventDefault();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
useEffect2(() => {
|
|
189
|
+
const input = inputRef.current;
|
|
190
|
+
if (!input) return;
|
|
191
|
+
const listener = (event) => beforeInput.current(event);
|
|
192
|
+
input.addEventListener("beforeinput", listener);
|
|
193
|
+
return () => input.removeEventListener("beforeinput", listener);
|
|
194
|
+
}, [inputRef]);
|
|
142
195
|
function syncSelection(event) {
|
|
143
196
|
const input = event.currentTarget;
|
|
144
197
|
const start = input.selectionStart ?? 0;
|
|
@@ -161,12 +214,6 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
161
214
|
maxLength: length,
|
|
162
215
|
pattern: validationType === "numeric" ? `\\d{${length}}` : `[A-Za-z0-9]{${length}}`,
|
|
163
216
|
disabled: disabled || void 0,
|
|
164
|
-
onBeforeInput(event) {
|
|
165
|
-
const typed = event.data;
|
|
166
|
-
if (typed && typed.length === 1 && !sanitize(typed, validationType)) {
|
|
167
|
-
event.preventDefault();
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
217
|
onChange(event) {
|
|
171
218
|
commit(event.currentTarget.value);
|
|
172
219
|
syncSelection(event);
|
|
@@ -177,12 +224,16 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
177
224
|
if (!pasted) return;
|
|
178
225
|
const input = event.currentTarget;
|
|
179
226
|
if (pasted.length >= length) {
|
|
180
|
-
|
|
227
|
+
edit(pasted, length);
|
|
181
228
|
return;
|
|
182
229
|
}
|
|
183
230
|
const start = input.selectionStart ?? value.length;
|
|
184
231
|
const end = input.selectionEnd ?? start;
|
|
185
|
-
|
|
232
|
+
const reach = start + pasted.length;
|
|
233
|
+
edit(
|
|
234
|
+
value.slice(0, start) + pasted + GAP.repeat(Math.max(0, end - reach)) + value.slice(Math.max(end, reach)),
|
|
235
|
+
reach
|
|
236
|
+
);
|
|
186
237
|
},
|
|
187
238
|
onKeyDown(event) {
|
|
188
239
|
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
@@ -193,13 +244,13 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
193
244
|
select(input, event.key === "ArrowLeft" ? at - 1 : at + 1);
|
|
194
245
|
},
|
|
195
246
|
onClick(event) {
|
|
196
|
-
if (event.detail > 1) return;
|
|
197
247
|
const index = slotAt(event.clientX);
|
|
198
248
|
if (index !== null) select(event.currentTarget, index);
|
|
199
249
|
},
|
|
200
250
|
onSelect: syncSelection,
|
|
201
251
|
onFocus(event) {
|
|
202
|
-
|
|
252
|
+
const gap = value.indexOf(GAP);
|
|
253
|
+
select(event.currentTarget, gap === -1 ? value.length : gap);
|
|
203
254
|
},
|
|
204
255
|
onBlur() {
|
|
205
256
|
setSelection(null);
|
|
@@ -213,7 +264,7 @@ function OtpInputInput({ render, ...rest }) {
|
|
|
213
264
|
import { useCallback as useCallback2 } from "react";
|
|
214
265
|
function OtpInputSlot({ index, className, children, render, ...rest }) {
|
|
215
266
|
const { value, length, disabled, selection, registerSlot } = useOtpInputRootContext("Slot");
|
|
216
|
-
const char = value.charAt(index);
|
|
267
|
+
const char = value.charAt(index) === GAP ? "" : value.charAt(index);
|
|
217
268
|
let active = false;
|
|
218
269
|
if (selection) {
|
|
219
270
|
active = selection.start === selection.end ? index === Math.min(selection.start, length - 1) : index >= selection.start && index < selection.end;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arun-dev/headless",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.19.0",
|
|
4
4
|
"description": "Unstyled React behaviour primitives — render engine, controlled/uncontrolled state, and data-* state projection. Ships no CSS and no class names.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|