forge-select 0.1.0 → 0.2.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.
@@ -56,6 +56,7 @@ var ForgeSelectBundle = (() => {
56
56
  en: {
57
57
  noResults: "No results found",
58
58
  loading: "Loading\u2026",
59
+ loadingMore: "Loading more\u2026",
59
60
  createOption: 'Create "{query}"',
60
61
  clearSelection: "Clear selection",
61
62
  removeItem: "Remove {label}",
@@ -64,6 +65,7 @@ var ForgeSelectBundle = (() => {
64
65
  vi: {
65
66
  noResults: "Kh\xF4ng t\xECm th\u1EA5y k\u1EBFt qu\u1EA3",
66
67
  loading: "\u0110ang t\u1EA3i\u2026",
68
+ loadingMore: "\u0110ang t\u1EA3i th\xEAm\u2026",
67
69
  createOption: 'T\u1EA1o "{query}"',
68
70
  clearSelection: "X\xF3a l\u1EF1a ch\u1ECDn",
69
71
  removeItem: "X\xF3a {label}",
@@ -89,6 +91,23 @@ var ForgeSelectBundle = (() => {
89
91
  function isGroup(item) {
90
92
  return item.options !== void 0;
91
93
  }
94
+ function collectDescendantValues(option) {
95
+ if (!option.children) return [];
96
+ const values = [];
97
+ for (const child of option.children) {
98
+ values.push(child.value, ...collectDescendantValues(child));
99
+ }
100
+ return values;
101
+ }
102
+ function computeCheckState(option, selected) {
103
+ if (!option.children || option.children.length === 0) {
104
+ return selected.includes(option.value) ? "all" : "none";
105
+ }
106
+ const states = option.children.map((child) => computeCheckState(child, selected));
107
+ if (states.every((s) => s === "all")) return "all";
108
+ if (states.every((s) => s === "none")) return "none";
109
+ return "some";
110
+ }
92
111
  var ForgeSelect = class {
93
112
  constructor(target, options = {}) {
94
113
  this.selected = [];
@@ -104,7 +123,11 @@ var ForgeSelectBundle = (() => {
104
123
  this.navItems = [];
105
124
  this.highlightedIndex = -1;
106
125
  this.rowContentCache = /* @__PURE__ */ new Map();
126
+ this.expandedValues = /* @__PURE__ */ new Set();
107
127
  this.loading = false;
128
+ this.loadingMore = false;
129
+ this.page = 0;
130
+ this.hasMore = true;
108
131
  this.ajaxTimer = null;
109
132
  this.ajaxRequestId = 0;
110
133
  this.remoteLoaded = false;
@@ -294,13 +317,23 @@ var ForgeSelectBundle = (() => {
294
317
  this.searchInput.addEventListener("keydown", (event) => this.handleKeydown(event));
295
318
  }
296
319
  this.list.addEventListener("click", (event) => {
297
- const li = event.target.closest("li[data-nav-index]");
320
+ const target = event.target;
321
+ const twisty = target.closest("[data-twisty]");
322
+ if (twisty) {
323
+ const value = twisty.dataset.twisty;
324
+ if (this.expandedValues.has(value)) this.expandedValues.delete(value);
325
+ else this.expandedValues.add(value);
326
+ this.renderList();
327
+ return;
328
+ }
329
+ const li = target.closest("li[data-nav-index]");
298
330
  if (!li) return;
299
331
  const navIndex = Number(li.dataset.navIndex);
300
332
  this.activateNavItem(navIndex);
301
333
  });
302
334
  this.list.addEventListener("scroll", () => {
303
335
  if (this.usesVirtualScroll()) this.renderRows();
336
+ this.maybeLoadNextPage();
304
337
  });
305
338
  }
306
339
  handleKeydown(event) {
@@ -343,16 +376,53 @@ var ForgeSelectBundle = (() => {
343
376
  if (this.selected.includes(value)) return;
344
377
  const option = this.findOption(value) ?? this.selectedOptions.get(value) ?? { value, label: value };
345
378
  this.selectedOptions.set(value, option);
346
- if (this.opts.multiple) this.selected.push(value);
347
- else this.selected = [value];
379
+ if (this.opts.multiple) {
380
+ this.selected.push(value);
381
+ for (const v of collectDescendantValues(option)) {
382
+ if (!this.selected.includes(v)) this.selected.push(v);
383
+ }
384
+ this.syncTreeAncestors();
385
+ } else {
386
+ this.selected = [value];
387
+ }
348
388
  if (notify) this.afterSelectionChange();
349
389
  }
350
390
  deselectValue(value, notify) {
351
391
  const index = this.selected.indexOf(value);
352
392
  if (index === -1) return;
353
393
  this.selected.splice(index, 1);
394
+ if (this.opts.multiple) {
395
+ const option = this.findOption(value) ?? this.selectedOptions.get(value);
396
+ if (option) {
397
+ for (const v of collectDescendantValues(option)) {
398
+ const i = this.selected.indexOf(v);
399
+ if (i !== -1) this.selected.splice(i, 1);
400
+ }
401
+ }
402
+ this.syncTreeAncestors();
403
+ }
354
404
  if (notify) this.afterSelectionChange();
355
405
  }
406
+ /**
407
+ * Keeps every tree parent's own membership in `selected` consistent with
408
+ * its descendants (post-order, so parents see already-corrected children):
409
+ * a parent counts as selected only when `computeCheckState` says "all".
410
+ * No-op for data with no `children` anywhere.
411
+ */
412
+ syncTreeAncestors() {
413
+ const sync = (option) => {
414
+ if (!option.children || option.children.length === 0) return;
415
+ for (const child of option.children) sync(child);
416
+ const state = computeCheckState(option, this.selected);
417
+ const index = this.selected.indexOf(option.value);
418
+ if (state === "all" && index === -1) this.selected.push(option.value);
419
+ else if (state !== "all" && index !== -1) this.selected.splice(index, 1);
420
+ };
421
+ for (const item of this.data) {
422
+ const options = isGroup(item) ? item.options : [item];
423
+ options.forEach(sync);
424
+ }
425
+ }
356
426
  clearSelection() {
357
427
  if (this.selected.length === 0) return;
358
428
  this.selected = [];
@@ -383,13 +453,19 @@ var ForgeSelectBundle = (() => {
383
453
  this.el.dispatchEvent(new Event("change", { bubbles: true }));
384
454
  }
385
455
  findOption(value) {
386
- for (const item of this.data) {
387
- if (isGroup(item)) {
388
- const found = item.options.find((o) => o.value === value);
389
- if (found) return found;
390
- } else if (item.value === value) {
391
- return item;
456
+ const search = (options) => {
457
+ for (const option of options) {
458
+ if (option.value === value) return option;
459
+ if (option.children) {
460
+ const found = search(option.children);
461
+ if (found) return found;
462
+ }
392
463
  }
464
+ return void 0;
465
+ };
466
+ for (const item of this.data) {
467
+ const found = search(isGroup(item) ? item.options : [item]);
468
+ if (found) return found;
393
469
  }
394
470
  return void 0;
395
471
  }
@@ -507,13 +583,23 @@ var ForgeSelectBundle = (() => {
507
583
  this.navItems = [];
508
584
  const query = this.query.trim().toLowerCase();
509
585
  const matches = (option) => query === "" || option.label.toLowerCase().includes(query) || (option.description?.toLowerCase().includes(query) ?? false);
510
- const pushOption = (option) => {
586
+ const subtreeMatches = (option) => query === "" || matches(option) || (option.children ?? []).some(subtreeMatches);
587
+ const pushOption = (option, depth) => {
511
588
  let navIndex = -1;
512
589
  if (!option.disabled) {
513
590
  navIndex = this.navItems.length;
514
591
  this.navItems.push({ kind: "option", option });
515
592
  }
516
- this.rows.push({ kind: "option", option, navIndex });
593
+ const hasChildren = !!option.children && option.children.length > 0;
594
+ this.rows.push({ kind: "option", option, navIndex, depth, hasChildren });
595
+ if (hasChildren) {
596
+ const expanded = query !== "" || this.expandedValues.has(option.value);
597
+ if (expanded) {
598
+ for (const child of option.children) {
599
+ if (subtreeMatches(child)) pushOption(child, depth + 1);
600
+ }
601
+ }
602
+ }
517
603
  };
518
604
  if (this.loading) {
519
605
  this.rows.push({ kind: "loading" });
@@ -521,12 +607,12 @@ var ForgeSelectBundle = (() => {
521
607
  }
522
608
  for (const item of this.data) {
523
609
  if (isGroup(item)) {
524
- const visible = item.options.filter(matches);
610
+ const visible = item.options.filter(subtreeMatches);
525
611
  if (visible.length === 0) continue;
526
612
  this.rows.push({ kind: "group", label: item.label });
527
- visible.forEach(pushOption);
528
- } else if (matches(item)) {
529
- pushOption(item);
613
+ visible.forEach((o) => pushOption(o, 0));
614
+ } else if (subtreeMatches(item)) {
615
+ pushOption(item, 0);
530
616
  }
531
617
  }
532
618
  if (this.opts.allowCreate && query !== "" && !this.hasExactMatch(query)) {
@@ -535,11 +621,13 @@ var ForgeSelectBundle = (() => {
535
621
  this.rows.push({ kind: "create", navIndex });
536
622
  }
537
623
  if (this.rows.length === 0) this.rows.push({ kind: "empty" });
624
+ else if (this.loadingMore) this.rows.push({ kind: "loading-more" });
538
625
  }
539
626
  hasExactMatch(lowerQuery) {
627
+ const matchesExactly = (option) => option.label.toLowerCase() === lowerQuery || (option.children ?? []).some(matchesExactly);
540
628
  for (const item of this.data) {
541
629
  const options = isGroup(item) ? item.options : [item];
542
- if (options.some((o) => o.label.toLowerCase() === lowerQuery)) return true;
630
+ if (options.some(matchesExactly)) return true;
543
631
  }
544
632
  return false;
545
633
  }
@@ -599,6 +687,11 @@ var ForgeSelectBundle = (() => {
599
687
  li.className = "forge-select__loading";
600
688
  li.textContent = this.strings.loading;
601
689
  break;
690
+ case "loading-more":
691
+ li.className = "forge-select__loading-more";
692
+ li.setAttribute("aria-hidden", "true");
693
+ li.textContent = this.strings.loadingMore;
694
+ break;
602
695
  case "create":
603
696
  li.className = "forge-select__option forge-select__option--create";
604
697
  li.setAttribute("role", "option");
@@ -613,6 +706,12 @@ var ForgeSelectBundle = (() => {
613
706
  const isSelected = this.selected.includes(row.option.value);
614
707
  li.setAttribute("aria-selected", String(isSelected));
615
708
  if (isSelected) li.classList.add("forge-select__option--selected");
709
+ if (this.opts.multiple && row.hasChildren && computeCheckState(row.option, this.selected) === "some") {
710
+ li.classList.add("forge-select__option--indeterminate");
711
+ }
712
+ if (row.depth > 0) {
713
+ li.style.paddingLeft = `calc(12px + ${row.depth} * var(--fs-tree-indent, 18px))`;
714
+ }
616
715
  if (row.option.disabled) {
617
716
  li.classList.add("forge-select__option--disabled");
618
717
  li.setAttribute("aria-disabled", "true");
@@ -621,6 +720,14 @@ var ForgeSelectBundle = (() => {
621
720
  li.dataset.navIndex = String(row.navIndex);
622
721
  if (row.navIndex === this.highlightedIndex) li.classList.add("forge-select__option--highlighted");
623
722
  }
723
+ if (row.hasChildren) {
724
+ const twisty = document.createElement("span");
725
+ twisty.className = "forge-select__twisty";
726
+ twisty.dataset.twisty = row.option.value;
727
+ twisty.setAttribute("aria-hidden", "true");
728
+ twisty.textContent = this.expandedValues.has(row.option.value) ? "\u25BC" : "\u25B6";
729
+ li.append(twisty);
730
+ }
624
731
  li.append(this.optionContent(row.option));
625
732
  break;
626
733
  }
@@ -683,30 +790,62 @@ var ForgeSelectBundle = (() => {
683
790
  // ---------------------------------------------------------------- remote data
684
791
  scheduleRemoteLoad(query, delay) {
685
792
  if (this.ajaxTimer) clearTimeout(this.ajaxTimer);
793
+ this.page = 0;
794
+ this.hasMore = true;
686
795
  this.loading = true;
687
796
  this.renderList();
688
797
  this.ajaxTimer = setTimeout(() => {
689
798
  void this.loadRemote(query);
690
799
  }, delay);
691
800
  }
692
- async loadRemote(query) {
801
+ /**
802
+ * Fires on every list scroll. Only acts when pagination is opted into via
803
+ * `ajax.pagination`; reads real scroll geometry rather than row counts so
804
+ * it works whether or not virtual scrolling is active for this list.
805
+ */
806
+ maybeLoadNextPage() {
807
+ const ajax = this.opts.ajax;
808
+ if (!ajax?.pagination || !this.hasMore || this.loading || this.loadingMore) return;
809
+ const { scrollHeight, scrollTop, clientHeight } = this.list;
810
+ const threshold = this.opts.itemHeight * 2;
811
+ if (scrollHeight - scrollTop - clientHeight >= threshold) return;
812
+ this.loadingMore = true;
813
+ this.renderList();
814
+ void this.loadRemote(this.query, { append: true });
815
+ }
816
+ async loadRemote(query, { append = false } = {}) {
693
817
  const ajax = this.opts.ajax;
694
818
  const requestId = ++this.ajaxRequestId;
819
+ const page = append ? this.page + 1 : 0;
695
820
  try {
696
- const url = buildUrl(ajax, query);
821
+ const url = buildUrl(ajax, query, page);
697
822
  const response = await fetch(url);
698
823
  const json = await response.json();
699
824
  if (requestId !== this.ajaxRequestId || this.destroyed) return;
700
- this.data = ajax.transform ? ajax.transform(json) : json;
701
- this.rowContentCache.clear();
825
+ const result = ajax.transform ? ajax.transform(json) : json;
826
+ const options = Array.isArray(result) ? result : result.options;
827
+ const hasMore = ajax.pagination ? Array.isArray(result) ? false : result.hasMore : false;
828
+ if (append) {
829
+ const existing = collectValues(this.data);
830
+ this.data = [...this.data, ...options.filter((o) => !existing.has(o.value))];
831
+ } else {
832
+ this.data = options;
833
+ this.rowContentCache.clear();
834
+ }
835
+ this.page = page;
836
+ this.hasMore = hasMore;
702
837
  this.remoteLoaded = true;
703
838
  } catch {
704
839
  if (requestId !== this.ajaxRequestId || this.destroyed) return;
705
- this.data = [];
706
- this.rowContentCache.clear();
840
+ if (!append) {
841
+ this.data = [];
842
+ this.rowContentCache.clear();
843
+ }
844
+ this.hasMore = false;
707
845
  } finally {
708
846
  if (requestId === this.ajaxRequestId && !this.destroyed) {
709
847
  this.loading = false;
848
+ this.loadingMore = false;
710
849
  if (this.isOpen) this.renderList();
711
850
  }
712
851
  }
@@ -733,16 +872,27 @@ var ForgeSelectBundle = (() => {
733
872
  disabled: option.disabled || void 0
734
873
  };
735
874
  }
736
- function buildUrl(ajax, query) {
875
+ function buildUrl(ajax, query, page) {
737
876
  if (typeof ajax.url === "function") return ajax.url(query);
738
877
  if (!ajax.params) return ajax.url;
739
878
  const params = new URLSearchParams();
740
- for (const [key, value] of Object.entries(ajax.params(query))) {
879
+ for (const [key, value] of Object.entries(ajax.params(query, page))) {
741
880
  params.set(key, String(value));
742
881
  }
743
882
  const separator = ajax.url.includes("?") ? "&" : "?";
744
883
  return `${ajax.url}${separator}${params.toString()}`;
745
884
  }
885
+ function collectValues(items) {
886
+ const values = /* @__PURE__ */ new Set();
887
+ for (const item of items) {
888
+ if (isGroup(item)) {
889
+ for (const option of item.options) values.add(option.value);
890
+ } else {
891
+ values.add(item.value);
892
+ }
893
+ }
894
+ return values;
895
+ }
746
896
  function arraysEqual(a, b) {
747
897
  return a.length === b.length && a.every((value, index) => value === b[index]);
748
898
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/emitter.ts","../src/i18n.ts","../src/ForgeSelect.ts"],"sourcesContent":["export { default } from \"./ForgeSelect\";\nexport { default as ForgeSelect } from \"./ForgeSelect\";\nexport type {\n AjaxConfig,\n DataItem,\n ForgeSelectEvent,\n ForgeSelectOptions,\n ForgeSelectPlugin,\n ForgeSelectValue,\n Option,\n OptionGroup,\n TemplateFn,\n} from \"./types\";\n","export type Handler = (...args: unknown[]) => void;\n\nexport class Emitter {\n private handlers = new Map<string, Set<Handler>>();\n\n on(event: string, handler: Handler): void {\n let set = this.handlers.get(event);\n if (!set) {\n set = new Set();\n this.handlers.set(event, set);\n }\n set.add(handler);\n }\n\n off(event: string, handler: Handler): void {\n this.handlers.get(event)?.delete(handler);\n }\n\n emit(event: string, ...args: unknown[]): void {\n const set = this.handlers.get(event);\n if (!set) return;\n for (const handler of [...set]) handler(...args);\n }\n\n clear(): void {\n this.handlers.clear();\n }\n}\n","export type Strings = Record<string, string>;\n\nconst locales: Record<string, Strings> = {\n en: {\n noResults: \"No results found\",\n loading: \"Loading…\",\n createOption: 'Create \"{query}\"',\n clearSelection: \"Clear selection\",\n removeItem: \"Remove {label}\",\n search: \"Search\",\n },\n vi: {\n noResults: \"Không tìm thấy kết quả\",\n loading: \"Đang tải…\",\n createOption: 'Tạo \"{query}\"',\n clearSelection: \"Xóa lựa chọn\",\n removeItem: \"Xóa {label}\",\n search: \"Tìm kiếm\",\n },\n};\n\nexport function getStrings(language: string | Strings): Strings {\n if (typeof language === \"string\") {\n return locales[language] ?? locales.en;\n }\n return { ...locales.en, ...language };\n}\n\nexport function format(template: string, vars: Record<string, string>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => vars[key] ?? match);\n}\n","import { Emitter, type Handler } from \"./emitter\";\nimport { format, getStrings, type Strings } from \"./i18n\";\nimport type {\n AjaxConfig,\n DataItem,\n ForgeSelectEvent,\n ForgeSelectOptions,\n ForgeSelectPlugin,\n ForgeSelectValue,\n Option,\n OptionGroup,\n TemplateFn,\n} from \"./types\";\n\ntype Row =\n | { kind: \"group\"; label: string }\n | { kind: \"option\"; option: Option; navIndex: number }\n | { kind: \"create\"; navIndex: number }\n | { kind: \"empty\" }\n | { kind: \"loading\" };\n\ntype NavItem = { kind: \"option\"; option: Option } | { kind: \"create\" };\n\ninterface ResolvedOptions {\n placeholder: string;\n searchable: boolean;\n multiple: boolean;\n clearable: boolean;\n allowCreate: boolean;\n theme: string;\n disabled: boolean;\n data?: DataItem[];\n ajax?: AjaxConfig;\n templateResult?: TemplateFn;\n templateSelection?: TemplateFn;\n virtualScroll: boolean | undefined;\n itemHeight: number;\n language: string | Record<string, string>;\n plugins: ForgeSelectPlugin[];\n}\n\nconst DEFAULT_ITEM_HEIGHT = 36;\nconst VIRTUAL_BUFFER = 5;\nconst VIRTUAL_THRESHOLD = 100;\nconst ROW_CACHE_LIMIT = 2000;\n\nlet uidCounter = 0;\n\nfunction isGroup(item: DataItem): item is OptionGroup {\n return (item as OptionGroup).options !== undefined;\n}\n\nexport default class ForgeSelect {\n /** The original element ForgeSelect was mounted on. */\n readonly el: HTMLElement;\n\n private opts: ResolvedOptions;\n private strings: Strings;\n private data: DataItem[];\n private selected: string[] = [];\n private selectedOptions = new Map<string, Option>();\n private emitter = new Emitter();\n private plugins: ForgeSelectPlugin[];\n\n private uid = `forge-select-${++uidCounter}`;\n private root!: HTMLDivElement;\n private control!: HTMLDivElement;\n private valueEl!: HTMLDivElement;\n private clearBtn!: HTMLButtonElement;\n private dropdown!: HTMLDivElement;\n private searchInput: HTMLInputElement | null = null;\n private list!: HTMLUListElement;\n\n private isOpen = false;\n private isDisabled = false;\n private destroyed = false;\n private query = \"\";\n private rows: Row[] = [];\n private navItems: NavItem[] = [];\n private highlightedIndex = -1;\n private rowContentCache = new Map<string, Node>();\n\n private loading = false;\n private ajaxTimer: ReturnType<typeof setTimeout> | null = null;\n private ajaxRequestId = 0;\n private remoteLoaded = false;\n\n private onDocumentMouseDown = (event: MouseEvent): void => {\n if (!this.root.contains(event.target as Node)) this.close();\n };\n\n constructor(target: string | HTMLElement, options: ForgeSelectOptions = {}) {\n const el = typeof target === \"string\" ? document.querySelector<HTMLElement>(target) : target;\n if (!el) {\n throw new Error(`ForgeSelect: target element not found: ${String(target)}`);\n }\n this.el = el;\n\n const nativeSelect = el instanceof HTMLSelectElement ? el : null;\n this.opts = {\n placeholder: options.placeholder ?? \"\",\n searchable: options.searchable ?? true,\n multiple: options.multiple ?? nativeSelect?.multiple ?? false,\n clearable: options.clearable ?? false,\n allowCreate: options.allowCreate ?? false,\n theme: options.theme ?? \"default\",\n disabled: options.disabled ?? false,\n data: options.data,\n ajax: options.ajax,\n templateResult: options.templateResult,\n templateSelection: options.templateSelection,\n virtualScroll: options.virtualScroll,\n itemHeight: options.itemHeight ?? DEFAULT_ITEM_HEIGHT,\n language: options.language ?? \"en\",\n plugins: options.plugins ?? [],\n };\n this.strings = getStrings(this.opts.language);\n this.plugins = this.opts.plugins;\n\n this.data = this.opts.data ?? (nativeSelect ? parseNativeOptions(nativeSelect) : []);\n if (nativeSelect && !this.opts.data) {\n for (const option of Array.from(nativeSelect.querySelectorAll(\"option\"))) {\n if (option.hasAttribute(\"selected\")) this.selectValue(option.value, false);\n }\n }\n\n this.buildDom();\n this.renderValue();\n if (this.opts.disabled) this.disable();\n\n for (const plugin of this.plugins) plugin.onInit?.(this);\n }\n\n // ---------------------------------------------------------------- public API\n\n open(): void {\n if (this.isOpen || this.isDisabled || this.destroyed) return;\n this.isOpen = true;\n this.dropdown.hidden = false;\n this.root.classList.add(\"forge-select--open\");\n this.control.setAttribute(\"aria-expanded\", \"true\");\n document.addEventListener(\"mousedown\", this.onDocumentMouseDown);\n\n if (this.opts.ajax && !this.remoteLoaded) {\n this.scheduleRemoteLoad(this.query, 0);\n }\n this.renderList();\n if (this.searchInput) this.searchInput.focus();\n\n this.emitter.emit(\"open\");\n for (const plugin of this.plugins) plugin.onOpen?.(this);\n }\n\n close(): void {\n if (!this.isOpen) return;\n this.isOpen = false;\n this.dropdown.hidden = true;\n this.root.classList.remove(\"forge-select--open\");\n this.control.setAttribute(\"aria-expanded\", \"false\");\n document.removeEventListener(\"mousedown\", this.onDocumentMouseDown);\n this.highlightedIndex = -1;\n if (this.searchInput) {\n this.searchInput.value = \"\";\n this.query = \"\";\n }\n\n this.emitter.emit(\"close\");\n for (const plugin of this.plugins) plugin.onClose?.(this);\n }\n\n destroy(): void {\n if (this.destroyed) return;\n this.close();\n for (const plugin of this.plugins) plugin.onDestroy?.(this);\n this.destroyed = true;\n if (this.ajaxTimer) clearTimeout(this.ajaxTimer);\n this.rowContentCache.clear();\n this.root.remove();\n this.el.style.display = \"\";\n this.emitter.clear();\n }\n\n getValue(): ForgeSelectValue {\n if (this.opts.multiple) return [...this.selected];\n return this.selected[0] ?? null;\n }\n\n setValue(value: ForgeSelectValue): void {\n const values = value == null ? [] : Array.isArray(value) ? value : [value];\n const next = this.opts.multiple ? values : values.slice(0, 1);\n if (arraysEqual(next, this.selected)) return;\n this.selected = [];\n for (const v of next) this.selectValue(v, false);\n this.afterSelectionChange();\n }\n\n enable(): void {\n this.isDisabled = false;\n this.root.classList.remove(\"forge-select--disabled\");\n this.control.tabIndex = 0;\n this.control.setAttribute(\"aria-disabled\", \"false\");\n }\n\n disable(): void {\n this.close();\n this.isDisabled = true;\n this.root.classList.add(\"forge-select--disabled\");\n this.control.tabIndex = -1;\n this.control.setAttribute(\"aria-disabled\", \"true\");\n }\n\n on(event: ForgeSelectEvent, handler: Handler): void {\n this.emitter.on(event, handler);\n }\n\n off(event: ForgeSelectEvent, handler: Handler): void {\n this.emitter.off(event, handler);\n }\n\n // ---------------------------------------------------------------- DOM setup\n\n private buildDom(): void {\n this.root = document.createElement(\"div\");\n this.root.className = \"forge-select\";\n this.root.dataset.theme = this.opts.theme;\n this.root.style.setProperty(\"--fs-item-height\", `${this.opts.itemHeight}px`);\n\n this.control = document.createElement(\"div\");\n this.control.className = \"forge-select__control\";\n this.control.setAttribute(\"role\", \"combobox\");\n this.control.setAttribute(\"aria-haspopup\", \"listbox\");\n this.control.setAttribute(\"aria-expanded\", \"false\");\n this.control.setAttribute(\"aria-controls\", `${this.uid}-list`);\n this.control.tabIndex = 0;\n\n this.valueEl = document.createElement(\"div\");\n this.valueEl.className = \"forge-select__value\";\n\n this.clearBtn = document.createElement(\"button\");\n this.clearBtn.type = \"button\";\n this.clearBtn.className = \"forge-select__clear\";\n this.clearBtn.setAttribute(\"aria-label\", this.strings.clearSelection);\n this.clearBtn.textContent = \"×\";\n this.clearBtn.hidden = true;\n\n const arrow = document.createElement(\"span\");\n arrow.className = \"forge-select__arrow\";\n arrow.setAttribute(\"aria-hidden\", \"true\");\n\n this.control.append(this.valueEl, this.clearBtn, arrow);\n\n this.dropdown = document.createElement(\"div\");\n this.dropdown.className = \"forge-select__dropdown\";\n this.dropdown.hidden = true;\n\n if (this.opts.searchable) {\n this.searchInput = document.createElement(\"input\");\n this.searchInput.type = \"search\";\n this.searchInput.className = \"forge-select__search\";\n this.searchInput.setAttribute(\"aria-label\", this.strings.search);\n this.searchInput.setAttribute(\"aria-autocomplete\", \"list\");\n this.searchInput.setAttribute(\"aria-controls\", `${this.uid}-list`);\n this.dropdown.append(this.searchInput);\n }\n\n this.list = document.createElement(\"ul\");\n this.list.className = \"forge-select__list\";\n this.list.id = `${this.uid}-list`;\n this.list.setAttribute(\"role\", \"listbox\");\n if (this.opts.multiple) this.list.setAttribute(\"aria-multiselectable\", \"true\");\n this.dropdown.append(this.list);\n\n this.root.append(this.control, this.dropdown);\n this.el.style.display = \"none\";\n this.el.insertAdjacentElement(\"afterend\", this.root);\n\n this.bindEvents();\n }\n\n private bindEvents(): void {\n this.control.addEventListener(\"click\", (event) => {\n if (event.target === this.clearBtn) return;\n if (this.isDisabled) return;\n this.isOpen ? this.close() : this.open();\n });\n\n this.control.addEventListener(\"keydown\", (event) => this.handleKeydown(event));\n\n this.clearBtn.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n this.clearSelection();\n });\n\n if (this.searchInput) {\n this.searchInput.addEventListener(\"input\", () => {\n this.query = this.searchInput!.value;\n this.highlightedIndex = -1;\n this.list.scrollTop = 0;\n this.emitter.emit(\"search\", this.query);\n if (this.opts.ajax) {\n this.scheduleRemoteLoad(this.query, this.opts.ajax.debounce ?? 250);\n } else {\n this.renderList();\n }\n });\n this.searchInput.addEventListener(\"keydown\", (event) => this.handleKeydown(event));\n }\n\n this.list.addEventListener(\"click\", (event) => {\n const li = (event.target as HTMLElement).closest<HTMLLIElement>(\"li[data-nav-index]\");\n if (!li) return;\n const navIndex = Number(li.dataset.navIndex);\n this.activateNavItem(navIndex);\n });\n\n this.list.addEventListener(\"scroll\", () => {\n if (this.usesVirtualScroll()) this.renderRows();\n });\n }\n\n private handleKeydown(event: KeyboardEvent): void {\n if (this.isDisabled) return;\n switch (event.key) {\n case \"Enter\":\n event.preventDefault();\n if (!this.isOpen) this.open();\n else if (this.highlightedIndex >= 0) this.activateNavItem(this.highlightedIndex);\n break;\n case \" \":\n if (event.target === this.control) {\n event.preventDefault();\n if (!this.isOpen) this.open();\n }\n break;\n case \"ArrowDown\":\n event.preventDefault();\n if (!this.isOpen) this.open();\n else this.moveHighlight(1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n if (this.isOpen) this.moveHighlight(-1);\n break;\n case \"Escape\":\n if (this.isOpen) {\n event.preventDefault();\n this.close();\n this.control.focus();\n }\n break;\n case \"Tab\":\n this.close();\n break;\n }\n }\n\n // ---------------------------------------------------------------- selection\n\n private selectValue(value: string, notify: boolean): void {\n if (this.selected.includes(value)) return;\n const option = this.findOption(value) ?? this.selectedOptions.get(value) ?? { value, label: value };\n this.selectedOptions.set(value, option);\n if (this.opts.multiple) this.selected.push(value);\n else this.selected = [value];\n if (notify) this.afterSelectionChange();\n }\n\n private deselectValue(value: string, notify: boolean): void {\n const index = this.selected.indexOf(value);\n if (index === -1) return;\n this.selected.splice(index, 1);\n if (notify) this.afterSelectionChange();\n }\n\n private clearSelection(): void {\n if (this.selected.length === 0) return;\n this.selected = [];\n this.emitter.emit(\"clear\");\n this.afterSelectionChange();\n }\n\n private afterSelectionChange(): void {\n this.renderValue();\n this.syncNativeSelect();\n if (this.isOpen) this.renderList();\n this.emitter.emit(\"change\", this.getValue());\n }\n\n private syncNativeSelect(): void {\n if (!(this.el instanceof HTMLSelectElement)) return;\n const existing = new Set<string>();\n for (const option of Array.from(this.el.options)) {\n existing.add(option.value);\n option.selected = this.selected.includes(option.value);\n }\n for (const value of this.selected) {\n if (existing.has(value)) continue;\n const option = document.createElement(\"option\");\n option.value = value;\n option.textContent = this.selectedOptions.get(value)?.label ?? value;\n option.selected = true;\n this.el.append(option);\n }\n this.el.dispatchEvent(new Event(\"change\", { bubbles: true }));\n }\n\n private findOption(value: string): Option | undefined {\n for (const item of this.data) {\n if (isGroup(item)) {\n const found = item.options.find((o) => o.value === value);\n if (found) return found;\n } else if (item.value === value) {\n return item;\n }\n }\n return undefined;\n }\n\n private createFromQuery(): void {\n const label = this.query.trim();\n if (!label) return;\n const option: Option = { value: label, label };\n this.data.push(option);\n if (this.searchInput) {\n this.searchInput.value = \"\";\n this.query = \"\";\n }\n this.selectValue(option.value, true);\n if (!this.opts.multiple) this.close();\n }\n\n private activateNavItem(navIndex: number): void {\n const item = this.navItems[navIndex];\n if (!item) return;\n if (item.kind === \"create\") {\n this.createFromQuery();\n return;\n }\n const { value } = item.option;\n if (this.opts.multiple) {\n this.selected.includes(value) ? this.deselectValue(value, true) : this.selectValue(value, true);\n } else {\n this.selectValue(value, true);\n this.close();\n this.control.focus();\n }\n }\n\n // ---------------------------------------------------------------- rendering\n\n private renderValue(): void {\n this.valueEl.textContent = \"\";\n const hasValue = this.selected.length > 0;\n this.clearBtn.hidden = !(this.opts.clearable && hasValue);\n\n if (!hasValue) {\n const placeholder = document.createElement(\"span\");\n placeholder.className = \"forge-select__placeholder\";\n placeholder.textContent = this.opts.placeholder;\n this.valueEl.append(placeholder);\n return;\n }\n\n if (this.opts.multiple) {\n for (const value of this.selected) {\n const option = this.selectedOptions.get(value) ?? { value, label: value };\n const tag = document.createElement(\"span\");\n tag.className = \"forge-select__tag\";\n const label = document.createElement(\"span\");\n label.className = \"forge-select__tag-label\";\n this.renderTemplate(label, option, this.opts.templateSelection, \"inline\");\n const remove = document.createElement(\"button\");\n remove.type = \"button\";\n remove.className = \"forge-select__tag-remove\";\n remove.setAttribute(\"aria-label\", format(this.strings.removeItem, { label: option.label }));\n remove.textContent = \"×\";\n remove.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n if (!this.isDisabled) this.deselectValue(value, true);\n });\n tag.append(label, remove);\n this.valueEl.append(tag);\n }\n } else {\n const option = this.selectedOptions.get(this.selected[0]) ?? {\n value: this.selected[0],\n label: this.selected[0],\n };\n const span = document.createElement(\"span\");\n span.className = \"forge-select__single-value\";\n this.renderTemplate(span, option, this.opts.templateSelection, \"inline\");\n this.valueEl.append(span);\n }\n }\n\n private renderTemplate(\n container: HTMLElement,\n option: Option,\n template?: TemplateFn,\n variant: \"row\" | \"inline\" = \"row\",\n ): void {\n if (template) {\n const result = template(option);\n if (typeof result === \"string\") container.innerHTML = result;\n else container.append(result);\n return;\n }\n if (!option.avatar && !option.description) {\n container.textContent = option.label;\n return;\n }\n // Built-in rich renderer: DOM built via textContent, so all fields are XSS-safe.\n if (option.avatar) {\n const avatar = document.createElement(\"img\");\n avatar.className =\n variant === \"row\" ? \"forge-select__option-avatar\" : \"forge-select__inline-avatar\";\n avatar.src = option.avatar;\n avatar.alt = \"\";\n avatar.setAttribute(\"loading\", \"lazy\");\n avatar.setAttribute(\"decoding\", \"async\");\n container.append(avatar);\n }\n if (variant === \"row\" && option.description) {\n const body = document.createElement(\"span\");\n body.className = \"forge-select__option-body\";\n const label = document.createElement(\"span\");\n label.className = \"forge-select__option-label\";\n label.textContent = option.label;\n const desc = document.createElement(\"span\");\n desc.className = \"forge-select__option-desc\";\n desc.textContent = option.description;\n body.append(label, desc);\n container.append(body);\n } else {\n const label = document.createElement(\"span\");\n label.className = \"forge-select__option-label\";\n label.textContent = option.label;\n container.append(label);\n }\n }\n\n private buildRows(): void {\n this.rows = [];\n this.navItems = [];\n const query = this.query.trim().toLowerCase();\n const matches = (option: Option): boolean =>\n query === \"\" ||\n option.label.toLowerCase().includes(query) ||\n (option.description?.toLowerCase().includes(query) ?? false);\n\n const pushOption = (option: Option): void => {\n let navIndex = -1;\n if (!option.disabled) {\n navIndex = this.navItems.length;\n this.navItems.push({ kind: \"option\", option });\n }\n this.rows.push({ kind: \"option\", option, navIndex });\n };\n\n if (this.loading) {\n this.rows.push({ kind: \"loading\" });\n return;\n }\n\n for (const item of this.data) {\n if (isGroup(item)) {\n const visible = item.options.filter(matches);\n if (visible.length === 0) continue;\n this.rows.push({ kind: \"group\", label: item.label });\n visible.forEach(pushOption);\n } else if (matches(item)) {\n pushOption(item);\n }\n }\n\n if (this.opts.allowCreate && query !== \"\" && !this.hasExactMatch(query)) {\n const navIndex = this.navItems.length;\n this.navItems.push({ kind: \"create\" });\n this.rows.push({ kind: \"create\", navIndex });\n }\n\n if (this.rows.length === 0) this.rows.push({ kind: \"empty\" });\n }\n\n private hasExactMatch(lowerQuery: string): boolean {\n for (const item of this.data) {\n const options = isGroup(item) ? item.options : [item];\n if (options.some((o) => o.label.toLowerCase() === lowerQuery)) return true;\n }\n return false;\n }\n\n private usesVirtualScroll(): boolean {\n return this.opts.virtualScroll !== false && this.rows.length > VIRTUAL_THRESHOLD;\n }\n\n private renderList(): void {\n this.buildRows();\n this.renderRows();\n }\n\n private renderRows(): void {\n // Capture the scroll offset and viewport height BEFORE clearing the list:\n // removing the children collapses both scrollHeight (clamping scrollTop to 0)\n // and clientHeight (the list has no explicit height, only max-height, so an\n // empty list reports just its padding instead of the real box height).\n const scrollTop = this.list.scrollTop;\n const clientHeight = this.list.clientHeight;\n const virtual = this.usesVirtualScroll();\n this.list.textContent = \"\";\n\n const rowHeight = this.opts.itemHeight;\n let start = 0;\n let end = this.rows.length;\n if (virtual) {\n const viewport = clientHeight || rowHeight * 8;\n start = Math.max(0, Math.floor(scrollTop / rowHeight) - VIRTUAL_BUFFER);\n end = Math.min(this.rows.length, start + Math.ceil(viewport / rowHeight) + VIRTUAL_BUFFER * 2);\n\n const topSpacer = document.createElement(\"li\");\n topSpacer.className = \"forge-select__spacer\";\n topSpacer.setAttribute(\"aria-hidden\", \"true\");\n topSpacer.style.height = `${start * rowHeight}px`;\n this.list.append(topSpacer);\n }\n\n for (let i = start; i < end; i++) {\n this.list.append(this.renderRow(this.rows[i]));\n }\n\n if (virtual) {\n const bottomSpacer = document.createElement(\"li\");\n bottomSpacer.className = \"forge-select__spacer\";\n bottomSpacer.setAttribute(\"aria-hidden\", \"true\");\n bottomSpacer.style.height = `${(this.rows.length - end) * rowHeight}px`;\n this.list.append(bottomSpacer);\n\n // Restore the offset that clearing clamped away. The net scroll change\n // within this handler is zero, so this does not re-fire the scroll\n // listener; even if it did, the re-render is idempotent and settles.\n if (this.list.scrollTop !== scrollTop) {\n this.list.scrollTop = scrollTop;\n }\n }\n\n this.updateActiveDescendant();\n }\n\n private renderRow(row: Row): HTMLLIElement {\n const li = document.createElement(\"li\");\n switch (row.kind) {\n case \"group\":\n li.className = \"forge-select__group-label\";\n li.setAttribute(\"role\", \"presentation\");\n li.textContent = row.label;\n break;\n case \"empty\":\n li.className = \"forge-select__empty\";\n li.textContent = this.strings.noResults;\n break;\n case \"loading\":\n li.className = \"forge-select__loading\";\n li.textContent = this.strings.loading;\n break;\n case \"create\":\n li.className = \"forge-select__option forge-select__option--create\";\n li.setAttribute(\"role\", \"option\");\n li.id = `${this.uid}-nav-${row.navIndex}`;\n li.dataset.navIndex = String(row.navIndex);\n li.textContent = format(this.strings.createOption, { query: this.query.trim() });\n if (row.navIndex === this.highlightedIndex) li.classList.add(\"forge-select__option--highlighted\");\n break;\n case \"option\": {\n li.className = \"forge-select__option\";\n li.setAttribute(\"role\", \"option\");\n const isSelected = this.selected.includes(row.option.value);\n li.setAttribute(\"aria-selected\", String(isSelected));\n if (isSelected) li.classList.add(\"forge-select__option--selected\");\n if (row.option.disabled) {\n li.classList.add(\"forge-select__option--disabled\");\n li.setAttribute(\"aria-disabled\", \"true\");\n } else {\n li.id = `${this.uid}-nav-${row.navIndex}`;\n li.dataset.navIndex = String(row.navIndex);\n if (row.navIndex === this.highlightedIndex) li.classList.add(\"forge-select__option--highlighted\");\n }\n li.append(this.optionContent(row.option));\n break;\n }\n }\n return li;\n }\n\n /**\n * Rendered row content is cached per option value and cloned on each render,\n * so templates run once per option instead of once per scroll frame.\n * State classes (selected/highlighted/disabled) live on the <li>, keeping the\n * cached content state-free.\n */\n private optionContent(option: Option): Node {\n let cached = this.rowContentCache.get(option.value);\n if (!cached) {\n const holder = document.createElement(\"span\");\n holder.className = \"forge-select__option-content\";\n this.renderTemplate(holder, option, this.opts.templateResult);\n if (this.rowContentCache.size >= ROW_CACHE_LIMIT) {\n // FIFO eviction keeps memory bounded on very large lists.\n const oldest = this.rowContentCache.keys().next().value as string;\n this.rowContentCache.delete(oldest);\n }\n this.rowContentCache.set(option.value, holder);\n cached = holder;\n }\n return cached.cloneNode(true);\n }\n\n private moveHighlight(delta: number): void {\n if (this.navItems.length === 0) return;\n const next =\n this.highlightedIndex === -1 && delta > 0\n ? 0\n : (this.highlightedIndex + delta + this.navItems.length) % this.navItems.length;\n this.highlightedIndex = next;\n\n if (this.usesVirtualScroll()) {\n const rowIndex = this.rows.findIndex(\n (row) => (row.kind === \"option\" || row.kind === \"create\") && row.navIndex === next,\n );\n if (rowIndex >= 0) {\n const rowHeight = this.opts.itemHeight;\n const top = rowIndex * rowHeight;\n const viewport = this.list.clientHeight || rowHeight * 8;\n let target = this.list.scrollTop;\n if (top < target) target = top;\n else if (top + rowHeight > target + viewport) target = top + rowHeight - viewport;\n if (target !== this.list.scrollTop) this.list.scrollTop = target;\n }\n this.renderRows();\n } else {\n this.renderRows();\n const highlighted = this.list.querySelector<HTMLElement>(\".forge-select__option--highlighted\");\n highlighted?.scrollIntoView?.({ block: \"nearest\" });\n }\n }\n\n private updateActiveDescendant(): void {\n const target = this.searchInput ?? this.control;\n if (this.highlightedIndex >= 0) {\n target.setAttribute(\"aria-activedescendant\", `${this.uid}-nav-${this.highlightedIndex}`);\n } else {\n target.removeAttribute(\"aria-activedescendant\");\n }\n }\n\n // ---------------------------------------------------------------- remote data\n\n private scheduleRemoteLoad(query: string, delay: number): void {\n if (this.ajaxTimer) clearTimeout(this.ajaxTimer);\n this.loading = true;\n this.renderList();\n this.ajaxTimer = setTimeout(() => {\n void this.loadRemote(query);\n }, delay);\n }\n\n private async loadRemote(query: string): Promise<void> {\n const ajax = this.opts.ajax!;\n const requestId = ++this.ajaxRequestId;\n try {\n const url = buildUrl(ajax, query);\n const response = await fetch(url);\n const json: unknown = await response.json();\n if (requestId !== this.ajaxRequestId || this.destroyed) return;\n this.data = ajax.transform ? ajax.transform(json) : (json as Option[]);\n this.rowContentCache.clear();\n this.remoteLoaded = true;\n } catch {\n if (requestId !== this.ajaxRequestId || this.destroyed) return;\n this.data = [];\n this.rowContentCache.clear();\n } finally {\n if (requestId === this.ajaxRequestId && !this.destroyed) {\n this.loading = false;\n if (this.isOpen) this.renderList();\n }\n }\n }\n}\n\nfunction parseNativeOptions(select: HTMLSelectElement): DataItem[] {\n const data: DataItem[] = [];\n for (const child of Array.from(select.children)) {\n if (child instanceof HTMLOptGroupElement) {\n data.push({\n label: child.label,\n options: Array.from(child.querySelectorAll(\"option\")).map(parseOption),\n });\n } else if (child instanceof HTMLOptionElement) {\n data.push(parseOption(child));\n }\n }\n return data;\n}\n\nfunction parseOption(option: HTMLOptionElement): Option {\n return {\n value: option.value,\n label: option.textContent?.trim() ?? option.value,\n disabled: option.disabled || undefined,\n };\n}\n\nfunction buildUrl(ajax: AjaxConfig, query: string): string {\n if (typeof ajax.url === \"function\") return ajax.url(query);\n if (!ajax.params) return ajax.url;\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(ajax.params(query))) {\n params.set(key, String(value));\n }\n const separator = ajax.url.includes(\"?\") ? \"&\" : \"?\";\n return `${ajax.url}${separator}${params.toString()}`;\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n return a.length === b.length && a.every((value, index) => value === b[index]);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/emitter.ts","../src/i18n.ts","../src/ForgeSelect.ts"],"sourcesContent":["export { default } from \"./ForgeSelect\";\nexport { default as ForgeSelect } from \"./ForgeSelect\";\nexport type {\n AjaxConfig,\n DataItem,\n ForgeSelectEvent,\n ForgeSelectOptions,\n ForgeSelectPlugin,\n ForgeSelectValue,\n Option,\n OptionGroup,\n TemplateFn,\n} from \"./types\";\n","export type Handler = (...args: unknown[]) => void;\n\nexport class Emitter {\n private handlers = new Map<string, Set<Handler>>();\n\n on(event: string, handler: Handler): void {\n let set = this.handlers.get(event);\n if (!set) {\n set = new Set();\n this.handlers.set(event, set);\n }\n set.add(handler);\n }\n\n off(event: string, handler: Handler): void {\n this.handlers.get(event)?.delete(handler);\n }\n\n emit(event: string, ...args: unknown[]): void {\n const set = this.handlers.get(event);\n if (!set) return;\n for (const handler of [...set]) handler(...args);\n }\n\n clear(): void {\n this.handlers.clear();\n }\n}\n","export type Strings = Record<string, string>;\n\nconst locales: Record<string, Strings> = {\n en: {\n noResults: \"No results found\",\n loading: \"Loading…\",\n 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":[]}