@unabridged/midwest 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/app/assets/javascript/midwest/index.ts +2 -0
  2. package/app/assets/javascript/midwest.js +754 -97
  3. package/app/assets/javascript/midwest.js.map +1 -1
  4. package/app/assets/stylesheets/midwest.css +1 -1
  5. package/app/assets/stylesheets/midwest.tailwind.css +3 -1
  6. package/dist/css/midwest.css +1 -1
  7. package/dist/javascript/collection/app/assets/javascript/midwest/index.js +2 -0
  8. package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
  9. package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +17 -5
  10. package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js.map +1 -1
  11. package/dist/javascript/collection/app/components/midwest/form/autocomplete_component/autocomplete_component_controller.js +180 -92
  12. package/dist/javascript/collection/app/components/midwest/form/autocomplete_component/autocomplete_component_controller.js.map +1 -1
  13. package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js +12 -0
  14. package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js.map +1 -1
  15. package/dist/javascript/collection/app/components/midwest/image_component/color_thief.js +490 -0
  16. package/dist/javascript/collection/app/components/midwest/image_component/color_thief.js.map +1 -0
  17. package/dist/javascript/collection/app/components/midwest/image_component/image_component_controller.js +47 -0
  18. package/dist/javascript/collection/app/components/midwest/image_component/image_component_controller.js.map +1 -0
  19. package/dist/javascript/collection/app/components/midwest/tabs_component/tabs_component_controller.js +15 -1
  20. package/dist/javascript/collection/app/components/midwest/tabs_component/tabs_component_controller.js.map +1 -1
  21. package/dist/javascript/midwest.js +754 -97
  22. package/dist/javascript/midwest.js.map +1 -1
  23. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/autocomplete_component/autocomplete_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\ninterface Option {\n value: string\n label: string\n support?: string\n}\n\nexport default class Autocomplete extends Controller<HTMLElement> {\n static targets = ['input', 'dropdown', 'list', 'tokens', 'token', 'multipleTokenTemplate', 'singleTokenTemplate', 'status']\n static values = {\n options: { type: Array, default: [] },\n url: { type: String, default: '' },\n multiple: { type: Boolean, default: true }\n }\n\n declare readonly inputTarget: HTMLInputElement\n declare readonly dropdownTarget: HTMLElement\n declare readonly listTarget: HTMLElement\n declare readonly tokensTarget: HTMLElement\n declare readonly tokenTargets: HTMLElement[]\n declare readonly multipleTokenTemplateTarget: HTMLTemplateElement\n declare readonly singleTokenTemplateTarget: HTMLTemplateElement\n declare readonly statusTarget: HTMLElement\n declare readonly hasStatusTarget: boolean\n\n declare optionsValue: Option[]\n declare urlValue: string\n declare multipleValue: boolean\n\n private selectedValues = new Map<string, Option>()\n private highlightedIndex = -1\n private fetchAbort: AbortController | null = null\n\n connect () {\n this.loadInitialTokens()\n }\n\n disconnect () {\n this.fetchAbort?.abort()\n }\n\n // ── Public actions ─────────────────────────────────────────────────────────\n\n focusInput () {\n this.inputTarget.focus()\n this.open()\n }\n\n open () {\n if (this.dropdownTarget.matches(':popover-open')) return\n const query = this.inputTarget.value.trim()\n if (this.urlValue) {\n this.fetch(query)\n } else {\n this.renderOptions(this.filteredOptions(query))\n }\n }\n\n async search () {\n const query = this.inputTarget.value.trim()\n if (this.urlValue) {\n await this.fetch(query)\n } else {\n this.renderOptions(this.filteredOptions(query))\n }\n this.showDropdown()\n }\n\n navigate (event: KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault()\n if (!this.dropdownTarget.matches(':popover-open')) this.open()\n const items = this.visibleOptions()\n this.highlightedIndex = Math.min(this.highlightedIndex + 1, items.length - 1)\n this.syncHighlight(items)\n break\n }\n\n case 'ArrowUp': {\n event.preventDefault()\n const items = this.visibleOptions()\n this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0)\n this.syncHighlight(items)\n break\n }\n\n case 'Enter': {\n event.preventDefault()\n const items = this.visibleOptions()\n if (this.highlightedIndex >= 0 && items[this.highlightedIndex]) {\n this.pickItem(items[this.highlightedIndex])\n }\n break\n }\n\n case 'Escape':\n this.hideDropdown()\n break\n\n case 'Backspace':\n if (this.inputTarget.value === '' && this.multipleValue) {\n const entries = Array.from(this.selectedValues.keys())\n if (entries.length > 0) this.deselect(entries[entries.length - 1])\n }\n break\n }\n }\n\n private visibleOptions (): NodeListOf<HTMLElement> {\n return this.listTarget.querySelectorAll<HTMLElement>('.midwest-autocomplete-option:not([aria-selected=\"true\"])')\n }\n\n handleBlur () {\n // Delay to let mousedown on an option fire first.\n setTimeout(() => this.hideDropdown(), 150)\n }\n\n removeToken (event: MouseEvent) {\n event.stopPropagation()\n const btn = event.currentTarget as HTMLElement\n const value = btn.dataset.value\n if (value) this.deselect(value)\n }\n\n // ── Private ────────────────────────────────────────────────────────────────\n\n private get optionIdPrefix (): string {\n return `ac-opt-${(this.element.dataset.name ?? 'field').replace(/\\W/g, '-')}`\n }\n\n private loadInitialTokens () {\n this.tokenTargets.forEach(token => {\n const value = token.dataset.value ?? ''\n const label = token.querySelector('.value')?.textContent?.trim() ?? value\n this.selectedValues.set(value, { value, label })\n })\n }\n\n private filteredOptions (query: string): Option[] {\n const q = query.toLowerCase()\n return (this.optionsValue as Option[]).filter(\n o => q === '' || o.label.toLowerCase().includes(q) || (o.support?.toLowerCase().includes(q) ?? false)\n )\n }\n\n private async fetch (query: string) {\n this.fetchAbort?.abort()\n this.fetchAbort = new AbortController()\n\n this.showLoading()\n\n try {\n const url = new URL(this.urlValue, window.location.href)\n if (query) url.searchParams.set('q', query)\n\n const res = await globalThis.fetch(url.toString(), {\n signal: this.fetchAbort.signal,\n headers: { Accept: 'application/json' }\n })\n\n const data: Option[] = await res.json()\n this.renderOptions(data)\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n this.renderEmpty()\n }\n }\n }\n\n private select (option: Option) {\n if (!this.multipleValue) {\n // Clear any existing hidden inputs and tokens for single-select\n this.selectedValues.forEach((_, val) => this.removeTokenElement(val))\n this.selectedValues.clear()\n }\n\n this.selectedValues.set(option.value, option)\n this.appendToken(option)\n this.hideDropdown()\n this.inputTarget.value = ''\n this.inputTarget.focus()\n this.announce(`${option.label} selected`)\n\n this.dispatch('change', { detail: { value: option.value, label: option.label } })\n }\n\n private deselect (value: string) {\n const option = this.selectedValues.get(value)\n this.selectedValues.delete(value)\n this.removeTokenElement(value)\n if (option) this.announce(`${option.label} removed`)\n this.dispatch('change', { detail: { value: null } })\n }\n\n private appendToken (option: Option) {\n const name = this.element.dataset.name ?? ''\n\n if (this.multipleValue) {\n const fragment = this.multipleTokenTemplateTarget.content.cloneNode(true) as DocumentFragment\n const badge = fragment.querySelector<HTMLElement>('.midwest-badge')!\n badge.dataset.value = option.value\n badge.querySelector<HTMLElement>('.value')!.textContent = option.label\n const removeBtn = badge.querySelector<HTMLElement>('.remove')!\n removeBtn.dataset.value = option.value\n removeBtn.setAttribute('aria-label', `Remove ${option.label}`)\n const input = badge.querySelector<HTMLInputElement>('input[type=hidden]')!\n input.name = name\n input.value = option.value\n this.tokensTarget.appendChild(fragment)\n } else {\n this.tokensTarget.querySelectorAll<HTMLElement>('[data-value]').forEach(el => el.remove())\n const fragment = this.singleTokenTemplateTarget.content.cloneNode(true) as DocumentFragment\n const badge = fragment.querySelector<HTMLElement>('.midwest-badge')!\n badge.dataset.value = option.value\n badge.querySelector<HTMLElement>('.value')!.textContent = option.label\n const input = badge.querySelector<HTMLInputElement>('input[type=hidden]')!\n input.name = name\n input.value = option.value\n this.tokensTarget.appendChild(fragment)\n }\n }\n\n private removeTokenElement (value: string) {\n const token = this.tokensTarget.querySelector(`[data-value=\"${CSS.escape(value)}\"]`)\n token?.remove()\n }\n\n private renderOptions (options: Option[]) {\n this.listTarget.innerHTML = ''\n this.highlightedIndex = -1\n\n if (options.length === 0) {\n this.renderEmpty()\n return\n }\n\n options.forEach((option, index) => {\n const li = document.createElement('li')\n li.id = `${this.optionIdPrefix}-${index}`\n li.className = 'midwest-autocomplete-option'\n li.setAttribute('role', 'option')\n li.setAttribute('aria-selected', this.selectedValues.has(option.value) ? 'true' : 'false')\n li.dataset.value = option.value\n li.innerHTML = `\n <span class=\"midwest-autocomplete-option-label\">${this.escapeHtml(option.label)}</span>\n ${option.support ? `<span class=\"midwest-autocomplete-option-support\">${this.escapeHtml(option.support)}</span>` : ''}\n `\n li.addEventListener('mousedown', e => {\n e.preventDefault()\n this.select(option)\n })\n this.listTarget.appendChild(li)\n })\n\n const availableCount = options.filter(o => !this.selectedValues.has(o.value)).length\n if (availableCount === 0) {\n this.renderEmpty('No more options')\n return\n }\n this.announce(`${availableCount} option${availableCount === 1 ? '' : 's'} available`)\n this.showDropdown()\n }\n\n private renderEmpty (message = 'No results') {\n this.listTarget.innerHTML = `<li class=\"midwest-autocomplete-empty\" aria-hidden=\"true\">${this.escapeHtml(message)}</li>`\n this.announce(message)\n this.showDropdown()\n }\n\n private showLoading () {\n this.listTarget.innerHTML = '<li class=\"midwest-autocomplete-loading\" aria-hidden=\"true\">Loading…</li>'\n this.announce('Loading')\n this.showDropdown()\n }\n\n private showDropdown () {\n if (!this.dropdownTarget.matches(':popover-open')) this.dropdownTarget.showPopover()\n this.inputTarget.setAttribute('aria-expanded', 'true')\n }\n\n private hideDropdown () {\n if (this.dropdownTarget.matches(':popover-open')) this.dropdownTarget.hidePopover()\n this.inputTarget.setAttribute('aria-expanded', 'false')\n this.inputTarget.removeAttribute('aria-activedescendant')\n this.highlightedIndex = -1\n }\n\n private syncHighlight (items: NodeListOf<HTMLElement>) {\n items.forEach((item, i) => item.classList.toggle('is-highlighted', i === this.highlightedIndex))\n const active = items[this.highlightedIndex]\n active?.scrollIntoView({ block: 'nearest' })\n if (active) {\n this.inputTarget.setAttribute('aria-activedescendant', active.id)\n } else {\n this.inputTarget.removeAttribute('aria-activedescendant')\n }\n }\n\n private pickItem (item: HTMLElement) {\n const value = item.dataset.value ?? ''\n const label = item.querySelector('.midwest-autocomplete-option-label')?.textContent?.trim() ?? value\n const support = item.querySelector('.midwest-autocomplete-option-support')?.textContent?.trim()\n this.select({ value, label, support })\n }\n\n private announce (message: string) {\n if (this.hasStatusTarget) this.statusTarget.textContent = message\n }\n\n private escapeHtml (str: string): string {\n return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n }\n}\n"],"names":[],"mappings":";;AAQA,MAAqB,qBAAqB,UAAwB,CAAA;AAAA,EAChE,OAAO,OAAU,GAAA,CAAC,OAAS,EAAA,UAAA,EAAY,QAAQ,QAAU,EAAA,OAAA,EAAS,uBAAyB,EAAA,qBAAA,EAAuB,QAAQ,CAAA,CAAA;AAAA,EAC1H,OAAO,MAAS,GAAA;AAAA,IACd,SAAS,EAAE,IAAA,EAAM,KAAO,EAAA,OAAA,EAAS,EAAG,EAAA;AAAA,IACpC,GAAK,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,EAAG,EAAA;AAAA,IACjC,QAAU,EAAA,EAAE,IAAM,EAAA,OAAA,EAAS,SAAS,IAAK,EAAA;AAAA,GAC3C,CAAA;AAAA,EAgBQ,cAAA,uBAAqB,GAAoB,EAAA,CAAA;AAAA,EACzC,gBAAmB,GAAA,CAAA,CAAA,CAAA;AAAA,EACnB,UAAqC,GAAA,IAAA,CAAA;AAAA,EAE7C,OAAW,GAAA;AACT,IAAA,IAAA,CAAK,iBAAkB,EAAA,CAAA;AAAA,GACzB;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AAAA,GACzB;AAAA;AAAA,EAIA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAA,IAAA,CAAK,IAAK,EAAA,CAAA;AAAA,GACZ;AAAA,EAEA,IAAQ,GAAA;AACN,IAAI,IAAA,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,MAAA,OAAA;AAClD,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,WAAY,CAAA,KAAA,CAAM,IAAK,EAAA,CAAA;AAC1C,IAAA,IAAI,KAAK,QAAU,EAAA;AACjB,MAAA,IAAA,CAAK,MAAM,KAAK,CAAA,CAAA;AAAA,KACX,MAAA;AACL,MAAA,IAAA,CAAK,aAAc,CAAA,IAAA,CAAK,eAAgB,CAAA,KAAK,CAAC,CAAA,CAAA;AAAA,KAChD;AAAA,GACF;AAAA,EAEA,MAAM,MAAU,GAAA;AACd,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,WAAY,CAAA,KAAA,CAAM,IAAK,EAAA,CAAA;AAC1C,IAAA,IAAI,KAAK,QAAU,EAAA;AACjB,MAAM,MAAA,IAAA,CAAK,MAAM,KAAK,CAAA,CAAA;AAAA,KACjB,MAAA;AACL,MAAA,IAAA,CAAK,aAAc,CAAA,IAAA,CAAK,eAAgB,CAAA,KAAK,CAAC,CAAA,CAAA;AAAA,KAChD;AACA,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA,EAEA,SAAU,KAAsB,EAAA;AAC9B,IAAA,QAAQ,MAAM,GAAK;AAAA,MACjB,KAAK,WAAa,EAAA;AAChB,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,IAAI,CAAC,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,UAAA,IAAA,CAAK,IAAK,EAAA,CAAA;AAC7D,QAAM,MAAA,KAAA,GAAQ,KAAK,cAAe,EAAA,CAAA;AAClC,QAAK,IAAA,CAAA,gBAAA,GAAmB,KAAK,GAAI,CAAA,IAAA,CAAK,mBAAmB,CAAG,EAAA,KAAA,CAAM,SAAS,CAAC,CAAA,CAAA;AAC5E,QAAA,IAAA,CAAK,cAAc,KAAK,CAAA,CAAA;AACxB,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,SAAW,EAAA;AACd,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAM,MAAA,KAAA,GAAQ,KAAK,cAAe,EAAA,CAAA;AAClC,QAAA,IAAA,CAAK,mBAAmB,IAAK,CAAA,GAAA,CAAI,IAAK,CAAA,gBAAA,GAAmB,GAAG,CAAC,CAAA,CAAA;AAC7D,QAAA,IAAA,CAAK,cAAc,KAAK,CAAA,CAAA;AACxB,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,OAAS,EAAA;AACZ,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAM,MAAA,KAAA,GAAQ,KAAK,cAAe,EAAA,CAAA;AAClC,QAAA,IAAI,KAAK,gBAAoB,IAAA,CAAA,IAAK,KAAM,CAAA,IAAA,CAAK,gBAAgB,CAAG,EAAA;AAC9D,UAAA,IAAA,CAAK,QAAS,CAAA,KAAA,CAAM,IAAK,CAAA,gBAAgB,CAAC,CAAA,CAAA;AAAA,SAC5C;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAA;AACH,QAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAClB,QAAA,MAAA;AAAA,MAEF,KAAK,WAAA;AACH,QAAA,IAAI,IAAK,CAAA,WAAA,CAAY,KAAU,KAAA,EAAA,IAAM,KAAK,aAAe,EAAA;AACvD,UAAA,MAAM,UAAU,KAAM,CAAA,IAAA,CAAK,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA,CAAA;AACrD,UAAA,IAAI,QAAQ,MAAS,GAAA,CAAA;AAAG,YAAA,IAAA,CAAK,QAAS,CAAA,OAAA,CAAQ,OAAQ,CAAA,MAAA,GAAS,CAAC,CAAC,CAAA,CAAA;AAAA,SACnE;AACA,QAAA,MAAA;AAAA,KACJ;AAAA,GACF;AAAA,EAEQ,cAA2C,GAAA;AACjD,IAAO,OAAA,IAAA,CAAK,UAAW,CAAA,gBAAA,CAA8B,0DAA0D,CAAA,CAAA;AAAA,GACjH;AAAA,EAEA,UAAc,GAAA;AAEZ,IAAA,UAAA,CAAW,MAAM,IAAA,CAAK,YAAa,EAAA,EAAG,GAAG,CAAA,CAAA;AAAA,GAC3C;AAAA,EAEA,YAAa,KAAmB,EAAA;AAC9B,IAAA,KAAA,CAAM,eAAgB,EAAA,CAAA;AACtB,IAAA,MAAM,MAAM,KAAM,CAAA,aAAA,CAAA;AAClB,IAAM,MAAA,KAAA,GAAQ,IAAI,OAAQ,CAAA,KAAA,CAAA;AAC1B,IAAI,IAAA,KAAA;AAAO,MAAA,IAAA,CAAK,SAAS,KAAK,CAAA,CAAA;AAAA,GAChC;AAAA;AAAA,EAIA,IAAY,cAA0B,GAAA;AACpC,IAAO,OAAA,CAAA,OAAA,EAAA,CAAW,KAAK,OAAQ,CAAA,OAAA,CAAQ,QAAQ,OAAS,EAAA,OAAA,CAAQ,OAAO,GAAG,CAAA,CAAA,CAAA,CAAA;AAAA,GAC5E;AAAA,EAEQ,iBAAqB,GAAA;AAC3B,IAAK,IAAA,CAAA,YAAA,CAAa,QAAQ,CAAS,KAAA,KAAA;AACjC,MAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,OAAA,CAAQ,KAAS,IAAA,EAAA,CAAA;AACrC,MAAA,MAAM,QAAQ,KAAM,CAAA,aAAA,CAAc,QAAQ,CAAG,EAAA,WAAA,EAAa,MAAU,IAAA,KAAA,CAAA;AACpE,MAAA,IAAA,CAAK,eAAe,GAAI,CAAA,KAAA,EAAO,EAAE,KAAA,EAAO,OAAO,CAAA,CAAA;AAAA,KAChD,CAAA,CAAA;AAAA,GACH;AAAA,EAEQ,gBAAiB,KAAyB,EAAA;AAChD,IAAM,MAAA,CAAA,GAAI,MAAM,WAAY,EAAA,CAAA;AAC5B,IAAA,OAAQ,KAAK,YAA0B,CAAA,MAAA;AAAA,MACrC,OAAK,CAAM,KAAA,EAAA,IAAM,CAAE,CAAA,KAAA,CAAM,aAAc,CAAA,QAAA,CAAS,CAAC,CAAA,KAAM,EAAE,OAAS,EAAA,WAAA,EAAc,CAAA,QAAA,CAAS,CAAC,CAAK,IAAA,KAAA,CAAA;AAAA,KACjG,CAAA;AAAA,GACF;AAAA,EAEA,MAAc,MAAO,KAAe,EAAA;AAClC,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAK,IAAA,CAAA,UAAA,GAAa,IAAI,eAAgB,EAAA,CAAA;AAEtC,IAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAEjB,IAAI,IAAA;AACF,MAAA,MAAM,MAAM,IAAI,GAAA,CAAI,KAAK,QAAU,EAAA,MAAA,CAAO,SAAS,IAAI,CAAA,CAAA;AACvD,MAAI,IAAA,KAAA;AAAO,QAAI,GAAA,CAAA,YAAA,CAAa,GAAI,CAAA,GAAA,EAAK,KAAK,CAAA,CAAA;AAE1C,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,KAAM,CAAA,GAAA,CAAI,UAAY,EAAA;AAAA,QACjD,MAAA,EAAQ,KAAK,UAAW,CAAA,MAAA;AAAA,QACxB,OAAA,EAAS,EAAE,MAAA,EAAQ,kBAAmB,EAAA;AAAA,OACvC,CAAA,CAAA;AAED,MAAM,MAAA,IAAA,GAAiB,MAAM,GAAA,CAAI,IAAK,EAAA,CAAA;AACtC,MAAA,IAAA,CAAK,cAAc,IAAI,CAAA,CAAA;AAAA,aAChB,GAAP,EAAA;AACA,MAAK,IAAA,GAAA,CAAc,SAAS,YAAc,EAAA;AACxC,QAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,OACnB;AAAA,KACF;AAAA,GACF;AAAA,EAEQ,OAAQ,MAAgB,EAAA;AAC9B,IAAI,IAAA,CAAC,KAAK,aAAe,EAAA;AAEvB,MAAK,IAAA,CAAA,cAAA,CAAe,QAAQ,CAAC,CAAA,EAAG,QAAQ,IAAK,CAAA,kBAAA,CAAmB,GAAG,CAAC,CAAA,CAAA;AACpE,MAAA,IAAA,CAAK,eAAe,KAAM,EAAA,CAAA;AAAA,KAC5B;AAEA,IAAA,IAAA,CAAK,cAAe,CAAA,GAAA,CAAI,MAAO,CAAA,KAAA,EAAO,MAAM,CAAA,CAAA;AAC5C,IAAA,IAAA,CAAK,YAAY,MAAM,CAAA,CAAA;AACvB,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAClB,IAAA,IAAA,CAAK,YAAY,KAAQ,GAAA,EAAA,CAAA;AACzB,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAK,IAAA,CAAA,QAAA,CAAS,CAAG,EAAA,MAAA,CAAO,KAAgB,CAAA,SAAA,CAAA,CAAA,CAAA;AAExC,IAAA,IAAA,CAAK,QAAS,CAAA,QAAA,EAAU,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,MAAO,CAAA,KAAA,EAAO,KAAO,EAAA,MAAA,CAAO,KAAM,EAAA,EAAG,CAAA,CAAA;AAAA,GAClF;AAAA,EAEQ,SAAU,KAAe,EAAA;AAC/B,IAAA,MAAM,MAAS,GAAA,IAAA,CAAK,cAAe,CAAA,GAAA,CAAI,KAAK,CAAA,CAAA;AAC5C,IAAK,IAAA,CAAA,cAAA,CAAe,OAAO,KAAK,CAAA,CAAA;AAChC,IAAA,IAAA,CAAK,mBAAmB,KAAK,CAAA,CAAA;AAC7B,IAAI,IAAA,MAAA;AAAQ,MAAK,IAAA,CAAA,QAAA,CAAS,CAAG,EAAA,MAAA,CAAO,KAAe,CAAA,QAAA,CAAA,CAAA,CAAA;AACnD,IAAK,IAAA,CAAA,QAAA,CAAS,UAAU,EAAE,MAAA,EAAQ,EAAE,KAAO,EAAA,IAAA,IAAQ,CAAA,CAAA;AAAA,GACrD;AAAA,EAEQ,YAAa,MAAgB,EAAA;AACnC,IAAA,MAAM,IAAO,GAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,CAAQ,IAAQ,IAAA,EAAA,CAAA;AAE1C,IAAA,IAAI,KAAK,aAAe,EAAA;AACtB,MAAA,MAAM,QAAW,GAAA,IAAA,CAAK,2BAA4B,CAAA,OAAA,CAAQ,UAAU,IAAI,CAAA,CAAA;AACxE,MAAM,MAAA,KAAA,GAAQ,QAAS,CAAA,aAAA,CAA2B,gBAAgB,CAAA,CAAA;AAClE,MAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AAC7B,MAAA,KAAA,CAAM,aAA2B,CAAA,QAAQ,CAAG,CAAA,WAAA,GAAc,MAAO,CAAA,KAAA,CAAA;AACjE,MAAM,MAAA,SAAA,GAAY,KAAM,CAAA,aAAA,CAA2B,SAAS,CAAA,CAAA;AAC5D,MAAU,SAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AACjC,MAAA,SAAA,CAAU,YAAa,CAAA,YAAA,EAAc,CAAU,OAAA,EAAA,MAAA,CAAO,KAAO,CAAA,CAAA,CAAA,CAAA;AAC7D,MAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,aAAA,CAAgC,oBAAoB,CAAA,CAAA;AACxE,MAAA,KAAA,CAAM,IAAO,GAAA,IAAA,CAAA;AACb,MAAA,KAAA,CAAM,QAAQ,MAAO,CAAA,KAAA,CAAA;AACrB,MAAK,IAAA,CAAA,YAAA,CAAa,YAAY,QAAQ,CAAA,CAAA;AAAA,KACjC,MAAA;AACL,MAAK,IAAA,CAAA,YAAA,CAAa,iBAA8B,cAAc,CAAA,CAAE,QAAQ,CAAM,EAAA,KAAA,EAAA,CAAG,QAAQ,CAAA,CAAA;AACzF,MAAA,MAAM,QAAW,GAAA,IAAA,CAAK,yBAA0B,CAAA,OAAA,CAAQ,UAAU,IAAI,CAAA,CAAA;AACtE,MAAM,MAAA,KAAA,GAAQ,QAAS,CAAA,aAAA,CAA2B,gBAAgB,CAAA,CAAA;AAClE,MAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AAC7B,MAAA,KAAA,CAAM,aAA2B,CAAA,QAAQ,CAAG,CAAA,WAAA,GAAc,MAAO,CAAA,KAAA,CAAA;AACjE,MAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,aAAA,CAAgC,oBAAoB,CAAA,CAAA;AACxE,MAAA,KAAA,CAAM,IAAO,GAAA,IAAA,CAAA;AACb,MAAA,KAAA,CAAM,QAAQ,MAAO,CAAA,KAAA,CAAA;AACrB,MAAK,IAAA,CAAA,YAAA,CAAa,YAAY,QAAQ,CAAA,CAAA;AAAA,KACxC;AAAA,GACF;AAAA,EAEQ,mBAAoB,KAAe,EAAA;AACzC,IAAM,MAAA,KAAA,GAAQ,KAAK,YAAa,CAAA,aAAA,CAAc,gBAAgB,GAAI,CAAA,MAAA,CAAO,KAAK,CAAK,CAAA,EAAA,CAAA,CAAA,CAAA;AACnF,IAAA,KAAA,EAAO,MAAO,EAAA,CAAA;AAAA,GAChB;AAAA,EAEQ,cAAe,OAAmB,EAAA;AACxC,IAAA,IAAA,CAAK,WAAW,SAAY,GAAA,EAAA,CAAA;AAC5B,IAAA,IAAA,CAAK,gBAAmB,GAAA,CAAA,CAAA,CAAA;AAExB,IAAI,IAAA,OAAA,CAAQ,WAAW,CAAG,EAAA;AACxB,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AACjB,MAAA,OAAA;AAAA,KACF;AAEA,IAAQ,OAAA,CAAA,OAAA,CAAQ,CAAC,MAAA,EAAQ,KAAU,KAAA;AACjC,MAAM,MAAA,EAAA,GAAK,QAAS,CAAA,aAAA,CAAc,IAAI,CAAA,CAAA;AACtC,MAAG,EAAA,CAAA,EAAA,GAAK,CAAG,EAAA,IAAA,CAAK,cAAkB,CAAA,CAAA,EAAA,KAAA,CAAA,CAAA,CAAA;AAClC,MAAA,EAAA,CAAG,SAAY,GAAA,6BAAA,CAAA;AACf,MAAG,EAAA,CAAA,YAAA,CAAa,QAAQ,QAAQ,CAAA,CAAA;AAChC,MAAG,EAAA,CAAA,YAAA,CAAa,iBAAiB,IAAK,CAAA,cAAA,CAAe,IAAI,MAAO,CAAA,KAAK,CAAI,GAAA,MAAA,GAAS,OAAO,CAAA,CAAA;AACzF,MAAG,EAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AAC1B,MAAA,EAAA,CAAG,SAAY,GAAA,CAAA;AAAA,wDACqC,EAAA,IAAA,CAAK,UAAW,CAAA,MAAA,CAAO,KAAK,CAAA,CAAA;AAAA,QAAA,EAC5E,OAAO,OAAU,GAAA,CAAA,kDAAA,EAAqD,KAAK,UAAW,CAAA,MAAA,CAAO,OAAO,CAAa,CAAA,OAAA,CAAA,GAAA,EAAA,CAAA;AAAA,MAAA,CAAA,CAAA;AAErH,MAAG,EAAA,CAAA,gBAAA,CAAiB,aAAa,CAAK,CAAA,KAAA;AACpC,QAAA,CAAA,CAAE,cAAe,EAAA,CAAA;AACjB,QAAA,IAAA,CAAK,OAAO,MAAM,CAAA,CAAA;AAAA,OACnB,CAAA,CAAA;AACD,MAAK,IAAA,CAAA,UAAA,CAAW,YAAY,EAAE,CAAA,CAAA;AAAA,KAC/B,CAAA,CAAA;AAED,IAAM,MAAA,cAAA,GAAiB,OAAQ,CAAA,MAAA,CAAO,CAAK,CAAA,KAAA,CAAC,IAAK,CAAA,cAAA,CAAe,GAAI,CAAA,CAAA,CAAE,KAAK,CAAC,CAAE,CAAA,MAAA,CAAA;AAC9E,IAAA,IAAI,mBAAmB,CAAG,EAAA;AACxB,MAAA,IAAA,CAAK,YAAY,iBAAiB,CAAA,CAAA;AAClC,MAAA,OAAA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,SAAS,CAAG,EAAA,cAAA,CAAA,OAAA,EAAwB,cAAmB,KAAA,CAAA,GAAI,KAAK,GAAe,CAAA,UAAA,CAAA,CAAA,CAAA;AACpF,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA,EAEQ,WAAA,CAAa,UAAU,YAAc,EAAA;AAC3C,IAAA,IAAA,CAAK,UAAW,CAAA,SAAA,GAAY,CAA6D,0DAAA,EAAA,IAAA,CAAK,WAAW,OAAO,CAAA,CAAA,KAAA,CAAA,CAAA;AAChH,IAAA,IAAA,CAAK,SAAS,OAAO,CAAA,CAAA;AACrB,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA,EAEQ,WAAe,GAAA;AACrB,IAAA,IAAA,CAAK,WAAW,SAAY,GAAA,gFAAA,CAAA;AAC5B,IAAA,IAAA,CAAK,SAAS,SAAS,CAAA,CAAA;AACvB,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA,EAEQ,YAAgB,GAAA;AACtB,IAAA,IAAI,CAAC,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,MAAA,IAAA,CAAK,eAAe,WAAY,EAAA,CAAA;AACnF,IAAK,IAAA,CAAA,WAAA,CAAY,YAAa,CAAA,eAAA,EAAiB,MAAM,CAAA,CAAA;AAAA,GACvD;AAAA,EAEQ,YAAgB,GAAA;AACtB,IAAI,IAAA,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,MAAA,IAAA,CAAK,eAAe,WAAY,EAAA,CAAA;AAClF,IAAK,IAAA,CAAA,WAAA,CAAY,YAAa,CAAA,eAAA,EAAiB,OAAO,CAAA,CAAA;AACtD,IAAK,IAAA,CAAA,WAAA,CAAY,gBAAgB,uBAAuB,CAAA,CAAA;AACxD,IAAA,IAAA,CAAK,gBAAmB,GAAA,CAAA,CAAA,CAAA;AAAA,GAC1B;AAAA,EAEQ,cAAe,KAAgC,EAAA;AACrD,IAAM,KAAA,CAAA,OAAA,CAAQ,CAAC,IAAA,EAAM,CAAM,KAAA,IAAA,CAAK,SAAU,CAAA,MAAA,CAAO,gBAAkB,EAAA,CAAA,KAAM,IAAK,CAAA,gBAAgB,CAAC,CAAA,CAAA;AAC/F,IAAM,MAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA;AAC1C,IAAA,MAAA,EAAQ,cAAe,CAAA,EAAE,KAAO,EAAA,SAAA,EAAW,CAAA,CAAA;AAC3C,IAAA,IAAI,MAAQ,EAAA;AACV,MAAA,IAAA,CAAK,WAAY,CAAA,YAAA,CAAa,uBAAyB,EAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAAA,KAC3D,MAAA;AACL,MAAK,IAAA,CAAA,WAAA,CAAY,gBAAgB,uBAAuB,CAAA,CAAA;AAAA,KAC1D;AAAA,GACF;AAAA,EAEQ,SAAU,IAAmB,EAAA;AACnC,IAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,OAAA,CAAQ,KAAS,IAAA,EAAA,CAAA;AACpC,IAAA,MAAM,QAAQ,IAAK,CAAA,aAAA,CAAc,oCAAoC,CAAG,EAAA,WAAA,EAAa,MAAU,IAAA,KAAA,CAAA;AAC/F,IAAA,MAAM,UAAU,IAAK,CAAA,aAAA,CAAc,sCAAsC,CAAA,EAAG,aAAa,IAAK,EAAA,CAAA;AAC9F,IAAA,IAAA,CAAK,MAAO,CAAA,EAAE,KAAO,EAAA,KAAA,EAAO,SAAS,CAAA,CAAA;AAAA,GACvC;AAAA,EAEQ,SAAU,OAAiB,EAAA;AACjC,IAAA,IAAI,IAAK,CAAA,eAAA;AAAiB,MAAA,IAAA,CAAK,aAAa,WAAc,GAAA,OAAA,CAAA;AAAA,GAC5D;AAAA,EAEQ,WAAY,GAAqB,EAAA;AACvC,IAAA,OAAO,GAAI,CAAA,OAAA,CAAQ,IAAM,EAAA,OAAO,EAAE,OAAQ,CAAA,IAAA,EAAM,MAAM,CAAA,CAAE,QAAQ,IAAM,EAAA,MAAM,CAAE,CAAA,OAAA,CAAQ,MAAM,QAAQ,CAAA,CAAA;AAAA,GACtG;AACF;;;;"}
1
+ {"version":3,"file":"autocomplete_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/autocomplete_component/autocomplete_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\ninterface Option {\n value: string\n label: string\n support?: string\n}\n\nexport default class Autocomplete extends Controller<HTMLElement> {\n static targets = ['input', 'dropdown', 'list', 'tokens', 'multipleTokenTemplate', 'singleTokenTemplate', 'status', 'turboList', 'loader']\n static values = {\n options: { type: Array, default: [] },\n url: { type: String, default: '' },\n multiple: { type: Boolean, default: true },\n turboFrameUrl: { type: String, default: '' }\n }\n\n declare readonly inputTarget: HTMLInputElement\n declare readonly dropdownTarget: HTMLElement\n declare readonly listTarget: HTMLElement\n declare readonly hasListTarget: boolean\n declare readonly tokensTarget: HTMLElement\n declare readonly multipleTokenTemplateTarget: HTMLTemplateElement\n declare readonly singleTokenTemplateTarget: HTMLTemplateElement\n declare readonly statusTarget: HTMLElement\n declare readonly hasStatusTarget: boolean\n declare readonly turboListTarget: HTMLElement\n declare readonly hasTurboListTarget: boolean\n declare readonly loaderTarget: HTMLElement\n declare readonly hasLoaderTarget: boolean\n\n declare optionsValue: Option[]\n declare urlValue: string\n declare multipleValue: boolean\n declare turboFrameUrlValue: string\n\n private highlightedIndex = -1\n private fetchAbort: AbortController | null = null\n private searchTimer: number | undefined\n\n // ── Named handlers ─────────────────────────────────────────────────────────\n // Arrow-function class properties preserve `this` and produce a stable\n // reference so addEventListener/removeEventListener pairs always match.\n\n private onFrameLoad = () => {\n // syncSelectedState marks already-selected items as aria-selected=\"true\" (CSS hides them).\n // We hide the loader only after that DOM update so the brief flash of selected items\n // is covered by the overlay and never visible to the user.\n this.syncSelectedState()\n this.loading = false\n this.showDropdown()\n }\n\n private onToggle = (e: Event) => {\n const opened = (e as ToggleEvent).newState === 'open'\n this.inputTarget.setAttribute('aria-expanded', String(opened))\n if (!opened) {\n this.inputTarget.removeAttribute('aria-activedescendant')\n this.highlightedIndex = -1\n }\n }\n\n private onFocusOut = (e: FocusEvent) => {\n if (!this.element.contains(e.relatedTarget as Node)) {\n this.hideDropdown()\n }\n }\n\n private onListMouseDown = (e: MouseEvent) => {\n const option = (e.target as HTMLElement).closest<HTMLElement>('.midwest-autocomplete-option')\n if (option) { e.preventDefault(); this.pickItem(option) }\n }\n\n // ── Lifecycle ───────────────────────────────────────────────────────────────\n\n connect () {\n // focusout is on the controller root — not a target — so it lives here.\n this.element.addEventListener('focusout', this.onFocusOut)\n }\n\n disconnect () {\n this.fetchAbort?.abort()\n clearTimeout(this.searchTimer)\n this.element.removeEventListener('focusout', this.onFocusOut)\n }\n\n // Target callbacks — Stimulus calls these automatically when targets connect\n // or disconnect, including after the initial connect(). This replaces manual\n // hasTurboListTarget guards and addEventListener calls inside connect().\n\n dropdownTargetConnected (el: HTMLElement) {\n el.addEventListener('toggle', this.onToggle)\n }\n\n dropdownTargetDisconnected (el: HTMLElement) {\n el.removeEventListener('toggle', this.onToggle)\n }\n\n listTargetConnected (el: HTMLElement) {\n // Single delegated listener for client-rendered options.\n el.addEventListener('mousedown', this.onListMouseDown)\n }\n\n listTargetDisconnected (el: HTMLElement) {\n el.removeEventListener('mousedown', this.onListMouseDown)\n }\n\n turboListTargetConnected (el: HTMLElement) {\n el.addEventListener('turbo:frame-load', this.onFrameLoad)\n }\n\n turboListTargetDisconnected (el: HTMLElement) {\n el.removeEventListener('turbo:frame-load', this.onFrameLoad)\n }\n\n // ── Public actions ──────────────────────────────────────────────────────────\n\n focusInput () {\n this.inputTarget.focus()\n this.open()\n }\n\n open () {\n if (this.dropdownTarget.matches(':popover-open')) return\n // Cancel any pending debounced search so open() always shows results immediately.\n clearTimeout(this.searchTimer)\n this.resolve(this.inputTarget.value.trim())\n }\n\n search () {\n const query = this.inputTarget.value.trim()\n\n // Static options filter instantly — no debounce needed.\n if (!this.hasTurboListTarget && !this.urlValue) {\n this.renderOptions(this.filteredOptions(query))\n return\n }\n\n // Debounce network requests so only the final keystroke fires.\n clearTimeout(this.searchTimer)\n this.searchTimer = window.setTimeout(() => {\n this.searchTimer = undefined\n this.resolve(query)\n }, 200)\n }\n\n navigate (event: KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown': {\n event.preventDefault()\n if (!this.dropdownTarget.matches(':popover-open')) this.open()\n const items = this.visibleOptions()\n this.highlightedIndex = Math.min(this.highlightedIndex + 1, items.length - 1)\n this.syncHighlight(items)\n break\n }\n\n case 'ArrowUp': {\n event.preventDefault()\n if (!this.dropdownTarget.matches(':popover-open')) break\n const items = this.visibleOptions()\n this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0)\n this.syncHighlight(items)\n break\n }\n\n case 'Enter': {\n event.preventDefault()\n if (!this.dropdownTarget.matches(':popover-open')) break\n const items = this.visibleOptions()\n if (this.highlightedIndex >= 0 && items[this.highlightedIndex]) {\n this.pickItem(items[this.highlightedIndex])\n }\n break\n }\n\n case 'Escape':\n this.hideDropdown()\n break\n\n case 'Backspace':\n if (this.inputTarget.value === '' && this.multipleValue) {\n const tokens = this.tokensTarget.querySelectorAll<HTMLElement>('[data-value]')\n const last = tokens[tokens.length - 1]\n if (last?.dataset.value) this.deselect(last.dataset.value)\n }\n break\n }\n }\n\n removeToken (event: MouseEvent) {\n event.stopPropagation()\n const btn = event.currentTarget as HTMLElement\n const value = btn.dataset.value\n if (value) this.deselect(value)\n }\n\n // Public action used by turbo-frame option items via data-action.\n // Each server-rendered <li> should have:\n // data-action=\"mousedown->midwest-autocomplete#selectOption\"\n selectOption (event: MouseEvent) {\n event.preventDefault()\n this.pickItem(event.currentTarget as HTMLElement)\n }\n\n // ── Private ─────────────────────────────────────────────────────────────────\n\n private get optionIdPrefix (): string {\n return `ac-opt-${(this.element.dataset.name ?? 'field').replace(/\\W/g, '-')}`\n }\n\n private isSelected (value: string): boolean {\n return !!this.tokensTarget.querySelector(`[data-value=\"${CSS.escape(value)}\"]`)\n }\n\n // Routes to the correct data source. Shared by open() and the debounced search path.\n private resolve (query: string) {\n if (this.hasTurboListTarget) { this.navigateFrame(query); return }\n if (this.urlValue) { this.fetch(query); return }\n this.renderOptions(this.filteredOptions(query))\n }\n\n private filteredOptions (query: string): Option[] {\n const q = query.toLowerCase()\n return (this.optionsValue as Option[]).filter(\n o => q === '' || o.label.toLowerCase().includes(q) || (o.support?.toLowerCase().includes(q) ?? false)\n )\n }\n\n private navigateFrame (query: string) {\n const url = new URL(this.turboFrameUrlValue, window.location.href)\n if (query) url.searchParams.set('q', query)\n // Send already-selected values so the server can exclude duplicates.\n this.tokensTarget.querySelectorAll<HTMLInputElement>('input[type=hidden]').forEach(input => {\n url.searchParams.append('selected[]', input.value)\n })\n this.loading = true\n this.turboListTarget.setAttribute('src', url.toString())\n this.showDropdown()\n }\n\n // After a turbo frame loads, mark already-selected items and update the live region.\n // The empty state element is always present in the frame and CSS shows/hides it\n // based on whether any non-selected options exist.\n private syncSelectedState () {\n const options = this.turboListTarget.querySelectorAll<HTMLElement>('.midwest-autocomplete-option')\n options.forEach(option => {\n const val = option.dataset.value ?? ''\n option.setAttribute('aria-selected', this.isSelected(val) ? 'true' : 'false')\n })\n\n const visibleCount = this.visibleOptions().length\n this.announce(visibleCount > 0 ? `${visibleCount} option${visibleCount === 1 ? '' : 's'} available` : 'No more options')\n }\n\n private async fetch (query: string) {\n this.fetchAbort?.abort()\n this.fetchAbort = new AbortController()\n\n this.listTarget.replaceChildren()\n this.loading = true\n this.announce('Loading')\n this.showDropdown()\n\n try {\n const url = new URL(this.urlValue, window.location.href)\n if (query) url.searchParams.set('q', query)\n\n const res = await globalThis.fetch(url.toString(), {\n signal: this.fetchAbort.signal,\n headers: { Accept: 'application/json' }\n })\n\n const data: Option[] = await res.json()\n this.renderOptions(data)\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n this.renderEmpty()\n }\n }\n }\n\n private select (option: Option) {\n this.appendToken(option)\n this.hideDropdown()\n this.inputTarget.value = ''\n this.inputTarget.focus()\n this.announce(`${option.label} selected`)\n\n this.dispatch('change', { detail: { value: option.value, label: option.label } })\n }\n\n private deselect (value: string) {\n const token = this.tokensTarget.querySelector(`[data-value=\"${CSS.escape(value)}\"]`)\n const label = token?.querySelector('.value')?.textContent?.trim()\n token?.remove()\n if (label) this.announce(`${label} removed`)\n this.dispatch('change', { detail: { value: null } })\n }\n\n private appendToken (option: Option) {\n if (!this.multipleValue) {\n this.tokensTarget.querySelectorAll<HTMLElement>('[data-value]').forEach(el => el.remove())\n }\n const template = this.multipleValue ? this.multipleTokenTemplateTarget : this.singleTokenTemplateTarget\n const fragment = template.content.cloneNode(true) as DocumentFragment\n const badge = fragment.querySelector<HTMLElement>('.midwest-badge')\n if (!badge) return\n badge.dataset.value = option.value\n const valueEl = badge.querySelector<HTMLElement>('.value')\n if (valueEl) valueEl.textContent = option.label\n if (this.multipleValue) {\n const removeBtn = badge.querySelector<HTMLElement>('.remove')\n if (removeBtn) {\n removeBtn.dataset.value = option.value\n removeBtn.setAttribute('aria-label', `Remove ${option.label}`)\n }\n }\n const input = badge.querySelector<HTMLInputElement>('input[type=hidden]')\n if (input) {\n input.name = this.element.dataset.name ?? ''\n input.value = option.value\n }\n this.tokensTarget.appendChild(fragment)\n }\n\n private renderOptions (options: Option[]) {\n this.highlightedIndex = -1\n\n if (options.length === 0) {\n this.renderEmpty()\n return\n }\n\n this.listTarget.replaceChildren()\n\n options.forEach((option, index) => {\n const li = document.createElement('li')\n li.id = `${this.optionIdPrefix}-${index}`\n li.className = 'midwest-autocomplete-option'\n li.setAttribute('role', 'option')\n li.setAttribute('aria-selected', this.isSelected(option.value) ? 'true' : 'false')\n li.dataset.value = option.value\n\n const label = document.createElement('span')\n label.className = 'midwest-autocomplete-option-label'\n label.textContent = option.label\n li.appendChild(label)\n\n if (option.support) {\n const support = document.createElement('span')\n support.className = 'midwest-autocomplete-option-support'\n support.textContent = option.support\n li.appendChild(support)\n }\n\n this.listTarget.appendChild(li)\n })\n\n const availableCount = options.filter(o => !this.isSelected(o.value)).length\n if (availableCount === 0) {\n this.renderEmpty('No more options')\n return\n }\n this.loading = false\n this.announce(`${availableCount} option${availableCount === 1 ? '' : 's'} available`)\n this.showDropdown()\n }\n\n private renderEmpty (message = 'No results') {\n const li = document.createElement('li')\n li.className = 'midwest-autocomplete-empty'\n li.setAttribute('aria-hidden', 'true')\n li.textContent = message\n this.listTarget.replaceChildren(li)\n this.loading = false\n this.announce(message)\n this.showDropdown()\n }\n\n private set loading (on: boolean) {\n if (this.hasLoaderTarget) this.loaderTarget.hidden = !on\n }\n\n private showDropdown () {\n if (!this.dropdownTarget.matches(':popover-open')) this.dropdownTarget.showPopover()\n }\n\n private hideDropdown () {\n if (this.dropdownTarget.matches(':popover-open')) this.dropdownTarget.hidePopover()\n }\n\n private visibleOptions (): NodeListOf<HTMLElement> {\n const container = this.hasTurboListTarget ? this.turboListTarget : this.listTarget\n return container.querySelectorAll<HTMLElement>('.midwest-autocomplete-option:not([aria-selected=\"true\"])')\n }\n\n private syncHighlight (items: NodeListOf<HTMLElement>) {\n items.forEach((item, i) => item.classList.toggle('is-highlighted', i === this.highlightedIndex))\n const active = items[this.highlightedIndex]\n active?.scrollIntoView({ block: 'nearest' })\n if (active?.id) {\n this.inputTarget.setAttribute('aria-activedescendant', active.id)\n } else {\n this.inputTarget.removeAttribute('aria-activedescendant')\n }\n }\n\n private pickItem (item: HTMLElement) {\n const value = item.dataset.value ?? ''\n // Prefer data-label (set by AutocompleteOptionComponent) so rich slot content\n // like avatars does not corrupt the badge text via textContent.\n const label = item.dataset.label?.trim() || item.querySelector('.midwest-autocomplete-option-label')?.textContent?.trim() || value\n const support = item.querySelector('.midwest-autocomplete-option-support')?.textContent?.trim()\n this.select({ value, label, support })\n }\n\n private announce (message: string) {\n if (this.hasStatusTarget) this.statusTarget.textContent = message\n }\n}\n"],"names":[],"mappings":";;AAQA,MAAqB,qBAAqB,UAAwB,CAAA;AAAA,EAChE,OAAO,OAAU,GAAA,CAAC,OAAS,EAAA,UAAA,EAAY,MAAQ,EAAA,QAAA,EAAU,uBAAyB,EAAA,qBAAA,EAAuB,QAAU,EAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAAA,EACxI,OAAO,MAAS,GAAA;AAAA,IACd,SAAS,EAAE,IAAA,EAAM,KAAO,EAAA,OAAA,EAAS,EAAG,EAAA;AAAA,IACpC,GAAK,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,EAAG,EAAA;AAAA,IACjC,QAAU,EAAA,EAAE,IAAM,EAAA,OAAA,EAAS,SAAS,IAAK,EAAA;AAAA,IACzC,aAAe,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,EAAG,EAAA;AAAA,GAC7C,CAAA;AAAA,EAqBQ,gBAAmB,GAAA,CAAA,CAAA,CAAA;AAAA,EACnB,UAAqC,GAAA,IAAA,CAAA;AAAA,EACrC,WAAA,CAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,MAAM;AAI1B,IAAA,IAAA,CAAK,iBAAkB,EAAA,CAAA;AACvB,IAAA,IAAA,CAAK,OAAU,GAAA,KAAA,CAAA;AACf,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB,CAAA;AAAA,EAEQ,QAAA,GAAW,CAAC,CAAa,KAAA;AAC/B,IAAM,MAAA,MAAA,GAAU,EAAkB,QAAa,KAAA,MAAA,CAAA;AAC/C,IAAA,IAAA,CAAK,WAAY,CAAA,YAAA,CAAa,eAAiB,EAAA,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAC7D,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAK,IAAA,CAAA,WAAA,CAAY,gBAAgB,uBAAuB,CAAA,CAAA;AACxD,MAAA,IAAA,CAAK,gBAAmB,GAAA,CAAA,CAAA,CAAA;AAAA,KAC1B;AAAA,GACF,CAAA;AAAA,EAEQ,UAAA,GAAa,CAAC,CAAkB,KAAA;AACtC,IAAA,IAAI,CAAC,IAAK,CAAA,OAAA,CAAQ,QAAS,CAAA,CAAA,CAAE,aAAqB,CAAG,EAAA;AACnD,MAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,KACpB;AAAA,GACF,CAAA;AAAA,EAEQ,eAAA,GAAkB,CAAC,CAAkB,KAAA;AAC3C,IAAA,MAAM,MAAU,GAAA,CAAA,CAAE,MAAuB,CAAA,OAAA,CAAqB,8BAA8B,CAAA,CAAA;AAC5F,IAAA,IAAI,MAAQ,EAAA;AAAE,MAAA,CAAA,CAAE,cAAe,EAAA,CAAA;AAAG,MAAA,IAAA,CAAK,SAAS,MAAM,CAAA,CAAA;AAAA,KAAE;AAAA,GAC1D,CAAA;AAAA;AAAA,EAIA,OAAW,GAAA;AAET,IAAA,IAAA,CAAK,OAAQ,CAAA,gBAAA,CAAiB,UAAY,EAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,GAC3D;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAA,YAAA,CAAa,KAAK,WAAW,CAAA,CAAA;AAC7B,IAAA,IAAA,CAAK,OAAQ,CAAA,mBAAA,CAAoB,UAAY,EAAA,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,GAC9D;AAAA;AAAA;AAAA;AAAA,EAMA,wBAAyB,EAAiB,EAAA;AACxC,IAAG,EAAA,CAAA,gBAAA,CAAiB,QAAU,EAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,GAC7C;AAAA,EAEA,2BAA4B,EAAiB,EAAA;AAC3C,IAAG,EAAA,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,QAAQ,CAAA,CAAA;AAAA,GAChD;AAAA,EAEA,oBAAqB,EAAiB,EAAA;AAEpC,IAAG,EAAA,CAAA,gBAAA,CAAiB,WAAa,EAAA,IAAA,CAAK,eAAe,CAAA,CAAA;AAAA,GACvD;AAAA,EAEA,uBAAwB,EAAiB,EAAA;AACvC,IAAG,EAAA,CAAA,mBAAA,CAAoB,WAAa,EAAA,IAAA,CAAK,eAAe,CAAA,CAAA;AAAA,GAC1D;AAAA,EAEA,yBAA0B,EAAiB,EAAA;AACzC,IAAG,EAAA,CAAA,gBAAA,CAAiB,kBAAoB,EAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AAAA,GAC1D;AAAA,EAEA,4BAA6B,EAAiB,EAAA;AAC5C,IAAG,EAAA,CAAA,mBAAA,CAAoB,kBAAoB,EAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AAAA,GAC7D;AAAA;AAAA,EAIA,UAAc,GAAA;AACZ,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAA,IAAA,CAAK,IAAK,EAAA,CAAA;AAAA,GACZ;AAAA,EAEA,IAAQ,GAAA;AACN,IAAI,IAAA,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,MAAA,OAAA;AAElD,IAAA,YAAA,CAAa,KAAK,WAAW,CAAA,CAAA;AAC7B,IAAA,IAAA,CAAK,OAAQ,CAAA,IAAA,CAAK,WAAY,CAAA,KAAA,CAAM,MAAM,CAAA,CAAA;AAAA,GAC5C;AAAA,EAEA,MAAU,GAAA;AACR,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,WAAY,CAAA,KAAA,CAAM,IAAK,EAAA,CAAA;AAG1C,IAAA,IAAI,CAAC,IAAA,CAAK,kBAAsB,IAAA,CAAC,KAAK,QAAU,EAAA;AAC9C,MAAA,IAAA,CAAK,aAAc,CAAA,IAAA,CAAK,eAAgB,CAAA,KAAK,CAAC,CAAA,CAAA;AAC9C,MAAA,OAAA;AAAA,KACF;AAGA,IAAA,YAAA,CAAa,KAAK,WAAW,CAAA,CAAA;AAC7B,IAAK,IAAA,CAAA,WAAA,GAAc,MAAO,CAAA,UAAA,CAAW,MAAM;AACzC,MAAA,IAAA,CAAK,WAAc,GAAA,KAAA,CAAA,CAAA;AACnB,MAAA,IAAA,CAAK,QAAQ,KAAK,CAAA,CAAA;AAAA,OACjB,GAAG,CAAA,CAAA;AAAA,GACR;AAAA,EAEA,SAAU,KAAsB,EAAA;AAC9B,IAAA,QAAQ,MAAM,GAAK;AAAA,MACjB,KAAK,WAAa,EAAA;AAChB,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,IAAI,CAAC,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,UAAA,IAAA,CAAK,IAAK,EAAA,CAAA;AAC7D,QAAM,MAAA,KAAA,GAAQ,KAAK,cAAe,EAAA,CAAA;AAClC,QAAK,IAAA,CAAA,gBAAA,GAAmB,KAAK,GAAI,CAAA,IAAA,CAAK,mBAAmB,CAAG,EAAA,KAAA,CAAM,SAAS,CAAC,CAAA,CAAA;AAC5E,QAAA,IAAA,CAAK,cAAc,KAAK,CAAA,CAAA;AACxB,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,SAAW,EAAA;AACd,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,IAAI,CAAC,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,UAAA,MAAA;AACnD,QAAM,MAAA,KAAA,GAAQ,KAAK,cAAe,EAAA,CAAA;AAClC,QAAA,IAAA,CAAK,mBAAmB,IAAK,CAAA,GAAA,CAAI,IAAK,CAAA,gBAAA,GAAmB,GAAG,CAAC,CAAA,CAAA;AAC7D,QAAA,IAAA,CAAK,cAAc,KAAK,CAAA,CAAA;AACxB,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,OAAS,EAAA;AACZ,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,QAAA,IAAI,CAAC,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,UAAA,MAAA;AACnD,QAAM,MAAA,KAAA,GAAQ,KAAK,cAAe,EAAA,CAAA;AAClC,QAAA,IAAI,KAAK,gBAAoB,IAAA,CAAA,IAAK,KAAM,CAAA,IAAA,CAAK,gBAAgB,CAAG,EAAA;AAC9D,UAAA,IAAA,CAAK,QAAS,CAAA,KAAA,CAAM,IAAK,CAAA,gBAAgB,CAAC,CAAA,CAAA;AAAA,SAC5C;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAA;AACH,QAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAClB,QAAA,MAAA;AAAA,MAEF,KAAK,WAAA;AACH,QAAA,IAAI,IAAK,CAAA,WAAA,CAAY,KAAU,KAAA,EAAA,IAAM,KAAK,aAAe,EAAA;AACvD,UAAA,MAAM,MAAS,GAAA,IAAA,CAAK,YAAa,CAAA,gBAAA,CAA8B,cAAc,CAAA,CAAA;AAC7E,UAAA,MAAM,IAAO,GAAA,MAAA,CAAO,MAAO,CAAA,MAAA,GAAS,CAAC,CAAA,CAAA;AACrC,UAAA,IAAI,MAAM,OAAQ,CAAA,KAAA;AAAO,YAAK,IAAA,CAAA,QAAA,CAAS,IAAK,CAAA,OAAA,CAAQ,KAAK,CAAA,CAAA;AAAA,SAC3D;AACA,QAAA,MAAA;AAAA,KACJ;AAAA,GACF;AAAA,EAEA,YAAa,KAAmB,EAAA;AAC9B,IAAA,KAAA,CAAM,eAAgB,EAAA,CAAA;AACtB,IAAA,MAAM,MAAM,KAAM,CAAA,aAAA,CAAA;AAClB,IAAM,MAAA,KAAA,GAAQ,IAAI,OAAQ,CAAA,KAAA,CAAA;AAC1B,IAAI,IAAA,KAAA;AAAO,MAAA,IAAA,CAAK,SAAS,KAAK,CAAA,CAAA;AAAA,GAChC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAc,KAAmB,EAAA;AAC/B,IAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,IAAK,IAAA,CAAA,QAAA,CAAS,MAAM,aAA4B,CAAA,CAAA;AAAA,GAClD;AAAA;AAAA,EAIA,IAAY,cAA0B,GAAA;AACpC,IAAO,OAAA,CAAA,OAAA,EAAA,CAAW,KAAK,OAAQ,CAAA,OAAA,CAAQ,QAAQ,OAAS,EAAA,OAAA,CAAQ,OAAO,GAAG,CAAA,CAAA,CAAA,CAAA;AAAA,GAC5E;AAAA,EAEQ,WAAY,KAAwB,EAAA;AAC1C,IAAO,OAAA,CAAC,CAAC,IAAK,CAAA,YAAA,CAAa,cAAc,CAAgB,aAAA,EAAA,GAAA,CAAI,MAAO,CAAA,KAAK,CAAK,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,GAChF;AAAA;AAAA,EAGQ,QAAS,KAAe,EAAA;AAC9B,IAAA,IAAI,KAAK,kBAAoB,EAAA;AAAE,MAAA,IAAA,CAAK,cAAc,KAAK,CAAA,CAAA;AAAG,MAAA,OAAA;AAAA,KAAO;AACjE,IAAA,IAAI,KAAK,QAAU,EAAA;AAAE,MAAA,IAAA,CAAK,MAAM,KAAK,CAAA,CAAA;AAAG,MAAA,OAAA;AAAA,KAAO;AAC/C,IAAA,IAAA,CAAK,aAAc,CAAA,IAAA,CAAK,eAAgB,CAAA,KAAK,CAAC,CAAA,CAAA;AAAA,GAChD;AAAA,EAEQ,gBAAiB,KAAyB,EAAA;AAChD,IAAM,MAAA,CAAA,GAAI,MAAM,WAAY,EAAA,CAAA;AAC5B,IAAA,OAAQ,KAAK,YAA0B,CAAA,MAAA;AAAA,MACrC,OAAK,CAAM,KAAA,EAAA,IAAM,CAAE,CAAA,KAAA,CAAM,aAAc,CAAA,QAAA,CAAS,CAAC,CAAA,KAAM,EAAE,OAAS,EAAA,WAAA,EAAc,CAAA,QAAA,CAAS,CAAC,CAAK,IAAA,KAAA,CAAA;AAAA,KACjG,CAAA;AAAA,GACF;AAAA,EAEQ,cAAe,KAAe,EAAA;AACpC,IAAA,MAAM,MAAM,IAAI,GAAA,CAAI,KAAK,kBAAoB,EAAA,MAAA,CAAO,SAAS,IAAI,CAAA,CAAA;AACjE,IAAI,IAAA,KAAA;AAAO,MAAI,GAAA,CAAA,YAAA,CAAa,GAAI,CAAA,GAAA,EAAK,KAAK,CAAA,CAAA;AAE1C,IAAA,IAAA,CAAK,YAAa,CAAA,gBAAA,CAAmC,oBAAoB,CAAA,CAAE,QAAQ,CAAS,KAAA,KAAA;AAC1F,MAAA,GAAA,CAAI,YAAa,CAAA,MAAA,CAAO,YAAc,EAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AAAA,KAClD,CAAA,CAAA;AACD,IAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AACf,IAAA,IAAA,CAAK,eAAgB,CAAA,YAAA,CAAa,KAAO,EAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AACvD,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAqB,GAAA;AAC3B,IAAA,MAAM,OAAU,GAAA,IAAA,CAAK,eAAgB,CAAA,gBAAA,CAA8B,8BAA8B,CAAA,CAAA;AACjG,IAAA,OAAA,CAAQ,QAAQ,CAAU,MAAA,KAAA;AACxB,MAAM,MAAA,GAAA,GAAM,MAAO,CAAA,OAAA,CAAQ,KAAS,IAAA,EAAA,CAAA;AACpC,MAAA,MAAA,CAAO,aAAa,eAAiB,EAAA,IAAA,CAAK,WAAW,GAAG,CAAA,GAAI,SAAS,OAAO,CAAA,CAAA;AAAA,KAC7E,CAAA,CAAA;AAED,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,cAAA,EAAiB,CAAA,MAAA,CAAA;AAC3C,IAAK,IAAA,CAAA,QAAA,CAAS,eAAe,CAAI,GAAA,CAAA,EAAG,sBAAsB,YAAiB,KAAA,CAAA,GAAI,EAAK,GAAA,GAAA,CAAA,UAAA,CAAA,GAAkB,iBAAiB,CAAA,CAAA;AAAA,GACzH;AAAA,EAEA,MAAc,MAAO,KAAe,EAAA;AAClC,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAK,IAAA,CAAA,UAAA,GAAa,IAAI,eAAgB,EAAA,CAAA;AAEtC,IAAA,IAAA,CAAK,WAAW,eAAgB,EAAA,CAAA;AAChC,IAAA,IAAA,CAAK,OAAU,GAAA,IAAA,CAAA;AACf,IAAA,IAAA,CAAK,SAAS,SAAS,CAAA,CAAA;AACvB,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAElB,IAAI,IAAA;AACF,MAAA,MAAM,MAAM,IAAI,GAAA,CAAI,KAAK,QAAU,EAAA,MAAA,CAAO,SAAS,IAAI,CAAA,CAAA;AACvD,MAAI,IAAA,KAAA;AAAO,QAAI,GAAA,CAAA,YAAA,CAAa,GAAI,CAAA,GAAA,EAAK,KAAK,CAAA,CAAA;AAE1C,MAAA,MAAM,MAAM,MAAM,UAAA,CAAW,KAAM,CAAA,GAAA,CAAI,UAAY,EAAA;AAAA,QACjD,MAAA,EAAQ,KAAK,UAAW,CAAA,MAAA;AAAA,QACxB,OAAA,EAAS,EAAE,MAAA,EAAQ,kBAAmB,EAAA;AAAA,OACvC,CAAA,CAAA;AAED,MAAM,MAAA,IAAA,GAAiB,MAAM,GAAA,CAAI,IAAK,EAAA,CAAA;AACtC,MAAA,IAAA,CAAK,cAAc,IAAI,CAAA,CAAA;AAAA,aAChB,GAAP,EAAA;AACA,MAAK,IAAA,GAAA,CAAc,SAAS,YAAc,EAAA;AACxC,QAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AAAA,OACnB;AAAA,KACF;AAAA,GACF;AAAA,EAEQ,OAAQ,MAAgB,EAAA;AAC9B,IAAA,IAAA,CAAK,YAAY,MAAM,CAAA,CAAA;AACvB,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAClB,IAAA,IAAA,CAAK,YAAY,KAAQ,GAAA,EAAA,CAAA;AACzB,IAAA,IAAA,CAAK,YAAY,KAAM,EAAA,CAAA;AACvB,IAAK,IAAA,CAAA,QAAA,CAAS,CAAG,EAAA,MAAA,CAAO,KAAgB,CAAA,SAAA,CAAA,CAAA,CAAA;AAExC,IAAA,IAAA,CAAK,QAAS,CAAA,QAAA,EAAU,EAAE,MAAA,EAAQ,EAAE,KAAA,EAAO,MAAO,CAAA,KAAA,EAAO,KAAO,EAAA,MAAA,CAAO,KAAM,EAAA,EAAG,CAAA,CAAA;AAAA,GAClF;AAAA,EAEQ,SAAU,KAAe,EAAA;AAC/B,IAAM,MAAA,KAAA,GAAQ,KAAK,YAAa,CAAA,aAAA,CAAc,gBAAgB,GAAI,CAAA,MAAA,CAAO,KAAK,CAAK,CAAA,EAAA,CAAA,CAAA,CAAA;AACnF,IAAA,MAAM,QAAQ,KAAO,EAAA,aAAA,CAAc,QAAQ,CAAA,EAAG,aAAa,IAAK,EAAA,CAAA;AAChE,IAAA,KAAA,EAAO,MAAO,EAAA,CAAA;AACd,IAAI,IAAA,KAAA;AAAO,MAAK,IAAA,CAAA,QAAA,CAAS,GAAG,KAAe,CAAA,QAAA,CAAA,CAAA,CAAA;AAC3C,IAAK,IAAA,CAAA,QAAA,CAAS,UAAU,EAAE,MAAA,EAAQ,EAAE,KAAO,EAAA,IAAA,IAAQ,CAAA,CAAA;AAAA,GACrD;AAAA,EAEQ,YAAa,MAAgB,EAAA;AACnC,IAAI,IAAA,CAAC,KAAK,aAAe,EAAA;AACvB,MAAK,IAAA,CAAA,YAAA,CAAa,iBAA8B,cAAc,CAAA,CAAE,QAAQ,CAAM,EAAA,KAAA,EAAA,CAAG,QAAQ,CAAA,CAAA;AAAA,KAC3F;AACA,IAAA,MAAM,QAAW,GAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAK,8BAA8B,IAAK,CAAA,yBAAA,CAAA;AAC9E,IAAA,MAAM,QAAW,GAAA,QAAA,CAAS,OAAQ,CAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAChD,IAAM,MAAA,KAAA,GAAQ,QAAS,CAAA,aAAA,CAA2B,gBAAgB,CAAA,CAAA;AAClE,IAAA,IAAI,CAAC,KAAA;AAAO,MAAA,OAAA;AACZ,IAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AAC7B,IAAM,MAAA,OAAA,GAAU,KAAM,CAAA,aAAA,CAA2B,QAAQ,CAAA,CAAA;AACzD,IAAI,IAAA,OAAA;AAAS,MAAA,OAAA,CAAQ,cAAc,MAAO,CAAA,KAAA,CAAA;AAC1C,IAAA,IAAI,KAAK,aAAe,EAAA;AACtB,MAAM,MAAA,SAAA,GAAY,KAAM,CAAA,aAAA,CAA2B,SAAS,CAAA,CAAA;AAC5D,MAAA,IAAI,SAAW,EAAA;AACb,QAAU,SAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AACjC,QAAA,SAAA,CAAU,YAAa,CAAA,YAAA,EAAc,CAAU,OAAA,EAAA,MAAA,CAAO,KAAO,CAAA,CAAA,CAAA,CAAA;AAAA,OAC/D;AAAA,KACF;AACA,IAAM,MAAA,KAAA,GAAQ,KAAM,CAAA,aAAA,CAAgC,oBAAoB,CAAA,CAAA;AACxE,IAAA,IAAI,KAAO,EAAA;AACT,MAAA,KAAA,CAAM,IAAO,GAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,CAAQ,IAAQ,IAAA,EAAA,CAAA;AAC1C,MAAA,KAAA,CAAM,QAAQ,MAAO,CAAA,KAAA,CAAA;AAAA,KACvB;AACA,IAAK,IAAA,CAAA,YAAA,CAAa,YAAY,QAAQ,CAAA,CAAA;AAAA,GACxC;AAAA,EAEQ,cAAe,OAAmB,EAAA;AACxC,IAAA,IAAA,CAAK,gBAAmB,GAAA,CAAA,CAAA,CAAA;AAExB,IAAI,IAAA,OAAA,CAAQ,WAAW,CAAG,EAAA;AACxB,MAAA,IAAA,CAAK,WAAY,EAAA,CAAA;AACjB,MAAA,OAAA;AAAA,KACF;AAEA,IAAA,IAAA,CAAK,WAAW,eAAgB,EAAA,CAAA;AAEhC,IAAQ,OAAA,CAAA,OAAA,CAAQ,CAAC,MAAA,EAAQ,KAAU,KAAA;AACjC,MAAM,MAAA,EAAA,GAAK,QAAS,CAAA,aAAA,CAAc,IAAI,CAAA,CAAA;AACtC,MAAG,EAAA,CAAA,EAAA,GAAK,CAAG,EAAA,IAAA,CAAK,cAAkB,CAAA,CAAA,EAAA,KAAA,CAAA,CAAA,CAAA;AAClC,MAAA,EAAA,CAAG,SAAY,GAAA,6BAAA,CAAA;AACf,MAAG,EAAA,CAAA,YAAA,CAAa,QAAQ,QAAQ,CAAA,CAAA;AAChC,MAAG,EAAA,CAAA,YAAA,CAAa,iBAAiB,IAAK,CAAA,UAAA,CAAW,OAAO,KAAK,CAAA,GAAI,SAAS,OAAO,CAAA,CAAA;AACjF,MAAG,EAAA,CAAA,OAAA,CAAQ,QAAQ,MAAO,CAAA,KAAA,CAAA;AAE1B,MAAM,MAAA,KAAA,GAAQ,QAAS,CAAA,aAAA,CAAc,MAAM,CAAA,CAAA;AAC3C,MAAA,KAAA,CAAM,SAAY,GAAA,mCAAA,CAAA;AAClB,MAAA,KAAA,CAAM,cAAc,MAAO,CAAA,KAAA,CAAA;AAC3B,MAAA,EAAA,CAAG,YAAY,KAAK,CAAA,CAAA;AAEpB,MAAA,IAAI,OAAO,OAAS,EAAA;AAClB,QAAM,MAAA,OAAA,GAAU,QAAS,CAAA,aAAA,CAAc,MAAM,CAAA,CAAA;AAC7C,QAAA,OAAA,CAAQ,SAAY,GAAA,qCAAA,CAAA;AACpB,QAAA,OAAA,CAAQ,cAAc,MAAO,CAAA,OAAA,CAAA;AAC7B,QAAA,EAAA,CAAG,YAAY,OAAO,CAAA,CAAA;AAAA,OACxB;AAEA,MAAK,IAAA,CAAA,UAAA,CAAW,YAAY,EAAE,CAAA,CAAA;AAAA,KAC/B,CAAA,CAAA;AAED,IAAM,MAAA,cAAA,GAAiB,OAAQ,CAAA,MAAA,CAAO,CAAK,CAAA,KAAA,CAAC,KAAK,UAAW,CAAA,CAAA,CAAE,KAAK,CAAC,CAAE,CAAA,MAAA,CAAA;AACtE,IAAA,IAAI,mBAAmB,CAAG,EAAA;AACxB,MAAA,IAAA,CAAK,YAAY,iBAAiB,CAAA,CAAA;AAClC,MAAA,OAAA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,OAAU,GAAA,KAAA,CAAA;AACf,IAAA,IAAA,CAAK,SAAS,CAAG,EAAA,cAAA,CAAA,OAAA,EAAwB,cAAmB,KAAA,CAAA,GAAI,KAAK,GAAe,CAAA,UAAA,CAAA,CAAA,CAAA;AACpF,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA,EAEQ,WAAA,CAAa,UAAU,YAAc,EAAA;AAC3C,IAAM,MAAA,EAAA,GAAK,QAAS,CAAA,aAAA,CAAc,IAAI,CAAA,CAAA;AACtC,IAAA,EAAA,CAAG,SAAY,GAAA,4BAAA,CAAA;AACf,IAAG,EAAA,CAAA,YAAA,CAAa,eAAe,MAAM,CAAA,CAAA;AACrC,IAAA,EAAA,CAAG,WAAc,GAAA,OAAA,CAAA;AACjB,IAAK,IAAA,CAAA,UAAA,CAAW,gBAAgB,EAAE,CAAA,CAAA;AAClC,IAAA,IAAA,CAAK,OAAU,GAAA,KAAA,CAAA;AACf,IAAA,IAAA,CAAK,SAAS,OAAO,CAAA,CAAA;AACrB,IAAA,IAAA,CAAK,YAAa,EAAA,CAAA;AAAA,GACpB;AAAA,EAEA,IAAY,QAAS,EAAa,EAAA;AAChC,IAAA,IAAI,IAAK,CAAA,eAAA;AAAiB,MAAK,IAAA,CAAA,YAAA,CAAa,SAAS,CAAC,EAAA,CAAA;AAAA,GACxD;AAAA,EAEQ,YAAgB,GAAA;AACtB,IAAA,IAAI,CAAC,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,MAAA,IAAA,CAAK,eAAe,WAAY,EAAA,CAAA;AAAA,GACrF;AAAA,EAEQ,YAAgB,GAAA;AACtB,IAAI,IAAA,IAAA,CAAK,cAAe,CAAA,OAAA,CAAQ,eAAe,CAAA;AAAG,MAAA,IAAA,CAAK,eAAe,WAAY,EAAA,CAAA;AAAA,GACpF;AAAA,EAEQ,cAA2C,GAAA;AACjD,IAAA,MAAM,SAAY,GAAA,IAAA,CAAK,kBAAqB,GAAA,IAAA,CAAK,kBAAkB,IAAK,CAAA,UAAA,CAAA;AACxE,IAAO,OAAA,SAAA,CAAU,iBAA8B,0DAA0D,CAAA,CAAA;AAAA,GAC3G;AAAA,EAEQ,cAAe,KAAgC,EAAA;AACrD,IAAM,KAAA,CAAA,OAAA,CAAQ,CAAC,IAAA,EAAM,CAAM,KAAA,IAAA,CAAK,SAAU,CAAA,MAAA,CAAO,gBAAkB,EAAA,CAAA,KAAM,IAAK,CAAA,gBAAgB,CAAC,CAAA,CAAA;AAC/F,IAAM,MAAA,MAAA,GAAS,KAAM,CAAA,IAAA,CAAK,gBAAgB,CAAA,CAAA;AAC1C,IAAA,MAAA,EAAQ,cAAe,CAAA,EAAE,KAAO,EAAA,SAAA,EAAW,CAAA,CAAA;AAC3C,IAAA,IAAI,QAAQ,EAAI,EAAA;AACd,MAAA,IAAA,CAAK,WAAY,CAAA,YAAA,CAAa,uBAAyB,EAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAAA,KAC3D,MAAA;AACL,MAAK,IAAA,CAAA,WAAA,CAAY,gBAAgB,uBAAuB,CAAA,CAAA;AAAA,KAC1D;AAAA,GACF;AAAA,EAEQ,SAAU,IAAmB,EAAA;AACnC,IAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,OAAA,CAAQ,KAAS,IAAA,EAAA,CAAA;AAGpC,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,OAAQ,CAAA,KAAA,EAAO,IAAK,EAAA,IAAK,IAAK,CAAA,aAAA,CAAc,oCAAoC,CAAA,EAAG,WAAa,EAAA,IAAA,EAAU,IAAA,KAAA,CAAA;AAC7H,IAAA,MAAM,UAAU,IAAK,CAAA,aAAA,CAAc,sCAAsC,CAAA,EAAG,aAAa,IAAK,EAAA,CAAA;AAC9F,IAAA,IAAA,CAAK,MAAO,CAAA,EAAE,KAAO,EAAA,KAAA,EAAO,SAAS,CAAA,CAAA;AAAA,GACvC;AAAA,EAEQ,SAAU,OAAiB,EAAA;AACjC,IAAA,IAAI,IAAK,CAAA,eAAA;AAAiB,MAAA,IAAA,CAAK,aAAa,WAAc,GAAA,OAAA,CAAA;AAAA,GAC5D;AACF;;;;"}
@@ -13,10 +13,12 @@ class FormLiveSummary extends Controller {
13
13
  this.render();
14
14
  this.form?.addEventListener("input", this.render);
15
15
  this.form?.addEventListener("change", this.render);
16
+ this.form?.addEventListener("midwest-autocomplete:change", this.render);
16
17
  }
17
18
  disconnect() {
18
19
  this.form?.removeEventListener("input", this.render);
19
20
  this.form?.removeEventListener("change", this.render);
21
+ this.form?.removeEventListener("midwest-autocomplete:change", this.render);
20
22
  }
21
23
  get form() {
22
24
  return this.element.closest("form");
@@ -99,6 +101,16 @@ class FormLiveSummary extends Controller {
99
101
  value: element.value
100
102
  });
101
103
  });
104
+ form.querySelectorAll(".midwest-autocomplete").forEach((ac) => {
105
+ if (this.element.contains(ac))
106
+ return;
107
+ if (!ac.querySelector('[role="combobox"]'))
108
+ return;
109
+ const labelEl = ac.querySelector("label");
110
+ const label = labelEl?.textContent?.trim() || this.prettifyName((ac.dataset.name ?? "").replace(/\[.*\]$/, ""));
111
+ const selected = Array.from(ac.querySelectorAll(".midwest-autocomplete-tokens .value")).map((el) => el.textContent?.trim()).filter(Boolean).join(", ");
112
+ fields.push({ label, value: selected || "\u2014" });
113
+ });
102
114
  return fields;
103
115
  }
104
116
  // Finds the label associated with a specific element via `for` attribute,
@@ -1 +1 @@
1
- {"version":3,"file":"live_summary_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/live_summary_component/live_summary_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Input types that should never appear in a form live summary.\nconst SKIPPED_INPUT_TYPES = new Set([\n 'hidden', 'submit', 'reset', 'button', 'image'\n])\n\ninterface FieldSummary {\n label: string\n value: string\n}\n\nexport default class FormLiveSummary extends Controller<HTMLElement> {\n static targets = ['list']\n\n declare readonly listTarget: HTMLElement\n\n connect () {\n this.render()\n this.form?.addEventListener('input', this.render)\n this.form?.addEventListener('change', this.render)\n }\n\n disconnect () {\n this.form?.removeEventListener('input', this.render)\n this.form?.removeEventListener('change', this.render)\n }\n\n private get form (): HTMLFormElement | null {\n return this.element.closest('form')\n }\n\n private render = () => {\n const fields = this.collectFields()\n\n if (fields.length === 0) {\n this.listTarget.replaceChildren(\n Object.assign(document.createElement('p'), {\n className: 'midwest-form-live-summary-empty',\n textContent: 'No values to display.'\n })\n )\n return\n }\n\n const dl = document.createElement('dl')\n dl.className = 'midwest-form-live-summary-list'\n\n fields.forEach(({ label, value }) => {\n const dt = Object.assign(document.createElement('dt'), {\n className: 'midwest-form-live-summary-term',\n textContent: label\n })\n const dd = Object.assign(document.createElement('dd'), {\n className: 'midwest-form-live-summary-definition',\n textContent: value || '—'\n })\n dl.append(dt, dd)\n })\n\n this.listTarget.replaceChildren(dl)\n }\n\n private collectFields (): FieldSummary[] {\n const form = this.form\n if (!form) return []\n\n const fields: FieldSummary[] = []\n const seenRadioNames = new Set<string>()\n\n Array.from(form.elements).forEach(el => {\n const element = el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n\n if (!element.name) return\n\n // Skip elements that live inside the summary itself.\n if (this.element.contains(element)) return\n\n // Skip all button elements regardless of how they are declared.\n if (element instanceof HTMLButtonElement) return\n\n if (element instanceof HTMLInputElement) {\n if (SKIPPED_INPUT_TYPES.has(element.type)) return\n\n if (element.type === 'radio') {\n if (seenRadioNames.has(element.name)) return\n seenRadioNames.add(element.name)\n\n const checked = form.querySelector<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${CSS.escape(element.name)}\"]:checked`\n )\n if (!checked) return\n\n fields.push({\n label: this.groupLabelFor(element),\n value: this.labelFor(checked) || checked.value\n })\n return\n }\n\n if (element.type === 'checkbox') {\n fields.push({\n label: this.labelFor(element),\n value: element.checked ? 'Yes' : 'No'\n })\n return\n }\n }\n\n if (element instanceof HTMLSelectElement) {\n fields.push({\n label: this.labelFor(element),\n value: Array.from(element.selectedOptions).map(o => o.text).join(', ') || '—'\n })\n return\n }\n\n // Text-like inputs and textareas only reach this point.\n fields.push({\n label: this.labelFor(element),\n value: element.value\n })\n })\n\n return fields\n }\n\n // Finds the label associated with a specific element via `for` attribute,\n // wrapping label, or falls back to a prettified version of the element name.\n private labelFor (el: Element): string {\n const id = (el as HTMLElement).id\n if (id) {\n const label = this.form?.querySelector(`label[for=\"${CSS.escape(id)}\"]`)\n if (label) return label.textContent?.trim() ?? ''\n }\n const wrapper = el.closest('label')\n if (wrapper) return wrapper.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // For radio groups, prefer the containing fieldset legend over the\n // individual radio's label, then fall back to prettifying the name.\n private groupLabelFor (el: Element): string {\n const legend = el.closest('fieldset')?.querySelector('legend')\n if (legend) return legend.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // Converts \"user[first_name]\" or \"first_name\" into \"First name\".\n private prettifyName (name: string): string {\n return name\n .replace(/\\[.*?\\]/g, '')\n .replace(/_/g, ' ')\n .replace(/^\\w/, c => c.toUpperCase())\n .trim()\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"live_summary_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/live_summary_component/live_summary_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Input types that should never appear in a form live summary.\nconst SKIPPED_INPUT_TYPES = new Set([\n 'hidden', 'submit', 'reset', 'button', 'image'\n])\n\ninterface FieldSummary {\n label: string\n value: string\n}\n\nexport default class FormLiveSummary extends Controller<HTMLElement> {\n static targets = ['list']\n\n declare readonly listTarget: HTMLElement\n\n connect () {\n this.render()\n this.form?.addEventListener('input', this.render)\n this.form?.addEventListener('change', this.render)\n this.form?.addEventListener('midwest-autocomplete:change', this.render)\n }\n\n disconnect () {\n this.form?.removeEventListener('input', this.render)\n this.form?.removeEventListener('change', this.render)\n this.form?.removeEventListener('midwest-autocomplete:change', this.render)\n }\n\n private get form (): HTMLFormElement | null {\n return this.element.closest('form')\n }\n\n private render = () => {\n const fields = this.collectFields()\n\n if (fields.length === 0) {\n this.listTarget.replaceChildren(\n Object.assign(document.createElement('p'), {\n className: 'midwest-form-live-summary-empty',\n textContent: 'No values to display.'\n })\n )\n return\n }\n\n const dl = document.createElement('dl')\n dl.className = 'midwest-form-live-summary-list'\n\n fields.forEach(({ label, value }) => {\n const dt = Object.assign(document.createElement('dt'), {\n className: 'midwest-form-live-summary-term',\n textContent: label\n })\n const dd = Object.assign(document.createElement('dd'), {\n className: 'midwest-form-live-summary-definition',\n textContent: value || '—'\n })\n dl.append(dt, dd)\n })\n\n this.listTarget.replaceChildren(dl)\n }\n\n private collectFields (): FieldSummary[] {\n const form = this.form\n if (!form) return []\n\n const fields: FieldSummary[] = []\n const seenRadioNames = new Set<string>()\n\n Array.from(form.elements).forEach(el => {\n const element = el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n\n if (!element.name) return\n\n // Skip elements that live inside the summary itself.\n if (this.element.contains(element)) return\n\n // Skip all button elements regardless of how they are declared.\n if (element instanceof HTMLButtonElement) return\n\n if (element instanceof HTMLInputElement) {\n if (SKIPPED_INPUT_TYPES.has(element.type)) return\n\n if (element.type === 'radio') {\n if (seenRadioNames.has(element.name)) return\n seenRadioNames.add(element.name)\n\n const checked = form.querySelector<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${CSS.escape(element.name)}\"]:checked`\n )\n if (!checked) return\n\n fields.push({\n label: this.groupLabelFor(element),\n value: this.labelFor(checked) || checked.value\n })\n return\n }\n\n if (element.type === 'checkbox') {\n fields.push({\n label: this.labelFor(element),\n value: element.checked ? 'Yes' : 'No'\n })\n return\n }\n }\n\n if (element instanceof HTMLSelectElement) {\n fields.push({\n label: this.labelFor(element),\n value: Array.from(element.selectedOptions).map(o => o.text).join(', ') || '—'\n })\n return\n }\n\n // Text-like inputs and textareas only reach this point.\n fields.push({\n label: this.labelFor(element),\n value: element.value\n })\n })\n\n // Autocomplete components use a nameless combobox input + hidden inputs —\n // neither surfaces through the standard form.elements loop. Query them\n // separately so their selected badge labels appear in the summary.\n // Note: labelFor(input) doesn't work here because InputComponent assigns\n // its own id to the <input>, which won't match the <label>'s for attribute.\n form.querySelectorAll<HTMLElement>('.midwest-autocomplete').forEach(ac => {\n if (this.element.contains(ac)) return\n if (!ac.querySelector('[role=\"combobox\"]')) return\n\n const labelEl = ac.querySelector<HTMLElement>('label')\n const label = labelEl?.textContent?.trim() ||\n this.prettifyName((ac.dataset.name ?? '').replace(/\\[.*\\]$/, ''))\n\n const selected = Array.from(ac.querySelectorAll<HTMLElement>('.midwest-autocomplete-tokens .value'))\n .map(el => el.textContent?.trim())\n .filter(Boolean)\n .join(', ')\n fields.push({ label, value: selected || '—' })\n })\n\n return fields\n }\n\n // Finds the label associated with a specific element via `for` attribute,\n // wrapping label, or falls back to a prettified version of the element name.\n private labelFor (el: Element): string {\n const id = (el as HTMLElement).id\n if (id) {\n const label = this.form?.querySelector(`label[for=\"${CSS.escape(id)}\"]`)\n if (label) return label.textContent?.trim() ?? ''\n }\n const wrapper = el.closest('label')\n if (wrapper) return wrapper.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // For radio groups, prefer the containing fieldset legend over the\n // individual radio's label, then fall back to prettifying the name.\n private groupLabelFor (el: Element): string {\n const legend = el.closest('fieldset')?.querySelector('legend')\n if (legend) return legend.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // Converts \"user[first_name]\" or \"first_name\" into \"First name\".\n private prettifyName (name: string): string {\n return name\n .replace(/\\[.*?\\]/g, '')\n .replace(/_/g, ' ')\n .replace(/^\\w/, c => c.toUpperCase())\n .trim()\n }\n}\n"],"names":[],"mappings":"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"}