1 line
9.2 KiB
JavaScript
1 line
9.2 KiB
JavaScript
const smSelect=document.createElement("template");smSelect.innerHTML='\n<style> \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 --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --max-height: auto;\n --min-width: 100%;\n}\n:host([disabled]) .select{\n opacity: 0.6;\n cursor: not-allowed;\n}\n.hide{\n display: none !important;\n}\n.select{\n position: relative;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n -ms-flex-direction: column;\n flex-direction: column;\n cursor: pointer;\n width: 100%;\n -webkit-tap-highlight-color: transparent;\n}\n.icon {\n height: 1.5rem;\n width: 1.5rem;\n fill: rgba(var(--text-color), 0.7);\n} \n.selected-option-text{\n font-size: 0.9rem;\n overflow: hidden;\n -o-text-overflow: ellipsis;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.selection{\n border-radius: 0.3rem;\n display: -ms-grid;\n display: grid;\n -ms-grid-columns: 1fr auto;\n grid-template-columns: 1fr auto;\n grid-template-areas: \'heading heading\' \'. .\';\n padding: 0.4rem 1rem;\n background: rgba(var(--text-color), 0.06);\n border: solid 1px rgba(var(--text-color), 0.2);\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n outline: none;\n}\n.selection:focus{\n -webkit-box-shadow: 0 0 0 0.1rem var(--accent-color);\n box-shadow: 0 0 0 0.1rem var(--accent-color) \n}\n.icon{\n margin-left: 1rem;\n}\n:host([align-select="left"]) .options{\n left: 0;\n}\n:host([align-select="right"]) .options{\n right: 0;\n}\n.options{\n top: 100%;\n margin-top: 0.2rem; \n overflow: hidden auto;\n position: absolute;\n grid-area: options;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex;\n -webkit-box-orient: vertical;\n -webkit-box-direction: normal;\n -ms-flex-direction: column;\n flex-direction: column;\n min-width: var(--min-width);\n max-height: var(--max-height);\n background: rgba(var(--background-color), 1);\n border: solid 1px rgba(var(--text-color), 0.2);\n border-radius: 0.3rem;\n z-index: 2;\n -webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;\n box-shadow: 0.4rem 0.8rem 1.2rem #00000030;\n}\n.rotate{\n -webkit-transform: rotate(180deg);\n -ms-transform: rotate(180deg);\n transform: rotate(180deg)\n}\n@media (any-hover: hover){\n ::-webkit-scrollbar{\n width: 0.5rem;\n height: 0.5rem;\n }\n \n ::-webkit-scrollbar-thumb{\n background: rgba(var(--text-color), 0.3);\n border-radius: 1rem;\n &:hover{\n background: rgba(var(--text-color), 0.5);\n }\n }\n}\n</style>\n<div class="select" >\n <div class="selection">\n <div class="selected-option-text"></div>\n <svg class="icon toggle" 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 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg>\n </div>\n <div part="options" class="options hide">\n <slot></slot> \n </div>\n</div>',customElements.define("sm-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smSelect.content.cloneNode(!0)),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.availableOptions,this.previousOption,this.isOpen=!1,this.slideDown=[{transform:"translateY(-0.5rem)",opacity:0},{transform:"translateY(0)",opacity:1}],this.slideUp=[{transform:"translateY(0)",opacity:1},{transform:"translateY(-0.5rem)",opacity:0}],this.animationOptions={duration:300,fill:"forwards",easing:"ease"},this.optionList=this.shadowRoot.querySelector(".options"),this.chevron=this.shadowRoot.querySelector(".toggle"),this.selection=this.shadowRoot.querySelector(".selection"),this.selectedOptionText=this.shadowRoot.querySelector(".selected-option-text")}static get observedAttributes(){return["value","disabled"]}get value(){return this.getAttribute("value")}set value(e){this.setAttribute("value",e)}reset(e=!0){if(this.availableOptions[0]&&this.previousOption!==this.availableOptions[0]){const t=this.availableOptions[0];this.previousOption&&this.previousOption.classList.remove("check-selected"),t.classList.add("check-selected"),this.value=t.getAttribute("value"),this.selectedOptionText.textContent=t.textContent,this.previousOption=t,e&&this.fireEvent()}}open(){this.optionList.classList.remove("hide"),this.optionList.animate(this.slideDown,this.animationOptions),this.chevron.classList.add("rotate"),this.isOpen=!0}collapse(){this.chevron.classList.remove("rotate"),this.optionList.animate(this.slideUp,this.animationOptions).onfinish=(()=>{this.optionList.classList.add("hide"),this.isOpen=!1})}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(e){"ArrowUp"===e.code?(e.preventDefault(),document.activeElement.previousElementSibling?document.activeElement.previousElementSibling.focus():this.availableOptions[this.availableOptions.length-1].focus()):"ArrowDown"===e.code&&(e.preventDefault(),document.activeElement.nextElementSibling?document.activeElement.nextElementSibling.focus():this.availableOptions[0].focus())}handleOptionSelection(e){this.previousOption!==document.activeElement&&(this.value=document.activeElement.getAttribute("value"),this.selectedOptionText.textContent=document.activeElement.textContent,this.fireEvent(),this.previousOption&&this.previousOption.classList.remove("check-selected"),document.activeElement.classList.add("check-selected"),this.previousOption=document.activeElement)}handleClick(e){e.target===this?this.toggle():(this.handleOptionSelection(),this.collapse())}handleKeydown(e){e.target===this?this.isOpen&&"ArrowDown"===e.code?(e.preventDefault(),this.availableOptions[0].focus(),this.handleOptionSelection(e)):"Enter"!==e.code&&"Space"!==e.code||(e.preventDefault(),this.toggle()):(this.handleOptionsNavigation(e),this.handleOptionSelection(e),"Enter"!==e.code&&"Space"!==e.code||(e.preventDefault(),this.collapse()))}handleClickOutside(e){this.isOpen&&!this.contains(e.target)&&this.collapse()}connectedCallback(){this.setAttribute("role","listbox"),this.hasAttribute("disabled")||this.selection.setAttribute("tabindex","0");let e=this.shadowRoot.querySelector("slot");e.addEventListener("slotchange",t=>{this.availableOptions=e.assignedElements(),this.reset(!1)}),this.addEventListener("click",this.handleClick),this.addEventListener("keydown",this.handleKeydown),document.addEventListener("mousedown",this.handleClickOutside)}disconnectedCallback(){this.removeEventListener("click",this.toggle),this.removeEventListener("keydown",this.handleKeydown),document.removeEventListener("mousedown",this.handleClickOutside)}attributeChangedCallback(e){"disabled"===e&&(this.hasAttribute("disabled")?this.selection.removeAttribute("tabindex"):this.selection.setAttribute("tabindex","0"))}});const smOption=document.createElement("template");smOption.innerHTML='\n<style> \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}\n.option{\n display: grid;\n -webkit-box-align: center;\n -ms-flex-align: center;\n align-items: center;\n min-width: 100%;\n gap: 0.5rem;\n grid-template-columns: max-content minmax(0, 1fr);\n padding: 0.8rem 1.2rem;\n cursor: pointer;\n overflow-wrap: break-word;\n outline: none;\n user-select: none;\n}\n:host(:focus){\n outline: none;\n background: rgba(var(--text-color), 0.1);\n}\n.icon {\n opacity: 0;\n height: 1.2rem;\n width: 1.2rem;\n fill: rgba(var(--text-color), 0.8);\n}\n:host(:focus) .option .icon{\n opacity: 0.4\n}\n:host(.check-selected) .icon{\n opacity: 1\n}\n@media (hover: hover){\n .option:hover{\n background: rgba(var(--text-color), 0.1);\n }\n :host(:not(.check-selected):hover) .icon{\n opacity: 0.4\n }\n}\n</style>\n<div class="option">\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="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"/></svg>\n <slot></slot> \n</div>',customElements.define("sm-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(smOption.content.cloneNode(!0))}connectedCallback(){this.setAttribute("role","option"),this.setAttribute("tabindex","0")}}); |