UNPKG

@magic-spells/dropdown-select

Version:
2 lines (1 loc) 5.6 kB
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).DropdownSelect={})}(this,(function(t){"use strict";class e extends HTMLElement{#t;#e;#i;#n;#o;#s;#r;#d=-1;static get observedAttributes(){return["position"]}constructor(){super(),this.setAttribute("aria-hidden","true"),this.#t=this.handleOutsideClick.bind(this),this.#e=this.handleKeyboardNavigation.bind(this)}connectedCallback(){this.#i=this.querySelector("dropdown-select-trigger"),this.#n=this.querySelector("input"),this.#o=this.querySelector("dropdown-options"),this.#s=this.querySelectorAll("dropdown-option"),this.#r=this.#i?.querySelector(".dropdown-label"),this.setAttribute("tabindex","-1"),this.setupAriaAttributes(),this.bindUI(),this.hide()}disconnectedCallback(){this.unbindUI()}setupAriaAttributes(){const t=this.#o,e=this.#i;e.setAttribute("aria-haspopup","listbox"),e.setAttribute("aria-expanded","false"),e.setAttribute("role","combobox"),e.id||(e.id=`dropdown-select-trigger-${Date.now()}`),t.setAttribute("role","listbox"),t.setAttribute("aria-labelledby",e.id),this.#s.forEach(((t,i)=>{t.setAttribute("role","option"),t.setAttribute("aria-selected","false"),t.setAttribute("tabindex","-1"),t.id=`${e.id}-option-${i}`}))}bindUI(){}unbindUI(){document.removeEventListener("click",this.#t),document.removeEventListener("keydown",this.#e)}handleOutsideClick(t){this.contains(t.target)||this.hide()}handleKeyboardNavigation(t){const e=Array.from(this.#s);switch(t.key){case"Escape":t.preventDefault(),this.hide();break;case"ArrowDown":t.preventDefault(),document.activeElement===this.#i&&(this.#d=-1),this.#d<e.length-1&&this.focusOption(this.#d+1);break;case"ArrowUp":t.preventDefault(),this.#d>0?this.focusOption(this.#d-1):0===this.#d&&(this.#i.focus(),this.#d=-1);break;case"Home":t.preventDefault(),this.focusOption(0);break;case"End":t.preventDefault(),this.focusOption(e.length-1);break;case"Enter":case" ":if(t.preventDefault(),"true"===this.getAttribute("aria-hidden")&&document.activeElement===this.#i)return void this.show();this.#d>=0?this.selectOption({target:e[this.#d]}):document.activeElement===this.#i&&this.toggleDropdown();break;default:const i=t.key.toLowerCase();if(1===i.length){const t=e.find((t=>t.textContent.trim().toLowerCase().startsWith(i)));if(t){const i=e.indexOf(t);this.focusOption(i)}}}}focusOption(t){const e=Array.from(this.#s);e.forEach((t=>{t.setAttribute("tabindex","-1")})),e[t]&&(e[t].setAttribute("tabindex","0"),e[t].focus(),this.#d=t)}toggleDropdown(){"true"===this.getAttribute("aria-hidden")?this.show():this.hide()}selectOption(t){const e=t.target.closest("dropdown-option");e&&(this.#s.forEach((t=>{t.setAttribute("aria-selected","false")})),e.setAttribute("aria-selected","true"),this.#n&&(this.#n.value=e.dataset.value||e.textContent.trim()),this.#r&&(this.#r.textContent=e.textContent.trim()),this.dispatchEvent(new CustomEvent("change",{detail:{value:e.dataset.value||e.textContent.trim(),text:e.textContent.trim()},bubbles:!0})),this.hide())}#c(){const t=this.getAttribute("position");if("up"===t||"down"===t)return t;const e=this.getBoundingClientRect(),i=window.innerHeight-e.bottom,n=Math.min(40*this.#s.length,16*parseInt(getComputedStyle(this).getPropertyValue("--options-max-height")||"15rem"));return i<n&&e.top>n?"up":"down"}show(){const t=this.#c();this.setAttribute("direction",t),this.setAttribute("aria-hidden","false"),this.#i.setAttribute("aria-expanded","true");const e=Array.from(this.#s).find((t=>"true"===t.getAttribute("aria-selected")));if(e){const t=Array.from(this.#s).indexOf(e);this.focusOption(t)}else this.#s.length>0&&this.focusOption(0);document.addEventListener("click",this.#t),document.addEventListener("keydown",this.#e)}hide(){this.setAttribute("aria-hidden","true"),this.#i.setAttribute("aria-expanded","false"),this.removeAttribute("direction"),this.#d=-1,document.removeEventListener("click",this.#t),document.removeEventListener("keydown",this.#e),this.#i.focus()}}class i extends HTMLElement{#e;#h;constructor(){super(),this.setAttribute("tabindex","0"),this.#e=this.#l.bind(this),this.#h=this.#a.bind(this)}connectedCallback(){if(!this.querySelector(".dropdown-caret")){const t=document.createElement("span");t.className="dropdown-caret",this.appendChild(t)}this.addEventListener("keydown",this.#e),this.addEventListener("click",this.#h)}disconnectedCallback(){this.removeEventListener("keydown",this.#e),this.removeEventListener("click",this.#h)}#l(t){"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),t.stopPropagation(),this.#u())}#a(t){this.#u()}#u(){const t=this.closest("dropdown-select");t&&"function"==typeof t.toggleDropdown&&t.toggleDropdown()}}class n extends HTMLElement{constructor(){super()}}class o extends HTMLElement{#h;constructor(){super(),this.#h=this.#a.bind(this)}connectedCallback(){this.addEventListener("click",this.#h)}disconnectedCallback(){this.removeEventListener("click",this.#h)}#a(t){t.preventDefault(),this.#p()}#p(){const t=this.closest("dropdown-select");t&&"function"==typeof t.selectOption&&t.selectOption({target:this})}}customElements.get("dropdown-select")||customElements.define("dropdown-select",e),customElements.get("dropdown-select-trigger")||customElements.define("dropdown-select-trigger",i),customElements.get("dropdown-options")||customElements.define("dropdown-options",n),customElements.get("dropdown-option")||customElements.define("dropdown-option",o),t.DropdownOption=o,t.DropdownOptions=n,t.DropdownSelect=e,t.DropdownSelectTrigger=i}));