1 line
8.3 KiB
JavaScript
1 line
8.3 KiB
JavaScript
const stripSelect=document.createElement("template");stripSelect.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 --accent-color: #4d2588;\n --text-color: 17, 17, 17;\n --background-color: 255, 255, 255;\n --gap: 0.5rem;\n padding: 1rem 0;\n }\n .hide{\n display: none !important;\n }\n input[type="radio"]{\n display: none;\n }\n .scrolling-container{\n position: relative;\n display: flex;\n align-items: center;\n }\n .strip-select{\n position: relative;\n }\n :host([multiline]) .strip-select{\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n overflow: auto hidden;\n }\n :host(:not([multiline])) .strip-select{\n display: grid;\n grid-auto-flow: column;\n gap: var(--gap);\n max-width: 100%; \n align-items: center;\n overflow: auto hidden;\n }\n .nav-button{\n display: flex;\n top: 50%;\n z-index: 2;\n border: none;\n padding: 0.3rem;\n cursor: pointer;\n position: absolute;\n align-items: center;\n background: rgba(var(--background-color), 1);\n transform: translateY(-50%);\n }\n .nav-button--right{\n right: 0;\n }\n .cover{\n position: absolute;\n z-index: 1;\n width: 5rem;\n height: 100%;\n pointer-events: none;\n }\n .nav-button--right::before{\n background-color: red;\n }\n .icon{\n height: 1.5rem;\n width: 1.5rem;\n fill: rgba(var(--text-color), .8);\n }\n @media (hover: none){\n .nav-button{\n display: none;\n }\n .strip-select{\n overflow: auto hidden;\n }\n .cover{\n width: 2rem;\n }\n .cover--left{\n background: linear-gradient(90deg, rgba(var(--background-color), 1), transparent);\n }\n .cover--right{\n right: 0;\n background: linear-gradient(90deg, transparent, rgba(var(--background-color), 1));\n }\n }\n @media (hover: hover){\n ::-webkit-scrollbar-track {\n background-color: transparent !important;\n }\n ::-webkit-scrollbar {\n height: 0;\n background-color: transparent;\n }\n .strip-select{\n overflow: hidden;\n }\n .cover--left{\n background: linear-gradient(90deg, rgba(var(--background-color), 1) 60%, transparent);\n }\n .cover--right{\n right: 0;\n background: linear-gradient(90deg, transparent 0%, rgba(var(--background-color), 1) 40%);\n }\n }\n</style>\n<section class="scrolling-container">\n <div class="cover cover--left hide"></div>\n <button class="nav-button nav-button--left hide">\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.828 12l4.95 4.95-1.414 1.414L8 12l6.364-6.364 1.414 1.414z"/></svg>\n </button>\n <section class="strip-select">\n <slot></slot>\n </section>\n <button class="nav-button nav-button--right hide">\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="M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z"/></svg>\n </button>\n <div class="cover cover--right hide"></div>\n</section>\n\n',customElements.define("strip-select",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(stripSelect.content.cloneNode(!0)),this.stripSelect=this.shadowRoot.querySelector(".strip-select"),this.slottedOptions,this._value,this.scrollDistance,this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.fireEvent=this.fireEvent.bind(this)}get value(){return this._value}scrollLeft(){this.stripSelect.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.stripSelect.scrollBy({left:this.scrollDistance,behavior:"smooth"})}fireEvent(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this._value}}))}connectedCallback(){this.setAttribute("role","listbox");const t=this.shadowRoot.querySelector("slot"),e=this.shadowRoot.querySelector(".cover--left"),n=this.shadowRoot.querySelector(".cover--right"),i=this.shadowRoot.querySelector(".nav-button--left"),o=this.shadowRoot.querySelector(".nav-button--right");t.addEventListener("slotchange",s=>{const l=t.assignedElements();l.forEach(t=>{t.hasAttribute("selected")&&(t.setAttribute("active",""),this._value=t.value)}),this.hasAttribute("multiline")||(l.length>0?(r.observe(t.assignedElements()[0]),a.observe(t.assignedElements()[t.assignedElements().length-1])):(i.classList.add("hide"),o.classList.add("hide"),e.classList.add("hide"),n.classList.add("hide"),r.disconnect(),a.disconnect()))});const s=new ResizeObserver(t=>{t.forEach(t=>{if(t.contentBoxSize){const e=Array.isArray(t.contentBoxSize)?t.contentBoxSize[0]:t.contentBoxSize;this.scrollDistance=.6*e.inlineSize}else this.scrollDistance=.6*t.contentRect.width})});s.observe(this),this.stripSelect.addEventListener("option-clicked",e=>{this._value!==e.target.value&&(this._value=e.target.value,t.assignedElements().forEach(t=>t.removeAttribute("active")),e.target.setAttribute("active",""),e.target.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"}),this.fireEvent())});const r=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?(i.classList.add("hide"),e.classList.add("hide")):(i.classList.remove("hide"),e.classList.remove("hide"))})},{threshold:.9,root:this}),a=new IntersectionObserver(t=>{t.forEach(t=>{t.isIntersecting?(o.classList.add("hide"),n.classList.add("hide")):(o.classList.remove("hide"),n.classList.remove("hide"))})},{threshold:.9,root:this});i.addEventListener("click",this.scrollLeft),o.addEventListener("click",this.scrollRight)}disconnectedCallback(){navButtonLeft.removeEventListener("click",this.scrollLeft),navButtonRight.removeEventListener("click",this.scrollRight)}});const stripOption=document.createElement("template");stripOption.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 --border-radius: 2rem;\n --background-color: inherit;\n --active-option-color: inherit;\n --active-option-backgroud-color: rgba(var(--text-color), .2);\n }\n .strip-option{\n display: flex;\n flex-shrink: 0;\n cursor: pointer;\n white-space: nowrap;\n padding: 0.5rem 0.8rem;\n transition: background 0.3s;\n border-radius: var(--border-radius);\n box-shadow: 0 0 0 1px rgba(var(--text-color), .2) inset;\n -webkit-tap-highlight-color: transparent;\n }\n :host([active]) .strip-option{\n color: var(--active-option-color);\n background-color: var(--active-option-backgroud-color);\n }\n :host(:focus-within){\n outline: none;\n }\n :host(:focus-within) .strip-option{\n box-shadow: 0 0 0 0.1rem var(--accent-color) inset;\n }\n :host(:hover:not([active])) .strip-option{\n background-color: rgba(var(--text-color), 0.06);\n }\n</style>\n<label class="strip-option">\n <slot></slot>\n</label>\n',customElements.define("strip-option",class extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}).append(stripOption.content.cloneNode(!0)),this._value,this.radioButton=this.shadowRoot.querySelector("input"),this.fireEvent=this.fireEvent.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this)}get value(){return this._value}fireEvent(){this.dispatchEvent(new CustomEvent("option-clicked",{bubbles:!0,composed:!0,detail:{value:this._value}}))}handleKeyDown(t){"Enter"!==t.key&&"Space"!==t.key||this.fireEvent()}connectedCallback(){this.setAttribute("role","option"),this.setAttribute("tabindex","0"),this._value=this.getAttribute("value"),this.addEventListener("click",this.fireEvent),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){this.removeEventListener("click",this.fireEvent),this.removeEventListener("keydown",this.handleKeyDown)}}); |