1 line
11 KiB
JavaScript
1 line
11 KiB
JavaScript
const smInput=document.createElement("template");smInput.innerHTML='\n<style>\n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \ninput[type="search"]::-webkit-search-decoration,\ninput[type="search"]::-webkit-search-cancel-button,\ninput[type="search"]::-webkit-search-results-button,\ninput[type="search"]::-webkit-search-results-decoration { display: none; }\ninput[type=number] {\n-moz-appearance:textfield;\n}\ninput[type=number]::-webkit-inner-spin-button, \ninput[type=number]::-webkit-outer-spin-button { \n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n margin: 0; \n}\ninput::-ms-reveal,\ninput::-ms-clear {\n display: none;\n}\ninput:invalid{\n outline: none;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n::-moz-focus-inner{\nborder: none;\n}\n:host{\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --success-color: #00C853;\n --danger-color: red;\n --width: 100%;\n --font-size: 1rem;\n --icon-gap: 0.5rem;\n --border-radius: 0.3rem;\n --padding: 0.7rem 1rem;\n --background: rgba(var(--text-color), 0.06);\n}\n.hide{\n opacity: 0 !important;\n pointer-events: none !important;\n}\n.hide-completely{\n display: none;\n}\n.icon {\n fill: rgba(var(--text-color), 0.6);\n height: 1.4rem;\n width: 1.4rem;\n border-radius: 1rem;\n cursor: pointer;\n min-width: 0;\n}\n\n:host(.round) .input{\n border-radius: 10rem;\n}\n.input {\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n cursor: text;\n min-width: 0;\n text-align: left;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n position: relative;\n gap: var(--icon-gap);\n padding: var(--padding);\n border-radius: var(--border-radius);\n -webkit-transition: opacity 0.3s;\n -o-transition: opacity 0.3s;\n transition: opacity 0.3s;\n background: var(--background);\n width: 100%;\n outline: none;\n}\n.input.readonly .clear{\n opacity: 0 !important;\n margin-right: -2rem;\n pointer-events: none !important;\n}\n.readonly{\n pointer-events: none;\n}\n.input:focus-within:not(.readonly){\n box-shadow: 0 0 0 0.1rem var(--accent-color) inset !important;\n}\n.disabled{\n pointer-events: none;\n opacity: 0.6;\n}\n.label {\n opacity: .7;\n font-weight: 400;\n font-size: var(--font-size);\n position: absolute;\n top: 0;\n -webkit-transition: -webkit-transform 0.3s;\n transition: -webkit-transform 0.3s;\n -o-transition: transform 0.3s;\n transition: transform 0.3s;\n transition: transform 0.3s, -webkit-transform 0.3s;\n -webkit-transform-origin: left;\n -ms-transform-origin: left;\n transform-origin: left;\n pointer-events: none;\n white-space: nowrap;\n overflow: hidden;\n -o-text-overflow: ellipsis;\n text-overflow: ellipsis;\n width: 100%;\n user-select: none;\n will-change: transform;\n}\n.outer-container{\n position: relative;\n width: var(--width);\n}\n.container{\n width: 100%;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n position: relative;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n -webkit-box-flex: 1;\n -ms-flex: 1;\n flex: 1;\n} \ninput{\n font-size: var(--font-size);\n border: none;\n background: transparent;\n outline: none;\n color: rgba(var(--text-color), 1);\n width: 100%;\n}\n:host(:not([variant="outlined"])) .animate-label .container input {\n -webkit-transform: translateY(0.6rem);\n -ms-transform: translateY(0.6rem);\n transform: translateY(0.6rem);\n }\n \n:host(:not([variant="outlined"])) .animate-label .label {\n -webkit-transform: translateY(-0.7em) scale(0.8);\n -ms-transform: translateY(-0.7em) scale(0.8);\n transform: translateY(-0.7em) scale(0.8);\n opacity: 1;\n color: var(--accent-color)\n}\n:host([variant="outlined"]) .input {\n box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 0.4) inset;\n background: rgba(var(--background-color), 1);\n}\n:host([variant="outlined"]) .label {\n width: max-content;\n margin-left: -0.5rem;\n padding: 0 0.5rem;\n}\n:host([variant="outlined"]) .animate-label .label {\n -webkit-transform: translate(0.1rem, -1.5rem) scale(0.8);\n -ms-transform: translate(0.1rem, -1.5rem) scale(0.8);\n transform: translate(0.1rem, -1.5rem) scale(0.8);\n opacity: 1;\n background: rgba(var(--background-color), 1);\n}\n.animate-label:focus-within:not(.readonly) .label{\n color: var(--accent-color)\n}\n.feedback-text:not(:empty){\n display: flex;\n width: 100%;\n text-align: left;\n font-size: 0.9rem;\n align-items: center;\n padding: 0.8rem 0;\n color: rgba(var(--text-color), 0.8);\n}\n.success{\n color: var(--success-color);\n}\n.error{\n color: var(--danger-color);\n}\n.status-icon{\n margin-right: 0.2rem;\n}\n.status-icon--error{\n fill: var(--danger-color);\n}\n.status-icon--success{\n fill: var(--success-color);\n}\n@media (any-hover: hover){\n .icon:hover{\n background: rgba(var(--text-color), 0.1);\n }\n}\n</style>\n<div class="outer-container">\n <label part="input" class="input">\n <slot name="icon"></slot>\n <div class="container">\n <input type="text"/>\n <div part="placeholder" class="label"></div>\n </div>\n <svg class="icon clear hide" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.414L9.172 7.757 7.757 9.172 10.586 12l-2.829 2.828 1.415 1.415L12 13.414l2.828 2.829 1.415-1.415L13.414 12l2.829-2.828-1.415-1.415L12 10.586z"/></svg>\n </label>\n <p class="feedback-text"></p>\n</div>\n',customElements.define("sm-input",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smInput.content.cloneNode(!0)),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=!1,this.validationFunction,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"]}get value(){return this.input.value}set value(t){this.input.value=t,this.checkInput(),this.fireEvent()}get placeholder(){return this.getAttribute("placeholder")}set placeholder(t){this.setAttribute("placeholder",t)}get type(){return this.getAttribute("type")}set type(t){this.setAttribute("type",t)}get validity(){return this.input.validity}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}set readOnly(t){t?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(t){this.validationFunction=t}set errorText(t){this._errorText=t}set helperText(t){this._helperText=t}get isValid(){if(""!==this.input.value){const t=this.input.checkValidity();let e=!0;return this.validationFunction&&(e=Boolean(this.validationFunction(this.input.value))),t&&e?(this.feedbackText.classList.remove("error"),this.feedbackText.classList.add("success"),this.feedbackText.textContent=""):this._errorText&&(this.feedbackText.classList.add("error"),this.feedbackText.classList.remove("success"),this.feedbackText.innerHTML=`\n <svg class="status-icon status-icon--error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>\n ${this._errorText}\n `),t&&e}}reset(){this.value=""}focusIn(){this.input.focus()}focusOut(){this.input.blur()}fireEvent(){let t=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(t)}checkInput(t){this.hasAttribute("readonly")||(""!==this.input.value.trim()?this.clearBtn.classList.remove("hide"):(this.clearBtn.classList.add("hide"),this.isRequired&&(this.feedbackText.textContent="* required"))),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-label"):this.label.classList.add("hide"):this.animate?this.inputParent.classList.remove("animate-label"):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(t,e,n){e!==n&&(this.reflectedAttributes.includes(t)&&(this.hasAttribute(t)?this.input.setAttribute(t,this.getAttribute(t)?this.getAttribute(t):""):this.input.removeAttribute(t)),"placeholder"===t?(this.label.textContent=n,this.setAttribute("aria-label",n)):this.hasAttribute("value")?this.checkInput():"type"===t?this.hasAttribute("type")&&"number"===this.getAttribute("type")&&this.input.setAttribute("inputmode","numeric"):"helper-text"===t?this._helperText=this.getAttribute("helper-text"):"error-text"===t?this._errorText=this.getAttribute("error-text"):"required"===t?(this.isRequired=this.hasAttribute("required"),this.isRequired?(this.feedbackText.textContent="* required",this.setAttribute("aria-required","true")):(this.feedbackText.textContent="",this.setAttribute("aria-required","false"))):"readonly"===t?this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly"):"disabled"===t&&(this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")))}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.reset)}}); |