CluPilotCloud/resources/js/app.js

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());
}
},
}));
});