forge-select 0.7.3 → 0.7.5

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 CHANGED
@@ -205,6 +205,17 @@ Forge Select is vanilla TypeScript/JavaScript, so it can be mounted inside any f
205
205
 
206
206
  Forge Select is designed as a drop-in-concept replacement for Select2: no jQuery dependency, native accessibility, and a smaller API surface. A full option/event/method mapping table and a step-by-step migration checklist are available in [`docs/migration-from-select2.md`](./docs/migration-from-select2.md).
207
207
 
208
+ ## Bundle size
209
+
210
+ Forge Select ships as a single class, so **the whole feature set is in the bundle whether or not you use it** — tree select, AJAX, tags, sortable tags and virtualization cannot be tree-shaken away. Measured with esbuild (minified + gzipped):
211
+
212
+ | Usage | JS |
213
+ | --------------------------------------------------------------- | ------- |
214
+ | Minimal — `new ForgeSelect(el, { placeholder })` | 13.3 KB |
215
+ | Every feature — tree, AJAX, tags, sortable, measured rows, etc. | 13.4 KB |
216
+
217
+ Plus 1.7 KB gzipped for `forge-select/styles.css`. Budget ~15 KB gzipped total and the number won't move as you adopt more of the API. Splitting the core into opt-in subpath entrypoints is under consideration for a future major version; it is not planned as a patch, since it would change the public import surface.
218
+
208
219
  ## Benchmarks
209
220
 
210
221
  Run `npm run bench` for a reproducible JSON baseline covering bundle size, initialization, 10,000-option search latency, and virtual-scroll performance. The methodology and result fields are documented in [`docs/benchmarks.md`](./docs/benchmarks.md).
package/dist/index.cjs CHANGED
@@ -543,22 +543,20 @@ var ForgeSelect = class {
543
543
  }
544
544
  this.typeaheadBuffer = "";
545
545
  this.highlightedIndex = -1;
546
- if (this.searchInput) {
547
- const hadQuery = this.query !== "";
548
- this.searchInput.value = "";
549
- this.query = "";
550
- if (hadQuery && this.opts.ajax) {
551
- this.ajaxRequestId += 1;
552
- if (this.ajaxTimer) {
553
- clearTimeout(this.ajaxTimer);
554
- this.ajaxTimer = null;
555
- }
556
- this.ajaxController?.abort();
557
- this.ajaxController = null;
558
- this.setLoading(false);
559
- this.loadingMore = false;
560
- this.remoteLoaded = false;
546
+ const hadQuery = this.query !== "";
547
+ if (this.searchInput) this.searchInput.value = "";
548
+ this.query = "";
549
+ if (hadQuery && this.opts.ajax) {
550
+ this.ajaxRequestId += 1;
551
+ if (this.ajaxTimer) {
552
+ clearTimeout(this.ajaxTimer);
553
+ this.ajaxTimer = null;
561
554
  }
555
+ this.ajaxController?.abort();
556
+ this.ajaxController = null;
557
+ this.setLoading(false);
558
+ this.loadingMore = false;
559
+ this.remoteLoaded = false;
562
560
  }
563
561
  this.emitter.emit("close");
564
562
  for (const plugin of this.plugins) plugin.onClose?.(this);
@@ -654,16 +652,17 @@ var ForgeSelect = class {
654
652
  if (options.beforeCreate !== void 0) this.opts.beforeCreate = options.beforeCreate;
655
653
  if (options.createOption !== void 0) this.opts.createOption = options.createOption;
656
654
  if (options.missingSelectionPolicy !== void 0) this.opts.missingSelectionPolicy = options.missingSelectionPolicy;
655
+ let needsReindex = false;
657
656
  if (options.duplicateValuePolicy !== void 0) {
658
657
  this.opts.duplicateValuePolicy = options.duplicateValuePolicy;
659
- this.rebuildOptionIndexes();
658
+ needsReindex = true;
660
659
  }
661
660
  if (options.filterOption !== void 0) this.opts.filterOption = options.filterOption;
662
661
  if (options.searchFields !== void 0) this.opts.searchFields = options.searchFields;
663
662
  if (options.tokenSearch !== void 0) this.opts.tokenSearch = options.tokenSearch;
664
663
  if (options.accentInsensitive !== void 0) {
665
664
  this.opts.accentInsensitive = options.accentInsensitive;
666
- this.rebuildOptionIndexes();
665
+ needsReindex = true;
667
666
  }
668
667
  if (options.searchScorer !== void 0) this.opts.searchScorer = options.searchScorer;
669
668
  if (options.highlightSearch !== void 0) this.opts.highlightSearch = options.highlightSearch;
@@ -690,6 +689,7 @@ var ForgeSelect = class {
690
689
  if (options.disabled) this.disable();
691
690
  else this.enable();
692
691
  }
692
+ if (needsReindex) this.rebuildOptionIndexes();
693
693
  this.root.classList.toggle("forge-select--sortable", this.opts.sortable && this.opts.multiple);
694
694
  this.updateSearchVisibility();
695
695
  this.clearRowCaches();
@@ -741,20 +741,6 @@ var ForgeSelect = class {
741
741
  * the same fallback used for values selected from a stale ajax page).
742
742
  */
743
743
  setData(data) {
744
- if (this.ajaxTimer) {
745
- clearTimeout(this.ajaxTimer);
746
- this.ajaxTimer = null;
747
- }
748
- this.ajaxController?.abort();
749
- this.ajaxController = null;
750
- this.ajaxRequestId += 1;
751
- this.setLoading(false);
752
- this.loadingMore = false;
753
- this.loadError = null;
754
- this.remoteLoaded = true;
755
- this.page = 0;
756
- this.hasMore = false;
757
- this.nextCursor = void 0;
758
744
  const previousData = this.data;
759
745
  this.data = data;
760
746
  try {
@@ -770,6 +756,20 @@ var ForgeSelect = class {
770
756
  this.rebuildOptionIndexes();
771
757
  throw new Error(`ForgeSelect: setData() is missing selected value(s): ${missing.join(", ")}`);
772
758
  }
759
+ if (this.ajaxTimer) {
760
+ clearTimeout(this.ajaxTimer);
761
+ this.ajaxTimer = null;
762
+ }
763
+ this.ajaxController?.abort();
764
+ this.ajaxController = null;
765
+ this.ajaxRequestId += 1;
766
+ this.setLoading(false);
767
+ this.loadingMore = false;
768
+ this.loadError = null;
769
+ this.remoteLoaded = true;
770
+ this.page = 0;
771
+ this.hasMore = false;
772
+ this.nextCursor = void 0;
773
773
  this.opts.data = data;
774
774
  if (missing.length > 0 && this.opts.missingSelectionPolicy === "prune") {
775
775
  this.selected = this.selected.filter((value) => this.optionByValue.has(value));
@@ -1301,7 +1301,8 @@ var ForgeSelect = class {
1301
1301
  return { option: existing, created: false };
1302
1302
  }
1303
1303
  if (this.opts.beforeCreate?.(trimmed) === false) return void 0;
1304
- const created = this.opts.createOption?.(trimmed) ?? { value: trimmed, label: trimmed };
1304
+ if (!this.opts.createOption) return this.addCreatedOption({ value: trimmed, label: trimmed });
1305
+ const created = this.opts.createOption(trimmed);
1305
1306
  if (created instanceof Promise) {
1306
1307
  return created.then((option) => option ? this.addCreatedOption(option) : void 0);
1307
1308
  }
@@ -1981,7 +1982,7 @@ var ForgeSelect = class {
1981
1982
  this.emitter.emit("loading", loading);
1982
1983
  }
1983
1984
  remoteCacheKey(query, page, cursor) {
1984
- return `${query}\0${cursor ?? page}`;
1985
+ return `${query}\0${cursor !== void 0 ? `c:${cursor}` : `p:${page}`}`;
1985
1986
  }
1986
1987
  fetchRemoteResult(query, page, signal, cursor) {
1987
1988
  const key = this.remoteCacheKey(query, page, cursor);
@@ -2089,6 +2090,7 @@ var ForgeSelect = class {
2089
2090
  if (!append) {
2090
2091
  this.data = [];
2091
2092
  this.clearRowCaches();
2093
+ this.rebuildOptionIndexes();
2092
2094
  }
2093
2095
  this.hasMore = false;
2094
2096
  this.loadError = error;