1 line
8.8 KiB
JavaScript
1 line
8.8 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 padding: 1rem 0;\n max-width: 100%;\n }\n .hide{\n opacity: 0;\n pointer-events: none;\n }\n input[type="radio"]{\n display: none;\n }\n .scrolling-container{\n position: relative;\n display: grid;\n grid-template-columns: min-content minmax(0,1fr) min-content;\n grid-template-rows: 1fr;\n }\n .strip-select{\n display: flex;\n position: relative;\n grid-area: 1/1/2/-1;\n gap: var(--gap, 0.5rem);\n overflow: auto hidden;\n }\n :host([multiline]) .strip-select{\n flex-wrap: wrap;\n }\n :host(:not([multiline])) .strip-select{\n max-width: 100%; \n align-items: center;\n }\n .nav-button{\n display: flex;\n z-index: 2;\n border: none;\n padding: 0.3rem;\n cursor: pointer;\n align-items: center;\n background: rgba(var(--background-color,(255,255,255)), 1);\n transition: opacity 0.2s;\n grid-row: 1;\n }\n .nav-button--left{\n grid-column: 1;\n justify-self: start;\n }\n .nav-button--right{\n grid-column: 3;\n justify-self: end;\n }\n .cover{\n position: absolute;\n z-index: 1;\n width: 5rem;\n height: 100%;\n pointer-events: none;\n grid-row: 1;\n transition: opacity 0.2s;\n }\n .cover--left{\n grid-column: 1;\n }\n .cover--right{\n grid-column: 3;\n }\n .nav-button--right::before{\n background-color: red;\n }\n .icon{\n height: 1.2rem;\n width: 1.2rem;\n fill: rgba(var(--text-color,(17,17,17)), .8);\n }\n @media (hover: none){\n ::-webkit-scrollbar {\n height: 0;\n }\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,(255,255,255)), 1), transparent);\n }\n .cover--right{\n right: 0;\n background: linear-gradient(90deg, transparent, rgba(var(--background-color,(255,255,255)), 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,(255,255,255)), 1) 60%, transparent);\n }\n .cover--right{\n right: 0;\n background: linear-gradient(90deg, transparent 0%, rgba(var(--background-color,(255,255,255)), 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=void 0,this._value=void 0,this.scrollDistance=0,this.assignedElements=[],this.scrollLeft=this.scrollLeft.bind(this),this.scrollRight=this.scrollRight.bind(this),this.fireEvent=this.fireEvent.bind(this),this.setSelectedOption=this.setSelectedOption.bind(this)}get value(){return this._value}set value(e){this.setSelectedOption(e)}scrollLeft(){this.stripSelect.scrollBy({left:-this.scrollDistance,behavior:"smooth"})}scrollRight(){this.stripSelect.scrollBy({left:this.scrollDistance,behavior:"smooth"})}setSelectedOption(e){this._value!==e&&(this._value=e,this.assignedElements.forEach(t=>{t.value===e?(t.setAttribute("selected",""),t.scrollIntoView({behavior:"smooth",block:"nearest",inline:"center"})):t.removeAttribute("selected")}))}fireEvent(){this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{value:this._value}}))}connectedCallback(){this.setAttribute("role","listbox");const e=this.shadowRoot.querySelector("slot"),t=this.shadowRoot.querySelector(".cover--left"),n=this.shadowRoot.querySelector(".cover--right"),i=this.shadowRoot.querySelector(".nav-button--left"),s=this.shadowRoot.querySelector(".nav-button--right");e.addEventListener("slotchange",o=>{clearTimeout(this.slotChangeTimeout),this.slotChangeTimeout=setTimeout(()=>{this.assignedElements=e.assignedElements(),this.assignedElements.forEach(e=>{e.hasAttribute("selected")&&(this._value=e.value)}),this.hasAttribute("multiline")||(this.assignedElements.length>0?(r.observe(this.assignedElements[0]),l.observe(this.assignedElements[this.assignedElements.length-1])):(i.classList.add("hide"),s.classList.add("hide"),t.classList.add("hide"),n.classList.add("hide"),r.disconnect(),l.disconnect()))},100)});const o=new ResizeObserver(e=>{e.forEach(e=>{if(e.contentBoxSize){const t=Array.isArray(e.contentBoxSize)?e.contentBoxSize[0]:e.contentBoxSize;this.scrollDistance=.6*t.inlineSize}else this.scrollDistance=.6*e.contentRect.width})});o.observe(this),this.stripSelect.addEventListener("option-clicked",e=>{this._value!==e.target.value&&(this.setSelectedOption(e.target.value),this.fireEvent())});const r=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting?(i.classList.add("hide"),t.classList.add("hide")):(i.classList.remove("hide"),t.classList.remove("hide"))})},{threshold:.9,root:this}),l=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting?(s.classList.add("hide"),n.classList.add("hide")):(s.classList.remove("hide"),n.classList.remove("hide"))})},{threshold:.9,root:this});i.addEventListener("click",this.scrollLeft),s.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 .strip-option{\n display: flex;\n flex-shrink: 0;\n cursor: pointer;\n white-space: nowrap;\n padding: var(--padding, 0.4rem 0.6rem);\n transition: background 0.3s;\n border-radius: var(--border-radius, 2rem);\n -webkit-tap-highlight-color: transparent;\n }\n :host([selected]) .strip-option{\n color: var(--selected-option-color, rgba(var(--background-color,white)));\n background-color: var(--selected-background-color, var(--accent-color,teal));\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,teal) inset;\n }\n :host(:hover:not([selected])) .strip-option{\n background-color: rgba(var(--text-color,(17,17,17)), 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=void 0,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(e){"Enter"!==e.key&&"Space"!==e.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)}}); |