forge-select 0.7.4 → 0.7.6
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 +11 -0
- package/dist/index.cjs +22 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.global.js +1 -1
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +22 -5
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
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
|
@@ -334,7 +334,12 @@ var uidCounter = 0;
|
|
|
334
334
|
var ForgeSelect = class {
|
|
335
335
|
constructor(target, options = {}) {
|
|
336
336
|
this.optionByValue = /* @__PURE__ */ new Map();
|
|
337
|
-
|
|
337
|
+
// Built on demand: only the allowCreate paths read it, and filling it eagerly
|
|
338
|
+
// normalizes every label (NFD + regex) at construction for the majority of
|
|
339
|
+
// selects that never create tags. rebuildOptionIndexes() nulls it, so every
|
|
340
|
+
// existing invalidation point — including an accentInsensitive change —
|
|
341
|
+
// already covers it.
|
|
342
|
+
this.optionByLabel = null;
|
|
338
343
|
this.selected = [];
|
|
339
344
|
this.selectedOptions = /* @__PURE__ */ new Map();
|
|
340
345
|
this.suppressNextTagClick = false;
|
|
@@ -507,6 +512,7 @@ var ForgeSelect = class {
|
|
|
507
512
|
if (this.opts.ajax && (this.opts.ajax.loadOnOpen ?? true) && !this.remoteLoaded) {
|
|
508
513
|
this.scheduleRemoteLoad(this.query, 0);
|
|
509
514
|
}
|
|
515
|
+
if (this.opts.allowCreate) this.labelIndex();
|
|
510
516
|
this.renderList();
|
|
511
517
|
this.positionDropdown();
|
|
512
518
|
window.addEventListener("resize", this.onWindowResize);
|
|
@@ -1265,18 +1271,29 @@ var ForgeSelect = class {
|
|
|
1265
1271
|
findOption(value) {
|
|
1266
1272
|
return this.optionByValue.get(value);
|
|
1267
1273
|
}
|
|
1274
|
+
/** Fills the label index on first use; see the field for why it is deferred. */
|
|
1275
|
+
labelIndex() {
|
|
1276
|
+
if (this.optionByLabel) return this.optionByLabel;
|
|
1277
|
+
const index = /* @__PURE__ */ new Map();
|
|
1278
|
+
const visit = (option) => {
|
|
1279
|
+
const label = normalizeSearchText(option.label, this.opts.accentInsensitive);
|
|
1280
|
+
if (!index.has(label)) index.set(label, option);
|
|
1281
|
+
option.children?.forEach(visit);
|
|
1282
|
+
};
|
|
1283
|
+
for (const item of this.data) (isGroup(item) ? item.options : [item]).forEach(visit);
|
|
1284
|
+
this.optionByLabel = index;
|
|
1285
|
+
return index;
|
|
1286
|
+
}
|
|
1268
1287
|
findOptionByLabel(label) {
|
|
1269
|
-
return this.
|
|
1288
|
+
return this.labelIndex().get(normalizeSearchText(label, this.opts.accentInsensitive));
|
|
1270
1289
|
}
|
|
1271
1290
|
rebuildOptionIndexes() {
|
|
1272
1291
|
this.optionByValue.clear();
|
|
1273
|
-
this.optionByLabel
|
|
1292
|
+
this.optionByLabel = null;
|
|
1274
1293
|
const duplicates = /* @__PURE__ */ new Set();
|
|
1275
1294
|
const visit = (option) => {
|
|
1276
1295
|
if (this.optionByValue.has(option.value)) duplicates.add(option.value);
|
|
1277
1296
|
else this.optionByValue.set(option.value, option);
|
|
1278
|
-
const label = normalizeSearchText(option.label, this.opts.accentInsensitive);
|
|
1279
|
-
if (!this.optionByLabel.has(label)) this.optionByLabel.set(label, option);
|
|
1280
1297
|
option.children?.forEach(visit);
|
|
1281
1298
|
};
|
|
1282
1299
|
for (const item of this.data) (isGroup(item) ? item.options : [item]).forEach(visit);
|