forge-select 0.2.0 → 0.4.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 -40
- package/dist/index.cjs +754 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +175 -9
- package/dist/index.d.ts +175 -9
- package/dist/index.global.js +1 -900
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +754 -174
- package/dist/index.js.map +1 -1
- package/package.json +32 -7
- package/styles/forge-select.css +50 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/emitter.ts","../src/i18n.ts","../src/ForgeSelect.ts"],"sourcesContent":["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 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 loadingMore: \"Đang tải thêm…\",\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; depth: number; hasChildren: boolean }\n | { kind: \"create\"; navIndex: number }\n | { kind: \"empty\" }\n | { kind: \"loading\" }\n | { kind: \"loading-more\" };\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\n/** All descendant values under `option` (children, recursively), not including `option` itself. */\nfunction collectDescendantValues(option: Option): string[] {\n if (!option.children) return [];\n const values: string[] = [];\n for (const child of option.children) {\n values.push(child.value, ...collectDescendantValues(child));\n }\n return values;\n}\n\n/**\n * Tri-state checkbox state for a tree node, derived purely from `selected`:\n * \"all\"/\"none\" if every (or no) leaf descendant is selected, \"some\" otherwise.\n * Leaf options (no children) are just \"all\"/\"none\" based on their own value.\n */\nfunction computeCheckState(option: Option, selected: string[]): \"none\" | \"some\" | \"all\" {\n if (!option.children || option.children.length === 0) {\n return selected.includes(option.value) ? \"all\" : \"none\";\n }\n const states = option.children.map((child) => computeCheckState(child, selected));\n if (states.every((s) => s === \"all\")) return \"all\";\n if (states.every((s) => s === \"none\")) return \"none\";\n return \"some\";\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 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 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 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 \"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 const sync = (option: Option): void => {\n if (!option.children || option.children.length === 0) return;\n for (const child of option.children) sync(child);\n const state = computeCheckState(option, this.selected);\n const index = this.selected.indexOf(option.value);\n if (state === \"all\" && index === -1) this.selected.push(option.value);\n else if (state !== \"all\" && index !== -1) this.selected.splice(index, 1);\n };\n for (const item of this.data) {\n const options = isGroup(item) ? item.options : [item];\n options.forEach(sync);\n }\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 const search = (options: Option[]): Option | undefined => {\n for (const option of options) {\n if (option.value === value) return option;\n if (option.children) {\n const found = search(option.children);\n if (found) return found;\n }\n }\n return undefined;\n };\n for (const item of this.data) {\n const found = search(isGroup(item) ? item.options : [item]);\n if (found) return found;\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 // 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): void => {\n let navIndex = -1;\n if (!option.disabled) {\n navIndex = this.navItems.length;\n this.navItems.push({ kind: \"option\", option });\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);\n }\n }\n }\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(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 }\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 \"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 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 = this.expandedValues.has(row.option.value) ? \"▼\" : \"▶\";\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 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.page = 0;\n this.hasMore = true;\n this.loading = true;\n this.renderList();\n this.ajaxTimer = setTimeout(() => {\n void this.loadRemote(query);\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(query: string, { append = false }: { append?: boolean } = {}): Promise<void> {\n const ajax = this.opts.ajax!;\n const requestId = ++this.ajaxRequestId;\n const page = append ? this.page + 1 : 0;\n try {\n const url = buildUrl(ajax, query, page);\n const response = await fetch(url);\n const json: unknown = await response.json();\n if (requestId !== this.ajaxRequestId || this.destroyed) return;\n const result = ajax.transform ? ajax.transform(json) : (json as Option[]);\n const options = Array.isArray(result) ? result : result.options;\n const hasMore = ajax.pagination ? (Array.isArray(result) ? false : result.hasMore) : false;\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 } catch {\n if (requestId !== this.ajaxRequestId || this.destroyed) return;\n if (!append) {\n this.data = [];\n this.rowContentCache.clear();\n }\n this.hasMore = false;\n } finally {\n if (requestId === this.ajaxRequestId && !this.destroyed) {\n this.loading = false;\n this.loadingMore = 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, page: number): 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, page))) {\n params.set(key, String(value));\n }\n const separator = ajax.url.includes(\"?\") ? \"&\" : \"?\";\n return `${ajax.url}${separator}${params.toString()}`;\n}\n\nfunction collectValues(items: DataItem[]): Set<string> {\n const values = new Set<string>();\n for (const item of items) {\n if (isGroup(item)) {\n for (const option of item.options) values.add(option.value);\n } else {\n values.add(item.value);\n }\n }\n return values;\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/emitter.ts","../src/dropdown-position.ts","../src/i18n.ts","../src/native-select.ts","../src/option-renderer.ts","../src/remote.ts","../src/selection.ts","../src/ForgeSelect.ts"],"sourcesContent":["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 interface DropdownPlacement {\n dropUp: boolean;\n top: number;\n}\n\n/** Pure geometry used by both inline and portalled dropdown positioning. */\nexport function computeDropdownPlacement(\n controlRect: Pick<DOMRect, \"top\" | \"bottom\">,\n dropdownHeight: number,\n viewportHeight: number,\n gap = 4,\n): DropdownPlacement {\n const spaceBelow = viewportHeight - controlRect.bottom;\n const spaceAbove = controlRect.top;\n const dropUp = dropdownHeight > spaceBelow && spaceAbove > spaceBelow;\n return {\n dropUp,\n top: dropUp ? controlRect.top - dropdownHeight - gap : controlRect.bottom + gap,\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 minSearchLength: \"Type {count} or more characters to search\",\n maximumSelected: \"Maximum of {count} selections reached\",\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 minSearchLength: \"Nhập thêm {count} ký tự để tìm kiếm\",\n maximumSelected: \"Đã đạt tối đa {count} lựa chọn\",\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 (!ajax.url) throw new Error(\"ForgeSelect: ajax requires either url or request.\");\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\nexport type IsDisabled = (option: Option) => boolean;\nconst defaultIsDisabled: IsDisabled = (option) => !!option.disabled;\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.\n// `isDisabled` defaults to the static `option.disabled` check so callers that\n// don't pass one keep today's exact behavior; ForgeSelect.ts passes a\n// predicate that also folds in the dynamic `isOptionDisabled` callback.\nexport function collectDescendantValues(option: Option, isDisabled: IsDisabled = defaultIsDisabled): string[] {\n if (!option.children) return [];\n const values: string[] = [];\n for (const child of option.children) {\n if (!isDisabled(child)) values.push(child.value);\n values.push(...collectDescendantValues(child, isDisabled));\n }\n return values;\n}\n\nexport function computeCheckState(\n option: Option,\n selected: string[],\n isDisabled: IsDisabled = defaultIsDisabled,\n): \"none\" | \"some\" | \"all\" {\n if (!option.children?.length) return selected.includes(option.value) ? \"all\" : \"none\";\n const states = option.children\n .filter((child) => !isDisabled(child))\n .map((child) => computeCheckState(child, selected, isDisabled));\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(\n items: DataItem[],\n selected: string[],\n isDisabled: IsDisabled = defaultIsDisabled,\n): 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, isDisabled);\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 { computeDropdownPlacement } from \"./dropdown-position\";\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 ForgeSelectEventHandler,\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 | { kind: \"min-length\" };\n\ntype NavItem = { kind: \"option\"; option: Option; parentValue?: string } | { kind: \"create\" };\ntype TagCreation = { option: Option; created: boolean };\n\ninterface ResolvedOptions {\n placeholder: string;\n searchable: boolean;\n multiple: boolean;\n clearable: boolean;\n allowCreate: boolean;\n sortable: boolean;\n closeOnSelect: boolean;\n maxSelections?: number;\n theme: string;\n disabled: boolean;\n required: boolean;\n data?: DataItem[];\n ajax?: AjaxConfig;\n templateResult?: TemplateFn;\n templateSelection?: TemplateFn;\n filterOption?: (option: Option, query: string) => boolean;\n minSearchLength: number;\n isOptionDisabled?: (option: Option) => boolean;\n minResultsForSearch: number;\n virtualScroll: boolean | undefined;\n itemHeight: number;\n language: string | Record<string, string>;\n plugins: ForgeSelectPlugin[];\n openOnFocus: boolean;\n dropdownParent?: HTMLElement | string;\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 private portalHost: HTMLDivElement | null = null;\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 /** Combines the static `disabled` field with the dynamic `isOptionDisabled` callback. */\n private isOptionDisabled = (option: Option): boolean =>\n option.disabled === true || (this.opts.isOptionDisabled?.(option) ?? false);\n\n private pointerDownOnControl = false;\n\n private onDocumentMouseDown = (event: MouseEvent): void => {\n const target = event.target as Node;\n if (!this.root.contains(target) && !this.portalHost?.contains(target)) this.close();\n };\n\n private onWindowResize = (): void => {\n this.positionDropdown();\n };\n\n private onAncestorScroll = (): void => {\n if (this.portalHost) this.positionDropdown();\n };\n\n private onNativeInvalid = (event: Event): void => {\n event.preventDefault();\n this.control.classList.add(\"forge-select__control--invalid\");\n this.control.setAttribute(\"aria-invalid\", \"true\");\n if (!this.isOpen) this.open();\n this.control.focus();\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 closeOnSelect: options.closeOnSelect ?? false,\n maxSelections:\n options.maxSelections == null || !Number.isFinite(options.maxSelections)\n ? undefined\n : Math.max(0, Math.floor(options.maxSelections)),\n theme: options.theme ?? \"default\",\n disabled: options.disabled ?? nativeSelect?.disabled ?? false,\n required: options.required ?? nativeSelect?.required ?? false,\n data: options.data,\n ajax: options.ajax,\n templateResult: options.templateResult,\n templateSelection: options.templateSelection,\n filterOption: options.filterOption,\n minSearchLength: Math.max(0, Math.floor(options.minSearchLength ?? 0)),\n minResultsForSearch: Math.max(0, Math.floor(options.minResultsForSearch ?? 0)),\n isOptionDisabled: options.isOptionDisabled,\n virtualScroll: options.virtualScroll,\n itemHeight: options.itemHeight ?? DEFAULT_ITEM_HEIGHT,\n language: options.language ?? \"en\",\n plugins: options.plugins ?? [],\n openOnFocus: options.openOnFocus ?? false,\n dropdownParent: options.dropdownParent,\n };\n this.strings = getStrings(this.opts.language);\n this.plugins = this.opts.plugins;\n if (nativeSelect) nativeSelect.required = this.opts.required;\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 nativeSelect?.addEventListener(\"invalid\", this.onNativeInvalid);\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 this.positionDropdown();\n window.addEventListener(\"resize\", this.onWindowResize);\n document.addEventListener(\"scroll\", this.onAncestorScroll, true);\n if (this.searchInput && !this.searchInput.hidden) 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.root.classList.remove(\"forge-select--drop-up\");\n this.control.setAttribute(\"aria-expanded\", \"false\");\n document.removeEventListener(\"mousedown\", this.onDocumentMouseDown);\n window.removeEventListener(\"resize\", this.onWindowResize);\n document.removeEventListener(\"scroll\", this.onAncestorScroll, true);\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 /**\n * Flips the dropdown above the control when there isn't enough room below\n * but there is above. Recomputed on open() and on window resize — the\n * dropdown is positioned absolutely inside the relatively-positioned root,\n * so it already tracks the control correctly on page scroll without\n * needing a scroll listener.\n */\n private positionDropdown(): void {\n const controlRect = this.control.getBoundingClientRect();\n const placement = computeDropdownPlacement(controlRect, this.dropdown.offsetHeight, window.innerHeight);\n this.root.classList.toggle(\"forge-select--drop-up\", placement.dropUp);\n if (this.portalHost) {\n this.portalHost.style.top = `${placement.top}px`;\n this.portalHost.style.left = `${controlRect.left}px`;\n this.portalHost.style.width = `${controlRect.width}px`;\n }\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.nativeSelect?.removeEventListener(\"invalid\", this.onNativeInvalid);\n this.nativeForm?.removeEventListener(\"reset\", this.onFormReset);\n this.rowContentCache.clear();\n this.portalHost?.remove();\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 /**\n * Replaces the option list after construction. An open dropdown re-renders\n * immediately; a selection whose value isn't in the new data stays\n * selected (rendered via the already-selected option's own label/avatar,\n * the same fallback used for values selected from a stale ajax page).\n */\n setData(data: DataItem[]): void {\n if (this.ajaxTimer) {\n clearTimeout(this.ajaxTimer);\n this.ajaxTimer = null;\n }\n this.ajaxController?.abort();\n this.ajaxController = null;\n this.ajaxRequestId += 1;\n this.loading = false;\n this.loadingMore = false;\n this.loadError = null;\n this.remoteLoaded = true;\n this.page = 0;\n this.hasMore = false;\n this.data = data;\n this.opts.data = data;\n this.updateSearchVisibility();\n this.rowContentCache.clear();\n this.highlightedIndex = -1;\n if (this.isOpen) this.renderList();\n }\n\n /**\n * Multi-select only: selects every currently non-disabled option, including\n * nested tree descendants and options inside groups. If `maxSelections` is\n * set, stops once the cap is reached rather than exceeding it. A no-op for\n * single-select.\n */\n selectAll(): void {\n if (!this.opts.multiple) return;\n this.selected = [];\n for (const value of this.allSelectableValues()) {\n const option = this.findOption(value);\n if (option && this.canSelectOption(option)) this.selectValue(value, false);\n }\n this.afterSelectionChange();\n }\n\n /** Clears every selection. Equivalent to `setValue(null)`. */\n clearAll(): void {\n this.clearSelection();\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<E extends ForgeSelectEvent>(event: E, handler: ForgeSelectEventHandler<E>): void {\n this.emitter.on(event, handler as Handler);\n }\n\n off<E extends ForgeSelectEvent>(event: E, handler: ForgeSelectEventHandler<E>): void {\n this.emitter.off(event, handler as 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 shouldShowSearch(): boolean {\n return (\n this.opts.searchable && (this.opts.ajax != null || collectValues(this.data).size >= this.opts.minResultsForSearch)\n );\n }\n\n private updateSearchVisibility(): void {\n if (!this.searchInput) return;\n this.searchInput.hidden = !this.shouldShowSearch();\n if (this.searchInput.hidden) {\n this.searchInput.value = \"\";\n this.query = \"\";\n }\n }\n\n private buildDom(): void {\n const portalParent =\n typeof this.opts.dropdownParent === \"string\"\n ? document.querySelector<HTMLElement>(this.opts.dropdownParent)\n : this.opts.dropdownParent;\n if (this.opts.dropdownParent && !portalParent) {\n throw new Error(`ForgeSelect: dropdown parent not found: ${String(this.opts.dropdownParent)}`);\n }\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 if (this.opts.required) this.control.setAttribute(\"aria-required\", \"true\");\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.searchInput.hidden = !this.shouldShowSearch();\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.liveRegion);\n if (!portalParent) this.root.append(this.dropdown);\n this.el.style.display = \"none\";\n this.el.insertAdjacentElement(\"afterend\", this.root);\n\n if (portalParent) {\n this.portalHost = document.createElement(\"div\");\n this.portalHost.className = \"forge-select forge-select--portal-host\";\n this.portalHost.dataset.theme = this.opts.theme;\n this.portalHost.style.setProperty(\"--fs-item-height\", `${this.opts.itemHeight}px`);\n this.portalHost.append(this.dropdown);\n portalParent.append(this.portalHost);\n }\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 // A mouse click fires mousedown -> focus -> click, in that order. Without\n // tracking pointerDownOnControl, openOnFocus would open the dropdown\n // during the focus phase, and the click handler above would then\n // immediately close it again via its own open/close toggle. Tracking\n // whether a mousedown preceded this focus distinguishes \"focused via\n // mouse click\" (skip auto-open, let the click handler's toggle run) from\n // \"focused via keyboard Tab\" (auto-open).\n this.control.addEventListener(\"mousedown\", () => {\n this.pointerDownOnControl = true;\n });\n this.control.addEventListener(\"focus\", () => {\n if (this.opts.openOnFocus && !this.pointerDownOnControl && !this.isOpen && !this.isDisabled) {\n this.open();\n }\n this.pointerDownOnControl = false;\n });\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 const trimmed = this.query.trim();\n const belowMinLength = trimmed !== \"\" && trimmed.length < this.opts.minSearchLength;\n if (this.opts.ajax && !belowMinLength) {\n this.scheduleRemoteLoad(this.query, this.opts.ajax.debounce ?? 250);\n } else {\n if (belowMinLength) {\n if (this.ajaxTimer) {\n clearTimeout(this.ajaxTimer);\n this.ajaxTimer = null;\n }\n this.ajaxController?.abort();\n this.loading = false;\n }\n this.renderList();\n }\n });\n this.searchInput.addEventListener(\"keydown\", (event) => this.handleKeydown(event));\n this.searchInput.addEventListener(\"paste\", (event) => {\n if (!this.opts.multiple || !this.opts.allowCreate) return;\n const text = event.clipboardData?.getData(\"text\") ?? \"\";\n const labels = text\n .split(/[,\\n]+/)\n .map((s) => s.trim())\n .filter(Boolean);\n if (labels.length < 2) return;\n event.preventDefault();\n const created: TagCreation[] = [];\n for (const label of labels) {\n const result = this.createTag(label);\n if (result) created.push(result);\n }\n if (created.length === 0) return;\n this.searchInput!.value = \"\";\n this.query = \"\";\n this.afterSelectionChange();\n for (const result of created) {\n if (result.created) this.emitter.emit(\"create\", result.option);\n this.emitter.emit(\"select\", result.option);\n }\n if (this.opts.closeOnSelect) this.close();\n else this.renderList();\n });\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) {\n const optionRow = target.closest<HTMLLIElement>(\"li[data-option-value]\");\n const option = optionRow ? this.findOption(optionRow.dataset.optionValue!) : undefined;\n if (option && this.hasReachedMaximum() && !this.selected.includes(option.value)) this.announceMaximum(option);\n return;\n }\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 canSelectOption(option: Option): boolean {\n if (this.opts.maxSelections == null) return true;\n const projected = [...this.selected];\n if (!projected.includes(option.value)) projected.push(option.value);\n for (const value of collectDescendantValues(option, this.isOptionDisabled)) {\n if (!projected.includes(value)) projected.push(value);\n }\n syncDataTreeAncestors(this.data, projected, this.isOptionDisabled);\n return projected.length <= this.opts.maxSelections;\n }\n\n private hasReachedMaximum(): boolean {\n return this.opts.maxSelections != null && this.selected.length >= this.opts.maxSelections;\n }\n\n private announceMaximum(option: Option): void {\n const limit = this.opts.maxSelections;\n if (limit == null) return;\n this.liveRegion.textContent = format(this.strings.maximumSelected, { count: String(limit) });\n this.emitter.emit(\"maximum\", { limit, option });\n }\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, this.isOptionDisabled)) {\n if (!this.selected.includes(v)) this.selected.push(v);\n }\n this.syncTreeAncestors();\n } else {\n this.selected = [value];\n }\n if (notify) {\n this.afterSelectionChange();\n this.emitter.emit(\"select\", option);\n }\n }\n\n private deselectValue(value: string, notify: boolean): void {\n const index = this.selected.indexOf(value);\n if (index === -1) return;\n const option = this.findOption(value) ?? this.selectedOptions.get(value);\n this.selected.splice(index, 1);\n if (this.opts.multiple) {\n if (option) {\n for (const v of collectDescendantValues(option, this.isOptionDisabled)) {\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) {\n this.afterSelectionChange();\n this.emitter.emit(\"unselect\", option ?? { value, label: value });\n }\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, this.isOptionDisabled);\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 allSelectableValues(): string[] {\n const values: string[] = [];\n const visit = (option: Option): void => {\n if (!this.isOptionDisabled(option)) values.push(option.value);\n option.children?.forEach(visit);\n };\n for (const item of this.data) (isGroup(item) ? item.options : [item]).forEach(visit);\n return values;\n }\n\n private afterSelectionChange(emitChange = true): void {\n this.renderValue();\n this.syncNativeSelect(emitChange);\n if (!this.opts.required || this.selected.length > 0) {\n this.control.classList.remove(\"forge-select__control--invalid\");\n this.control.removeAttribute(\"aria-invalid\");\n }\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 findOptionByLabel(label: string): Option | undefined {\n const lower = label.toLowerCase();\n const search = (options: Option[]): Option | undefined => {\n for (const option of options) {\n if (option.label.toLowerCase() === lower) 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 this.data) {\n const found = search(isGroup(item) ? item.options : [item]);\n if (found) return found;\n }\n return undefined;\n }\n\n /** Selects an existing option matching `label` exactly, or creates and selects a new one. */\n private createTag(label: string): TagCreation | undefined {\n const trimmed = label.trim();\n if (!trimmed) return undefined;\n const existing = this.findOptionByLabel(trimmed);\n if (existing) {\n if (this.selected.includes(existing.value)) return undefined;\n if (this.opts.multiple && !this.canSelectOption(existing)) {\n this.announceMaximum(existing);\n return undefined;\n }\n this.selectValue(existing.value, false);\n return { option: existing, created: false };\n }\n const option: Option = { value: trimmed, label: trimmed };\n if (this.opts.multiple && !this.canSelectOption(option)) {\n this.announceMaximum(option);\n return undefined;\n }\n this.data.push(option);\n this.selectValue(option.value, false);\n return { option, created: true };\n }\n\n private createFromQuery(): void {\n const label = this.query.trim();\n if (!label) return;\n const result = this.createTag(label);\n if (!result) return;\n if (this.searchInput) {\n this.searchInput.value = \"\";\n this.query = \"\";\n }\n this.afterSelectionChange();\n if (result.created) this.emitter.emit(\"create\", result.option);\n this.emitter.emit(\"select\", result.option);\n if (!this.opts.multiple || this.opts.closeOnSelect) 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 let changed = false;\n if (this.selected.includes(value)) {\n this.deselectValue(value, true);\n changed = true;\n } else if (this.canSelectOption(item.option)) {\n this.selectValue(value, true);\n changed = true;\n } else {\n this.announceMaximum(item.option);\n }\n if (changed && this.opts.closeOnSelect) this.close();\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 this.emitter.emit(\"reorder\", [...this.selected]);\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.emitter.emit(\"reorder\", [...this.selected]);\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 trimmedQuery = this.query.trim();\n const query = trimmedQuery.toLowerCase();\n const matches = (option: Option): boolean =>\n query === \"\" ||\n (this.opts.filterOption\n ? this.opts.filterOption(option, trimmedQuery)\n : option.label.toLowerCase().includes(query) || (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 const interactionDisabled =\n this.isOptionDisabled(option) || (this.hasReachedMaximum() && !this.selected.includes(option.value));\n if (!interactionDisabled) {\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 (trimmedQuery !== \"\" && trimmedQuery.length < this.opts.minSearchLength) {\n this.rows.push({ kind: \"min-length\" });\n return;\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 return !!this.findOptionByLabel(lowerQuery);\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 = this.hasReachedMaximum()\n ? format(this.strings.maximumSelected, { count: String(this.opts.maxSelections) })\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 : first?.kind === \"min-length\"\n ? format(this.strings.minSearchLength, { count: String(this.opts.minSearchLength) })\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 \"min-length\":\n li.className = \"forge-select__min-length\";\n li.setAttribute(\"role\", \"option\");\n li.setAttribute(\"aria-disabled\", \"true\");\n li.setAttribute(\"aria-selected\", \"false\");\n li.textContent = format(this.strings.minSearchLength, { count: String(this.opts.minSearchLength) });\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.dataset.optionValue = row.option.value;\n if (row.option.className) li.classList.add(...row.option.className.trim().split(/\\s+/).filter(Boolean));\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 (\n this.opts.multiple &&\n row.hasChildren &&\n computeCheckState(row.option, this.selected, this.isOptionDisabled) === \"some\"\n ) {\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 (\n this.isOptionDisabled(row.option) ||\n (this.hasReachedMaximum() && !this.selected.includes(row.option.value))\n ) {\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 let json: unknown;\n if (ajax.request) {\n json = await ajax.request(query, page, controller.signal);\n } else {\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 json = await response.json();\n }\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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forge-select",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A modern, lightweight, highly customizable replacement for Select2.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"select",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
],
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"author": "KonexForge",
|
|
16
|
-
"homepage": "https://
|
|
16
|
+
"homepage": "https://forgeselect.konexforge.com/",
|
|
17
17
|
"bugs": {
|
|
18
18
|
"url": "https://github.com/cmm-cmm/ForgeSelect/issues"
|
|
19
19
|
},
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"url": "git+https://github.com/cmm-cmm/ForgeSelect.git"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=20.19"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|
|
@@ -47,20 +47,45 @@
|
|
|
47
47
|
"styles"
|
|
48
48
|
],
|
|
49
49
|
"sideEffects": false,
|
|
50
|
+
"overrides": {
|
|
51
|
+
"esbuild": "0.28.1"
|
|
52
|
+
},
|
|
50
53
|
"scripts": {
|
|
51
54
|
"build": "tsup",
|
|
55
|
+
"bench": "npm run build && node scripts/benchmark.mjs",
|
|
52
56
|
"build:site": "npm run build && node scripts/build-site.mjs",
|
|
57
|
+
"check:package": "npm run build && npm run build --workspaces --if-present && npm pack --dry-run --ignore-scripts && npm pack ./packages/react --dry-run --ignore-scripts && npm pack ./packages/vue --dry-run --ignore-scripts",
|
|
58
|
+
"check:site": "npm run build:site && node scripts/check-site.mjs",
|
|
59
|
+
"format": "prettier --write \"**/*.{ts,tsx,js,mjs,json,jsonc,md,css,yml,yaml}\"",
|
|
60
|
+
"format:check": "prettier --check \"**/*.{ts,tsx,js,mjs,json,jsonc,md,css,yml,yaml}\"",
|
|
61
|
+
"lint": "eslint .",
|
|
53
62
|
"test": "vitest run",
|
|
63
|
+
"test:browser": "npm run build && playwright test",
|
|
64
|
+
"test:coverage": "vitest run --coverage",
|
|
54
65
|
"test:watch": "vitest",
|
|
55
66
|
"typecheck": "tsc --noEmit",
|
|
56
|
-
"
|
|
67
|
+
"verify": "npm run lint && npm run format:check && npm run typecheck && npm run test:coverage && npm run build",
|
|
68
|
+
"prepublishOnly": "npm run verify",
|
|
69
|
+
"deploy:cloudflare": "wrangler deploy"
|
|
57
70
|
},
|
|
58
71
|
"devDependencies": {
|
|
72
|
+
"@axe-core/playwright": "^4.12.1",
|
|
73
|
+
"@eslint/js": "^9.39.5",
|
|
74
|
+
"@playwright/test": "^1.61.1",
|
|
75
|
+
"@types/node": "^26.1.1",
|
|
76
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
77
|
+
"eslint": "^10.7.0",
|
|
78
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
79
|
+
"globals": "^17.7.0",
|
|
59
80
|
"highlight.js": "^11.11.1",
|
|
60
|
-
"jsdom": "^
|
|
81
|
+
"jsdom": "^29.1.1",
|
|
61
82
|
"markdown-it": "^14.3.0",
|
|
83
|
+
"prettier": "^3.9.5",
|
|
84
|
+
"sharp": "^0.34.5",
|
|
62
85
|
"tsup": "^8.3.5",
|
|
63
|
-
"typescript": "^5.
|
|
64
|
-
"
|
|
86
|
+
"typescript": "^5.9.3",
|
|
87
|
+
"typescript-eslint": "^8.65.0",
|
|
88
|
+
"vitest": "^4.1.10",
|
|
89
|
+
"wrangler": "^4.110.0"
|
|
65
90
|
}
|
|
66
91
|
}
|
package/styles/forge-select.css
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
.forge-select {
|
|
4
4
|
--fs-bg: #ffffff;
|
|
5
5
|
--fs-fg: #1f2937;
|
|
6
|
-
--fs-muted: #
|
|
6
|
+
--fs-muted: #6b7280;
|
|
7
7
|
--fs-border: #d1d5db;
|
|
8
8
|
--fs-border-focus: #6366f1;
|
|
9
|
+
--fs-border-invalid: #dc2626;
|
|
9
10
|
--fs-radius: 8px;
|
|
10
11
|
--fs-dropdown-bg: #ffffff;
|
|
11
12
|
--fs-dropdown-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
--fs-muted: #6b7280;
|
|
31
32
|
--fs-border: #374151;
|
|
32
33
|
--fs-border-focus: #818cf8;
|
|
34
|
+
--fs-border-invalid: #f87171;
|
|
33
35
|
--fs-dropdown-bg: #111827;
|
|
34
36
|
--fs-dropdown-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
35
37
|
--fs-option-hover-bg: #312e81;
|
|
@@ -58,6 +60,10 @@
|
|
|
58
60
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--fs-border-focus) 25%, transparent);
|
|
59
61
|
}
|
|
60
62
|
|
|
63
|
+
.forge-select__control--invalid {
|
|
64
|
+
border-color: var(--fs-border-invalid);
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
.forge-select--disabled .forge-select__control {
|
|
62
68
|
opacity: 0.55;
|
|
63
69
|
cursor: not-allowed;
|
|
@@ -92,6 +98,17 @@
|
|
|
92
98
|
border-radius: calc(var(--fs-radius) - 4px);
|
|
93
99
|
}
|
|
94
100
|
|
|
101
|
+
.forge-select--sortable .forge-select__tag {
|
|
102
|
+
cursor: grab;
|
|
103
|
+
touch-action: none;
|
|
104
|
+
user-select: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.forge-select__tag--dragging {
|
|
108
|
+
opacity: 0.5;
|
|
109
|
+
cursor: grabbing;
|
|
110
|
+
}
|
|
111
|
+
|
|
95
112
|
.forge-select__tag-remove,
|
|
96
113
|
.forge-select__clear {
|
|
97
114
|
padding: 0 2px;
|
|
@@ -135,6 +152,23 @@
|
|
|
135
152
|
overflow: hidden;
|
|
136
153
|
}
|
|
137
154
|
|
|
155
|
+
.forge-select--drop-up .forge-select__dropdown {
|
|
156
|
+
top: auto;
|
|
157
|
+
bottom: calc(100% + 4px);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.forge-select--portal-host {
|
|
161
|
+
position: fixed;
|
|
162
|
+
z-index: 1000;
|
|
163
|
+
min-width: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.forge-select--portal-host .forge-select__dropdown {
|
|
167
|
+
top: 0;
|
|
168
|
+
right: 0;
|
|
169
|
+
bottom: auto;
|
|
170
|
+
}
|
|
171
|
+
|
|
138
172
|
.forge-select__search {
|
|
139
173
|
width: 100%;
|
|
140
174
|
padding: 8px 10px;
|
|
@@ -256,8 +290,10 @@
|
|
|
256
290
|
}
|
|
257
291
|
|
|
258
292
|
.forge-select__empty,
|
|
293
|
+
.forge-select__error,
|
|
259
294
|
.forge-select__loading,
|
|
260
|
-
.forge-select__loading-more
|
|
295
|
+
.forge-select__loading-more,
|
|
296
|
+
.forge-select__min-length {
|
|
261
297
|
padding: 10px 12px;
|
|
262
298
|
color: var(--fs-muted);
|
|
263
299
|
text-align: center;
|
|
@@ -267,3 +303,15 @@
|
|
|
267
303
|
padding: 0;
|
|
268
304
|
margin: 0;
|
|
269
305
|
}
|
|
306
|
+
|
|
307
|
+
.forge-select__sr-only {
|
|
308
|
+
position: absolute;
|
|
309
|
+
width: 1px;
|
|
310
|
+
height: 1px;
|
|
311
|
+
padding: 0;
|
|
312
|
+
margin: -1px;
|
|
313
|
+
overflow: hidden;
|
|
314
|
+
clip: rect(0, 0, 0, 0);
|
|
315
|
+
white-space: nowrap;
|
|
316
|
+
border: 0;
|
|
317
|
+
}
|