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.outerContainer = this.shadowRoot.querySelector('.outer-container'); this._helperText = ''; this._errorText = ''; this.isRequired = false; this.hideRequired = false; this.validationFunction = undefined; this.reflectedAttributes = ['value', 'required', 'disabled', 'type', 'inputmode', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step']; this.reset = this.reset.bind(this); this.focusIn = this.focusIn.bind(this); this.focusOut = this.focusOut.bind(this); this.fireEvent = this.fireEvent.bind(this); this.checkInput = this.checkInput.bind(this); this.vibrate = this.vibrate.bind(this); } static get observedAttributes() { return ['value', 'placeholder', 'required', 'disabled', 'type', 'inputmode', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step', 'helper-text', 'error-text', 'hiderequired']; } 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 validity() { return this.input.validity; } get disabled() { return this.hasAttribute('disabled'); } set disabled(value) { if (value) this.inputParent.classList.add('disabled'); else this.inputParent.classList.remove('disabled'); } get readOnly() { return this.hasAttribute('readonly'); } set readOnly(value) { if (value) { this.setAttribute('readonly', ''); } else { this.removeAttribute('readonly'); } } set customValidation(val) { this.validationFunction = val; } set errorText(val) { this._errorText = val; } set helperText(val) { this._helperText = val; } get isValid() { if (this.input.value !== '') { const _isValid = this.input.checkValidity(); let _customValid = true; if (this.validationFunction) { _customValid = Boolean(this.validationFunction(this.input.value)); } if (_isValid && _customValid) { this.feedbackText.classList.remove('error'); this.feedbackText.classList.add('success'); this.feedbackText.textContent = ''; } else { if (this._errorText) { this.feedbackText.classList.add('error'); this.feedbackText.classList.remove('success'); this.feedbackText.innerHTML = ` ${this._errorText} `; } } return (_isValid && _customValid); } } reset() { this.value = ''; } focusIn() { this.input.focus(); } focusOut() { this.input.blur(); } fireEvent() { let event = new Event('input', { bubbles: true, cancelable: true, composed: true }); this.dispatchEvent(event); } checkInput(e) { if (!this.hasAttribute('readonly')) { if (this.input.value.trim() !== '') { this.clearBtn.classList.remove('hide'); } else { this.clearBtn.classList.add('hide'); if (this.isRequired && !this.hideRequired) { this.feedbackText.textContent = '*required'; } } } if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder').trim() === '') 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'); } } vibrate() { this.outerContainer.animate([ { transform: 'translateX(-1rem)' }, { transform: 'translateX(1rem)' }, { transform: 'translateX(-0.5rem)' }, { transform: 'translateX(0.5rem)' }, { transform: 'translateX(0)' }, ], { duration: 300, easing: 'ease' }); } connectedCallback() { this.animate = this.hasAttribute('animate'); this.setAttribute('role', 'textbox'); this.input.addEventListener('input', this.checkInput); this.clearBtn.addEventListener('click', this.reset); } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { if (this.reflectedAttributes.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 (this.hasAttribute('value')) { this.checkInput(); } else if (name === 'type') { if (this.hasAttribute('type') && this.getAttribute('type') === 'number') { this.input.setAttribute('inputmode', 'numeric'); } } else if (name === 'helper-text') { this._helperText = this.getAttribute('helper-text'); } else if (name === 'error-text') { this._errorText = this.getAttribute('error-text'); } else if (name === 'required') { this.isRequired = this.hasAttribute('required'); if (this.isRequired && !this.hideRequired) { this.feedbackText.textContent = ''; } else { this.feedbackText.textContent = '*required'; } if (this.isRequired) { this.setAttribute('aria-required', 'true'); } else { this.setAttribute('aria-required', 'false'); } } else if (name === 'hiderequired') { this.hideRequired = this.hasAttribute('hiderequired') } 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); } })