standard-ui/components/dist/input.min.js
2023-10-09 13:36:01 +05:30

1 line
16 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 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 .hidden{\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 .outer-container{\n position: relative;\n width: var(--width);\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 overflow: hidden;\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,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: transform 0.3s;\n transform-origin: left;\n pointer-events: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n width: 100%;\n user-select: none;\n will-change: transform;\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 height: 300%;\n width: 100%;\n caret-color: var(--accent-color, teal);\n font-weight: inherit;\n }\n .animate-placeholder .container input {\n transform: translateY(0.6rem);\n }\n \n .animate-placeholder .label {\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 position: absolute;\n display: flex;\n width: fit-content;\n text-align: left;\n font-size: 0.9rem;\n align-items: center;\n padding: 0.8rem;\n border-radius: var(--border-radius,0.5rem);\n color: rgba(var(--text-color, (17,17,17)), 0.8);\n background: rgba(var(--foreground-color, (255,255,255)), 1);\n margin-top: 0.5rem;\n box-shadow: 0 0.5rem 1rem rgba(var(--text-color, (17,17,17)), 0.1);\n z-index: 10;\n isolation: isolate;\n }\n .feedback-text:not(:empty)::before{\n content: \'\';\n height: 0;\n width: 0;\n position: absolute;\n border: 0.5rem solid transparent;\n border-bottom-color: rgba(var(--foreground-color, (255,255,255)), 1);\n top: -1rem;\n left: 1rem;\n }\n .success{\n color: var(--success-color);\n }\n .error{\n color: var(--danger-color);\n }\n .status-icon{\n margin-right: 0.5rem;\n flex-shrink: 0;\n }\n .status-icon--error{\n fill: var(--danger-color);\n }\n .status-icon--success{\n fill: var(--success-color);\n }\n .datalist{\n position: absolute;\n top: 100%;\n left: 0;\n width: 100%;\n z-index: 100;\n background: rgba(var(--foreground-color, (255,255,255)), 1);\n border-radius: 0 0 var(--border-radius,0.5rem) var(--border-radius,0.5rem);\n box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.1);\n max-height: 20rem;\n overflow-y: auto;\n overflow-x: hidden;\n padding: 0.3rem;\n }\n .datalist-item{\n padding: 0.8rem 1rem;\n cursor: pointer;\n transition: background 0.2s;\n border-radius: 0.5rem;\n content-visibility: auto;\n }\n .datalist-item:focus{\n outline: none;\n }\n .datalist-item:focus-visible{\n outline: var(--accent-color, teal) solid medium;\n }\n @media (any-hover: hover){\n .icon:hover{\n background: rgba(var(--text-color, (17,17,17)), 0.1);\n }\n .datalist-item:hover{\n background: rgba(var(--text-color, (17,17,17)), 0.06);\n }\n }\n </style>\n <div class="outer-container">\n <div part="input-wrapper" class="input">\n <slot name="icon"></slot>\n <div class="container">\n <label part="placeholder" class="label"></label>\n <input part="input" type="text"/>\n </div>\n <button class="clear hidden" 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 <slot name="right"></slot>\n </div>\n <ul class="datalist hidden" part="datalist"></ul>\n <p class="feedback-text" part="feedback"></p>\n </div>\n ',customElements.define("sm-input",class extends HTMLElement{#validationState={validatedFor:void 0,isValid:!1,errorMessage:"Please fill out this field."};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.optionList=this.shadowRoot.querySelector(".datalist"),this._helperText="",this.isRequired=!1,this.datalist=[],this.validationFunction=void 0,this.reflectedAttributes=["value","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","list","autocomplete"]}static get observedAttributes(){return["value","placeholder","required","disabled","type","inputmode","readonly","min","max","pattern","minlength","maxlength","step","helper-text","error-text","list"]}get value(){return this.input.value}set value(val){val!==this.input.value&&(this.input.value=val,this._value=val,this.checkInput())}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){value?(this.inputParent.classList.add("disabled"),this.setAttribute("disabled","")):(this.inputParent.classList.remove("disabled"),this.removeAttribute("disabled"))}get readOnly(){return this.hasAttribute("readonly")}set readOnly(value){value?this.setAttribute("readonly",""):this.removeAttribute("readonly")}set customValidation(val){val&&(this.validationFunction=val)}set errorText(val){this.#validationState.errorText=val}showError=(errorText=this.#validationState.errorText)=>{this.feedbackText.className="feedback-text error",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 ${errorText}`};set helperText(val){this._helperText=val}get isValid(){if(this.#validationState.validatedFor===this.input.value)return this.#validationState.isValid;const _isValid=this.input.checkValidity();let _validity={isValid:!0,errorText:""};return this.validationFunction&&(_validity=this.validationFunction(this.input.value)),_isValid&&_validity.isValid?(this.feedbackText.className="feedback-text success",this.feedbackText.textContent=""):""!==this.value.trim()&&(_validity.errorText||this.#validationState.errorText)&&this.showError(_validity.errorText||this.#validationState.errorText),this.#validationState.validatedFor=this.input.value,this.#validationState.isValid=_isValid&&_validity.isValid,this.#validationState.errorText=_validity.errorText||this.#validationState.errorText,this.#validationState.isValid}reset=()=>{this.value=""};clear=()=>{this.value="",this.input.focus(),this.fireEvent()};focusIn=()=>{this.input.focus()};focusOut=()=>{this.input.blur()};fireEvent=()=>{let event=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(event)};searchDatalist=searchKey=>{const filteredData=this.datalist.filter((item=>item.toLowerCase().includes(searchKey.toLowerCase())));if(filteredData.sort(((a,b)=>a.toLowerCase().indexOf(searchKey.toLowerCase())-b.toLowerCase().indexOf(searchKey.toLowerCase()))),filteredData.length){if(this.optionList.children.length>filteredData.length){const optionsToRemove=this.optionList.children.length-filteredData.length;for(let i=0;i<optionsToRemove;i++)this.optionList.removeChild(this.optionList.lastChild)}filteredData.forEach(((item,index)=>{if(this.optionList.children[index])this.optionList.children[index].textContent=item;else{const option=document.createElement("li");option.textContent=item,option.classList.add("datalist-item"),option.setAttribute("tabindex","0"),this.optionList.appendChild(option)}})),this.optionList.classList.remove("hidden")}else this.optionList.classList.add("hidden")};checkInput=e=>{this.hasAttribute("readonly")||(""!==this.input.value?this.clearBtn.classList.remove("hidden"):this.clearBtn.classList.add("hidden")),this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder").trim()&&(""!==this.input.value?(this.shouldAnimateLabel&&this.inputParent.classList.add("animate-placeholder"),this.label.classList.toggle("hidden",!this.shouldAnimateLabel),this.datalist.length&&(this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout((()=>{this.searchDatalist(this.input.value.trim())}),100))):(this.shouldAnimateLabel&&this.inputParent.classList.remove("animate-placeholder"),this.label.classList.remove("hidden"),this.feedbackText.textContent="",this.datalist.length&&(this.optionList.innerHTML="",this.optionList.classList.add("hidden"))))};allowOnlyNum=e=>{e.ctrlKey||1===e.key.length&&(("."!==e.key||!e.target.value.includes(".")&&0!==e.target.value.length)&&["0","1","2","3","4","5","6","7","8","9","."].includes(e.key)||e.preventDefault())};handleOptionClick=e=>{this.input.value=e.target.textContent,this.optionList.classList.add("hidden"),this.input.focus()};handleInputNavigation=e=>{"ArrowDown"===e.key?(e.preventDefault(),this.optionList.children.length&&this.optionList.children[0].focus()):"ArrowUp"===e.key&&(e.preventDefault(),this.optionList.children.length&&this.optionList.children[this.optionList.children.length-1].focus())};handleDatalistNavigation=e=>{"ArrowUp"===e.key?(e.preventDefault(),this.shadowRoot.activeElement.previousElementSibling?this.shadowRoot.activeElement.previousElementSibling.focus():this.input.focus()):"ArrowDown"===e.key?(e.preventDefault(),this.shadowRoot.activeElement.nextElementSibling?this.shadowRoot.activeElement.nextElementSibling.focus():this.input.focus()):"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.input.value=e.target.textContent,this.optionList.classList.add("hidden"),this.input.focus())};handleFocus=e=>{this.datalist.length&&this.searchDatalist(this.input.value.trim())};handleBlur=e=>{this.datalist.length&&this.optionList.classList.add("hidden")};connectedCallback(){const uuid=crypto.randomUUID();if(this.input.id=uuid,this.label.htmlFor=uuid,this.shouldAnimateLabel=this.hasAttribute("animate"),this.shouldAnimateLabel&&""!==this.placeholder&&this.value&&(this.inputParent.classList.add("animate-placeholder"),this.label.classList.remove("hidden")),this.setAttribute("role","textbox"),"undefined"!=typeof smCompConfig&&smCompConfig["sm-input"]){const config=smCompConfig["sm-input"].find((config=>this.matches(config.selector)));this.customValidation=config?.customValidation}this.input.addEventListener("input",this.checkInput),this.clearBtn.addEventListener("click",this.clear),this.datalist.length&&(this.optionList.addEventListener("click",this.handleOptionClick),this.input.addEventListener("keydown",this.handleInputNavigation),this.optionList.addEventListener("keydown",this.handleDatalistNavigation)),this.input.addEventListener("focusin",this.handleFocus),this.addEventListener("focusout",this.handleBlur)}attributeChangedCallback(name,oldValue,newValue){if(oldValue!==newValue)switch(this.reflectedAttributes.includes(name)&&(this.hasAttribute(name)?this.input.setAttribute(name,this.getAttribute(name)?this.getAttribute(name):""):this.input.removeAttribute(name)),name){case"placeholder":this.label.textContent=newValue,this.setAttribute("aria-label",newValue);break;case"value":this.checkInput();break;case"type":this.hasAttribute("type")&&"number"===this.getAttribute("type")?(this.input.setAttribute("inputmode","decimal"),this.input.addEventListener("keydown",this.allowOnlyNum)):this.input.removeEventListener("keydown",this.allowOnlyNum);break;case"helper-text":this._helperText=newValue;break;case"error-text":this.#validationState.errorText=newValue;break;case"required":this.isRequired=this.hasAttribute("required"),this.isRequired?this.setAttribute("aria-required","true"):this.setAttribute("aria-required","false");break;case"readonly":this.hasAttribute("readonly")?this.inputParent.classList.add("readonly"):this.inputParent.classList.remove("readonly");break;case"disabled":this.hasAttribute("disabled")?this.inputParent.classList.add("disabled"):this.inputParent.classList.remove("disabled");break;case"list":this.hasAttribute("list")&&""!==this.getAttribute("list").trim()&&(this.datalist=this.getAttribute("list").split(","))}}disconnectedCallback(){this.input.removeEventListener("input",this.checkInput),this.clearBtn.removeEventListener("click",this.clear),this.input.removeEventListener("keydown",this.allowOnlyNum),this.optionList.removeEventListener("click",this.handleOptionClick),this.input.removeEventListener("keydown",this.handleInputNavigation),this.optionList.removeEventListener("keydown",this.handleDatalistNavigation),this.input.removeEventListener("focusin",this.handleFocus),this.removeEventListener("focusout",this.handleBlur)}});