const pinInput = document.createElement('template');
pinInput.innerHTML = `
`;
customElements.define('pin-input',
class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(pinInput.content.cloneNode(true))
this.pinDigits = 4
this.arrayOfInput = [];
this.container = this.shadowRoot.querySelector('.pin-container');
this.toggleButton = this.shadowRoot.querySelector('button')
}
set value(val) {
this.arrayOfInput.forEach((input, index) => input.value = val[index] ? val[index] : '')
}
get value() {
return this.getValue()
}
set pinLength(val) {
this.pinDigits = val
this.setAttribute('pin-length', val)
this.style.setProperty('--pin-length', val)
this.render()
}
get isValid() {
return this.arrayOfInput.every(input => input.value.trim().length)
}
clear = () => {
this.value = ''
}
focusIn = () => {
this.arrayOfInput[0].focus();
}
getValue = () => {
return this.arrayOfInput.reduce((acc, val) => {
return acc += val.value
}, '')
}
render = () => {
this.container.innerHTML = ''
const frag = document.createDocumentFragment();
for (let i = 0; i < this.pinDigits; i++) {
const inputBox = document.createElement('input')
inputBox.setAttribute('type', 'password')
inputBox.setAttribute('inputmode', 'numeric')
inputBox.setAttribute('maxlength', '1')
inputBox.setAttribute('required', '')
this.arrayOfInput.push(inputBox);
frag.append(inputBox);
}
this.container.append(frag);
}
handleKeydown = (e) => {
const activeInput = e.target.closest('input')
if (/[0-9]/.test(e.key)) {
if (activeInput.value.trim().length > 2) {
e.preventDefault();
}
else {
if (activeInput.value.trim().length === 1) {
activeInput.value = e.key
}
if (activeInput.nextElementSibling) {
setTimeout(() => {
activeInput.nextElementSibling.focus();
}, 0)
}
}
}
else if (e.key === "Backspace") {
if (activeInput.previousElementSibling)
setTimeout(() => {
activeInput.previousElementSibling.focus();
}, 0)
}
else if (e.key.length === 1 && !/[0-9]/.test(e.key)) {
e.preventDefault();
}
}
handleInput = () => {
if (this.isValid) {
this.fireEvent(this.getValue())
}
}
fireEvent = (value) => {
let event = new CustomEvent('pincomplete', {
bubbles: true,
cancelable: true,
composed: true,
detail: {
value
}
});
this.dispatchEvent(event);
}
toggleVisibility = () => {
if (this.arrayOfInput[0].getAttribute('type') === 'password') {
this.toggleButton.innerHTML = `
Hide
`
this.arrayOfInput.forEach(input => input.setAttribute('type', 'text'))
}
else {
this.toggleButton.innerHTML = `
Show
`
this.arrayOfInput.forEach(input => input.setAttribute('type', 'password'))
}
}
connectedCallback() {
if (this.hasAttribute('pin-length')) {
const pinLength = parseInt(this.getAttribute('pin-length'))
this.pinDigits = pinLength
this.style.setProperty('--pin-length', pinLength)
}
this.render()
this.toggleButton.addEventListener('click', this.toggleVisibility)
this.container.addEventListener('input', this.handleInput);
this.container.addEventListener('keydown', this.handleKeydown);
}
disconnectedCallback() {
this.toggleButton.removeEventListener('click', this.toggleVisibility)
this.container.removeEventListener('input', this.handleInput);
this.container.removeEventListener('keydown', this.handleKeydown);
}
})