diff --git a/components.js b/components.js index 48073c3..2e55d86 100644 --- a/components.js +++ b/components.js @@ -2,91 +2,106 @@ const smButton = document.createElement('template') smButton.innerHTML = `
@@ -95,7 +110,9 @@ customElements.define('sm-button', class extends HTMLElement { constructor() { super() - this.attachShadow({ mode: 'open' }).append(smButton.content.cloneNode(true)) + this.attachShadow({ + mode: 'open' + }).append(smButton.content.cloneNode(true)) } get disabled() { @@ -107,8 +124,7 @@ customElements.define('sm-button', this.isDisabled = true this.setAttribute('disabled', '') this.button.removeAttribute('tabindex') - } - else if (!value && this.isDisabled) { + } else if (!value && this.isDisabled) { this.isDisabled = false this.removeAttribute('disabled') } @@ -120,8 +136,7 @@ customElements.define('sm-button', bubbles: true, composed: true })) - } - else { + } else { this.dispatchEvent(new CustomEvent('clicked', { bubbles: true, composed: true @@ -151,7 +166,8 @@ smInput.innerHTML = ` *{ padding: 0; margin: 0; - box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; } input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button, @@ -167,14 +183,21 @@ input[type=number]::-webkit-outer-spin-button { appearance: none; margin: 0; } +input::-ms-reveal, +input::-ms-clear { + display: none; +} input:invalid{ outline: none; - box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; } ::-moz-focus-inner{ border: none; } :host{ + display: -webkit-box; + display: -ms-flexbox; display: flex; } .hide{ @@ -186,14 +209,14 @@ border: none; } .icon { fill: none; - height: 1.6em; - width: 1.6em; - padding: 0.5em; + height: 1.6rem; + width: 1.6rem; + padding: 0.5rem; stroke: rgba(var(--text-color), 0.7); stroke-width: 10; overflow: visible; stroke-linecap: round; - border-radius: 1em; + border-radius: 1rem; stroke-linejoin: round; cursor: pointer; min-width: 0; @@ -202,41 +225,63 @@ border: none; border-radius: 10rem; } .input { + display: -webkit-box; + display: -ms-flexbox; display: flex; - align-items: center; - position: relative; - gap: 1em; - padding: 0.7em 1em; - border-radius: 0.3em; - transition: opacity 0.3s; - background: rgba(var(--text-color), 0.1); - font-family: var(--font-family); - width: 100% - outline: none; + cursor: text; min-width: 0; + text-align: left; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + position: relative; + gap: 1rem; + padding: 0.7rem 1rem; + border-radius: 0.3rem; + -webkit-transition: opacity 0.3s; + -o-transition: opacity 0.3s; + transition: opacity 0.3s; + background: rgba(var(--text-color), 0.06); + width: 100%; + outline: none; +} +.input.readonly .clear{ + opacity: 0 !important; + margin-right: -2rem; + pointer-events: none !important; +} +.readonly{ + pointer-events: none; } - input:focus{ caret-color: var(--accent-color); } -.input:focus-within{ - box-shadow: 0 0 0 0.1em var(--accent-color) inset; +.input:focus-within:not(.readonly){ + box-shadow: 0 0 0 0.1rem var(--accent-color) inset; +} +.disabled{ + pointer-events: none; + opacity: 0.6; } - .label { - user-select: none; opacity: .7; font-weight: 400; - font-size: 1em; + font-size: 1rem; position: absolute; top: 0; + -webkit-transition: -webkit-transform 0.3s; + transition: -webkit-transform 0.3s; + -o-transition: transform 0.3s; transition: transform 0.3s; + transition: transform 0.3s, -webkit-transform 0.3s; -webkit-transform-origin: left; - transform-origin: left; + -ms-transform-origin: left; + transform-origin: left; pointer-events: none; white-space: nowrap; overflow: hidden; - text-overflow: ellipsis; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; width: 100%; will-change: transform; } @@ -246,13 +291,19 @@ input:focus{ } .container{ width: 100%; + display: -webkit-box; + display: -ms-flexbox; display: flex; position: relative; - align-items: center; - flex: 1; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; } input{ - font-size: 1em; + font-size: 1rem; border: none; background: transparent; outline: none; @@ -260,26 +311,28 @@ input{ width: 100%; } .animate-label .container input { - -webkit-transform: translateY(0.6em); - transform: translateY(0.6em); + -webkit-transform: translateY(0.6rem); + -ms-transform: translateY(0.6rem); + transform: translateY(0.6rem); } .animate-label .container .label { - -webkit-transform: translateY(-0.6em) scale(0.8); - transform: translateY(-0.6em) scale(0.8); + -webkit-transform: translateY(-0.6rem) scale(0.8); + -ms-transform: translateY(-0.6rem) scale(0.8); + transform: translateY(-0.6rem) scale(0.8); opacity: 1; color: var(--accent-color) } -.helper-text{ - top: 100%; +.feedback-text{ + font-size: 0.9rem; width: 100%; - position: absolute; color: var(--error-color); background: rgba(var(--foreground-color), 1); - margin-top: 0.5em; - border-radius: 0.2em; - border: solid 1px rgba(var(--text-color), 0.2); - padding: 0.6em 1em; + padding: 0.6rem 1rem; + text-align: left; +} +.feedback-text:empty{ + padding: 0; } @media (any-hover: hover){ .icon:hover{ @@ -288,26 +341,28 @@ input{ }
- -
+ +
`; customElements.define('sm-input', class extends HTMLElement { constructor() { super() - this.attachShadow({ mode: 'open' }).append(smInput.content.cloneNode(true)) + this.attachShadow({ + mode: 'open' + }).append(smInput.content.cloneNode(true)) } static get observedAttributes() { return ['placeholder'] @@ -339,22 +394,47 @@ customElements.define('sm-input', return this.shadowRoot.querySelector('input').checkValidity() } - focusIn() { - this.shadowRoot.querySelector('input').focus() + get validity() { + return this.shadowRoot.querySelector('input').validity } - focusOut() { - this.shadowRoot.querySelector('input').blur() + set disabled(value) { + if (value) + this.shadowRoot.querySelector('.input').classList.add('disabled') + else + this.shadowRoot.querySelector('.input').classList.remove('disabled') } - - preventNonNumericalInput(e) { - let keyCode = e.keyCode; - if (!((keyCode > 47 && keyCode < 56) || (keyCode > 36 && keyCode < 39) || (keyCode > 95 && keyCode < 104) || keyCode === 110 || (keyCode > 7 && keyCode < 19))) { - e.preventDefault(); + set readOnly(value) { + if (value) { + this.shadowRoot.querySelector('input').setAttribute('readonly', '') + this.shadowRoot.querySelector('.input').classList.add('readonly') + } else { + this.shadowRoot.querySelector('input').removeAttribute('readonly') + this.shadowRoot.querySelector('.input').classList.remove('readonly') } } - fireEvent() { + 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, @@ -363,9 +443,8 @@ customElements.define('sm-input', this.dispatchEvent(event); } - checkInput() { - if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') - return; + checkInput = (e) => { + if (!this.hasAttribute('placeholder') || this.getAttribute('placeholder') === '') return; if (this.input.value !== '') { if (this.animate) this.inputParent.classList.add('animate-label') @@ -373,8 +452,7 @@ customElements.define('sm-input', this.label.classList.add('hide') if (!this.readonly) this.clearBtn.classList.remove('hide') - } - else { + } else { if (this.animate) this.inputParent.classList.remove('animate-label') else @@ -389,9 +467,12 @@ customElements.define('sm-input', this.inputParent = this.shadowRoot.querySelector('.input') this.clearBtn = this.shadowRoot.querySelector('.clear') this.label = this.shadowRoot.querySelector('.label') - this.helperText = this.shadowRoot.querySelector('.helper-text') + this.feedbackText = this.shadowRoot.querySelector('.feedback-text') this.valueChanged = false; this.readonly = false + this.isNumeric = false + this.min + this.max this.animate = this.hasAttribute('animate') this.input = this.shadowRoot.querySelector('input') this.shadowRoot.querySelector('.label').textContent = this.getAttribute('placeholder') @@ -402,28 +483,48 @@ customElements.define('sm-input', if (this.hasAttribute('required')) { this.input.setAttribute('required', '') } + if (this.hasAttribute('min')) { + let minValue = this.getAttribute('min') + this.input.setAttribute('min', minValue) + this.min = parseInt(minValue) + } + if (this.hasAttribute('max')) { + let maxValue = this.getAttribute('max') + this.input.setAttribute('max', maxValue) + this.max = parseInt(maxValue) + } + if (this.hasAttribute('minlength')) { + let minValue = this.getAttribute('minlength') + this.input.setAttribute('minlength', minValue) + } + if (this.hasAttribute('maxlength')) { + let maxValue = this.getAttribute('maxlength') + this.input.setAttribute('maxlength', maxValue) + } + if (this.hasAttribute('pattern')) { + this.input.setAttribute('pattern', this.getAttribute('pattern')) + } if (this.hasAttribute('readonly')) { this.input.setAttribute('readonly', '') this.readonly = true } - if (this.hasAttribute('helper-text')) { - this.helperText.textContent = this.getAttribute('helper-text') + if (this.hasAttribute('disabled')) { + this.inputParent.classList.add('disabled') + } + if (this.hasAttribute('error-text')) { + this.feedbackText.textContent = this.getAttribute('error-text') } if (this.hasAttribute('type')) { if (this.getAttribute('type') === 'number') { this.input.setAttribute('inputmode', 'numeric') - } - else + this.input.setAttribute('type', 'number') + this.isNumeric = true + } else this.input.setAttribute('type', this.getAttribute('type')) - } - else + } else this.input.setAttribute('type', 'text') - this.input.addEventListener('keydown', e => { - if (this.getAttribute('type') === 'number') - this.preventNonNumericalInput(e); - }) this.input.addEventListener('input', e => { - this.checkInput() + this.checkInput(e) }) this.clearBtn.addEventListener('click', e => { this.value = '' @@ -432,8 +533,10 @@ customElements.define('sm-input', attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { - if (name === 'placeholder') + if (name === 'placeholder') { this.shadowRoot.querySelector('.label').textContent = newValue; + this.setAttribute('aria-label', newValue); + } } } }) @@ -442,145 +545,104 @@ customElements.define('sm-input', const smTextarea = document.createElement('template') smTextarea.innerHTML = ` -