From 73f1911761c25d9fdb4003ab98777ad51c9e65d5 Mon Sep 17 00:00:00 2001 From: sairaj mote Date: Sat, 22 Oct 2022 02:29:38 +0530 Subject: [PATCH] functional improvements and bug fixes --- components/dist/input.js | 16 ++++++++++++++++ components/dist/input.min.js | 2 +- components/dist/select.js | 4 +++- components/dist/select.min.js | 2 +- components/dist/textarea.js | 1 - components/dist/textarea.min.js | 2 +- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/components/dist/input.js b/components/dist/input.js index 7a65d2d..75ff487 100644 --- a/components/dist/input.js +++ b/components/dist/input.js @@ -272,6 +272,8 @@ customElements.define('sm-input', this.handleOptionClick = this.handleOptionClick.bind(this); this.handleInputNavigation = this.handleInputNavigation.bind(this); this.handleDatalistNavigation = this.handleDatalistNavigation.bind(this); + this.handleFocus = this.handleFocus.bind(this); + this.handleBlur = this.handleBlur.bind(this); } static get observedAttributes() { @@ -504,6 +506,16 @@ customElements.define('sm-input', this.input.focus(); } } + handleFocus(e) { + if (this.datalist.length) { + this.searchDatalist(this.input.value.trim()); + } + } + handleBlur(e) { + if (this.datalist.length) { + this.optionList.classList.add('hidden'); + } + } connectedCallback() { this.animate = this.hasAttribute('animate'); @@ -515,6 +527,8 @@ customElements.define('sm-input', this.input.addEventListener('keydown', this.handleInputNavigation); this.optionList.addEventListener('keydown', this.handleDatalistNavigation); } + this.input.addEventListener('focusin', this.handleFocus); + this.input.addEventListener('focusout', this.handleBlur); } attributeChangedCallback(name, oldValue, newValue) { @@ -579,5 +593,7 @@ customElements.define('sm-input', 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.input.removeEventListener('focusout', this.handleBlur); } }) \ No newline at end of file diff --git a/components/dist/input.min.js b/components/dist/input.min.js index 21f6f9b..f01957d 100644 --- a/components/dist/input.min.js +++ b/components/dist/input.min.js @@ -1 +1 @@ -const smInput=document.createElement("template");smInput.innerHTML='\n \n
\n \n \n \n
\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.optionList=this.shadowRoot.querySelector(".datalist"),this._helperText="",this._errorText="",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"],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),this.handleOptionClick=this.handleOptionClick.bind(this),this.handleInputNavigation=this.handleInputNavigation.bind(this),this.handleDatalistNavigation=this.handleDatalistNavigation.bind(this)}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(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 \n ${this._errorText}`),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)}searchDatalist(t){const e=this.datalist.filter(e=>e.toLowerCase().includes(t.toLowerCase()));if(e.sort((e,n)=>{const i=e.toLowerCase().indexOf(t.toLowerCase()),s=n.toLowerCase().indexOf(t.toLowerCase());return i-s}),e.length){if(this.optionList.children.length>e.length){const t=this.optionList.children.length-e.length;for(let e=0;e{if(this.optionList.children[e])this.optionList.children[e].textContent=t;else{const e=document.createElement("li");e.textContent=t,e.classList.add("datalist-item"),e.setAttribute("tabindex","0"),this.optionList.appendChild(e)}}),this.optionList.classList.remove("hidden")}else this.optionList.classList.add("hidden")}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("hidden"),this.datalist.length&&(this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.searchDatalist(this.input.value.trim())},100))):(this.animate?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(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"})}handleOptionClick(t){this.input.value=t.target.textContent,this.optionList.classList.add("hidden"),this.input.focus()}handleInputNavigation(t){"ArrowDown"===t.key?(t.preventDefault(),this.optionList.children.length&&this.optionList.children[0].focus()):"ArrowUp"===t.key&&(t.preventDefault(),this.optionList.children.length&&this.optionList.children[this.optionList.children.length-1].focus())}handleDatalistNavigation(t){"ArrowUp"===t.key?(t.preventDefault(),this.shadowRoot.activeElement.previousElementSibling?this.shadowRoot.activeElement.previousElementSibling.focus():this.input.focus()):"ArrowDown"===t.key?(t.preventDefault(),this.shadowRoot.activeElement.nextElementSibling?this.shadowRoot.activeElement.nextElementSibling.focus():this.input.focus()):"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.input.value=t.target.textContent,this.optionList.classList.add("hidden"),this.input.focus())}connectedCallback(){this.animate=this.hasAttribute("animate"),this.setAttribute("role","textbox"),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))}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"):"list"===t&&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)}}); \ No newline at end of file +const smInput=document.createElement("template");smInput.innerHTML='\n \n
\n \n \n \n
\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.optionList=this.shadowRoot.querySelector(".datalist"),this._helperText="",this._errorText="",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"],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),this.handleOptionClick=this.handleOptionClick.bind(this),this.handleInputNavigation=this.handleInputNavigation.bind(this),this.handleDatalistNavigation=this.handleDatalistNavigation.bind(this),this.handleFocus=this.handleFocus.bind(this),this.handleBlur=this.handleBlur.bind(this)}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(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 \n ${this._errorText}`),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)}searchDatalist(t){const e=this.datalist.filter(e=>e.toLowerCase().includes(t.toLowerCase()));if(e.sort((e,n)=>{const i=e.toLowerCase().indexOf(t.toLowerCase()),s=n.toLowerCase().indexOf(t.toLowerCase());return i-s}),e.length){if(this.optionList.children.length>e.length){const t=this.optionList.children.length-e.length;for(let e=0;e{if(this.optionList.children[e])this.optionList.children[e].textContent=t;else{const e=document.createElement("li");e.textContent=t,e.classList.add("datalist-item"),e.setAttribute("tabindex","0"),this.optionList.appendChild(e)}}),this.optionList.classList.remove("hidden")}else this.optionList.classList.add("hidden")}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("hidden"),this.datalist.length&&(this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>{this.searchDatalist(this.input.value.trim())},100))):(this.animate?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(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"})}handleOptionClick(t){this.input.value=t.target.textContent,this.optionList.classList.add("hidden"),this.input.focus()}handleInputNavigation(t){"ArrowDown"===t.key?(t.preventDefault(),this.optionList.children.length&&this.optionList.children[0].focus()):"ArrowUp"===t.key&&(t.preventDefault(),this.optionList.children.length&&this.optionList.children[this.optionList.children.length-1].focus())}handleDatalistNavigation(t){"ArrowUp"===t.key?(t.preventDefault(),this.shadowRoot.activeElement.previousElementSibling?this.shadowRoot.activeElement.previousElementSibling.focus():this.input.focus()):"ArrowDown"===t.key?(t.preventDefault(),this.shadowRoot.activeElement.nextElementSibling?this.shadowRoot.activeElement.nextElementSibling.focus():this.input.focus()):"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),this.input.value=t.target.textContent,this.optionList.classList.add("hidden"),this.input.focus())}handleFocus(t){this.datalist.length&&this.searchDatalist(this.input.value.trim())}handleBlur(t){this.datalist.length&&this.optionList.classList.add("hidden")}connectedCallback(){this.animate=this.hasAttribute("animate"),this.setAttribute("role","textbox"),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.input.addEventListener("focusout",this.handleBlur)}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"):"list"===t&&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.input.removeEventListener("focusout",this.handleBlur)}}); \ No newline at end of file diff --git a/components/dist/select.js b/components/dist/select.js index 8f35836..9602bbf 100644 --- a/components/dist/select.js +++ b/components/dist/select.js @@ -162,6 +162,7 @@ customElements.define('sm-select', class extends HTMLElement { this.previousOption this.isOpen = false; this.label = '' + this.defaultSelected = '' this.isUnderViewport = false this.animationOptions = { duration: 300, @@ -200,7 +201,7 @@ customElements.define('sm-select', class extends HTMLElement { reset(fire = true) { if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) { - const selectedOption = this.availableOptions.find(option => option.hasAttribute('selected')) || this.availableOptions[0]; + const selectedOption = this.availableOptions.find(option => option.getAttribute('value') === this.defaultSelected) || this.availableOptions[0]; this.value = selectedOption.getAttribute('value') if (fire) { this.fireEvent() @@ -349,6 +350,7 @@ customElements.define('sm-select', class extends HTMLElement { slot.addEventListener('slotchange', this.debounce(e => { this.availableOptions = slot.assignedElements() this.reset(false) + this.defaultSelected = this.value }, 100)); new IntersectionObserver((entries, observer) => { entries.forEach(entry => { diff --git a/components/dist/select.min.js b/components/dist/select.min.js index aeeea8c..b5bac40 100644 --- a/components/dist/select.min.js +++ b/components/dist/select.min.js @@ -1 +1 @@ -const smSelect=document.createElement("template");smSelect.innerHTML='\n\n
\n
\n
\n \n \n
\n \n
',customElements.define("sm-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSelect.content.cloneNode(!0)),this.focusIn=this.focusIn.bind(this),this.reset=this.reset.bind(this),this.open=this.open.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleOptionsNavigation=this.handleOptionsNavigation.bind(this),this.handleOptionSelection=this.handleOptionSelection.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.handleClickOutside=this.handleClickOutside.bind(this),this.selectOption=this.selectOption.bind(this),this.debounce=this.debounce.bind(this),this.availableOptions=[],this.previousOption,this.isOpen=!1,this.label="",this.isUnderViewport=!1,this.animationOptions={duration:300,fill:"forwards",easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.selection=this.shadowRoot.querySelector(".selection"),this.selectedOptionText=this.shadowRoot.querySelector(".selected-option-text")}static get observedAttributes(){return["disabled","label"]}get value(){return this.getAttribute("value")}set value(t){const e=this.shadowRoot.querySelector("slot").assignedElements().find(e=>e.getAttribute("value")===t);e?(this.setAttribute("value",t),this.selectOption(e)):console.warn(`There is no option with ${t} as value`)}debounce(t,e){let n=null;return(...i)=>{window.clearTimeout(n),n=window.setTimeout(()=>{t.apply(null,i)},e)}}reset(t=!0){if(this.availableOptions[0]&&this.previousOption!==this.availableOptions[0]){const e=this.availableOptions.find(t=>t.hasAttribute("selected"))||this.availableOptions[0];this.value=e.getAttribute("value"),t&&this.fireEvent()}}selectOption(t){this.previousOption!==t&&(this.querySelectorAll("[selected]").forEach(t=>t.removeAttribute("selected")),this.selectedOptionText.textContent=`${this.label}${t.textContent}`,t.setAttribute("selected",""),this.previousOption=t)}focusIn(){this.selection.focus()}open(){this.availableOptions.forEach(t=>t.setAttribute("tabindex",0)),this.optionList.classList.remove("hidden"),this.isUnderViewport=this.getBoundingClientRect().bottom+this.optionList.getBoundingClientRect().height>window.innerHeight,this.isUnderViewport?this.setAttribute("isUnder",""):this.removeAttribute("isUnder"),this.optionList.animate([{transform:`translateY(${this.isUnderViewport?"":"-"}0.5rem)`,opacity:0},{transform:"translateY(0)",opacity:1}],this.animationOptions),this.setAttribute("open",""),this.style.zIndex=1e3,(this.availableOptions.find(t=>t.hasAttribute("selected"))||this.availableOptions[0]).focus(),document.addEventListener("mousedown",this.handleClickOutside),this.isOpen=!0}collapse(){this.removeAttribute("open"),this.optionList.animate([{transform:"translateY(0)",opacity:1},{transform:`translateY(${this.isUnderViewport?"":"-"}0.5rem)`,opacity:0}],this.animationOptions).onfinish=(()=>{this.availableOptions.forEach(t=>t.removeAttribute("tabindex")),document.removeEventListener("mousedown",this.handleClickOutside),this.optionList.classList.add("hidden"),this.isOpen=!1,this.style.zIndex="auto"})}toggle(){this.isOpen||this.hasAttribute("disabled")?this.collapse():this.open()}fireEvent(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this.value}}))}handleOptionsNavigation(t){"ArrowUp"===t.key?(t.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===t.key&&(t.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}handleOptionSelection(t){this.previousOption!==document.activeElement&&(this.value=document.activeElement.getAttribute("value"),this.fireEvent())}handleClick(t){t.target===this?this.toggle():(this.handleOptionSelection(),this.collapse())}handleKeydown(t){t.target===this?this.isOpen&&"ArrowDown"===t.key?(t.preventDefault(),(this.availableOptions.find(t=>t.hasAttribute("selected"))||this.availableOptions[0]).focus(),this.handleOptionSelection(t)):" "===t.key&&(t.preventDefault(),this.toggle()):(this.handleOptionsNavigation(t),this.handleOptionSelection(t),["Enter"," ","Escape","Tab"].includes(t.key)&&(t.preventDefault(),this.collapse(),this.focusIn()))}handleClickOutside(t){this.isOpen&&!this.contains(t.target)&&this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.hasAttribute("disabled")||this.selection.setAttribute("tabindex","0");let t=this.shadowRoot.querySelector("slot");t.addEventListener("slotchange",this.debounce(e=>{this.availableOptions=t.assignedElements(),this.reset(!1)},100)),new IntersectionObserver((t,e)=>{t.forEach(t=>{if(t.isIntersecting){const t=this.selection.getBoundingClientRect().left;t \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n overflow: hidden;\n border-radius: var(--border-radius, 0.3rem);\n}\n.option{\n position: relative;\n display: grid;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 100%;\n gap: 0.5rem;\n grid-template-columns: max-content minmax(0, 1fr);\n padding: var(--padding, 0.6rem 1rem);\n cursor: pointer;\n outline: none;\n user-select: none;\n}\n.option::before{\n position: absolute;\n content: '';\n display: block;\n width: 0.2rem;\n height: 1em;\n border-radius: 0 1em 1em 0;\n background: rgba(var(--text-color,(17,17,17)), 0.5);\n transition: all 0.2s ease-in-out;\n opacity: 0;\n}\n:host(:focus){\n outline: none;\n background: rgba(var(--text-color,(17,17,17)), 0.1);\n}\n:host(:focus) .option::before{\n opacity: 1\n}\n:host([selected]) .option::before{\n opacity: 1;\n background: var(--accent-color, teal);\n}\n@media (hover: hover){\n .option:hover{\n background: rgba(var(--text-color,(17,17,17)), 0.1);\n }\n :host(:not([selected]):hover) .option::before{\n opacity: 1\n }\n}\n\n
\n \n
",customElements.define("sm-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option")}}); \ No newline at end of file +const smSelect=document.createElement("template");smSelect.innerHTML='\n\n
\n
\n
\n \n \n
\n \n
',customElements.define("sm-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSelect.content.cloneNode(!0)),this.focusIn=this.focusIn.bind(this),this.reset=this.reset.bind(this),this.open=this.open.bind(this),this.collapse=this.collapse.bind(this),this.toggle=this.toggle.bind(this),this.handleOptionsNavigation=this.handleOptionsNavigation.bind(this),this.handleOptionSelection=this.handleOptionSelection.bind(this),this.handleKeydown=this.handleKeydown.bind(this),this.handleClickOutside=this.handleClickOutside.bind(this),this.selectOption=this.selectOption.bind(this),this.debounce=this.debounce.bind(this),this.availableOptions=[],this.previousOption,this.isOpen=!1,this.label="",this.defaultSelected="",this.isUnderViewport=!1,this.animationOptions={duration:300,fill:"forwards",easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.selection=this.shadowRoot.querySelector(".selection"),this.selectedOptionText=this.shadowRoot.querySelector(".selected-option-text")}static get observedAttributes(){return["disabled","label"]}get value(){return this.getAttribute("value")}set value(t){const e=this.shadowRoot.querySelector("slot").assignedElements().find(e=>e.getAttribute("value")===t);e?(this.setAttribute("value",t),this.selectOption(e)):console.warn(`There is no option with ${t} as value`)}debounce(t,e){let n=null;return(...i)=>{window.clearTimeout(n),n=window.setTimeout(()=>{t.apply(null,i)},e)}}reset(t=!0){if(this.availableOptions[0]&&this.previousOption!==this.availableOptions[0]){const e=this.availableOptions.find(t=>t.getAttribute("value")===this.defaultSelected)||this.availableOptions[0];this.value=e.getAttribute("value"),t&&this.fireEvent()}}selectOption(t){this.previousOption!==t&&(this.querySelectorAll("[selected]").forEach(t=>t.removeAttribute("selected")),this.selectedOptionText.textContent=`${this.label}${t.textContent}`,t.setAttribute("selected",""),this.previousOption=t)}focusIn(){this.selection.focus()}open(){this.availableOptions.forEach(t=>t.setAttribute("tabindex",0)),this.optionList.classList.remove("hidden"),this.isUnderViewport=this.getBoundingClientRect().bottom+this.optionList.getBoundingClientRect().height>window.innerHeight,this.isUnderViewport?this.setAttribute("isUnder",""):this.removeAttribute("isUnder"),this.optionList.animate([{transform:`translateY(${this.isUnderViewport?"":"-"}0.5rem)`,opacity:0},{transform:"translateY(0)",opacity:1}],this.animationOptions),this.setAttribute("open",""),this.style.zIndex=1e3,(this.availableOptions.find(t=>t.hasAttribute("selected"))||this.availableOptions[0]).focus(),document.addEventListener("mousedown",this.handleClickOutside),this.isOpen=!0}collapse(){this.removeAttribute("open"),this.optionList.animate([{transform:"translateY(0)",opacity:1},{transform:`translateY(${this.isUnderViewport?"":"-"}0.5rem)`,opacity:0}],this.animationOptions).onfinish=(()=>{this.availableOptions.forEach(t=>t.removeAttribute("tabindex")),document.removeEventListener("mousedown",this.handleClickOutside),this.optionList.classList.add("hidden"),this.isOpen=!1,this.style.zIndex="auto"})}toggle(){this.isOpen||this.hasAttribute("disabled")?this.collapse():this.open()}fireEvent(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this.value}}))}handleOptionsNavigation(t){"ArrowUp"===t.key?(t.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===t.key&&(t.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}handleOptionSelection(t){this.previousOption!==document.activeElement&&(this.value=document.activeElement.getAttribute("value"),this.fireEvent())}handleClick(t){t.target===this?this.toggle():(this.handleOptionSelection(),this.collapse())}handleKeydown(t){t.target===this?this.isOpen&&"ArrowDown"===t.key?(t.preventDefault(),(this.availableOptions.find(t=>t.hasAttribute("selected"))||this.availableOptions[0]).focus(),this.handleOptionSelection(t)):" "===t.key&&(t.preventDefault(),this.toggle()):(this.handleOptionsNavigation(t),this.handleOptionSelection(t),["Enter"," ","Escape","Tab"].includes(t.key)&&(t.preventDefault(),this.collapse(),this.focusIn()))}handleClickOutside(t){this.isOpen&&!this.contains(t.target)&&this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.hasAttribute("disabled")||this.selection.setAttribute("tabindex","0");let t=this.shadowRoot.querySelector("slot");t.addEventListener("slotchange",this.debounce(e=>{this.availableOptions=t.assignedElements(),this.reset(!1),this.defaultSelected=this.value},100)),new IntersectionObserver((t,e)=>{t.forEach(t=>{if(t.isIntersecting){const t=this.selection.getBoundingClientRect().left;t \n*{\n padding: 0;\n margin: 0;\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n} \n:host{\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n overflow: hidden;\n border-radius: var(--border-radius, 0.3rem);\n}\n.option{\n position: relative;\n display: grid;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n width: 100%;\n gap: 0.5rem;\n grid-template-columns: max-content minmax(0, 1fr);\n padding: var(--padding, 0.6rem 1rem);\n cursor: pointer;\n outline: none;\n user-select: none;\n}\n.option::before{\n position: absolute;\n content: '';\n display: block;\n width: 0.2rem;\n height: 1em;\n border-radius: 0 1em 1em 0;\n background: rgba(var(--text-color,(17,17,17)), 0.5);\n transition: all 0.2s ease-in-out;\n opacity: 0;\n}\n:host(:focus){\n outline: none;\n background: rgba(var(--text-color,(17,17,17)), 0.1);\n}\n:host(:focus) .option::before{\n opacity: 1\n}\n:host([selected]) .option::before{\n opacity: 1;\n background: var(--accent-color, teal);\n}\n@media (hover: hover){\n .option:hover{\n background: rgba(var(--text-color,(17,17,17)), 0.1);\n }\n :host(:not([selected]):hover) .option::before{\n opacity: 1\n }\n}\n\n
\n \n
",customElements.define("sm-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option")}}); \ No newline at end of file diff --git a/components/dist/textarea.js b/components/dist/textarea.js index a600637..bc76376 100644 --- a/components/dist/textarea.js +++ b/components/dist/textarea.js @@ -57,7 +57,6 @@ smTextarea.innerHTML = ` border: none; outline: none; line-height: 1.5; - overflow: hidden; } .textarea::after{ content: attr(data-value) ' '; diff --git a/components/dist/textarea.min.js b/components/dist/textarea.min.js index a8c8c3b..c10937f 100644 --- a/components/dist/textarea.min.js +++ b/components/dist/textarea.min.js @@ -1 +1 @@ -const smTextarea=document.createElement("template");smTextarea.innerHTML='\n \n \n ',customElements.define("sm-textarea",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTextarea.content.cloneNode(!0)),this.textarea=this.shadowRoot.querySelector("textarea"),this.textareaBox=this.shadowRoot.querySelector(".textarea"),this.placeholder=this.shadowRoot.querySelector(".placeholder"),this.reflectedAttributes=["disabled","required","readonly","rows","minlength","maxlength"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["disabled","value","placeholder","required","readonly","rows","minlength","maxlength"]}get value(){return this.textarea.value}set value(e){this.setAttribute("value",e),this.fireEvent()}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get isValid(){return this.textarea.checkValidity()}reset(){this.setAttribute("value","")}focusIn(){this.textarea.focus()}fireEvent(){let e=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(e)}checkInput(){this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder")&&(""!==this.textarea.value?this.placeholder.classList.add("hide"):this.placeholder.classList.remove("hide"))}connectedCallback(){this.textarea.addEventListener("input",e=>{this.textareaBox.dataset.value=this.textarea.value,this.checkInput()})}attributeChangedCallback(e,t,n){this.reflectedAttributes.includes(e)?this.hasAttribute(e)?this.textarea.setAttribute(e,this.getAttribute(e)?this.getAttribute(e):""):this.textContent.removeAttribute(e):"placeholder"===e?this.placeholder.textContent=this.getAttribute("placeholder"):"value"===e&&(this.textarea.value=n,this.textareaBox.dataset.value=n,this.checkInput())}}); \ No newline at end of file +const smTextarea=document.createElement("template");smTextarea.innerHTML='\n \n \n ',customElements.define("sm-textarea",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smTextarea.content.cloneNode(!0)),this.textarea=this.shadowRoot.querySelector("textarea"),this.textareaBox=this.shadowRoot.querySelector(".textarea"),this.placeholder=this.shadowRoot.querySelector(".placeholder"),this.reflectedAttributes=["disabled","required","readonly","rows","minlength","maxlength"],this.reset=this.reset.bind(this),this.focusIn=this.focusIn.bind(this),this.fireEvent=this.fireEvent.bind(this),this.checkInput=this.checkInput.bind(this)}static get observedAttributes(){return["disabled","value","placeholder","required","readonly","rows","minlength","maxlength"]}get value(){return this.textarea.value}set value(e){this.setAttribute("value",e),this.fireEvent()}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get isValid(){return this.textarea.checkValidity()}reset(){this.setAttribute("value","")}focusIn(){this.textarea.focus()}fireEvent(){let e=new Event("input",{bubbles:!0,cancelable:!0,composed:!0});this.dispatchEvent(e)}checkInput(){this.hasAttribute("placeholder")&&""!==this.getAttribute("placeholder")&&(""!==this.textarea.value?this.placeholder.classList.add("hide"):this.placeholder.classList.remove("hide"))}connectedCallback(){this.textarea.addEventListener("input",e=>{this.textareaBox.dataset.value=this.textarea.value,this.checkInput()})}attributeChangedCallback(e,t,n){this.reflectedAttributes.includes(e)?this.hasAttribute(e)?this.textarea.setAttribute(e,this.getAttribute(e)?this.getAttribute(e):""):this.textContent.removeAttribute(e):"placeholder"===e?this.placeholder.textContent=this.getAttribute("placeholder"):"value"===e&&(this.textarea.value=n,this.textareaBox.dataset.value=n,this.checkInput())}}); \ No newline at end of file