1 line
12 KiB
JavaScript
1 line
12 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 } \n input[type="search"]::-webkit-search-decoration,\n input[type="search"]::-webkit-search-cancel-button,\n input[type="search"]::-webkit-search-results-button,\n input[type="search"]::-webkit-search-results-decoration { display: none; }\n input[type=number] {\n -moz-appearance:textfield;\n }\n input[type=number]::-webkit-inner-spin-button, \n input[type=number]::-webkit-outer-spin-button { \n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n margin: 0; \n }\n input::-ms-reveal,\n input::-ms-clear {\n display: none;\n }\n input:invalid{\n outline: none;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n ::-moz-focus-inner{\n border: none;\n }\n :host{\n display: flex;\n --success-color: #00C853;\n --danger-color: red;\n --width: 100%;\n --icon-gap: 0.5rem;\n --min-height: 3.2rem;\n --background: rgba(var(--text-color, (17,17,17)), 0.06);\n }\n .hide{\n display: none !important;\n }\n\n button{\n display: flex;\n border: none;\n background: none;\n padding: 0;\n border-radius: 1rem;\n min-width: 0;\n cursor: pointer;\n }\n button:focus{\n outline: var(--accent-color, teal) solid medium;\n }\n .icon {\n height: 1.2rem;\n width: 1.2rem;\n fill: rgba(var(--text-color, (17,17,17)), 0.6);\n }\n \n :host(.round) .input{\n border-radius: 10rem;\n }\n .input {\n display: flex;\n cursor: text;\n min-width: 0;\n text-align: left;\n align-items: center;\n position: relative;\n gap: var(--icon-gap);\n padding: var(--padding, 0.6rem 0.8rem);\n border-radius: var(--border-radius,0.3rem);\n transition: opacity 0.3s, box-shadow 0.2s;\n background: var(--background);\n width: 100%;\n outline: none;\n min-height: var(--min-height);\n }\n .input.readonly .clear{\n opacity: 0 !important;\n margin-right: -2rem;\n pointer-events: none !important;\n }\n .clear{\n visibility: hidden;\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,teal) inset !important;\n }\n .disabled{\n pointer-events: none;\n opacity: 0.6;\n }\n .label {\n grid-area: 1/1/2/2;\n font-size: inherit;\n opacity: .7;\n font-weight: 400;\n transition: -webkit-transform 0.3s;\n transition: transform 0.3s;\n transition: transform 0.3s, -webkit-transform 0.3s, color .03;\n transform-origin: left;\n pointer-events: none;\n white-space: nowrap;\n overflow: hidden;\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: grid;\n grid-template-columns: 1fr auto;\n position: relative;\n align-items: center;\n } \n input{\n grid-area: 1/1/2/2;\n font-size: inherit;\n border: none;\n background: transparent;\n outline: none;\n color: inherit;\n font-family: inherit;\n width: 100%;\n caret-color: var(--accent-color, teal);\n }\n :host([animate]) .input:focus-within .container input,\n .animate-placeholder .container input {\n -webkit-transform: translateY(0.6rem);\n -ms-transform: translateY(0.6rem);\n transform: translateY(0.6rem);\n }\n \n :host([animate]) .input:focus-within .label,\n .animate-placeholder .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,teal)\n }\n :host([variant="outlined"]) .input {\n box-shadow: 0 0 0 1px var(--border-color, rgba(var(--text-color, (17,17,17)), 0.3)) inset;\n background: rgba(var(--background-color, (255,255,255)), 1);\n }\n .animate-placeholder:focus-within:not(.readonly) .label{\n color: var(--accent-color,teal)\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, (17,17,17)), 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, (17,17,17)), 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 <button class="clear" title="Clear" tabindex="-1">\n <svg class="icon" 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 </button>\n </div>\n <slot name="right"></slot>\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=void 0,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","list","autocomplete"],this.reset=this.reset.bind(this),this.clear=this.clear.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.allowOnlyNum=this.allowOnlyNum.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){t!==this.input.value&&(this.input.value=t,this.checkInput())}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}get disabled(){return this.hasAttribute("disabled")}set disabled(t){t?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled")}get readOnly(){return this.hasAttribute("readonly")}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=""}clear(){this.value="",this.input.focus(),this.fireEvent()}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.clearBtn.style.visibility=""!==this.input.value?"visible":"hidden"),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?this.animate?this.inputParent.classList.add("animate-placeholder"):this.label.classList.add("hide"):(this.animate?this.inputParent.classList.remove("animate-placeholder"):this.label.classList.remove("hide"),this.feedbackText.textContent=""))}allowOnlyNum(t){1===t.key.length&&(("."!==t.key||!t.target.value.includes(".")&&0!==t.target.value.length)&&["0","1","2","3","4","5","6","7","8","9","."].includes(t.key)||t.preventDefault())}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.clear)}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","decimal"),this.input.addEventListener("keydown",this.allowOnlyNum)):this.input.removeEventListener("keydown",this.allowOnlyNum):"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.setAttribute("aria-required","true"):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.clear),this.input.removeEventListener("keydown",this.allowOnlyNum)}}); |