1import{Controller}from"@hotwired/stimulus";const NO_MATCHES_MESSAGE="No matching options";export default class extends Controller{static targets=["container","input","hidden","results","option","helpText","caret","caretIcon"];static values={errorMessage:String};connect(){this.activeIndex=-1}disconnect(){clearTimeout(this.blurTimeout)}handleFocus(){this.filterOptions(),this.openResults()}handleInput(){this.clearServerErrorFlag(),this.filterOptions(),this.openResults(),this.setActiveIndex(-1)}handleBlur(t){this.element.contains(t.relatedTarget)||(this.blurTimeout=setTimeout(()=>{this.closeResults(),this.validateInput()},150))}toggleResults(){this.resultsTarget.classList.contains("mds-hidden")?(this.inputTarget.focus(),this.filterOptions(""),this.openResults()):this.closeResults()}selectOption(t){const e=t.target.closest('[data-combobox-target="option"]');e&&(clearTimeout(this.blurTimeout),this.applySelection(e),this.closeResults())}handleKeydown(t){const e=!this.resultsTarget.classList.contains("mds-hidden");switch(t.key){case"ArrowDown":t.preventDefault(),e||this.openResults(),this.moveActive(1);break;case"ArrowUp":t.preventDefault(),e||this.openResults(),this.moveActive(-1);break;case"Enter":if(!e)return;if(t.preventDefault(),this.activeIndex>=0){const t=this.visibleOptions()[this.activeIndex];t&&this.applySelection(t)}else this.validateInput();this.closeResults();break;case"Escape":this.closeResults()}}applySelection(t){this.clearServerErrorFlag();const e=t.dataset.id,s=t.dataset.label;this.inputTarget.value=s,this.hiddenTarget.value=e,this.optionTargets.forEach(e=>e.setAttribute("aria-selected",e===t?"true":"false")),this.clearError(),this.element.dispatchEvent(new CustomEvent("combobox:select",{bubbles:!0,detail:{id:e,label:s}}))}validateInput(){const t=this.inputTarget.value.trim();if(""===t&&!this.inputTarget.required)return this.hiddenTarget.value="",void this.clearError();const e=this.optionTargets.find(e=>this.matches(e,t));e?this.applySelection(e):this.showError()}matches(t,e){const s=e.toLowerCase();return t.dataset.label.toLowerCase()===s||t.dataset.id.toLowerCase()===s}showError(){this.hiddenTarget.value="",this.containerTarget.classList.add("error"),this.inputTarget.setAttribute("data-error-field",""),this.inputTarget.setAttribute("aria-invalid","true"),this.helpTextTarget.classList.add("mds-error"),this.helpTextTarget.dataset.serverErrors||(this.helpTextTarget.textContent=this.errorMessageValue)}clearServerErrorFlag(){delete this.helpTextTarget.dataset.serverErrors}clearError(){this.containerTarget.classList.remove("error"),this.inputTarget.removeAttribute("data-error-field"),this.inputTarget.setAttribute("aria-invalid","false"),this.helpTextTarget.classList.remove("mds-error"),this.helpTextTarget.dataset.serverErrors||(this.helpTextTarget.textContent="")}filterOptions(t){const e=(t??this.inputTarget.value).trim().toLowerCase();let s=0;return this.optionTargets.forEach(t=>{const i=!e||t.dataset.label.toLowerCase().includes(e)||t.dataset.id.toLowerCase().includes(e);t.classList.toggle("mds-hidden",!i),i&&s++}),this.announceMatchCount(s),s}announceMatchCount(t){this.containerTarget.classList.contains("error")||this.helpTextTarget.dataset.serverErrors||(this.helpTextTarget.textContent=0===t?NO_MATCHES_MESSAGE:"")}openResults(){this.resultsTarget.classList.remove("mds-hidden"),this.inputTarget.setAttribute("aria-expanded","true"),this.caretTarget.setAttribute("aria-label","Close options"),this.caretIconTarget.classList.add("mds-rotate-180")}closeResults(){this.resultsTarget.classList.add("mds-hidden"),this.inputTarget.setAttribute("aria-expanded","false"),this.caretTarget.setAttribute("aria-label","Open options"),this.caretIconTarget.classList.remove("mds-rotate-180"),this.setActiveIndex(-1)}moveActive(t){const e=this.visibleOptions();if(!e.length)return;const s=Math.max(-1,Math.min(e.length-1,this.activeIndex+t));this.setActiveIndex(s)}setActiveIndex(t){const e=this.visibleOptions();e.forEach((e,s)=>{e.classList.toggle("focused",s===t)}),this.activeIndex=t;const s=e[t];s?this.inputTarget.setAttribute("aria-activedescendant",s.id):this.inputTarget.removeAttribute("aria-activedescendant"),s?.scrollIntoView({block:"nearest"})}visibleOptions(){return this.optionTargets.filter(t=>!t.classList.contains("mds-hidden"))}}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.