const smInput = document.createElement('template') smInput.innerHTML = `
`; customElements.define('sm-input', class extends HTMLElement { constructor() { super() this.attachShadow({ mode: 'open' }).append(smInput.content.cloneNode(true)) this.inputParent = this.shadowRoot.querySelector('.input') this.input = this.shadowRoot.querySelector('input') this.clearBtn = this.shadowRoot.querySelector('.clear') this.label = this.shadowRoot.querySelector('.label') this.feedbackText = this.shadowRoot.querySelector('.feedback-text') this.validationFunction this.observeList = ['type', 'required', 'disabled', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step'] this.reset = this.reset.bind(this) this.setValidity = this.setValidity.bind(this) this.showValidity = this.showValidity.bind(this) this.hideValidity = this.hideValidity.bind(this) this.focusIn = this.focusIn.bind(this) this.focusOut = this.focusOut.bind(this) this.fireEvent = this.fireEvent.bind(this) this.debounce = this.debounce.bind(this) this.checkInput = this.checkInput.bind(this) } static get observedAttributes() { return ['placeholder', 'type', 'required', 'disabled', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step'] } get value() { return this.input.value } set value(val) { this.input.value = val; this.checkInput() this.fireEvent() } get placeholder() { return this.getAttribute('placeholder') } set placeholder(val) { this.setAttribute('placeholder', val) } get type() { return this.getAttribute('type') } set type(val) { this.setAttribute('type', val) } get isValid() { if (this.customValidation) { return this.validationFunction(this.input.value) } else { return this.input.checkValidity() } } get validity() { return this.input.validity } set disabled(value) { if (value) this.inputParent.classList.add('disabled') else this.inputParent.classList.remove('disabled') } set readOnly(value) { if (value) { this.setAttribute('readonly', '') } else { this.removeAttribute('readonly') } } set customValidation(val) { this.validationFunction = val } reset(){ this.value = '' } setValidity(message){ this.feedbackText.textContent = message } showValidity(){ this.feedbackText.classList.remove('hide-completely') } hideValidity(){ this.feedbackText.classList.add('hide-completely') } focusIn(){ this.input.focus() } focusOut(){ this.input.blur() } fireEvent(){ let event = new Event('input', { bubbles: true, cancelable: true, composed: true }); this.dispatchEvent(event); } debounce(callback, wait){ let timeoutId = null; return (...args) => { window.clearTimeout(timeoutId); timeoutId = window.setTimeout(() => { callback.apply(null, args); }, wait); }; } checkInput(e){ if (!this.hasAttribute('readonly')) { if (this.input.value !== '') { this.clearBtn.classList.remove('hide') } else { this.clearBtn.classList.add('hide') } } if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') return; if (this.input.value !== '') { if (this.animate) this.inputParent.classList.add('animate-label') else this.label.classList.add('hide') } else { if (this.animate) this.inputParent.classList.remove('animate-label') else this.label.classList.remove('hide') } } connectedCallback() { this.animate = this.hasAttribute('animate') if (this.hasAttribute('value')) { this.input.value = this.getAttribute('value') this.checkInput() } if (this.hasAttribute('error-text')) { this.feedbackText.textContent = this.getAttribute('error-text') } if (!this.hasAttribute('type')) { this.setAttribute('type', 'text') } this.input.addEventListener('input', this.checkInput) this.clearBtn.addEventListener('click', this.reset) } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { if (this.observeList.includes(name)) { if (this.hasAttribute(name)) { this.input.setAttribute(name, this.getAttribute(name) ? this.getAttribute(name) : '') } else { this.input.removeAttribute(name) } } if (name === 'placeholder') { this.label.textContent = newValue; this.setAttribute('aria-label', newValue); } else if (name === 'type') { if (this.hasAttribute('type') && this.getAttribute('type') === 'number') { this.input.setAttribute('inputmode', 'numeric') } } else if (name === 'readonly') { if (this.hasAttribute('readonly')) { this.inputParent.classList.add('readonly') } else { this.inputParent.classList.remove('readonly') } } else if (name === 'disabled') { if (this.hasAttribute('disabled')) { this.inputParent.classList.add('disabled') } else { this.inputParent.classList.remove('disabled') } } } } disconnectedCallback() { this.input.removeEventListener('input', this.checkInput) this.clearBtn.removeEventListener('click', this.reset) } })