@ionic/core 8.6.4 → 8.6.5-dev.11752243397.18475074
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/components/ion-input-otp.js +118 -64
- package/dist/cjs/ion-input-otp.cjs.entry.js +117 -64
- package/dist/cjs/ionic.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/input-otp/input-otp.js +119 -65
- package/dist/docs.json +1 -1
- package/dist/esm/ion-input-otp.entry.js +117 -64
- package/dist/esm/ionic.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-77e2daa9.entry.js +4 -0
- package/dist/types/components/input-otp/input-otp.d.ts +12 -8
- package/hydrate/index.js +118 -64
- package/hydrate/index.mjs +118 -64
- package/package.json +1 -1
- package/dist/ionic/p-e30ff968.entry.js +0 -4
|
@@ -33,6 +33,7 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
33
33
|
this.isKeyboardNavigation = false;
|
|
34
34
|
this.inputValues = [];
|
|
35
35
|
this.hasFocus = false;
|
|
36
|
+
this.previousInputValues = [];
|
|
36
37
|
/**
|
|
37
38
|
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
|
38
39
|
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
|
@@ -133,19 +134,12 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
133
134
|
}
|
|
134
135
|
};
|
|
135
136
|
/**
|
|
136
|
-
* Handles keyboard navigation
|
|
137
|
+
* Handles keyboard navigation for the OTP component.
|
|
137
138
|
*
|
|
138
139
|
* Navigation:
|
|
139
140
|
* - Backspace: Clears current input and moves to previous box if empty
|
|
140
141
|
* - Arrow Left/Right: Moves focus between input boxes
|
|
141
142
|
* - Tab: Allows normal tab navigation between components
|
|
142
|
-
*
|
|
143
|
-
* Input Behavior:
|
|
144
|
-
* - Validates input against the allowed pattern
|
|
145
|
-
* - When entering a key in a filled box:
|
|
146
|
-
* - Shifts existing values right if there is room
|
|
147
|
-
* - Updates the value of the input group
|
|
148
|
-
* - Prevents default behavior to avoid automatic focus shift
|
|
149
143
|
*/
|
|
150
144
|
this.onKeyDown = (index) => (event) => {
|
|
151
145
|
const { length } = this;
|
|
@@ -200,69 +194,132 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
200
194
|
// Let all tab events proceed normally
|
|
201
195
|
return;
|
|
202
196
|
}
|
|
203
|
-
// If the input box contains a value and the key being
|
|
204
|
-
// entered is a valid key for the input box update the value
|
|
205
|
-
// and shift the values to the right if there is room.
|
|
206
|
-
if (this.inputValues[index] && this.validKeyPattern.test(event.key)) {
|
|
207
|
-
if (!this.inputValues[length - 1]) {
|
|
208
|
-
for (let i = length - 1; i > index; i--) {
|
|
209
|
-
this.inputValues[i] = this.inputValues[i - 1];
|
|
210
|
-
this.inputRefs[i].value = this.inputValues[i] || '';
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
this.inputValues[index] = event.key;
|
|
214
|
-
this.inputRefs[index].value = event.key;
|
|
215
|
-
this.updateValue(event);
|
|
216
|
-
// Prevent default to avoid the browser from
|
|
217
|
-
// automatically moving the focus to the next input
|
|
218
|
-
event.preventDefault();
|
|
219
|
-
}
|
|
220
197
|
};
|
|
198
|
+
/**
|
|
199
|
+
* Processes all input scenarios for each input box.
|
|
200
|
+
*
|
|
201
|
+
* This function manages:
|
|
202
|
+
* 1. Autofill handling
|
|
203
|
+
* 2. Input validation
|
|
204
|
+
* 3. Full selection replacement or typing in an empty box
|
|
205
|
+
* 4. Inserting in the middle with available space (shifting)
|
|
206
|
+
* 5. Single character replacement
|
|
207
|
+
*/
|
|
221
208
|
this.onInput = (index) => (event) => {
|
|
209
|
+
var _a, _b;
|
|
222
210
|
const { length, validKeyPattern } = this;
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
211
|
+
const input = event.target;
|
|
212
|
+
const value = input.value;
|
|
213
|
+
const previousValue = this.previousInputValues[index] || '';
|
|
214
|
+
// 1. Autofill handling
|
|
215
|
+
// If the length of the value increases by more than 1 from the previous
|
|
216
|
+
// value, treat this as autofill. This is to prevent the case where the
|
|
217
|
+
// user is typing a single character into an input box containing a value
|
|
218
|
+
// as that will trigger this function with a value length of 2 characters.
|
|
219
|
+
const isAutofill = value.length - previousValue.length > 1;
|
|
220
|
+
if (isAutofill) {
|
|
221
|
+
// Distribute valid characters across input boxes
|
|
227
222
|
const validChars = value
|
|
228
223
|
.split('')
|
|
229
224
|
.filter((char) => validKeyPattern.test(char))
|
|
230
225
|
.slice(0, length);
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
this.inputRefs.forEach((input) => {
|
|
237
|
-
input.value = '';
|
|
238
|
-
});
|
|
239
|
-
});
|
|
226
|
+
for (let i = 0; i < length; i++) {
|
|
227
|
+
this.inputValues[i] = validChars[i] || '';
|
|
228
|
+
if (this.inputRefs[i] != null) {
|
|
229
|
+
this.inputRefs[i].value = validChars[i] || '';
|
|
230
|
+
}
|
|
240
231
|
}
|
|
241
|
-
// Update the value of the input group and emit the input change event
|
|
242
|
-
this.value = validChars.join('');
|
|
243
232
|
this.updateValue(event);
|
|
244
|
-
// Focus the
|
|
245
|
-
// are filled after a small delay to ensure the input boxes have been
|
|
246
|
-
// updated before moving the focus
|
|
233
|
+
// Focus the next empty input or the last one
|
|
247
234
|
setTimeout(() => {
|
|
248
|
-
var _a;
|
|
249
235
|
const nextIndex = validChars.length < length ? validChars.length : length - 1;
|
|
250
|
-
(
|
|
236
|
+
if (this.inputRefs[nextIndex] != null) {
|
|
237
|
+
this.inputRefs[nextIndex].focus();
|
|
238
|
+
}
|
|
251
239
|
}, 20);
|
|
240
|
+
this.previousInputValues = [...this.inputValues];
|
|
252
241
|
return;
|
|
253
242
|
}
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
243
|
+
// 2. Input validation
|
|
244
|
+
// If the character entered is invalid (does not match the pattern),
|
|
245
|
+
// restore the previous value and exit
|
|
246
|
+
if (value.length > 0 && !validKeyPattern.test(value[value.length - 1])) {
|
|
247
|
+
input.value = this.inputValues[index] || '';
|
|
248
|
+
this.previousInputValues[index] = this.inputValues[index] || '';
|
|
249
|
+
this.previousInputValues = [...this.inputValues];
|
|
258
250
|
return;
|
|
259
251
|
}
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
this.
|
|
263
|
-
|
|
252
|
+
// 3. Full selection replacement or typing in an empty box
|
|
253
|
+
// If the user selects all text in the input box and types, or if the
|
|
254
|
+
// input box is empty, replace only this input box. If the box is empty,
|
|
255
|
+
// move to the next box, otherwise stay focused on this box.
|
|
256
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === value.length;
|
|
257
|
+
const isEmpty = !this.inputValues[index];
|
|
258
|
+
if (isAllSelected || isEmpty) {
|
|
259
|
+
this.inputValues[index] = value;
|
|
260
|
+
input.value = value;
|
|
261
|
+
this.previousInputValues[index] = value;
|
|
262
|
+
this.updateValue(event);
|
|
264
263
|
this.focusNext(index);
|
|
264
|
+
this.previousInputValues = [...this.inputValues];
|
|
265
|
+
return;
|
|
265
266
|
}
|
|
267
|
+
// 4. Inserting in the middle with available space (shifting)
|
|
268
|
+
// If typing in a filled input box and there are empty boxes at the end,
|
|
269
|
+
// shift all values starting at the current box to the right, and insert
|
|
270
|
+
// the new character at the current box.
|
|
271
|
+
const hasAvailableBoxAtEnd = this.inputValues[this.inputValues.length - 1] === '';
|
|
272
|
+
if (this.inputValues[index] && hasAvailableBoxAtEnd && value.length === 2) {
|
|
273
|
+
// Get the inserted character (from event or by diffing value/previousValue)
|
|
274
|
+
let newChar = event.data;
|
|
275
|
+
if (!newChar) {
|
|
276
|
+
newChar = value.split('').find((c, i) => c !== previousValue[i]) || value[value.length - 1];
|
|
277
|
+
}
|
|
278
|
+
// Validate the new character before shifting
|
|
279
|
+
if (!validKeyPattern.test(newChar)) {
|
|
280
|
+
input.value = this.inputValues[index] || '';
|
|
281
|
+
this.previousInputValues[index] = this.inputValues[index] || '';
|
|
282
|
+
this.previousInputValues = [...this.inputValues];
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
// Shift values right from the end to the insertion point
|
|
286
|
+
for (let i = this.inputValues.length - 1; i > index; i--) {
|
|
287
|
+
this.inputValues[i] = this.inputValues[i - 1];
|
|
288
|
+
if (this.inputRefs[i] != null) {
|
|
289
|
+
this.inputRefs[i].value = this.inputValues[i] || '';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
this.inputValues[index] = newChar;
|
|
293
|
+
if (this.inputRefs[index] != null) {
|
|
294
|
+
this.inputRefs[index].value = newChar;
|
|
295
|
+
}
|
|
296
|
+
this.previousInputValues[index] = newChar;
|
|
297
|
+
this.updateValue(event);
|
|
298
|
+
this.previousInputValues = [...this.inputValues];
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
// 5. Single character replacement
|
|
302
|
+
// Handles replacing a single character in a box containing a value based
|
|
303
|
+
// on the cursor position. We need the cursor position to determine which
|
|
304
|
+
// character was the last character typed. For example, if the user types "2"
|
|
305
|
+
// in an input box with the cursor at the beginning of the value of "6",
|
|
306
|
+
// the value will be "26", but we want to grab the "2" as the last character
|
|
307
|
+
// typed.
|
|
308
|
+
const cursorPos = (_a = input.selectionStart) !== null && _a !== void 0 ? _a : value.length;
|
|
309
|
+
const newCharIndex = cursorPos - 1;
|
|
310
|
+
const newChar = (_b = value[newCharIndex]) !== null && _b !== void 0 ? _b : value[0];
|
|
311
|
+
// Check if the new character is valid before updating the value
|
|
312
|
+
if (!validKeyPattern.test(newChar)) {
|
|
313
|
+
input.value = this.inputValues[index] || '';
|
|
314
|
+
this.previousInputValues[index] = this.inputValues[index] || '';
|
|
315
|
+
this.previousInputValues = [...this.inputValues];
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
input.value = newChar;
|
|
319
|
+
this.inputValues[index] = newChar;
|
|
320
|
+
this.previousInputValues[index] = newChar;
|
|
321
|
+
this.updateValue(event);
|
|
322
|
+
this.previousInputValues = [...this.inputValues];
|
|
266
323
|
};
|
|
267
324
|
/**
|
|
268
325
|
* Handles pasting text into the input OTP component.
|
|
@@ -272,7 +329,7 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
272
329
|
* the next empty input after pasting.
|
|
273
330
|
*/
|
|
274
331
|
this.onPaste = (event) => {
|
|
275
|
-
var _a, _b
|
|
332
|
+
var _a, _b;
|
|
276
333
|
const { inputRefs, length, validKeyPattern } = this;
|
|
277
334
|
event.preventDefault();
|
|
278
335
|
const pastedText = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text');
|
|
@@ -299,13 +356,8 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
299
356
|
this.updateValue(event);
|
|
300
357
|
// Focus the next empty input after pasting
|
|
301
358
|
// If all boxes are filled, focus the last input
|
|
302
|
-
const nextEmptyIndex = validChars.length;
|
|
303
|
-
|
|
304
|
-
(_b = inputRefs[nextEmptyIndex]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
(_c = inputRefs[length - 1]) === null || _c === void 0 ? void 0 : _c.focus();
|
|
308
|
-
}
|
|
359
|
+
const nextEmptyIndex = validChars.length < length ? validChars.length : length - 1;
|
|
360
|
+
(_b = inputRefs[nextEmptyIndex]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
309
361
|
};
|
|
310
362
|
}
|
|
311
363
|
/**
|
|
@@ -444,6 +496,7 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
444
496
|
});
|
|
445
497
|
// Update the value without emitting events
|
|
446
498
|
this.value = this.inputValues.join('');
|
|
499
|
+
this.previousInputValues = [...this.inputValues];
|
|
447
500
|
}
|
|
448
501
|
/**
|
|
449
502
|
* Updates the value of the input group.
|
|
@@ -565,7 +618,7 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
565
618
|
const tabbableIndex = this.getTabbableIndex();
|
|
566
619
|
const pattern = this.getPattern();
|
|
567
620
|
const hasDescription = ((_b = (_a = el.querySelector('.input-otp-description')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== '';
|
|
568
|
-
return (h(Host, { key: '
|
|
621
|
+
return (h(Host, { key: '084b4f7d148a55aef6b4b51c11483ee51d70d3bd', class: createColorClasses(color, {
|
|
569
622
|
[mode]: true,
|
|
570
623
|
'has-focus': hasFocus,
|
|
571
624
|
[`input-otp-size-${size}`]: true,
|
|
@@ -573,10 +626,10 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
573
626
|
[`input-otp-fill-${fill}`]: true,
|
|
574
627
|
'input-otp-disabled': disabled,
|
|
575
628
|
'input-otp-readonly': readonly,
|
|
576
|
-
}) }, h("div", Object.assign({ key: '
|
|
629
|
+
}) }, h("div", Object.assign({ key: '9d797deb7170bf6e4cc1acf70cca0b5d4ef51610', role: "group", "aria-label": "One-time password input", class: "input-otp-group" }, inheritedAttributes), Array.from({ length }).map((_, index) => (h(Fragment, null, h("div", { class: "native-wrapper" }, h("input", { class: "native-input", id: `${inputId}-${index}`, "aria-label": `Input ${index + 1} of ${length}`, type: "text", autoCapitalize: autocapitalize, inputmode: inputmode, pattern: pattern, disabled: disabled, readOnly: readonly, tabIndex: index === tabbableIndex ? 0 : -1, value: inputValues[index] || '', autocomplete: "one-time-code", ref: (el) => (inputRefs[index] = el), onInput: this.onInput(index), onBlur: this.onBlur, onFocus: this.onFocus(index), onKeyDown: this.onKeyDown(index), onPaste: this.onPaste })), this.showSeparator(index) && h("div", { class: "input-otp-separator" }))))), h("div", { key: 'a0463205729699430560032a68ade2e2ffa49b61', class: {
|
|
577
630
|
'input-otp-description': true,
|
|
578
631
|
'input-otp-description-hidden': !hasDescription,
|
|
579
|
-
} }, h("slot", { key: '
|
|
632
|
+
} }, h("slot", { key: '287fdaf0375cda3dcfafa2762d7daebf6f2bfe68' }))));
|
|
580
633
|
}
|
|
581
634
|
get el() { return this; }
|
|
582
635
|
static get watchers() { return {
|
|
@@ -604,6 +657,7 @@ const InputOTP = /*@__PURE__*/ proxyCustomElement(class InputOTP extends HTMLEle
|
|
|
604
657
|
"value": [1032],
|
|
605
658
|
"inputValues": [32],
|
|
606
659
|
"hasFocus": [32],
|
|
660
|
+
"previousInputValues": [32],
|
|
607
661
|
"setFocus": [64]
|
|
608
662
|
}, undefined, {
|
|
609
663
|
"value": ["valueChanged"],
|
|
@@ -32,6 +32,7 @@ const InputOTP = class {
|
|
|
32
32
|
this.isKeyboardNavigation = false;
|
|
33
33
|
this.inputValues = [];
|
|
34
34
|
this.hasFocus = false;
|
|
35
|
+
this.previousInputValues = [];
|
|
35
36
|
/**
|
|
36
37
|
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
|
|
37
38
|
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
|
|
@@ -132,19 +133,12 @@ const InputOTP = class {
|
|
|
132
133
|
}
|
|
133
134
|
};
|
|
134
135
|
/**
|
|
135
|
-
* Handles keyboard navigation
|
|
136
|
+
* Handles keyboard navigation for the OTP component.
|
|
136
137
|
*
|
|
137
138
|
* Navigation:
|
|
138
139
|
* - Backspace: Clears current input and moves to previous box if empty
|
|
139
140
|
* - Arrow Left/Right: Moves focus between input boxes
|
|
140
141
|
* - Tab: Allows normal tab navigation between components
|
|
141
|
-
*
|
|
142
|
-
* Input Behavior:
|
|
143
|
-
* - Validates input against the allowed pattern
|
|
144
|
-
* - When entering a key in a filled box:
|
|
145
|
-
* - Shifts existing values right if there is room
|
|
146
|
-
* - Updates the value of the input group
|
|
147
|
-
* - Prevents default behavior to avoid automatic focus shift
|
|
148
142
|
*/
|
|
149
143
|
this.onKeyDown = (index) => (event) => {
|
|
150
144
|
const { length } = this;
|
|
@@ -199,69 +193,132 @@ const InputOTP = class {
|
|
|
199
193
|
// Let all tab events proceed normally
|
|
200
194
|
return;
|
|
201
195
|
}
|
|
202
|
-
// If the input box contains a value and the key being
|
|
203
|
-
// entered is a valid key for the input box update the value
|
|
204
|
-
// and shift the values to the right if there is room.
|
|
205
|
-
if (this.inputValues[index] && this.validKeyPattern.test(event.key)) {
|
|
206
|
-
if (!this.inputValues[length - 1]) {
|
|
207
|
-
for (let i = length - 1; i > index; i--) {
|
|
208
|
-
this.inputValues[i] = this.inputValues[i - 1];
|
|
209
|
-
this.inputRefs[i].value = this.inputValues[i] || '';
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
this.inputValues[index] = event.key;
|
|
213
|
-
this.inputRefs[index].value = event.key;
|
|
214
|
-
this.updateValue(event);
|
|
215
|
-
// Prevent default to avoid the browser from
|
|
216
|
-
// automatically moving the focus to the next input
|
|
217
|
-
event.preventDefault();
|
|
218
|
-
}
|
|
219
196
|
};
|
|
197
|
+
/**
|
|
198
|
+
* Processes all input scenarios for each input box.
|
|
199
|
+
*
|
|
200
|
+
* This function manages:
|
|
201
|
+
* 1. Autofill handling
|
|
202
|
+
* 2. Input validation
|
|
203
|
+
* 3. Full selection replacement or typing in an empty box
|
|
204
|
+
* 4. Inserting in the middle with available space (shifting)
|
|
205
|
+
* 5. Single character replacement
|
|
206
|
+
*/
|
|
220
207
|
this.onInput = (index) => (event) => {
|
|
208
|
+
var _a, _b;
|
|
221
209
|
const { length, validKeyPattern } = this;
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
210
|
+
const input = event.target;
|
|
211
|
+
const value = input.value;
|
|
212
|
+
const previousValue = this.previousInputValues[index] || '';
|
|
213
|
+
// 1. Autofill handling
|
|
214
|
+
// If the length of the value increases by more than 1 from the previous
|
|
215
|
+
// value, treat this as autofill. This is to prevent the case where the
|
|
216
|
+
// user is typing a single character into an input box containing a value
|
|
217
|
+
// as that will trigger this function with a value length of 2 characters.
|
|
218
|
+
const isAutofill = value.length - previousValue.length > 1;
|
|
219
|
+
if (isAutofill) {
|
|
220
|
+
// Distribute valid characters across input boxes
|
|
226
221
|
const validChars = value
|
|
227
222
|
.split('')
|
|
228
223
|
.filter((char) => validKeyPattern.test(char))
|
|
229
224
|
.slice(0, length);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
this.inputRefs.forEach((input) => {
|
|
236
|
-
input.value = '';
|
|
237
|
-
});
|
|
238
|
-
});
|
|
225
|
+
for (let i = 0; i < length; i++) {
|
|
226
|
+
this.inputValues[i] = validChars[i] || '';
|
|
227
|
+
if (this.inputRefs[i] != null) {
|
|
228
|
+
this.inputRefs[i].value = validChars[i] || '';
|
|
229
|
+
}
|
|
239
230
|
}
|
|
240
|
-
// Update the value of the input group and emit the input change event
|
|
241
|
-
this.value = validChars.join('');
|
|
242
231
|
this.updateValue(event);
|
|
243
|
-
// Focus the
|
|
244
|
-
// are filled after a small delay to ensure the input boxes have been
|
|
245
|
-
// updated before moving the focus
|
|
232
|
+
// Focus the next empty input or the last one
|
|
246
233
|
setTimeout(() => {
|
|
247
|
-
var _a;
|
|
248
234
|
const nextIndex = validChars.length < length ? validChars.length : length - 1;
|
|
249
|
-
(
|
|
235
|
+
if (this.inputRefs[nextIndex] != null) {
|
|
236
|
+
this.inputRefs[nextIndex].focus();
|
|
237
|
+
}
|
|
250
238
|
}, 20);
|
|
239
|
+
this.previousInputValues = [...this.inputValues];
|
|
251
240
|
return;
|
|
252
241
|
}
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
242
|
+
// 2. Input validation
|
|
243
|
+
// If the character entered is invalid (does not match the pattern),
|
|
244
|
+
// restore the previous value and exit
|
|
245
|
+
if (value.length > 0 && !validKeyPattern.test(value[value.length - 1])) {
|
|
246
|
+
input.value = this.inputValues[index] || '';
|
|
247
|
+
this.previousInputValues[index] = this.inputValues[index] || '';
|
|
248
|
+
this.previousInputValues = [...this.inputValues];
|
|
257
249
|
return;
|
|
258
250
|
}
|
|
259
|
-
//
|
|
260
|
-
|
|
261
|
-
this.
|
|
262
|
-
|
|
251
|
+
// 3. Full selection replacement or typing in an empty box
|
|
252
|
+
// If the user selects all text in the input box and types, or if the
|
|
253
|
+
// input box is empty, replace only this input box. If the box is empty,
|
|
254
|
+
// move to the next box, otherwise stay focused on this box.
|
|
255
|
+
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === value.length;
|
|
256
|
+
const isEmpty = !this.inputValues[index];
|
|
257
|
+
if (isAllSelected || isEmpty) {
|
|
258
|
+
this.inputValues[index] = value;
|
|
259
|
+
input.value = value;
|
|
260
|
+
this.previousInputValues[index] = value;
|
|
261
|
+
this.updateValue(event);
|
|
263
262
|
this.focusNext(index);
|
|
263
|
+
this.previousInputValues = [...this.inputValues];
|
|
264
|
+
return;
|
|
264
265
|
}
|
|
266
|
+
// 4. Inserting in the middle with available space (shifting)
|
|
267
|
+
// If typing in a filled input box and there are empty boxes at the end,
|
|
268
|
+
// shift all values starting at the current box to the right, and insert
|
|
269
|
+
// the new character at the current box.
|
|
270
|
+
const hasAvailableBoxAtEnd = this.inputValues[this.inputValues.length - 1] === '';
|
|
271
|
+
if (this.inputValues[index] && hasAvailableBoxAtEnd && value.length === 2) {
|
|
272
|
+
// Get the inserted character (from event or by diffing value/previousValue)
|
|
273
|
+
let newChar = event.data;
|
|
274
|
+
if (!newChar) {
|
|
275
|
+
newChar = value.split('').find((c, i) => c !== previousValue[i]) || value[value.length - 1];
|
|
276
|
+
}
|
|
277
|
+
// Validate the new character before shifting
|
|
278
|
+
if (!validKeyPattern.test(newChar)) {
|
|
279
|
+
input.value = this.inputValues[index] || '';
|
|
280
|
+
this.previousInputValues[index] = this.inputValues[index] || '';
|
|
281
|
+
this.previousInputValues = [...this.inputValues];
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
// Shift values right from the end to the insertion point
|
|
285
|
+
for (let i = this.inputValues.length - 1; i > index; i--) {
|
|
286
|
+
this.inputValues[i] = this.inputValues[i - 1];
|
|
287
|
+
if (this.inputRefs[i] != null) {
|
|
288
|
+
this.inputRefs[i].value = this.inputValues[i] || '';
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.inputValues[index] = newChar;
|
|
292
|
+
if (this.inputRefs[index] != null) {
|
|
293
|
+
this.inputRefs[index].value = newChar;
|
|
294
|
+
}
|
|
295
|
+
this.previousInputValues[index] = newChar;
|
|
296
|
+
this.updateValue(event);
|
|
297
|
+
this.previousInputValues = [...this.inputValues];
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// 5. Single character replacement
|
|
301
|
+
// Handles replacing a single character in a box containing a value based
|
|
302
|
+
// on the cursor position. We need the cursor position to determine which
|
|
303
|
+
// character was the last character typed. For example, if the user types "2"
|
|
304
|
+
// in an input box with the cursor at the beginning of the value of "6",
|
|
305
|
+
// the value will be "26", but we want to grab the "2" as the last character
|
|
306
|
+
// typed.
|
|
307
|
+
const cursorPos = (_a = input.selectionStart) !== null && _a !== void 0 ? _a : value.length;
|
|
308
|
+
const newCharIndex = cursorPos - 1;
|
|
309
|
+
const newChar = (_b = value[newCharIndex]) !== null && _b !== void 0 ? _b : value[0];
|
|
310
|
+
// Check if the new character is valid before updating the value
|
|
311
|
+
if (!validKeyPattern.test(newChar)) {
|
|
312
|
+
input.value = this.inputValues[index] || '';
|
|
313
|
+
this.previousInputValues[index] = this.inputValues[index] || '';
|
|
314
|
+
this.previousInputValues = [...this.inputValues];
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
input.value = newChar;
|
|
318
|
+
this.inputValues[index] = newChar;
|
|
319
|
+
this.previousInputValues[index] = newChar;
|
|
320
|
+
this.updateValue(event);
|
|
321
|
+
this.previousInputValues = [...this.inputValues];
|
|
265
322
|
};
|
|
266
323
|
/**
|
|
267
324
|
* Handles pasting text into the input OTP component.
|
|
@@ -271,7 +328,7 @@ const InputOTP = class {
|
|
|
271
328
|
* the next empty input after pasting.
|
|
272
329
|
*/
|
|
273
330
|
this.onPaste = (event) => {
|
|
274
|
-
var _a, _b
|
|
331
|
+
var _a, _b;
|
|
275
332
|
const { inputRefs, length, validKeyPattern } = this;
|
|
276
333
|
event.preventDefault();
|
|
277
334
|
const pastedText = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text');
|
|
@@ -298,13 +355,8 @@ const InputOTP = class {
|
|
|
298
355
|
this.updateValue(event);
|
|
299
356
|
// Focus the next empty input after pasting
|
|
300
357
|
// If all boxes are filled, focus the last input
|
|
301
|
-
const nextEmptyIndex = validChars.length;
|
|
302
|
-
|
|
303
|
-
(_b = inputRefs[nextEmptyIndex]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
(_c = inputRefs[length - 1]) === null || _c === void 0 ? void 0 : _c.focus();
|
|
307
|
-
}
|
|
358
|
+
const nextEmptyIndex = validChars.length < length ? validChars.length : length - 1;
|
|
359
|
+
(_b = inputRefs[nextEmptyIndex]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
308
360
|
};
|
|
309
361
|
}
|
|
310
362
|
/**
|
|
@@ -443,6 +495,7 @@ const InputOTP = class {
|
|
|
443
495
|
});
|
|
444
496
|
// Update the value without emitting events
|
|
445
497
|
this.value = this.inputValues.join('');
|
|
498
|
+
this.previousInputValues = [...this.inputValues];
|
|
446
499
|
}
|
|
447
500
|
/**
|
|
448
501
|
* Updates the value of the input group.
|
|
@@ -564,7 +617,7 @@ const InputOTP = class {
|
|
|
564
617
|
const tabbableIndex = this.getTabbableIndex();
|
|
565
618
|
const pattern = this.getPattern();
|
|
566
619
|
const hasDescription = ((_b = (_a = el.querySelector('.input-otp-description')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== '';
|
|
567
|
-
return (index.h(index.Host, { key: '
|
|
620
|
+
return (index.h(index.Host, { key: '084b4f7d148a55aef6b4b51c11483ee51d70d3bd', class: theme.createColorClasses(color, {
|
|
568
621
|
[mode]: true,
|
|
569
622
|
'has-focus': hasFocus,
|
|
570
623
|
[`input-otp-size-${size}`]: true,
|
|
@@ -572,10 +625,10 @@ const InputOTP = class {
|
|
|
572
625
|
[`input-otp-fill-${fill}`]: true,
|
|
573
626
|
'input-otp-disabled': disabled,
|
|
574
627
|
'input-otp-readonly': readonly,
|
|
575
|
-
}) }, index.h("div", Object.assign({ key: '
|
|
628
|
+
}) }, index.h("div", Object.assign({ key: '9d797deb7170bf6e4cc1acf70cca0b5d4ef51610', role: "group", "aria-label": "One-time password input", class: "input-otp-group" }, inheritedAttributes), Array.from({ length }).map((_, index$1) => (index.h(index.Fragment, null, index.h("div", { class: "native-wrapper" }, index.h("input", { class: "native-input", id: `${inputId}-${index$1}`, "aria-label": `Input ${index$1 + 1} of ${length}`, type: "text", autoCapitalize: autocapitalize, inputmode: inputmode, pattern: pattern, disabled: disabled, readOnly: readonly, tabIndex: index$1 === tabbableIndex ? 0 : -1, value: inputValues[index$1] || '', autocomplete: "one-time-code", ref: (el) => (inputRefs[index$1] = el), onInput: this.onInput(index$1), onBlur: this.onBlur, onFocus: this.onFocus(index$1), onKeyDown: this.onKeyDown(index$1), onPaste: this.onPaste })), this.showSeparator(index$1) && index.h("div", { class: "input-otp-separator" }))))), index.h("div", { key: 'a0463205729699430560032a68ade2e2ffa49b61', class: {
|
|
576
629
|
'input-otp-description': true,
|
|
577
630
|
'input-otp-description-hidden': !hasDescription,
|
|
578
|
-
} }, index.h("slot", { key: '
|
|
631
|
+
} }, index.h("slot", { key: '287fdaf0375cda3dcfafa2762d7daebf6f2bfe68' }))));
|
|
579
632
|
}
|
|
580
633
|
get el() { return index.getElement(this); }
|
|
581
634
|
static get watchers() { return {
|