forge-select 0.1.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.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/index.cjs +753 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +132 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.global.js +751 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +726 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
- package/styles/forge-select.css +253 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/emitter.ts","../src/i18n.ts","../src/ForgeSelect.ts"],"sourcesContent":["export { default } from \"./ForgeSelect\";\nexport { default as ForgeSelect } from \"./ForgeSelect\";\nexport type {\n AjaxConfig,\n DataItem,\n ForgeSelectEvent,\n ForgeSelectOptions,\n ForgeSelectPlugin,\n ForgeSelectValue,\n Option,\n OptionGroup,\n TemplateFn,\n} from \"./types\";\n","export type Handler = (...args: unknown[]) => void;\n\nexport class Emitter {\n private handlers = new Map<string, Set<Handler>>();\n\n on(event: string, handler: Handler): void {\n let set = this.handlers.get(event);\n if (!set) {\n set = new Set();\n this.handlers.set(event, set);\n }\n set.add(handler);\n }\n\n off(event: string, handler: Handler): void {\n this.handlers.get(event)?.delete(handler);\n }\n\n emit(event: string, ...args: unknown[]): void {\n const set = this.handlers.get(event);\n if (!set) return;\n for (const handler of [...set]) handler(...args);\n }\n\n clear(): void {\n this.handlers.clear();\n }\n}\n","export type Strings = Record<string, string>;\n\nconst locales: Record<string, Strings> = {\n en: {\n noResults: \"No results found\",\n loading: \"Loading…\",\n createOption: 'Create \"{query}\"',\n clearSelection: \"Clear selection\",\n removeItem: \"Remove {label}\",\n search: \"Search\",\n },\n vi: {\n noResults: \"Không tìm thấy kết quả\",\n loading: \"Đang tải…\",\n createOption: 'Tạo \"{query}\"',\n clearSelection: \"Xóa lựa chọn\",\n removeItem: \"Xóa {label}\",\n search: \"Tìm kiếm\",\n },\n};\n\nexport function getStrings(language: string | Strings): Strings {\n if (typeof language === \"string\") {\n return locales[language] ?? locales.en;\n }\n return { ...locales.en, ...language };\n}\n\nexport function format(template: string, vars: Record<string, string>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => vars[key] ?? match);\n}\n","import { Emitter, type Handler } from \"./emitter\";\nimport { format, getStrings, type Strings } from \"./i18n\";\nimport type {\n AjaxConfig,\n DataItem,\n ForgeSelectEvent,\n ForgeSelectOptions,\n ForgeSelectPlugin,\n ForgeSelectValue,\n Option,\n OptionGroup,\n TemplateFn,\n} from \"./types\";\n\ntype Row =\n | { kind: \"group\"; label: string }\n | { kind: \"option\"; option: Option; navIndex: number }\n | { kind: \"create\"; navIndex: number }\n | { kind: \"empty\" }\n | { kind: \"loading\" };\n\ntype NavItem = { kind: \"option\"; option: Option } | { kind: \"create\" };\n\ninterface ResolvedOptions {\n placeholder: string;\n searchable: boolean;\n multiple: boolean;\n clearable: boolean;\n allowCreate: boolean;\n theme: string;\n disabled: boolean;\n data?: DataItem[];\n ajax?: AjaxConfig;\n templateResult?: TemplateFn;\n templateSelection?: TemplateFn;\n virtualScroll: boolean | undefined;\n itemHeight: number;\n language: string | Record<string, string>;\n plugins: ForgeSelectPlugin[];\n}\n\nconst DEFAULT_ITEM_HEIGHT = 36;\nconst VIRTUAL_BUFFER = 5;\nconst VIRTUAL_THRESHOLD = 100;\nconst ROW_CACHE_LIMIT = 2000;\n\nlet uidCounter = 0;\n\nfunction isGroup(item: DataItem): item is OptionGroup {\n return (item as OptionGroup).options !== undefined;\n}\n\nexport default class ForgeSelect {\n /** The original element ForgeSelect was mounted on. */\n readonly el: HTMLElement;\n\n private opts: ResolvedOptions;\n private strings: Strings;\n private data: DataItem[];\n private selected: string[] = [];\n private selectedOptions = new Map<string, Option>();\n private emitter = new Emitter();\n private plugins: ForgeSelectPlugin[];\n\n private uid = `forge-select-${++uidCounter}`;\n private root!: HTMLDivElement;\n private control!: HTMLDivElement;\n private valueEl!: HTMLDivElement;\n private clearBtn!: HTMLButtonElement;\n private dropdown!: HTMLDivElement;\n private searchInput: HTMLInputElement | null = null;\n private list!: HTMLUListElement;\n\n private isOpen = false;\n private isDisabled = false;\n private destroyed = false;\n private query = \"\";\n private rows: Row[] = [];\n private navItems: NavItem[] = [];\n private highlightedIndex = -1;\n private rowContentCache = new Map<string, Node>();\n\n private loading = false;\n private ajaxTimer: ReturnType<typeof setTimeout> | null = null;\n private ajaxRequestId = 0;\n private remoteLoaded = false;\n\n private onDocumentMouseDown = (event: MouseEvent): void => {\n if (!this.root.contains(event.target as Node)) this.close();\n };\n\n constructor(target: string | HTMLElement, options: ForgeSelectOptions = {}) {\n const el = typeof target === \"string\" ? document.querySelector<HTMLElement>(target) : target;\n if (!el) {\n throw new Error(`ForgeSelect: target element not found: ${String(target)}`);\n }\n this.el = el;\n\n const nativeSelect = el instanceof HTMLSelectElement ? el : null;\n this.opts = {\n placeholder: options.placeholder ?? \"\",\n searchable: options.searchable ?? true,\n multiple: options.multiple ?? nativeSelect?.multiple ?? false,\n clearable: options.clearable ?? false,\n allowCreate: options.allowCreate ?? false,\n theme: options.theme ?? \"default\",\n disabled: options.disabled ?? false,\n data: options.data,\n ajax: options.ajax,\n templateResult: options.templateResult,\n templateSelection: options.templateSelection,\n virtualScroll: options.virtualScroll,\n itemHeight: options.itemHeight ?? DEFAULT_ITEM_HEIGHT,\n language: options.language ?? \"en\",\n plugins: options.plugins ?? [],\n };\n this.strings = getStrings(this.opts.language);\n this.plugins = this.opts.plugins;\n\n this.data = this.opts.data ?? (nativeSelect ? parseNativeOptions(nativeSelect) : []);\n if (nativeSelect && !this.opts.data) {\n for (const option of Array.from(nativeSelect.querySelectorAll(\"option\"))) {\n if (option.hasAttribute(\"selected\")) this.selectValue(option.value, false);\n }\n }\n\n this.buildDom();\n this.renderValue();\n if (this.opts.disabled) this.disable();\n\n for (const plugin of this.plugins) plugin.onInit?.(this);\n }\n\n // ---------------------------------------------------------------- public API\n\n open(): void {\n if (this.isOpen || this.isDisabled || this.destroyed) return;\n this.isOpen = true;\n this.dropdown.hidden = false;\n this.root.classList.add(\"forge-select--open\");\n this.control.setAttribute(\"aria-expanded\", \"true\");\n document.addEventListener(\"mousedown\", this.onDocumentMouseDown);\n\n if (this.opts.ajax && !this.remoteLoaded) {\n this.scheduleRemoteLoad(this.query, 0);\n }\n this.renderList();\n if (this.searchInput) this.searchInput.focus();\n\n this.emitter.emit(\"open\");\n for (const plugin of this.plugins) plugin.onOpen?.(this);\n }\n\n close(): void {\n if (!this.isOpen) return;\n this.isOpen = false;\n this.dropdown.hidden = true;\n this.root.classList.remove(\"forge-select--open\");\n this.control.setAttribute(\"aria-expanded\", \"false\");\n document.removeEventListener(\"mousedown\", this.onDocumentMouseDown);\n this.highlightedIndex = -1;\n if (this.searchInput) {\n this.searchInput.value = \"\";\n this.query = \"\";\n }\n\n this.emitter.emit(\"close\");\n for (const plugin of this.plugins) plugin.onClose?.(this);\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.close();\n for (const plugin of this.plugins) plugin.onDestroy?.(this);\n this.destroyed = true;\n if (this.ajaxTimer) clearTimeout(this.ajaxTimer);\n this.rowContentCache.clear();\n this.root.remove();\n this.el.style.display = \"\";\n this.emitter.clear();\n }\n\n getValue(): ForgeSelectValue {\n if (this.opts.multiple) return [...this.selected];\n return this.selected[0] ?? null;\n }\n\n setValue(value: ForgeSelectValue): void {\n const values = value == null ? [] : Array.isArray(value) ? value : [value];\n const next = this.opts.multiple ? values : values.slice(0, 1);\n if (arraysEqual(next, this.selected)) return;\n this.selected = [];\n for (const v of next) this.selectValue(v, false);\n this.afterSelectionChange();\n }\n\n enable(): void {\n this.isDisabled = false;\n this.root.classList.remove(\"forge-select--disabled\");\n this.control.tabIndex = 0;\n this.control.setAttribute(\"aria-disabled\", \"false\");\n }\n\n disable(): void {\n this.close();\n this.isDisabled = true;\n this.root.classList.add(\"forge-select--disabled\");\n this.control.tabIndex = -1;\n this.control.setAttribute(\"aria-disabled\", \"true\");\n }\n\n on(event: ForgeSelectEvent, handler: Handler): void {\n this.emitter.on(event, handler);\n }\n\n off(event: ForgeSelectEvent, handler: Handler): void {\n this.emitter.off(event, handler);\n }\n\n // ---------------------------------------------------------------- DOM setup\n\n private buildDom(): void {\n this.root = document.createElement(\"div\");\n this.root.className = \"forge-select\";\n this.root.dataset.theme = this.opts.theme;\n this.root.style.setProperty(\"--fs-item-height\", `${this.opts.itemHeight}px`);\n\n this.control = document.createElement(\"div\");\n this.control.className = \"forge-select__control\";\n this.control.setAttribute(\"role\", \"combobox\");\n this.control.setAttribute(\"aria-haspopup\", \"listbox\");\n this.control.setAttribute(\"aria-expanded\", \"false\");\n this.control.setAttribute(\"aria-controls\", `${this.uid}-list`);\n this.control.tabIndex = 0;\n\n this.valueEl = document.createElement(\"div\");\n this.valueEl.className = \"forge-select__value\";\n\n this.clearBtn = document.createElement(\"button\");\n this.clearBtn.type = \"button\";\n this.clearBtn.className = \"forge-select__clear\";\n this.clearBtn.setAttribute(\"aria-label\", this.strings.clearSelection);\n this.clearBtn.textContent = \"×\";\n this.clearBtn.hidden = true;\n\n const arrow = document.createElement(\"span\");\n arrow.className = \"forge-select__arrow\";\n arrow.setAttribute(\"aria-hidden\", \"true\");\n\n this.control.append(this.valueEl, this.clearBtn, arrow);\n\n this.dropdown = document.createElement(\"div\");\n this.dropdown.className = \"forge-select__dropdown\";\n this.dropdown.hidden = true;\n\n if (this.opts.searchable) {\n this.searchInput = document.createElement(\"input\");\n this.searchInput.type = \"search\";\n this.searchInput.className = \"forge-select__search\";\n this.searchInput.setAttribute(\"aria-label\", this.strings.search);\n this.searchInput.setAttribute(\"aria-autocomplete\", \"list\");\n this.searchInput.setAttribute(\"aria-controls\", `${this.uid}-list`);\n this.dropdown.append(this.searchInput);\n }\n\n this.list = document.createElement(\"ul\");\n this.list.className = \"forge-select__list\";\n this.list.id = `${this.uid}-list`;\n this.list.setAttribute(\"role\", \"listbox\");\n if (this.opts.multiple) this.list.setAttribute(\"aria-multiselectable\", \"true\");\n this.dropdown.append(this.list);\n\n this.root.append(this.control, this.dropdown);\n this.el.style.display = \"none\";\n this.el.insertAdjacentElement(\"afterend\", this.root);\n\n this.bindEvents();\n }\n\n private bindEvents(): void {\n this.control.addEventListener(\"click\", (event) => {\n if (event.target === this.clearBtn) return;\n if (this.isDisabled) return;\n this.isOpen ? this.close() : this.open();\n });\n\n this.control.addEventListener(\"keydown\", (event) => this.handleKeydown(event));\n\n this.clearBtn.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n this.clearSelection();\n });\n\n if (this.searchInput) {\n this.searchInput.addEventListener(\"input\", () => {\n this.query = this.searchInput!.value;\n this.highlightedIndex = -1;\n this.list.scrollTop = 0;\n this.emitter.emit(\"search\", this.query);\n if (this.opts.ajax) {\n this.scheduleRemoteLoad(this.query, this.opts.ajax.debounce ?? 250);\n } else {\n this.renderList();\n }\n });\n this.searchInput.addEventListener(\"keydown\", (event) => this.handleKeydown(event));\n }\n\n this.list.addEventListener(\"click\", (event) => {\n const li = (event.target as HTMLElement).closest<HTMLLIElement>(\"li[data-nav-index]\");\n if (!li) return;\n const navIndex = Number(li.dataset.navIndex);\n this.activateNavItem(navIndex);\n });\n\n this.list.addEventListener(\"scroll\", () => {\n if (this.usesVirtualScroll()) this.renderRows();\n });\n }\n\n private handleKeydown(event: KeyboardEvent): void {\n if (this.isDisabled) return;\n switch (event.key) {\n case \"Enter\":\n event.preventDefault();\n if (!this.isOpen) this.open();\n else if (this.highlightedIndex >= 0) this.activateNavItem(this.highlightedIndex);\n break;\n case \" \":\n if (event.target === this.control) {\n event.preventDefault();\n if (!this.isOpen) this.open();\n }\n break;\n case \"ArrowDown\":\n event.preventDefault();\n if (!this.isOpen) this.open();\n else this.moveHighlight(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (this.isOpen) this.moveHighlight(-1);\n break;\n case \"Escape\":\n if (this.isOpen) {\n event.preventDefault();\n this.close();\n this.control.focus();\n }\n break;\n case \"Tab\":\n this.close();\n break;\n }\n }\n\n // ---------------------------------------------------------------- selection\n\n private selectValue(value: string, notify: boolean): void {\n if (this.selected.includes(value)) return;\n const option = this.findOption(value) ?? this.selectedOptions.get(value) ?? { value, label: value };\n this.selectedOptions.set(value, option);\n if (this.opts.multiple) this.selected.push(value);\n else this.selected = [value];\n if (notify) this.afterSelectionChange();\n }\n\n private deselectValue(value: string, notify: boolean): void {\n const index = this.selected.indexOf(value);\n if (index === -1) return;\n this.selected.splice(index, 1);\n if (notify) this.afterSelectionChange();\n }\n\n private clearSelection(): void {\n if (this.selected.length === 0) return;\n this.selected = [];\n this.emitter.emit(\"clear\");\n this.afterSelectionChange();\n }\n\n private afterSelectionChange(): void {\n this.renderValue();\n this.syncNativeSelect();\n if (this.isOpen) this.renderList();\n this.emitter.emit(\"change\", this.getValue());\n }\n\n private syncNativeSelect(): void {\n if (!(this.el instanceof HTMLSelectElement)) return;\n const existing = new Set<string>();\n for (const option of Array.from(this.el.options)) {\n existing.add(option.value);\n option.selected = this.selected.includes(option.value);\n }\n for (const value of this.selected) {\n if (existing.has(value)) continue;\n const option = document.createElement(\"option\");\n option.value = value;\n option.textContent = this.selectedOptions.get(value)?.label ?? value;\n option.selected = true;\n this.el.append(option);\n }\n this.el.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n\n private findOption(value: string): Option | undefined {\n for (const item of this.data) {\n if (isGroup(item)) {\n const found = item.options.find((o) => o.value === value);\n if (found) return found;\n } else if (item.value === value) {\n return item;\n }\n }\n return undefined;\n }\n\n private createFromQuery(): void {\n const label = this.query.trim();\n if (!label) return;\n const option: Option = { value: label, label };\n this.data.push(option);\n if (this.searchInput) {\n this.searchInput.value = \"\";\n this.query = \"\";\n }\n this.selectValue(option.value, true);\n if (!this.opts.multiple) this.close();\n }\n\n private activateNavItem(navIndex: number): void {\n const item = this.navItems[navIndex];\n if (!item) return;\n if (item.kind === \"create\") {\n this.createFromQuery();\n return;\n }\n const { value } = item.option;\n if (this.opts.multiple) {\n this.selected.includes(value) ? this.deselectValue(value, true) : this.selectValue(value, true);\n } else {\n this.selectValue(value, true);\n this.close();\n this.control.focus();\n }\n }\n\n // ---------------------------------------------------------------- rendering\n\n private renderValue(): void {\n this.valueEl.textContent = \"\";\n const hasValue = this.selected.length > 0;\n this.clearBtn.hidden = !(this.opts.clearable && hasValue);\n\n if (!hasValue) {\n const placeholder = document.createElement(\"span\");\n placeholder.className = \"forge-select__placeholder\";\n placeholder.textContent = this.opts.placeholder;\n this.valueEl.append(placeholder);\n return;\n }\n\n if (this.opts.multiple) {\n for (const value of this.selected) {\n const option = this.selectedOptions.get(value) ?? { value, label: value };\n const tag = document.createElement(\"span\");\n tag.className = \"forge-select__tag\";\n const label = document.createElement(\"span\");\n label.className = \"forge-select__tag-label\";\n this.renderTemplate(label, option, this.opts.templateSelection, \"inline\");\n const remove = document.createElement(\"button\");\n remove.type = \"button\";\n remove.className = \"forge-select__tag-remove\";\n remove.setAttribute(\"aria-label\", format(this.strings.removeItem, { label: option.label }));\n remove.textContent = \"×\";\n remove.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n if (!this.isDisabled) this.deselectValue(value, true);\n });\n tag.append(label, remove);\n this.valueEl.append(tag);\n }\n } else {\n const option = this.selectedOptions.get(this.selected[0]) ?? {\n value: this.selected[0],\n label: this.selected[0],\n };\n const span = document.createElement(\"span\");\n span.className = \"forge-select__single-value\";\n this.renderTemplate(span, option, this.opts.templateSelection, \"inline\");\n this.valueEl.append(span);\n }\n }\n\n private renderTemplate(\n container: HTMLElement,\n option: Option,\n template?: TemplateFn,\n variant: \"row\" | \"inline\" = \"row\",\n ): void {\n if (template) {\n const result = template(option);\n if (typeof result === \"string\") container.innerHTML = result;\n else container.append(result);\n return;\n }\n if (!option.avatar && !option.description) {\n container.textContent = option.label;\n return;\n }\n // Built-in rich renderer: DOM built via textContent, so all fields are XSS-safe.\n if (option.avatar) {\n const avatar = document.createElement(\"img\");\n avatar.className =\n variant === \"row\" ? \"forge-select__option-avatar\" : \"forge-select__inline-avatar\";\n avatar.src = option.avatar;\n avatar.alt = \"\";\n avatar.setAttribute(\"loading\", \"lazy\");\n avatar.setAttribute(\"decoding\", \"async\");\n container.append(avatar);\n }\n if (variant === \"row\" && option.description) {\n const body = document.createElement(\"span\");\n body.className = \"forge-select__option-body\";\n const label = document.createElement(\"span\");\n label.className = \"forge-select__option-label\";\n label.textContent = option.label;\n const desc = document.createElement(\"span\");\n desc.className = \"forge-select__option-desc\";\n desc.textContent = option.description;\n body.append(label, desc);\n container.append(body);\n } else {\n const label = document.createElement(\"span\");\n label.className = \"forge-select__option-label\";\n label.textContent = option.label;\n container.append(label);\n }\n }\n\n private buildRows(): void {\n this.rows = [];\n this.navItems = [];\n const query = this.query.trim().toLowerCase();\n const matches = (option: Option): boolean =>\n query === \"\" ||\n option.label.toLowerCase().includes(query) ||\n (option.description?.toLowerCase().includes(query) ?? false);\n\n const pushOption = (option: Option): void => {\n let navIndex = -1;\n if (!option.disabled) {\n navIndex = this.navItems.length;\n this.navItems.push({ kind: \"option\", option });\n }\n this.rows.push({ kind: \"option\", option, navIndex });\n };\n\n if (this.loading) {\n this.rows.push({ kind: \"loading\" });\n return;\n }\n\n for (const item of this.data) {\n if (isGroup(item)) {\n const visible = item.options.filter(matches);\n if (visible.length === 0) continue;\n this.rows.push({ kind: \"group\", label: item.label });\n visible.forEach(pushOption);\n } else if (matches(item)) {\n pushOption(item);\n }\n }\n\n if (this.opts.allowCreate && query !== \"\" && !this.hasExactMatch(query)) {\n const navIndex = this.navItems.length;\n this.navItems.push({ kind: \"create\" });\n this.rows.push({ kind: \"create\", navIndex });\n }\n\n if (this.rows.length === 0) this.rows.push({ kind: \"empty\" });\n }\n\n private hasExactMatch(lowerQuery: string): boolean {\n for (const item of this.data) {\n const options = isGroup(item) ? item.options : [item];\n if (options.some((o) => o.label.toLowerCase() === lowerQuery)) return true;\n }\n return false;\n }\n\n private usesVirtualScroll(): boolean {\n return this.opts.virtualScroll !== false && this.rows.length > VIRTUAL_THRESHOLD;\n }\n\n private renderList(): void {\n this.buildRows();\n this.renderRows();\n }\n\n private renderRows(): void {\n // Capture the scroll offset and viewport height BEFORE clearing the list:\n // removing the children collapses both scrollHeight (clamping scrollTop to 0)\n // and clientHeight (the list has no explicit height, only max-height, so an\n // empty list reports just its padding instead of the real box height).\n const scrollTop = this.list.scrollTop;\n const clientHeight = this.list.clientHeight;\n const virtual = this.usesVirtualScroll();\n this.list.textContent = \"\";\n\n const rowHeight = this.opts.itemHeight;\n let start = 0;\n let end = this.rows.length;\n if (virtual) {\n const viewport = clientHeight || rowHeight * 8;\n start = Math.max(0, Math.floor(scrollTop / rowHeight) - VIRTUAL_BUFFER);\n end = Math.min(this.rows.length, start + Math.ceil(viewport / rowHeight) + VIRTUAL_BUFFER * 2);\n\n const topSpacer = document.createElement(\"li\");\n topSpacer.className = \"forge-select__spacer\";\n topSpacer.setAttribute(\"aria-hidden\", \"true\");\n topSpacer.style.height = `${start * rowHeight}px`;\n this.list.append(topSpacer);\n }\n\n for (let i = start; i < end; i++) {\n this.list.append(this.renderRow(this.rows[i]));\n }\n\n if (virtual) {\n const bottomSpacer = document.createElement(\"li\");\n bottomSpacer.className = \"forge-select__spacer\";\n bottomSpacer.setAttribute(\"aria-hidden\", \"true\");\n bottomSpacer.style.height = `${(this.rows.length - end) * rowHeight}px`;\n this.list.append(bottomSpacer);\n\n // Restore the offset that clearing clamped away. The net scroll change\n // within this handler is zero, so this does not re-fire the scroll\n // listener; even if it did, the re-render is idempotent and settles.\n if (this.list.scrollTop !== scrollTop) {\n this.list.scrollTop = scrollTop;\n }\n }\n\n this.updateActiveDescendant();\n }\n\n private renderRow(row: Row): HTMLLIElement {\n const li = document.createElement(\"li\");\n switch (row.kind) {\n case \"group\":\n li.className = \"forge-select__group-label\";\n li.setAttribute(\"role\", \"presentation\");\n li.textContent = row.label;\n break;\n case \"empty\":\n li.className = \"forge-select__empty\";\n li.textContent = this.strings.noResults;\n break;\n case \"loading\":\n li.className = \"forge-select__loading\";\n li.textContent = this.strings.loading;\n break;\n case \"create\":\n li.className = \"forge-select__option forge-select__option--create\";\n li.setAttribute(\"role\", \"option\");\n li.id = `${this.uid}-nav-${row.navIndex}`;\n li.dataset.navIndex = String(row.navIndex);\n li.textContent = format(this.strings.createOption, { query: this.query.trim() });\n if (row.navIndex === this.highlightedIndex) li.classList.add(\"forge-select__option--highlighted\");\n break;\n case \"option\": {\n li.className = \"forge-select__option\";\n li.setAttribute(\"role\", \"option\");\n const isSelected = this.selected.includes(row.option.value);\n li.setAttribute(\"aria-selected\", String(isSelected));\n if (isSelected) li.classList.add(\"forge-select__option--selected\");\n if (row.option.disabled) {\n li.classList.add(\"forge-select__option--disabled\");\n li.setAttribute(\"aria-disabled\", \"true\");\n } else {\n li.id = `${this.uid}-nav-${row.navIndex}`;\n li.dataset.navIndex = String(row.navIndex);\n if (row.navIndex === this.highlightedIndex) li.classList.add(\"forge-select__option--highlighted\");\n }\n li.append(this.optionContent(row.option));\n break;\n }\n }\n return li;\n }\n\n /**\n * Rendered row content is cached per option value and cloned on each render,\n * so templates run once per option instead of once per scroll frame.\n * State classes (selected/highlighted/disabled) live on the <li>, keeping the\n * cached content state-free.\n */\n private optionContent(option: Option): Node {\n let cached = this.rowContentCache.get(option.value);\n if (!cached) {\n const holder = document.createElement(\"span\");\n holder.className = \"forge-select__option-content\";\n this.renderTemplate(holder, option, this.opts.templateResult);\n if (this.rowContentCache.size >= ROW_CACHE_LIMIT) {\n // FIFO eviction keeps memory bounded on very large lists.\n const oldest = this.rowContentCache.keys().next().value as string;\n this.rowContentCache.delete(oldest);\n }\n this.rowContentCache.set(option.value, holder);\n cached = holder;\n }\n return cached.cloneNode(true);\n }\n\n private moveHighlight(delta: number): void {\n if (this.navItems.length === 0) return;\n const next =\n this.highlightedIndex === -1 && delta > 0\n ? 0\n : (this.highlightedIndex + delta + this.navItems.length) % this.navItems.length;\n this.highlightedIndex = next;\n\n if (this.usesVirtualScroll()) {\n const rowIndex = this.rows.findIndex(\n (row) => (row.kind === \"option\" || row.kind === \"create\") && row.navIndex === next,\n );\n if (rowIndex >= 0) {\n const rowHeight = this.opts.itemHeight;\n const top = rowIndex * rowHeight;\n const viewport = this.list.clientHeight || rowHeight * 8;\n let target = this.list.scrollTop;\n if (top < target) target = top;\n else if (top + rowHeight > target + viewport) target = top + rowHeight - viewport;\n if (target !== this.list.scrollTop) this.list.scrollTop = target;\n }\n this.renderRows();\n } else {\n this.renderRows();\n const highlighted = this.list.querySelector<HTMLElement>(\".forge-select__option--highlighted\");\n highlighted?.scrollIntoView?.({ block: \"nearest\" });\n }\n }\n\n private updateActiveDescendant(): void {\n const target = this.searchInput ?? this.control;\n if (this.highlightedIndex >= 0) {\n target.setAttribute(\"aria-activedescendant\", `${this.uid}-nav-${this.highlightedIndex}`);\n } else {\n target.removeAttribute(\"aria-activedescendant\");\n }\n }\n\n // ---------------------------------------------------------------- remote data\n\n private scheduleRemoteLoad(query: string, delay: number): void {\n if (this.ajaxTimer) clearTimeout(this.ajaxTimer);\n this.loading = true;\n this.renderList();\n this.ajaxTimer = setTimeout(() => {\n void this.loadRemote(query);\n }, delay);\n }\n\n private async loadRemote(query: string): Promise<void> {\n const ajax = this.opts.ajax!;\n const requestId = ++this.ajaxRequestId;\n try {\n const url = buildUrl(ajax, query);\n const response = await fetch(url);\n const json: unknown = await response.json();\n if (requestId !== this.ajaxRequestId || this.destroyed) return;\n this.data = ajax.transform ? ajax.transform(json) : (json as Option[]);\n this.rowContentCache.clear();\n this.remoteLoaded = true;\n } catch {\n if (requestId !== this.ajaxRequestId || this.destroyed) return;\n this.data = [];\n this.rowContentCache.clear();\n } finally {\n if (requestId === this.ajaxRequestId && !this.destroyed) {\n this.loading = false;\n if (this.isOpen) this.renderList();\n }\n }\n }\n}\n\nfunction parseNativeOptions(select: HTMLSelectElement): DataItem[] {\n const data: DataItem[] = [];\n for (const child of Array.from(select.children)) {\n if (child instanceof HTMLOptGroupElement) {\n data.push({\n label: child.label,\n options: Array.from(child.querySelectorAll(\"option\")).map(parseOption),\n });\n } else if (child instanceof HTMLOptionElement) {\n data.push(parseOption(child));\n }\n }\n return data;\n}\n\nfunction parseOption(option: HTMLOptionElement): Option {\n return {\n value: option.value,\n label: option.textContent?.trim() ?? option.value,\n disabled: option.disabled || undefined,\n };\n}\n\nfunction buildUrl(ajax: AjaxConfig, query: string): string {\n if (typeof ajax.url === \"function\") return ajax.url(query);\n if (!ajax.params) return ajax.url;\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(ajax.params(query))) {\n params.set(key, String(value));\n }\n const separator = ajax.url.includes(\"?\") ? \"&\" : \"?\";\n return `${ajax.url}${separator}${params.toString()}`;\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n return a.length === b.length && a.every((value, index) => value === b[index]);\n}\n"],"mappings":"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","names":[]}
|