forge-select 0.1.0 → 0.3.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/README.md +62 -46
- package/dist/index.cjs +562 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -7
- package/dist/index.d.ts +90 -7
- package/dist/index.global.js +1 -750
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +562 -126
- package/dist/index.js.map +1 -1
- package/package.json +34 -6
- package/styles/forge-select.css +42 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/emitter.ts","../src/i18n.ts","../src/native-select.ts","../src/option-renderer.ts","../src/remote.ts","../src/selection.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 SetValueOptions,\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 loadingMore: \"Loading more…\",\n errorLoading: \"Could not load options\",\n createOption: 'Create \"{query}\"',\n clearSelection: \"Clear selection\",\n removeItem: \"Remove {label}\",\n search: \"Search\",\n reorderHint: \"{label}. Press Alt+Left or Alt+Right to reorder.\",\n },\n vi: {\n noResults: \"Không tìm thấy kết quả\",\n loading: \"Đang tải…\",\n loadingMore: \"Đang tải thêm…\",\n errorLoading: \"Không thể tải tùy chọn\",\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 reorderHint: \"{label}. Nhấn Alt+Trái hoặc Alt+Phải để sắp xếp lại.\",\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 type { DataItem, Option } from \"./types\";\n\nexport function 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({ label: child.label, options: Array.from(child.querySelectorAll(\"option\")).map(parseOption) });\n } else if (child instanceof HTMLOptionElement) {\n data.push(parseOption(child));\n }\n }\n return data;\n}\n\nfunction parseOption(option: HTMLOptionElement): Option {\n const groupDisabled = option.parentElement instanceof HTMLOptGroupElement && option.parentElement.disabled;\n return {\n value: option.value,\n label: option.textContent?.trim() ?? option.value,\n disabled: option.disabled || groupDisabled || undefined,\n };\n}\n","import type { Option, TemplateFn } from \"./types\";\n\nexport type OptionRenderVariant = \"row\" | \"inline\";\n\n/** Render one option without coupling presentation details to the select controller. */\nexport function renderOptionContent(\n container: HTMLElement,\n option: Option,\n template?: TemplateFn,\n variant: OptionRenderVariant = \"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\n // Built-in rich rendering only uses textContent/attribute assignment.\n if (option.avatar) {\n const avatar = document.createElement(\"img\");\n avatar.className = 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 description = document.createElement(\"span\");\n description.className = \"forge-select__option-desc\";\n description.textContent = option.description;\n body.append(label, description);\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","import type { AjaxConfig, Option } from \"./types\";\n\nexport function buildUrl(ajax: AjaxConfig, query: string, page: number): string {\n if (typeof ajax.url === \"function\") return ajax.url(query, page);\n if (!ajax.params) return ajax.url;\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(ajax.params(query, page))) params.set(key, String(value));\n const separator = ajax.url.includes(\"?\") ? \"&\" : \"?\";\n return `${ajax.url}${separator}${params.toString()}`;\n}\n\nexport function normalizeRemoteResult(ajax: AjaxConfig, response: unknown): { options: Option[]; hasMore: boolean } {\n const result = ajax.transform ? ajax.transform(response) : (response as Option[]);\n if (Array.isArray(result)) return { options: result, hasMore: false };\n if (!result || !Array.isArray((result as { options?: unknown }).options)) {\n throw new Error(\n \"ForgeSelect: ajax.transform must return an array of options, or an object shaped like { options: Option[], hasMore?: boolean }.\",\n );\n }\n return { options: result.options, hasMore: ajax.pagination ? Boolean(result.hasMore) : false };\n}\n","import type { DataItem, Option, OptionGroup } from \"./types\";\n\nexport function isGroup(item: DataItem): item is OptionGroup {\n return (item as OptionGroup).options !== undefined;\n}\n\n// Disabled descendants are excluded from `navItems` (see buildRows in\n// ForgeSelect.ts) and so can never be toggled back off by the user through\n// the UI — cascading a parent's (de)selection onto them would strand them\n// permanently selected. Their own children remain independently selectable\n// (only the disabled node itself is skipped), matching buildRows' rendering.\nexport function collectDescendantValues(option: Option): string[] {\n if (!option.children) return [];\n const values: string[] = [];\n for (const child of option.children) {\n if (!child.disabled) values.push(child.value);\n values.push(...collectDescendantValues(child));\n }\n return values;\n}\n\nexport function computeCheckState(option: Option, selected: string[]): \"none\" | \"some\" | \"all\" {\n if (!option.children?.length) return selected.includes(option.value) ? \"all\" : \"none\";\n const states = option.children.filter((child) => !child.disabled).map((child) => computeCheckState(child, selected));\n if (states.length === 0) return \"none\";\n if (states.every((state) => state === \"all\")) return \"all\";\n if (states.every((state) => state === \"none\")) return \"none\";\n return \"some\";\n}\n\nexport function findOption(items: DataItem[], value: string): Option | undefined {\n const search = (options: Option[]): Option | undefined => {\n for (const option of options) {\n if (option.value === value) return option;\n const found = option.children ? search(option.children) : undefined;\n if (found) return found;\n }\n return undefined;\n };\n for (const item of items) {\n const found = search(isGroup(item) ? item.options : [item]);\n if (found) return found;\n }\n return undefined;\n}\n\nexport function syncTreeAncestors(items: DataItem[], selected: string[]): void {\n const sync = (option: Option): void => {\n if (!option.children?.length) return;\n for (const child of option.children) sync(child);\n const state = computeCheckState(option, selected);\n const index = selected.indexOf(option.value);\n if (state === \"all\" && index === -1) selected.push(option.value);\n else if (state !== \"all\" && index !== -1) selected.splice(index, 1);\n };\n for (const item of items) (isGroup(item) ? item.options : [item]).forEach(sync);\n}\n\nexport function collectValues(items: DataItem[]): Set<string> {\n const values = new Set<string>();\n const visit = (option: Option): void => {\n values.add(option.value);\n option.children?.forEach(visit);\n };\n for (const item of items) (isGroup(item) ? item.options : [item]).forEach(visit);\n return values;\n}\n\nexport function arraysEqual(a: string[], b: string[]): boolean {\n return a.length === b.length && a.every((value, index) => value === b[index]);\n}\n","import { Emitter, type Handler } from \"./emitter\";\nimport { format, getStrings, type Strings } from \"./i18n\";\nimport { parseNativeOptions } from \"./native-select\";\nimport { renderOptionContent } from \"./option-renderer\";\nimport { buildUrl, normalizeRemoteResult } from \"./remote\";\nimport {\n arraysEqual,\n collectDescendantValues,\n collectValues,\n computeCheckState,\n findOption as findDataOption,\n isGroup,\n syncTreeAncestors as syncDataTreeAncestors,\n} from \"./selection\";\nimport type {\n AjaxConfig,\n DataItem,\n ForgeSelectEvent,\n ForgeSelectOptions,\n ForgeSelectPlugin,\n ForgeSelectValue,\n Option,\n SetValueOptions,\n TemplateFn,\n} from \"./types\";\n\ntype Row =\n | { kind: \"group\"; label: string }\n | { kind: \"option\"; option: Option; navIndex: number; depth: number; hasChildren: boolean }\n | { kind: \"create\"; navIndex: number }\n | { kind: \"empty\" }\n | { kind: \"error\" }\n | { kind: \"loading\" }\n | { kind: \"loading-more\" };\n\ntype NavItem = { kind: \"option\"; option: Option; parentValue?: string } | { kind: \"create\" };\n\ninterface ResolvedOptions {\n placeholder: string;\n searchable: boolean;\n multiple: boolean;\n clearable: boolean;\n allowCreate: boolean;\n sortable: 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\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 suppressNextTagClick = false;\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 private liveRegion!: HTMLDivElement;\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 private expandedValues = new Set<string>();\n\n private loading = false;\n private loadingMore = false;\n private page = 0;\n private hasMore = true;\n private ajaxTimer: ReturnType<typeof setTimeout> | null = null;\n private ajaxRequestId = 0;\n private ajaxController: AbortController | null = null;\n private remoteLoaded = false;\n private loadError: Error | null = null;\n private originalDisplay = \"\";\n private originalDisabled = false;\n private nativeSelect: HTMLSelectElement | null = null;\n private nativeForm: HTMLFormElement | null = null;\n private syncingNative = false;\n\n private onDocumentMouseDown = (event: MouseEvent): void => {\n if (!this.root.contains(event.target as Node)) this.close();\n };\n\n private onNativeChange = (): void => {\n if (!this.nativeSelect || this.destroyed || this.syncingNative) return;\n const values = Array.from(this.nativeSelect.selectedOptions, (option) => option.value);\n this.applyNativeValues(values);\n };\n\n private applyNativeValues(values: string[]): void {\n this.selected = [];\n for (const value of this.opts.multiple ? values : values.slice(0, 1)) this.selectValue(value, false);\n this.renderValue();\n if (this.isOpen) this.renderList();\n this.emitter.emit(\"change\", this.getValue());\n }\n\n private onFormReset = (): void => {\n if (!this.nativeSelect || this.destroyed) return;\n const defaults = Array.from(this.nativeSelect.options)\n .filter((option) => option.defaultSelected)\n .map((option) => option.value);\n this.applyNativeValues(defaults);\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.nativeSelect = nativeSelect;\n this.nativeForm = nativeSelect?.form ?? null;\n this.originalDisplay = el.style.display;\n this.originalDisabled = nativeSelect?.disabled ?? false;\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 sortable: options.sortable ?? false,\n theme: options.theme ?? \"default\",\n disabled: options.disabled ?? nativeSelect?.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 const nativeOptions = Array.from(nativeSelect.options);\n const hasIntentionalSelection =\n nativeSelect.multiple ||\n nativeSelect.selectedIndex > 0 ||\n nativeOptions.some((option) => option.defaultSelected);\n for (const option of nativeOptions) {\n if (hasIntentionalSelection && option.selected) this.selectValue(option.value, false);\n }\n }\n\n this.buildDom();\n this.renderValue();\n if (this.opts.disabled) this.disable();\n nativeSelect?.addEventListener(\"change\", this.onNativeChange);\n this.nativeForm?.addEventListener(\"reset\", this.onFormReset);\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.ajaxController?.abort();\n this.nativeSelect?.removeEventListener(\"change\", this.onNativeChange);\n this.nativeForm?.removeEventListener(\"reset\", this.onFormReset);\n this.rowContentCache.clear();\n this.root.remove();\n this.el.style.display = this.originalDisplay;\n if (this.nativeSelect) this.nativeSelect.disabled = this.originalDisabled;\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, options: SetValueOptions = {}): 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(options.emitChange ?? true);\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 if (this.nativeSelect) this.nativeSelect.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 if (this.nativeSelect) this.nativeSelect.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 /**\n * The original target (a hidden native <select> or a plain mount div) can\n * carry an accessible name via aria-label/aria-labelledby, or via a\n * <label for> pointing at its id — but once `this.el` is display:none it\n * drops out of the accessibility tree, so any such association silently\n * stops reaching assistive tech unless we forward it onto the visible,\n * interactive `this.control` ourselves.\n */\n private applyAccessibleName(): void {\n const ariaLabelledby = this.el.getAttribute(\"aria-labelledby\");\n const ariaLabel = this.el.getAttribute(\"aria-label\");\n if (ariaLabelledby) {\n this.control.setAttribute(\"aria-labelledby\", ariaLabelledby);\n } else if (ariaLabel) {\n this.control.setAttribute(\"aria-label\", ariaLabel);\n } else if (this.el.id) {\n const label = Array.from(document.getElementsByTagName(\"label\")).find((el) => el.htmlFor === this.el.id);\n if (label) {\n if (!label.id) label.id = `${this.uid}-label`;\n this.control.setAttribute(\"aria-labelledby\", label.id);\n }\n }\n }\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 if (this.opts.sortable && this.opts.multiple) this.root.classList.add(\"forge-select--sortable\");\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 this.applyAccessibleName();\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.liveRegion = document.createElement(\"div\");\n this.liveRegion.className = \"forge-select__sr-only\";\n this.liveRegion.setAttribute(\"role\", \"status\");\n this.liveRegion.setAttribute(\"aria-live\", \"polite\");\n\n this.root.append(this.control, this.dropdown, this.liveRegion);\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.suppressNextTagClick) {\n this.suppressNextTagClick = false;\n return;\n }\n if (this.isDisabled) return;\n if (this.isOpen) this.close();\n else 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 target = event.target as HTMLElement;\n const twisty = target.closest<HTMLElement>(\"[data-twisty]\");\n if (twisty) {\n const value = twisty.dataset.twisty!;\n if (this.expandedValues.has(value)) this.expandedValues.delete(value);\n else this.expandedValues.add(value);\n this.renderList();\n return;\n }\n const li = target.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 this.maybeLoadNextPage();\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 \"ArrowRight\":\n if (this.isOpen && this.navigateTree(\"right\")) event.preventDefault();\n break;\n case \"ArrowLeft\":\n if (this.isOpen && this.navigateTree(\"left\")) event.preventDefault();\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) {\n this.selected.push(value);\n // Selecting a tree node cascades to its descendants too; for a plain\n // option (no children) this is a no-op.\n for (const v of collectDescendantValues(option)) {\n if (!this.selected.includes(v)) this.selected.push(v);\n }\n this.syncTreeAncestors();\n } else {\n this.selected = [value];\n }\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 (this.opts.multiple) {\n const option = this.findOption(value) ?? this.selectedOptions.get(value);\n if (option) {\n for (const v of collectDescendantValues(option)) {\n const i = this.selected.indexOf(v);\n if (i !== -1) this.selected.splice(i, 1);\n }\n }\n this.syncTreeAncestors();\n }\n if (notify) this.afterSelectionChange();\n }\n\n /**\n * Keeps every tree parent's own membership in `selected` consistent with\n * its descendants (post-order, so parents see already-corrected children):\n * a parent counts as selected only when `computeCheckState` says \"all\".\n * No-op for data with no `children` anywhere.\n */\n private syncTreeAncestors(): void {\n syncDataTreeAncestors(this.data, this.selected);\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(emitChange = true): void {\n this.renderValue();\n this.syncNativeSelect(emitChange);\n if (this.isOpen) this.renderList();\n if (emitChange) this.emitter.emit(\"change\", this.getValue());\n }\n\n private syncNativeSelect(dispatchChange = true): 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 if (this.opts.sortable && this.opts.multiple) {\n // Re-appending in `this.selected` order moves each selected <option> to\n // the end in that relative order, so a real <select multiple> form\n // submission serializes values in the dragged order (unselected options\n // simply end up interleaved before them, which submission ignores).\n for (const value of this.selected) {\n const option = Array.from(this.el.options).find((o) => o.value === value);\n if (option) this.el.append(option);\n }\n }\n if (!dispatchChange) return;\n this.syncingNative = true;\n try {\n this.el.dispatchEvent(new Event(\"change\", { bubbles: true }));\n } finally {\n this.syncingNative = false;\n }\n }\n\n private findOption(value: string): Option | undefined {\n return findDataOption(this.data, value);\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 if (this.selected.includes(value)) this.deselectValue(value, true);\n else 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 renderOptionContent(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 if (this.opts.sortable) {\n tag.dataset.value = value;\n tag.tabIndex = 0;\n tag.setAttribute(\"aria-roledescription\", \"draggable item\");\n tag.setAttribute(\"aria-label\", format(this.strings.reorderHint, { label: option.label }));\n tag.addEventListener(\"keydown\", (event) => this.handleTagKeydown(event, value));\n this.bindTagDrag(tag, value);\n }\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 renderOptionContent(span, option, this.opts.templateSelection, \"inline\");\n this.valueEl.append(span);\n }\n }\n\n /**\n * Pointer-based (mouse/touch/pen) reorder for a single tag. Only the real\n * dragged DOM node is moved during the gesture — a full renderValue()\n * mid-drag would destroy it — so the reordered `this.selected` is only\n * committed on release. The move/up listeners and pointer capture live on\n * the stable `this.valueEl` container rather than the tag itself: `tag`\n * gets repositioned via `insertBefore` during the drag, and browsers treat\n * that reparenting as detaching the node, which silently drops pointer\n * capture (and further move events) if it were captured on `tag`.\n */\n private bindTagDrag(tag: HTMLSpanElement, value: string): void {\n const DRAG_THRESHOLD = 4;\n let startX = 0;\n let dragging = false;\n let order: string[] = [];\n\n const onPointerMove = (event: PointerEvent): void => {\n if (!dragging) {\n if (Math.abs(event.clientX - startX) < DRAG_THRESHOLD) return;\n dragging = true;\n order = [...this.selected];\n if (typeof this.valueEl.setPointerCapture === \"function\") {\n this.valueEl.setPointerCapture(event.pointerId);\n }\n tag.classList.add(\"forge-select__tag--dragging\");\n }\n event.preventDefault();\n\n const draggedIndex = order.indexOf(value);\n const siblings = Array.from(this.valueEl.querySelectorAll<HTMLElement>(\".forge-select__tag\"));\n for (const sibling of siblings) {\n if (sibling === tag) continue;\n const siblingValue = sibling.dataset.value;\n if (!siblingValue) continue;\n const siblingIndex = order.indexOf(siblingValue);\n if (siblingIndex === -1) continue;\n const rect = sibling.getBoundingClientRect();\n const midX = rect.left + rect.width / 2;\n const movingRight = draggedIndex < siblingIndex;\n const crossed = movingRight ? event.clientX > midX : event.clientX < midX;\n if (!crossed) continue;\n order.splice(draggedIndex, 1);\n order.splice(siblingIndex, 0, value);\n if (movingRight) this.valueEl.insertBefore(tag, sibling.nextSibling);\n else this.valueEl.insertBefore(tag, sibling);\n break;\n }\n };\n\n const finishDrag = (event: PointerEvent): void => {\n this.valueEl.removeEventListener(\"pointermove\", onPointerMove);\n this.valueEl.removeEventListener(\"pointerup\", finishDrag);\n this.valueEl.removeEventListener(\"pointercancel\", finishDrag);\n if (!dragging) return;\n if (typeof this.valueEl.releasePointerCapture === \"function\") {\n this.valueEl.releasePointerCapture(event.pointerId);\n }\n tag.classList.remove(\"forge-select__tag--dragging\");\n this.selected = order;\n this.suppressNextTagClick = true;\n this.afterSelectionChange();\n };\n\n tag.addEventListener(\"pointerdown\", (event) => {\n if (this.isDisabled || event.button !== 0) return;\n if ((event.target as HTMLElement).closest(\".forge-select__tag-remove\")) return;\n startX = event.clientX;\n dragging = false;\n this.valueEl.addEventListener(\"pointermove\", onPointerMove);\n this.valueEl.addEventListener(\"pointerup\", finishDrag);\n this.valueEl.addEventListener(\"pointercancel\", finishDrag);\n });\n }\n\n /** Alt+Left/Alt+Right on a focused tag: the keyboard-operable equivalent of dragging. */\n private handleTagKeydown(event: KeyboardEvent, value: string): void {\n if (!event.altKey || (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\")) return;\n const index = this.selected.indexOf(value);\n const targetIndex = event.key === \"ArrowLeft\" ? index - 1 : index + 1;\n if (index === -1 || targetIndex < 0 || targetIndex >= this.selected.length) return;\n event.preventDefault();\n event.stopPropagation();\n const next = [...this.selected];\n [next[index], next[targetIndex]] = [next[targetIndex], next[index]];\n this.selected = next;\n this.afterSelectionChange();\n this.focusTagByValue(value);\n }\n\n private focusTagByValue(value: string): void {\n for (const tag of Array.from(this.valueEl.querySelectorAll<HTMLElement>(\".forge-select__tag\"))) {\n if (tag.dataset.value === value) {\n tag.focus();\n return;\n }\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 // A tree node is visible while searching if it matches, or any descendant\n // does (leaf options with no children just reduce to `matches()`).\n const subtreeMatches = (option: Option): boolean =>\n query === \"\" || matches(option) || (option.children ?? []).some(subtreeMatches);\n\n const pushOption = (option: Option, depth: number, parentValue?: string): void => {\n let navIndex = -1;\n if (!option.disabled) {\n navIndex = this.navItems.length;\n this.navItems.push({ kind: \"option\", option, parentValue });\n }\n const hasChildren = !!option.children && option.children.length > 0;\n this.rows.push({ kind: \"option\", option, navIndex, depth, hasChildren });\n if (hasChildren) {\n // Expanding is ephemeral while searching (never written to\n // expandedValues), so clearing the query restores manual state.\n const expanded = query !== \"\" || this.expandedValues.has(option.value);\n if (expanded) {\n for (const child of option.children!) {\n if (subtreeMatches(child)) pushOption(child, depth + 1, option.value);\n }\n }\n }\n };\n\n if (this.loading) {\n this.rows.push({ kind: \"loading\" });\n return;\n }\n if (this.loadError) {\n this.rows.push({ kind: \"error\" });\n return;\n }\n\n for (const item of this.data) {\n if (isGroup(item)) {\n const visible = item.options.filter(subtreeMatches);\n if (visible.length === 0) continue;\n this.rows.push({ kind: \"group\", label: item.label });\n visible.forEach((o) => pushOption(o, 0));\n } else if (subtreeMatches(item)) {\n pushOption(item, 0);\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 else if (this.loadingMore) this.rows.push({ kind: \"loading-more\" });\n }\n\n private hasExactMatch(lowerQuery: string): boolean {\n const matchesExactly = (option: Option): boolean =>\n option.label.toLowerCase() === lowerQuery || (option.children ?? []).some(matchesExactly);\n for (const item of this.data) {\n const options = isGroup(item) ? item.options : [item];\n if (options.some(matchesExactly)) 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 this.announceStatus();\n }\n\n private announceStatus(): void {\n const first = this.rows[0];\n const message =\n first?.kind === \"loading\"\n ? this.strings.loading\n : first?.kind === \"error\"\n ? this.strings.errorLoading\n : first?.kind === \"empty\"\n ? this.strings.noResults\n : \"\";\n if (this.liveRegion.textContent !== message) this.liveRegion.textContent = message;\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.setAttribute(\"role\", \"option\");\n li.setAttribute(\"aria-disabled\", \"true\");\n li.setAttribute(\"aria-selected\", \"false\");\n li.textContent = this.strings.noResults;\n break;\n case \"error\":\n li.className = \"forge-select__error\";\n li.setAttribute(\"role\", \"option\");\n li.setAttribute(\"aria-disabled\", \"true\");\n li.setAttribute(\"aria-selected\", \"false\");\n li.textContent = this.strings.errorLoading;\n break;\n case \"loading\":\n li.className = \"forge-select__loading\";\n li.setAttribute(\"role\", \"option\");\n li.setAttribute(\"aria-disabled\", \"true\");\n li.setAttribute(\"aria-selected\", \"false\");\n li.textContent = this.strings.loading;\n break;\n case \"loading-more\":\n li.className = \"forge-select__loading-more\";\n li.setAttribute(\"aria-hidden\", \"true\");\n li.textContent = this.strings.loadingMore;\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 (this.opts.multiple && row.hasChildren && computeCheckState(row.option, this.selected) === \"some\") {\n li.classList.add(\"forge-select__option--indeterminate\");\n }\n if (row.depth > 0) {\n li.style.paddingLeft = `calc(12px + ${row.depth} * var(--fs-tree-indent, 18px))`;\n }\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 if (row.hasChildren) {\n const expanded = this.query !== \"\" || this.expandedValues.has(row.option.value);\n li.setAttribute(\"aria-expanded\", String(expanded));\n const twisty = document.createElement(\"span\");\n twisty.className = \"forge-select__twisty\";\n twisty.dataset.twisty = row.option.value;\n twisty.setAttribute(\"aria-hidden\", \"true\");\n twisty.textContent = expanded ? \"▼\" : \"▶\";\n li.append(twisty);\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 renderOptionContent(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\n ? delta > 0\n ? 0\n : this.navItems.length - 1\n : (this.highlightedIndex + delta + this.navItems.length) % this.navItems.length;\n this.focusNavIndex(next);\n }\n\n private focusNavIndex(next: number): void {\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 navigateTree(direction: \"left\" | \"right\"): boolean {\n const item = this.navItems[this.highlightedIndex];\n if (!item || item.kind !== \"option\") return false;\n const { option, parentValue } = item;\n const hasChildren = !!option.children?.length;\n const expanded = this.query !== \"\" || this.expandedValues.has(option.value);\n\n if (direction === \"right\") {\n if (hasChildren && !expanded) {\n this.expandedValues.add(option.value);\n this.renderList();\n return true;\n }\n if (hasChildren) {\n const childIndex = this.navItems.findIndex((nav) => nav.kind === \"option\" && nav.parentValue === option.value);\n if (childIndex >= 0) {\n this.focusNavIndex(childIndex);\n return true;\n }\n }\n return false;\n }\n\n if (hasChildren && expanded && this.query === \"\") {\n this.expandedValues.delete(option.value);\n this.renderList();\n return true;\n }\n if (parentValue) {\n const parentIndex = this.navItems.findIndex((nav) => nav.kind === \"option\" && nav.option.value === parentValue);\n if (parentIndex >= 0) {\n this.focusNavIndex(parentIndex);\n return true;\n }\n }\n return false;\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 const requestId = ++this.ajaxRequestId;\n this.ajaxController?.abort();\n this.ajaxController = null;\n this.page = 0;\n this.hasMore = true;\n this.loading = true;\n this.loadingMore = false;\n this.loadError = null;\n this.renderList();\n this.ajaxTimer = setTimeout(() => {\n this.ajaxTimer = null;\n void this.loadRemote(query, { requestId });\n }, delay);\n }\n\n /**\n * Fires on every list scroll. Only acts when pagination is opted into via\n * `ajax.pagination`; reads real scroll geometry rather than row counts so\n * it works whether or not virtual scrolling is active for this list.\n */\n private maybeLoadNextPage(): void {\n const ajax = this.opts.ajax;\n if (!ajax?.pagination || !this.hasMore || this.loading || this.loadingMore) return;\n const { scrollHeight, scrollTop, clientHeight } = this.list;\n const threshold = this.opts.itemHeight * 2;\n if (scrollHeight - scrollTop - clientHeight >= threshold) return;\n this.loadingMore = true;\n this.renderList();\n void this.loadRemote(this.query, { append: true });\n }\n\n private async loadRemote(\n query: string,\n { append = false, requestId }: { append?: boolean; requestId?: number } = {},\n ): Promise<void> {\n const ajax = this.opts.ajax!;\n const activeRequestId = requestId ?? ++this.ajaxRequestId;\n if (activeRequestId !== this.ajaxRequestId) return;\n this.ajaxController?.abort();\n const controller = new AbortController();\n this.ajaxController = controller;\n const page = append ? this.page + 1 : 0;\n try {\n const url = buildUrl(ajax, query, page);\n const response = await fetch(url, { signal: controller.signal });\n if (response.ok === false) throw new Error(`ForgeSelect: remote request failed with HTTP ${response.status}`);\n const json: unknown = await response.json();\n if (activeRequestId !== this.ajaxRequestId || this.destroyed) return;\n const { options, hasMore } = normalizeRemoteResult(ajax, json);\n\n if (append) {\n const existing = collectValues(this.data);\n this.data = [...this.data, ...options.filter((o) => !existing.has(o.value))];\n } else {\n this.data = options;\n this.rowContentCache.clear();\n }\n this.page = page;\n this.hasMore = hasMore;\n this.remoteLoaded = true;\n this.loadError = null;\n } catch (cause) {\n if (activeRequestId !== this.ajaxRequestId || this.destroyed || controller.signal.aborted) return;\n const error = cause instanceof Error ? cause : new Error(String(cause));\n if (!append) {\n this.data = [];\n this.rowContentCache.clear();\n }\n this.hasMore = false;\n this.loadError = error;\n this.emitter.emit(\"error\", error);\n } finally {\n if (activeRequestId === this.ajaxRequestId && !this.destroyed) {\n this.ajaxController = null;\n this.loading = false;\n this.loadingMore = false;\n if (this.isOpen) this.renderList();\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -10,6 +10,11 @@ interface Option {
|
|
|
10
10
|
description?: string;
|
|
11
11
|
/** Arbitrary payload for custom templates; ForgeSelect never reads it. */
|
|
12
12
|
meta?: Record<string, unknown>;
|
|
13
|
+
/**
|
|
14
|
+
* Nested options, making this a tree node. Purely additive: lists where
|
|
15
|
+
* no option has `children` render and behave exactly as a flat list.
|
|
16
|
+
*/
|
|
17
|
+
children?: Option[];
|
|
13
18
|
}
|
|
14
19
|
interface OptionGroup {
|
|
15
20
|
label: string;
|
|
@@ -17,11 +22,24 @@ interface OptionGroup {
|
|
|
17
22
|
}
|
|
18
23
|
type DataItem = Option | OptionGroup;
|
|
19
24
|
interface AjaxConfig {
|
|
20
|
-
url: string | ((query: string) => string);
|
|
21
|
-
params?: (query: string) => Record<string, unknown>;
|
|
25
|
+
url: string | ((query: string, page: number) => string);
|
|
26
|
+
params?: (query: string, page: number) => Record<string, unknown>;
|
|
22
27
|
/** Debounce in milliseconds. Default 250. */
|
|
23
28
|
debounce?: number;
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Opt in to loading additional pages as the user scrolls near the bottom
|
|
31
|
+
* of the dropdown, instead of only reloading on search. Default false.
|
|
32
|
+
*/
|
|
33
|
+
pagination?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Return a plain array (page-replace behavior, unchanged from before
|
|
36
|
+
* `pagination` existed) or `{ options, hasMore }` so ForgeSelect knows
|
|
37
|
+
* whether to keep requesting further pages when `pagination` is true.
|
|
38
|
+
*/
|
|
39
|
+
transform?: (response: unknown) => Option[] | {
|
|
40
|
+
options: Option[];
|
|
41
|
+
hasMore: boolean;
|
|
42
|
+
};
|
|
25
43
|
}
|
|
26
44
|
interface ForgeSelectPlugin {
|
|
27
45
|
name: string;
|
|
@@ -37,6 +55,13 @@ interface ForgeSelectOptions {
|
|
|
37
55
|
multiple?: boolean;
|
|
38
56
|
clearable?: boolean;
|
|
39
57
|
allowCreate?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Let the user reorder selected tags by dragging them (mouse/touch/pen via
|
|
60
|
+
* Pointer Events), or via Alt+Left/Alt+Right when a tag has focus. Only
|
|
61
|
+
* meaningful when `multiple` is true. Default false — existing multi-select
|
|
62
|
+
* behavior and tag markup are unchanged when this is left off.
|
|
63
|
+
*/
|
|
64
|
+
sortable?: boolean;
|
|
40
65
|
theme?: string;
|
|
41
66
|
disabled?: boolean;
|
|
42
67
|
data?: DataItem[];
|
|
@@ -54,7 +79,11 @@ interface ForgeSelectOptions {
|
|
|
54
79
|
plugins?: ForgeSelectPlugin[];
|
|
55
80
|
}
|
|
56
81
|
type ForgeSelectValue = string | string[] | null;
|
|
57
|
-
|
|
82
|
+
interface SetValueOptions {
|
|
83
|
+
/** Emit Forge Select's `change` event after updating. Default true. */
|
|
84
|
+
emitChange?: boolean;
|
|
85
|
+
}
|
|
86
|
+
type ForgeSelectEvent = "change" | "open" | "close" | "search" | "clear" | "error";
|
|
58
87
|
|
|
59
88
|
declare class ForgeSelect {
|
|
60
89
|
/** The original element ForgeSelect was mounted on. */
|
|
@@ -64,6 +93,7 @@ declare class ForgeSelect {
|
|
|
64
93
|
private data;
|
|
65
94
|
private selected;
|
|
66
95
|
private selectedOptions;
|
|
96
|
+
private suppressNextTagClick;
|
|
67
97
|
private emitter;
|
|
68
98
|
private plugins;
|
|
69
99
|
private uid;
|
|
@@ -74,6 +104,7 @@ declare class ForgeSelect {
|
|
|
74
104
|
private dropdown;
|
|
75
105
|
private searchInput;
|
|
76
106
|
private list;
|
|
107
|
+
private liveRegion;
|
|
77
108
|
private isOpen;
|
|
78
109
|
private isDisabled;
|
|
79
110
|
private destroyed;
|
|
@@ -82,26 +113,56 @@ declare class ForgeSelect {
|
|
|
82
113
|
private navItems;
|
|
83
114
|
private highlightedIndex;
|
|
84
115
|
private rowContentCache;
|
|
116
|
+
private expandedValues;
|
|
85
117
|
private loading;
|
|
118
|
+
private loadingMore;
|
|
119
|
+
private page;
|
|
120
|
+
private hasMore;
|
|
86
121
|
private ajaxTimer;
|
|
87
122
|
private ajaxRequestId;
|
|
123
|
+
private ajaxController;
|
|
88
124
|
private remoteLoaded;
|
|
125
|
+
private loadError;
|
|
126
|
+
private originalDisplay;
|
|
127
|
+
private originalDisabled;
|
|
128
|
+
private nativeSelect;
|
|
129
|
+
private nativeForm;
|
|
130
|
+
private syncingNative;
|
|
89
131
|
private onDocumentMouseDown;
|
|
132
|
+
private onNativeChange;
|
|
133
|
+
private applyNativeValues;
|
|
134
|
+
private onFormReset;
|
|
90
135
|
constructor(target: string | HTMLElement, options?: ForgeSelectOptions);
|
|
91
136
|
open(): void;
|
|
92
137
|
close(): void;
|
|
93
138
|
destroy(): void;
|
|
94
139
|
getValue(): ForgeSelectValue;
|
|
95
|
-
setValue(value: ForgeSelectValue): void;
|
|
140
|
+
setValue(value: ForgeSelectValue, options?: SetValueOptions): void;
|
|
96
141
|
enable(): void;
|
|
97
142
|
disable(): void;
|
|
98
143
|
on(event: ForgeSelectEvent, handler: Handler): void;
|
|
99
144
|
off(event: ForgeSelectEvent, handler: Handler): void;
|
|
145
|
+
/**
|
|
146
|
+
* The original target (a hidden native <select> or a plain mount div) can
|
|
147
|
+
* carry an accessible name via aria-label/aria-labelledby, or via a
|
|
148
|
+
* <label for> pointing at its id — but once `this.el` is display:none it
|
|
149
|
+
* drops out of the accessibility tree, so any such association silently
|
|
150
|
+
* stops reaching assistive tech unless we forward it onto the visible,
|
|
151
|
+
* interactive `this.control` ourselves.
|
|
152
|
+
*/
|
|
153
|
+
private applyAccessibleName;
|
|
100
154
|
private buildDom;
|
|
101
155
|
private bindEvents;
|
|
102
156
|
private handleKeydown;
|
|
103
157
|
private selectValue;
|
|
104
158
|
private deselectValue;
|
|
159
|
+
/**
|
|
160
|
+
* Keeps every tree parent's own membership in `selected` consistent with
|
|
161
|
+
* its descendants (post-order, so parents see already-corrected children):
|
|
162
|
+
* a parent counts as selected only when `computeCheckState` says "all".
|
|
163
|
+
* No-op for data with no `children` anywhere.
|
|
164
|
+
*/
|
|
165
|
+
private syncTreeAncestors;
|
|
105
166
|
private clearSelection;
|
|
106
167
|
private afterSelectionChange;
|
|
107
168
|
private syncNativeSelect;
|
|
@@ -109,11 +170,25 @@ declare class ForgeSelect {
|
|
|
109
170
|
private createFromQuery;
|
|
110
171
|
private activateNavItem;
|
|
111
172
|
private renderValue;
|
|
112
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Pointer-based (mouse/touch/pen) reorder for a single tag. Only the real
|
|
175
|
+
* dragged DOM node is moved during the gesture — a full renderValue()
|
|
176
|
+
* mid-drag would destroy it — so the reordered `this.selected` is only
|
|
177
|
+
* committed on release. The move/up listeners and pointer capture live on
|
|
178
|
+
* the stable `this.valueEl` container rather than the tag itself: `tag`
|
|
179
|
+
* gets repositioned via `insertBefore` during the drag, and browsers treat
|
|
180
|
+
* that reparenting as detaching the node, which silently drops pointer
|
|
181
|
+
* capture (and further move events) if it were captured on `tag`.
|
|
182
|
+
*/
|
|
183
|
+
private bindTagDrag;
|
|
184
|
+
/** Alt+Left/Alt+Right on a focused tag: the keyboard-operable equivalent of dragging. */
|
|
185
|
+
private handleTagKeydown;
|
|
186
|
+
private focusTagByValue;
|
|
113
187
|
private buildRows;
|
|
114
188
|
private hasExactMatch;
|
|
115
189
|
private usesVirtualScroll;
|
|
116
190
|
private renderList;
|
|
191
|
+
private announceStatus;
|
|
117
192
|
private renderRows;
|
|
118
193
|
private renderRow;
|
|
119
194
|
/**
|
|
@@ -124,9 +199,17 @@ declare class ForgeSelect {
|
|
|
124
199
|
*/
|
|
125
200
|
private optionContent;
|
|
126
201
|
private moveHighlight;
|
|
202
|
+
private focusNavIndex;
|
|
203
|
+
private navigateTree;
|
|
127
204
|
private updateActiveDescendant;
|
|
128
205
|
private scheduleRemoteLoad;
|
|
206
|
+
/**
|
|
207
|
+
* Fires on every list scroll. Only acts when pagination is opted into via
|
|
208
|
+
* `ajax.pagination`; reads real scroll geometry rather than row counts so
|
|
209
|
+
* it works whether or not virtual scrolling is active for this list.
|
|
210
|
+
*/
|
|
211
|
+
private maybeLoadNextPage;
|
|
129
212
|
private loadRemote;
|
|
130
213
|
}
|
|
131
214
|
|
|
132
|
-
export { type AjaxConfig, type DataItem, ForgeSelect, type ForgeSelectEvent, type ForgeSelectOptions, type ForgeSelectPlugin, type ForgeSelectValue, type Option, type OptionGroup, type TemplateFn, ForgeSelect as default };
|
|
215
|
+
export { type AjaxConfig, type DataItem, ForgeSelect, type ForgeSelectEvent, type ForgeSelectOptions, type ForgeSelectPlugin, type ForgeSelectValue, type Option, type OptionGroup, type SetValueOptions, type TemplateFn, ForgeSelect as default };
|