50 lines
1.6 KiB
JavaScript
50 lines
1.6 KiB
JavaScript
import './echo';
|
|
|
|
// Segmented OTP input behaviour (used by <x-ui.otp-input>). Alpine ships with
|
|
// Livewire; register on alpine:init.
|
|
document.addEventListener('alpine:init', () => {
|
|
window.Alpine.data('otpInput', ({ length = 6 } = {}) => ({
|
|
length,
|
|
digits: Array(length).fill(''),
|
|
|
|
get value() {
|
|
return this.digits.join('');
|
|
},
|
|
|
|
cells() {
|
|
return this.$root.querySelectorAll('input[inputmode="numeric"]');
|
|
},
|
|
|
|
focusCell(i) {
|
|
const cell = this.cells()[i];
|
|
if (cell) cell.focus();
|
|
},
|
|
|
|
onInput(i, e) {
|
|
const digit = e.target.value.replace(/\D/g, '').slice(-1);
|
|
this.digits[i] = digit;
|
|
if (digit && i < this.length - 1) this.focusCell(i + 1);
|
|
this.maybeSubmit();
|
|
},
|
|
|
|
onBackspace(i) {
|
|
if (!this.digits[i] && i > 0) this.focusCell(i - 1);
|
|
},
|
|
|
|
onPaste(e) {
|
|
const text = (e.clipboardData.getData('text') || '').replace(/\D/g, '').slice(0, this.length);
|
|
for (let i = 0; i < this.length; i++) this.digits[i] = text[i] || '';
|
|
this.focusCell(Math.min(text.length, this.length - 1));
|
|
this.maybeSubmit();
|
|
},
|
|
|
|
maybeSubmit() {
|
|
if (this.value.length === this.length) {
|
|
// Wait for Alpine to flush :value into the hidden input, otherwise
|
|
// requestSubmit() can post a stale/short code.
|
|
this.$nextTick(() => this.$root.closest('form')?.requestSubmit());
|
|
}
|
|
},
|
|
}));
|
|
});
|