@ixfx/components 0.17.0 → 0.18.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.
Files changed (58) hide show
  1. package/bundle/index.d.ts +193 -8
  2. package/bundle/index.js +153 -152
  3. package/dist/{checked-select-BmwqpgGr.js → checked-select-DsQ-o9lI.js} +1 -1
  4. package/dist/checked-select.js +1 -1
  5. package/dist/{crumb-navigation-D7dAC0H-.js → crumb-navigation-09YFje6W.js} +2 -2
  6. package/dist/{crumb-navigation-Tm4fnsvN.d.ts → crumb-navigation-DOfOS7li.d.ts} +1 -1
  7. package/dist/crumbs.d.ts +1 -1
  8. package/dist/crumbs.js +1 -1
  9. package/dist/{data-grid-BcO3SMac.js → data-grid-BGmJbMCb.js} +4 -3
  10. package/dist/{data-grid-vasJtjFP.d.ts → data-grid-BQWmVYg0.d.ts} +8 -2
  11. package/dist/data-grid.d.ts +2 -2
  12. package/dist/data-grid.js +1 -1
  13. package/dist/{detail-list-E9WdMVbE.d.ts → detail-list-CfjoIl2N.d.ts} +9 -3
  14. package/dist/{detail-list-vPVwE1CP.js → detail-list-CrHASoAx.js} +2 -1
  15. package/dist/detail-list.d.ts +3 -3
  16. package/dist/detail-list.js +1 -1
  17. package/dist/{flat-list-CfutGqKY.d.ts → flat-list-C2z81bK6.d.ts} +5 -3
  18. package/dist/flat-list.d.ts +1 -1
  19. package/dist/flat-list.js +4 -2
  20. package/dist/{grid-list-Dg8hIiKO.d.ts → grid-list-Crv-hFJL.d.ts} +60 -4
  21. package/dist/{grid-list-BHo9TBxX.js → grid-list-DYU_z2K9.js} +258 -19
  22. package/dist/grid-list.d.ts +3 -3
  23. package/dist/grid-list.js +1 -1
  24. package/dist/incr-search.d.ts +1 -1
  25. package/dist/{index-CzhYJJsx.d.ts → index-BE0hk8xS.d.ts} +2 -2
  26. package/dist/{index-88ra6YHP.d.ts → index-BymYKGY-.d.ts} +3 -3
  27. package/dist/{index-CRLTVAyt.d.ts → index-Db5VGFR1.d.ts} +1 -1
  28. package/dist/index.d.ts +82 -20
  29. package/dist/index.js +293 -107
  30. package/dist/{interaction-8Kbbf6xN.js → interaction-BEcBIY0d.js} +1 -1
  31. package/dist/{list-native-drag-controller-ByftBooJ.js → list-native-drag-controller-Brk30s5d.js} +3 -0
  32. package/dist/{list-native-drag-controller-CgXKdmjr.d.ts → list-native-drag-controller-Cs-Tmtaa.d.ts} +1 -1
  33. package/dist/{menu-C3DhTjHx.js → menu-B6NFqEtm.js} +3 -3
  34. package/dist/{menu-item-BSxhlWnW.js → menu-item-D0zy1yax.js} +2 -2
  35. package/dist/menu.js +2 -2
  36. package/dist/{miller-DqDEaXqT.js → miller-B0qbnWwe.js} +1 -1
  37. package/dist/miller.d.ts +2 -2
  38. package/dist/miller.js +1 -1
  39. package/dist/narrowed-text.js +1 -1
  40. package/dist/{node-graph-DqEGv5QR.js → node-graph-D9iovxQp.js} +1 -1
  41. package/dist/node-graph.js +1 -1
  42. package/dist/{notification-pill-BiHEJk-o.d.ts → notification-pill-BJonE_wo.d.ts} +14 -1
  43. package/dist/notifier.d.ts +1 -1
  44. package/dist/select-horiz.js +1 -1
  45. package/dist/sunburst-tree.d.ts +1 -1
  46. package/dist/{sunbursttree-list-CsrmVSB8.d.ts → sunbursttree-list-XF7gBKod.d.ts} +2 -2
  47. package/dist/{tree-BP5fxvEX.js → tree-1CSNgw72.js} +2 -2
  48. package/dist/{tree-component-DNuzfo6R.d.ts → tree-component-BE7OEIiH.d.ts} +7 -1
  49. package/dist/tree.d.ts +2 -2
  50. package/dist/tree.js +1 -1
  51. package/dist/{vertical-list-B9z1lbjM.js → vertical-list-BNCRA_zy.js} +2 -1
  52. package/dist/{vertical-list-BzeXehBt.d.ts → vertical-list-Dyc5azxv.d.ts} +8 -2
  53. package/dist/vertical-list.d.ts +2 -2
  54. package/dist/vertical-list.js +1 -1
  55. package/docs-user/grid-list.md +70 -0
  56. package/docs-user/index.json +2 -2
  57. package/docs-user/notifier.md +28 -0
  58. package/package.json +3 -3
@@ -2,9 +2,9 @@ import { n as appearanceColor, t as appearanceAbsent } from "./item-appearance-F
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-pnieYweS.js";
3
3
  import { c as createElementListSearchAdapter, f as createDataListSearchAdapter, i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, u as keyForElement } from "./incr-search-C5114RxZ.js";
4
4
  import { i as resolveGroupKey, r as partitionByGroup } from "./grouping-kENdqzSV.js";
5
- import "./interaction-8Kbbf6xN.js";
5
+ import "./interaction-BEcBIY0d.js";
6
6
  import { i as ListDragSelectController, n as gestureOf, t as ListSelectionController } from "./list-selection-controller-Dkh3m3hX.js";
7
- import { a as listItemFadeKeyframes, t as ListNativeDragController } from "./list-native-drag-controller-ByftBooJ.js";
7
+ import { a as listItemFadeKeyframes, t as ListNativeDragController } from "./list-native-drag-controller-Brk30s5d.js";
8
8
  import { i as sameKeySet, r as isPartialKey, t as PARTIAL_DESCRIPTION } from "./partial-keys-D4l_ede_.js";
9
9
  import { c as keysAsFlags, f as withoutFlag, i as capFlags, l as keysToArray, o as flagsFromRecord, s as flagsToRecord, t as EMPTY_FLAGS } from "./pending-Afl4LT64.js";
10
10
  import { n as createScrollHoverGuard } from "./scroll-hover-guard-BGAjtyXT.js";
@@ -19,7 +19,104 @@ import { LitElement, css, html, nothing } from "lit";
19
19
  import { property, state } from "lit/decorators.js";
20
20
  import { createCommandRegistry } from "@clinth/ui-commands";
21
21
  import { repeat } from "lit/directives/repeat.js";
22
+ import { keyed } from "lit/directives/keyed.js";
22
23
  import { createRef, ref } from "lit/directives/ref.js";
24
+ // src/grid-list/grid-list-key-index.ts
25
+ var KeyIndex = class {
26
+ /** Key → raw index. The first occurrence of a key wins. */
27
+ #map = /* @__PURE__ */ new Map();
28
+ /** The items array the map was built from. */
29
+ #source = void 0;
30
+ /** The adapter the map was built with. */
31
+ #adapter = void 0;
32
+ /**
33
+ * Rebuild the map if `items` or `adapter` changed since it was built.
34
+ *
35
+ * The map is keyed on the identity of the array / adapter it was built from,
36
+ * so it stays correct even when the items are replaced between Lit update
37
+ * cycles (a host may assign `items` and then call `updateItem` before the
38
+ * update flushes).
39
+ *
40
+ * One pass — the adapter's `key` is called once per item.
41
+ */
42
+ ensure(items, adapter) {
43
+ if (this.#source === items && this.#adapter === adapter) return;
44
+ if (!adapter) {
45
+ this.#map = /* @__PURE__ */ new Map();
46
+ this.#source = items;
47
+ this.#adapter = void 0;
48
+ return;
49
+ }
50
+ const map = /* @__PURE__ */ new Map();
51
+ for (let i = 0; i < items.length; i++) {
52
+ const key = adapter.key(items[i], i);
53
+ if (!map.has(key)) map.set(key, i);
54
+ }
55
+ this.#map = map;
56
+ this.#source = items;
57
+ this.#adapter = adapter;
58
+ }
59
+ /** Raw index of `key`, or `-1`. O(1). */
60
+ get(key) {
61
+ return this.#map.get(key) ?? -1;
62
+ }
63
+ /** Whether `key` is known. */
64
+ has(key) {
65
+ return this.#map.has(key);
66
+ }
67
+ /**
68
+ * Record that `items` is now `next`, after `patch` updated the map.
69
+ *
70
+ * `patch` receives the live map so a mutation can adjust only the entries
71
+ * it touched. The map's "built from" pointer is updated to `next`, so the
72
+ * next {@link ensure} does not rebuild it.
73
+ */
74
+ commit(next, patch) {
75
+ if (patch) patch(this.#map);
76
+ this.#source = next;
77
+ }
78
+ /**
79
+ * Update the map after the item at `idx` changed.
80
+ *
81
+ * `next` is the new array; `oldKey` is the key the item had before the
82
+ * change, and the new key is derived from the item. If the item kept its key
83
+ * the map is untouched. If it was re-keyed, the old entry is dropped and the
84
+ * new one added — but only when no *earlier* item already claims the new
85
+ * key, so "the first occurrence wins" still holds.
86
+ */
87
+ rekey(next, idx, oldKey, item, adapter) {
88
+ const newKey = adapter.key(item, idx);
89
+ if (newKey === oldKey) return;
90
+ this.#map.delete(oldKey);
91
+ if (!this.#map.has(oldKey)) {
92
+ for (let i = idx + 1; i < next.length; i++) if (adapter.key(next[i], i) === oldKey) {
93
+ this.#map.set(oldKey, i);
94
+ break;
95
+ }
96
+ }
97
+ if (!this.#map.has(newKey)) this.#map.set(newKey, idx);
98
+ }
99
+ /**
100
+ * Rebuild the map from `items` — used after a removal, which shifts every
101
+ * later item down.
102
+ */
103
+ rebuild(items, adapter) {
104
+ const map = /* @__PURE__ */ new Map();
105
+ for (let i = 0; i < items.length; i++) {
106
+ const key = adapter.key(items[i], i);
107
+ if (!map.has(key)) map.set(key, i);
108
+ }
109
+ this.#map = map;
110
+ this.#source = items;
111
+ }
112
+ /** Add the keys of `items`, which were appended at `base`. */
113
+ addAppended(items, base, adapter) {
114
+ for (let i = 0; i < items.length; i++) {
115
+ const key = adapter.key(items[i], base + i);
116
+ if (!this.#map.has(key)) this.#map.set(key, base + i);
117
+ }
118
+ }
119
+ };
23
120
  // src/grid-list/grid-list-layout.ts
24
121
  /**
25
122
  * `itemWidth` is the square's width; `rowHeight` is the full cell height
@@ -393,15 +490,25 @@ const SYNTHETIC_PREFIX = `gl-auto-`;
393
490
  function isSyntheticKey(key) {
394
491
  return key.startsWith(SYNTHETIC_PREFIX);
395
492
  }
396
- function warnDuplicateKeys(keys) {
397
- const seen = /* @__PURE__ */ new Set();
493
+ /**
494
+ * Warn about duplicate keys while building the key → raw index map, in a single
495
+ * pass. Avoids the throwaway key array `items.map(adapter.key)` used to build.
496
+ * The map keeps the **first** occurrence of each key, matching the
497
+ * "first occurrence wins" contract the warning states.
498
+ */
499
+ function rawIndexByKey(items, keyOf) {
500
+ const index = /* @__PURE__ */ new Map();
398
501
  const dupes = /* @__PURE__ */ new Set();
399
- for (const k of keys) {
400
- if (isSyntheticKey(k)) continue;
401
- if (seen.has(k)) dupes.add(k);
402
- else seen.add(k);
502
+ for (let i = 0; i < items.length; i++) {
503
+ const key = keyOf(items[i], i);
504
+ if (index.has(key)) {
505
+ if (!isSyntheticKey(key)) dupes.add(key);
506
+ continue;
507
+ }
508
+ index.set(key, i);
403
509
  }
404
510
  if (dupes.size > 0) console.warn(`ixfx-grid-list: duplicate item key(s) ${[...dupes].map((k) => `"${k}"`).join(`, `)} — the first occurrence wins for key-based operations.`);
511
+ return index;
405
512
  }
406
513
  /** Key → first effective index, built from `keys` (first occurrence wins on duplicates). */
407
514
  function indexByKey(keys) {
@@ -421,6 +528,8 @@ var ElementGridListSource = class {
421
528
  #effectiveIndices = [];
422
529
  #keysCache;
423
530
  #indexCache;
531
+ /** Key → raw index, rebuilt with the items (first occurrence wins). */
532
+ #rawIndexByKey = /* @__PURE__ */ new Map();
424
533
  #grouping;
425
534
  #groups = [];
426
535
  #groupByKey = /* @__PURE__ */ new Map();
@@ -442,6 +551,9 @@ var ElementGridListSource = class {
442
551
  this.#indexCache ??= indexByKey(this.keys());
443
552
  return this.#indexCache.get(key) ?? -1;
444
553
  }
554
+ rawIndexOfKey(key) {
555
+ return this.#rawIndexByKey.get(key) ?? -1;
556
+ }
445
557
  keys() {
446
558
  this.#keysCache ??= this.#effectiveIndices.map((i) => this.#itemKey(this.#items[i]));
447
559
  return this.#keysCache;
@@ -489,7 +601,7 @@ var ElementGridListSource = class {
489
601
  }
490
602
  refresh() {
491
603
  this.#items = Array.from(this.#host.querySelectorAll(ITEM_SELECTOR$1)).filter((el) => !el.hidden);
492
- warnDuplicateKeys(this.#items.map((el) => this.#itemKey(el)));
604
+ this.#rawIndexByKey = rawIndexByKey(this.#items, (el) => this.#itemKey(el));
493
605
  this.#recomputeEffective();
494
606
  }
495
607
  /** Effective-order elements — the array `GridListElement` renders and slices. */
@@ -554,13 +666,20 @@ var DataGridListSource = class {
554
666
  #effectiveIndices = [];
555
667
  #keysCache;
556
668
  #indexCache;
669
+ /**
670
+ * Key → **raw** index, built in one pass over the items. The first
671
+ * occurrence of a key wins (same contract as the duplicate-key warning).
672
+ * Lets `resolveKeyToData` and the host's `updateItem` find an item without
673
+ * an O(n) scan per call.
674
+ */
675
+ #rawIndexByKey;
557
676
  #grouping;
558
677
  #groups = [];
559
678
  #groupByKey = /* @__PURE__ */ new Map();
560
679
  constructor(items, adapter) {
561
680
  this.#items = items;
562
681
  this.#adapter = adapter;
563
- warnDuplicateKeys(items.map((it, i) => adapter.key(it, i)));
682
+ this.#rawIndexByKey = rawIndexByKey(items, (it, i) => adapter.key(it, i));
564
683
  this.#recomputeEffective();
565
684
  }
566
685
  get count() {
@@ -647,8 +766,16 @@ var DataGridListSource = class {
647
766
  }
648
767
  resolveKeyToElement(_key) {}
649
768
  resolveKeyToData(key) {
650
- const idx = this.#items.findIndex((item, i) => this.#adapter.key(item, i) === key);
651
- return idx >= 0 ? this.#items[idx] : void 0;
769
+ const idx = this.#rawIndexByKey.get(key);
770
+ return idx === void 0 ? void 0 : this.#items[idx];
771
+ }
772
+ /**
773
+ * Raw (unfiltered) index of `key`, or `-1`. O(1) — the key → raw index map
774
+ * is built in one pass over the items. The first occurrence of a duplicate
775
+ * key wins.
776
+ */
777
+ rawIndexOfKey(key) {
778
+ return this.#rawIndexByKey.get(key) ?? -1;
652
779
  }
653
780
  #recomputeEffective() {
654
781
  const effective = [];
@@ -964,6 +1091,8 @@ let GridListElement = class GridListElement extends LitElement {
964
1091
  }
965
1092
  });
966
1093
  this.#groupByChanged = false;
1094
+ this.#keyIndex = new KeyIndex();
1095
+ this.#cellRevisions = /* @__PURE__ */ new Map();
967
1096
  this.#resolveKey = (key) => this.#source.indexOfKey(key) >= 0 ? key : void 0;
968
1097
  this.#markedTickled = /* @__PURE__ */ new Set();
969
1098
  this.#markedSelected = /* @__PURE__ */ new Set();
@@ -1893,13 +2022,17 @@ let GridListElement = class GridListElement extends LitElement {
1893
2022
  const dataModeChanged = changed.has(`items`) || changed.has(`itemAdapter`);
1894
2023
  if (dataModeChanged) {
1895
2024
  this.#zoomAnchor = void 0;
2025
+ this.#ensureRawIndex();
1896
2026
  const prevKeys = this.#source?.keys() ?? [];
1897
2027
  const modeFlipped = this.itemAdapter !== void 0 !== this.#source instanceof DataGridListSource;
1898
2028
  this.#rebuildSource();
1899
2029
  const nextKeys = this.#source.keys();
1900
2030
  const nextKeySet = new Set(nextKeys);
1901
2031
  const removedKeys = prevKeys.filter((k) => !nextKeySet.has(k));
1902
- if (removedKeys.length > 0) this.#demoteGone(removedKeys);
2032
+ if (removedKeys.length > 0) {
2033
+ this.#demoteGone(removedKeys);
2034
+ for (const key of removedKeys) this.#cellRevisions.delete(key);
2035
+ }
1903
2036
  const tickledId = this.tickled.tickledId;
1904
2037
  if (tickledId && !nextKeySet.has(tickledId)) this.#demoteFocus(tickledId);
1905
2038
  this._syncItemStates();
@@ -2199,11 +2332,19 @@ let GridListElement = class GridListElement extends LitElement {
2199
2332
  /**
2200
2333
  * Data mode only: raw index of `key` in `this.items`, or `-1`. Data-mode keys
2201
2334
  * come straight from the adapter, so this is exact even under a filter/search.
2335
+ *
2336
+ * O(1) — backed by {@link #keyIndex}, a key → raw index map kept in sync
2337
+ * with `items`.
2202
2338
  */
2203
2339
  #rawIndexOfKey(key) {
2204
- const adapter = this.itemAdapter;
2205
- if (!adapter) return -1;
2206
- return this.items.findIndex((it, i) => adapter.key(it, i) === key);
2340
+ this.#ensureRawIndex();
2341
+ return this.#keyIndex.get(key);
2342
+ }
2343
+ /** Key → raw index for the current `items`. See `grid-list-key-index.ts`. */
2344
+ #keyIndex;
2345
+ /** Rebuild the key → raw index map if `items` / `itemAdapter` changed. */
2346
+ #ensureRawIndex() {
2347
+ this.#keyIndex.ensure(this.items, this.itemAdapter);
2207
2348
  }
2208
2349
  /**
2209
2350
  * Data mode: replace the whole item array. Selection and cursor keep any key
@@ -2220,23 +2361,104 @@ let GridListElement = class GridListElement extends LitElement {
2220
2361
  * A no-op in element mode.
2221
2362
  */
2222
2363
  appendItems(items) {
2223
- if (this.itemAdapter && items.length > 0) this.items = [...this.items, ...items];
2364
+ if (this.itemAdapter && items.length > 0) {
2365
+ const base = this.items.length;
2366
+ const next = [...this.items, ...items];
2367
+ this.#ensureRawIndex();
2368
+ this.#keyIndex.addAppended(items, base, this.itemAdapter);
2369
+ this.#keyIndex.commit(next);
2370
+ this.items = next;
2371
+ }
2224
2372
  }
2225
2373
  /**
2226
2374
  * Data mode: replace the item carrying `key`. A visible cell re-renders in
2227
2375
  * place (the keyed subtree is kept); an offscreen item shows its new content
2228
2376
  * when scrolled into view. Scroll and selection are untouched. Unknown keys
2229
2377
  * are ignored.
2378
+ *
2379
+ * Passing the **same object** that is already at `key` is a no-op: the
2380
+ * `items` array is left untouched (same identity) and nothing is emitted.
2381
+ * Use {@link refreshItem} to re-render a cell without changing the data.
2382
+ *
2383
+ * Updating many items one by one? Use {@link updateItems} — it applies them
2384
+ * with a single array copy and a single rebuild.
2230
2385
  */
2231
2386
  updateItem(key, item) {
2232
2387
  if (!this.itemAdapter) return;
2233
2388
  const idx = this.#rawIndexOfKey(key);
2234
2389
  if (idx < 0) return;
2390
+ if (this.items[idx] === item) return;
2235
2391
  const next = [...this.items];
2236
2392
  next[idx] = item;
2393
+ this.#ensureRawIndex();
2394
+ this.#keyIndex.rekey(next, idx, key, item, this.itemAdapter);
2395
+ this.#keyIndex.commit(next);
2237
2396
  this.items = next;
2238
2397
  }
2239
2398
  /**
2399
+ * Data mode: replace several items at once — the batched form of
2400
+ * {@link updateItem}.
2401
+ *
2402
+ * `entries` is an array of `{ key, item }` pairs (a `Map<key, item>` is
2403
+ * accepted too). All the replacements are applied with **one** array copy
2404
+ * and **one** source rebuild, so a host that must refresh n rows does not
2405
+ * pay n copies and n scans.
2406
+ *
2407
+ * Semantics match n sequential {@link updateItem} calls:
2408
+ * - unknown keys are ignored;
2409
+ * - an entry whose `item` is the identical object already at that key is
2410
+ * skipped (it cannot change anything);
2411
+ * - selection, cursor and scroll are untouched;
2412
+ * - if no entry changes anything, `items` is left untouched (same identity)
2413
+ * and nothing is emitted.
2414
+ */
2415
+ updateItems(entries) {
2416
+ if (!this.itemAdapter) return;
2417
+ const pairs = [];
2418
+ for (const entry of entries) if (Array.isArray(entry)) pairs.push([entry[0], entry[1]]);
2419
+ else pairs.push([entry.key, entry.item]);
2420
+ if (pairs.length === 0) return;
2421
+ this.#ensureRawIndex();
2422
+ const next = [...this.items];
2423
+ const touched = [];
2424
+ for (const [key, item] of pairs) {
2425
+ const idx = this.#keyIndex.get(key);
2426
+ if (idx < 0) continue;
2427
+ if (next[idx] === item) continue;
2428
+ next[idx] = item;
2429
+ touched.push([
2430
+ idx,
2431
+ key,
2432
+ item
2433
+ ]);
2434
+ }
2435
+ if (touched.length === 0) return;
2436
+ for (const [idx, key, item] of touched) this.#keyIndex.rekey(next, idx, key, item, this.itemAdapter);
2437
+ this.#keyIndex.commit(next);
2438
+ this.items = next;
2439
+ }
2440
+ /**
2441
+ * Data mode: re-render the cell for `key` without touching `items`.
2442
+ *
2443
+ * Use this when the *data* is unchanged but the cell should be redrawn — for
2444
+ * example after mutating something the adapter reads from outside the item
2445
+ * (a thumbnail's load state). The `items` array keeps its identity, so the
2446
+ * collection is not copied and no source rebuild is triggered.
2447
+ *
2448
+ * The adapter's `render` is called again for that cell on the next render,
2449
+ * so the cell picks up the new state. Other cells are left alone.
2450
+ *
2451
+ * Unknown keys are ignored. A no-op in element mode.
2452
+ */
2453
+ refreshItem(key) {
2454
+ if (!this.itemAdapter) return;
2455
+ if (this.#rawIndexOfKey(key) < 0) return;
2456
+ this.#cellRevisions.set(key, (this.#cellRevisions.get(key) ?? 0) + 1);
2457
+ this.requestUpdate();
2458
+ }
2459
+ /** Per-key revision, bumped by {@link refreshItem}. */
2460
+ #cellRevisions;
2461
+ /**
2240
2462
  * Data mode: remove the items carrying these keys. Removed keys leave the
2241
2463
  * selection and cursor silently (via the `items` change) and are held as
2242
2464
  * pending view state. A no-op in element mode.
@@ -2245,7 +2467,12 @@ let GridListElement = class GridListElement extends LitElement {
2245
2467
  if (!this.itemAdapter) return;
2246
2468
  const adapter = this.itemAdapter;
2247
2469
  const keySet = new Set(keys);
2248
- this.items = this.items.filter((it, i) => !keySet.has(adapter.key(it, i)));
2470
+ const kept = this.items.filter((it, i) => !keySet.has(adapter.key(it, i)));
2471
+ if (kept.length === this.items.length) return;
2472
+ this.#ensureRawIndex();
2473
+ this.#keyIndex.rebuild(kept, adapter);
2474
+ this.#keyIndex.commit(kept);
2475
+ this.items = kept;
2249
2476
  }
2250
2477
  /**
2251
2478
  * Data mode: drop every item. Selection and cursor are reset and one
@@ -2708,13 +2935,24 @@ let GridListElement = class GridListElement extends LitElement {
2708
2935
  >
2709
2936
  <div class="content${icon === void 0 ? `` : ` has-icon`}" part="content">
2710
2937
  ${icon === void 0 ? nothing : html`<span class="cell-icon" part="icon" style=${this.#colorStyle(this.#source.iconColorAt(index))}>${icon}</span>`}
2711
- ${this.#source.renderCellContent(index)}
2938
+ ${this.#renderCellBody(index, key)}
2712
2939
  </div>
2713
2940
  ${showCaption ? this.#renderCaption(caption, captionCss, tickled, this.#source.badgeAt(index), this.#source.textColorAt(index)) : ``}
2714
2941
  </div>
2715
2942
  `;
2716
2943
  }
2717
2944
  /**
2945
+ * The cell's content, keyed by the cell's revision so {@link refreshItem}
2946
+ * can force it to be re-evaluated (and its DOM re-created) even though
2947
+ * `items` did not change. Without a revision change the content is bound
2948
+ * normally, so Lit keeps it in place.
2949
+ */
2950
+ #renderCellBody(index, key) {
2951
+ const revision = this.#cellRevisions.get(key);
2952
+ if (revision === void 0) return this.#source.renderCellContent(index);
2953
+ return keyed(revision, this.#source.renderCellContent(index));
2954
+ }
2955
+ /**
2718
2956
  * A tickled cell swaps its plain label for an `ixfx-pan-text` in loop mode
2719
2957
  * so a truncated label scrolls instead of staying an ellipsis. Unticked
2720
2958
  * cells keep the cheap plain-text caption.
@@ -3008,6 +3246,7 @@ __decorate([property({
3008
3246
  reflect: true
3009
3247
  })], GridListElement.prototype, "marqueeFromCellBlank", void 0);
3010
3248
  __decorate([property({ attribute: false })], GridListElement.prototype, "dragPreviewRenderer", void 0);
3249
+ __decorate([property({ attribute: false })], GridListElement.prototype, "writeDataTransfer", void 0);
3011
3250
  __decorate([property({ attribute: false })], GridListElement.prototype, "dragPreviewSource", void 0);
3012
3251
  __decorate([property({
3013
3252
  type: String,
@@ -1,5 +1,5 @@
1
- import { B as ListNativeDragStartDetail, F as ListDragPreview, I as ListDragPreviewContext, L as ListDragPreviewRenderer, P as ListDragEntry, V as ListNativeDragStartEvent, z as ListDragSource } from "./tree-component-DNuzfo6R.js";
2
- import { _ as GridListSelectEvent, a as GridListCaptionAlign, b as GridListViewportChangeDetail, c as GridListCaptionStyle, d as GridListFullElementEventMap, f as GridListItemClickDetail, g as GridListSelectDetail, h as GridListOrientation, i as GridListActivateEvent, l as GridListDataAdapter, m as GridListItemEventDetail, n as GridListViewState, o as GridListCaptionBackdrop, p as GridListItemClickEvent, r as GridListActivateDetail, s as GridListCaptionPosition, t as GridListElement, u as GridListElementEventMap, v as GridListTickleDetail, x as GridListViewportChangeEvent, y as GridListTickleEvent } from "./grid-list-Dg8hIiKO.js";
1
+ import { B as ListDragSource, F as ListDragEntry, H as ListNativeDragStartEvent, I as ListDragPreview, L as ListDragPreviewContext, R as ListDragPreviewRenderer, V as ListNativeDragStartDetail } from "./tree-component-BE7OEIiH.js";
2
+ import { S as GridListViewportChangeEvent, _ as GridListSelectDetail, a as GridListCaptionAlign, b as GridListTickleEvent, c as GridListCaptionStyle, d as GridListFullElementEventMap, f as GridListItemClickDetail, g as GridListOrientation, h as GridListItemUpdate, i as GridListActivateEvent, l as GridListDataAdapter, m as GridListItemEventDetail, n as GridListViewState, o as GridListCaptionBackdrop, p as GridListItemClickEvent, r as GridListActivateDetail, s as GridListCaptionPosition, t as GridListElement, u as GridListElementEventMap, v as GridListSelectEvent, x as GridListViewportChangeDetail, y as GridListTickleDetail } from "./grid-list-Crv-hFJL.js";
3
3
  import { h as ListSelectionMode, i as ListInteractionMode } from "./list-selection-types-CKTt7Rrw.js";
4
4
  import { i as ListGroupChangeEvent, l as ListGroupToggleDetail, n as ListGroupBy, o as ListGroupInfo, r as ListGroupChangeDetail, s as ListGroupLabel, u as ListGroupToggleEvent } from "./grouping-OoQ8WaKc.js";
5
- export { type GridListActivateDetail, type GridListActivateEvent, type GridListCaptionAlign, type GridListCaptionBackdrop, type GridListCaptionPosition, type GridListCaptionStyle, type GridListDataAdapter, GridListElement, type GridListElementEventMap, type GridListFullElementEventMap, type GridListItemClickDetail, type GridListItemClickEvent, type GridListItemEventDetail, type GridListOrientation, type GridListSelectDetail, type GridListSelectEvent, type GridListTickleDetail, type GridListTickleEvent, type GridListViewState, type GridListViewportChangeDetail, type GridListViewportChangeEvent, type ListDragEntry, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListGroupBy, type ListGroupChangeDetail, type ListGroupChangeEvent, type ListGroupInfo, type ListGroupLabel, type ListGroupToggleDetail, type ListGroupToggleEvent, type ListInteractionMode, type ListNativeDragStartDetail, type ListNativeDragStartEvent, type ListSelectionMode };
5
+ export { type GridListActivateDetail, type GridListActivateEvent, type GridListCaptionAlign, type GridListCaptionBackdrop, type GridListCaptionPosition, type GridListCaptionStyle, type GridListDataAdapter, GridListElement, type GridListElementEventMap, type GridListFullElementEventMap, type GridListItemClickDetail, type GridListItemClickEvent, type GridListItemEventDetail, type GridListItemUpdate, type GridListOrientation, type GridListSelectDetail, type GridListSelectEvent, type GridListTickleDetail, type GridListTickleEvent, type GridListViewState, type GridListViewportChangeDetail, type GridListViewportChangeEvent, type ListDragEntry, type ListDragPreview, type ListDragPreviewContext, type ListDragPreviewRenderer, type ListDragSource, type ListGroupBy, type ListGroupChangeDetail, type ListGroupChangeEvent, type ListGroupInfo, type ListGroupLabel, type ListGroupToggleDetail, type ListGroupToggleEvent, type ListInteractionMode, type ListNativeDragStartDetail, type ListNativeDragStartEvent, type ListSelectionMode };
package/dist/grid-list.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import "./list-group-header.js";
2
- export { t as GridListElement } from "./grid-list-BHo9TBxX.js";
2
+ export { t as GridListElement } from "./grid-list-DYU_z2K9.js";
@@ -1,2 +1,2 @@
1
- import { A as FuzzySearch, C as ListSearchControllerOptions, D as IncrSearchTreeOptions, E as IncrSearchTreeController, F as IncrSearchChangeCallback, I as IncrSearchOptions, L as IncrSearchResult, M as HighlightOptions, N as HighlightTarget, O as createAcCompletionProvider, P as IncrSearch, R as IncrSearchState, S as ListSearchController, T as ListSearchMode, _ as DataListSearchAdapterOptions, a as RegisterListSearchCommandsOptions, b as LIST_SEARCH_MODES, c as applyHighlights, d as createFuzzySearch, f as ElementIncrSearch, g as createElementListSearchAdapter, h as ElementListSearchHost, i as LIST_SEARCH_COMMAND_IDS, j as FuzzySearchOptions, k as ElementIncrSearchOptions, l as buildHighlightTargets, m as ElementListSearchAdapterOptions, n as createTreeListSearchAdapter, o as registerListSearchCommands, p as createElementIncrSearch, r as listSearchStyles, s as createIncrSearch, t as TreeListSearchAdapterOptions, u as clearHighlights, v as DataListSearchItem, w as ListSearchHost, x as ListSearchAdapter, y as createDataListSearchAdapter } from "./index-CRLTVAyt.js";
1
+ import { A as FuzzySearch, C as ListSearchControllerOptions, D as IncrSearchTreeOptions, E as IncrSearchTreeController, F as IncrSearchChangeCallback, I as IncrSearchOptions, L as IncrSearchResult, M as HighlightOptions, N as HighlightTarget, O as createAcCompletionProvider, P as IncrSearch, R as IncrSearchState, S as ListSearchController, T as ListSearchMode, _ as DataListSearchAdapterOptions, a as RegisterListSearchCommandsOptions, b as LIST_SEARCH_MODES, c as applyHighlights, d as createFuzzySearch, f as ElementIncrSearch, g as createElementListSearchAdapter, h as ElementListSearchHost, i as LIST_SEARCH_COMMAND_IDS, j as FuzzySearchOptions, k as ElementIncrSearchOptions, l as buildHighlightTargets, m as ElementListSearchAdapterOptions, n as createTreeListSearchAdapter, o as registerListSearchCommands, p as createElementIncrSearch, r as listSearchStyles, s as createIncrSearch, t as TreeListSearchAdapterOptions, u as clearHighlights, v as DataListSearchItem, w as ListSearchHost, x as ListSearchAdapter, y as createDataListSearchAdapter } from "./index-Db5VGFR1.js";
2
2
  export { type DataListSearchAdapterOptions, type DataListSearchItem, type ElementIncrSearch, type ElementIncrSearchOptions, type ElementListSearchAdapterOptions, type ElementListSearchHost, type FuzzySearch, type FuzzySearchOptions, type HighlightOptions, type HighlightTarget, type IncrSearch, type IncrSearchChangeCallback, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, type IncrSearchTreeOptions as IncrSearchMillerOptions, type IncrSearchTreeOptions, type IncrSearchOptions, type IncrSearchResult, type IncrSearchState, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, type ListSearchAdapter, ListSearchController, type ListSearchControllerOptions, type ListSearchHost, type ListSearchMode, type RegisterListSearchCommandsOptions, type TreeListSearchAdapterOptions, applyHighlights, buildHighlightTargets, clearHighlights, createAcCompletionProvider, createDataListSearchAdapter, createElementIncrSearch, createElementListSearchAdapter, createFuzzySearch, createIncrSearch, createTreeListSearchAdapter, listSearchStyles, registerListSearchCommands };
@@ -1,9 +1,9 @@
1
- import { E as TreeSearchHost, M as TreeDataModel, a as TreeComponent, i as TreeCollapseEvent, j as TreeTickleEvent, k as TreeSelectEvent, n as TreeActivateEvent, o as TreeComponentEventMap, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent } from "./tree-component-DNuzfo6R.js";
1
+ import { E as TreeSearchHost, M as TreeDataModel, a as TreeComponent, i as TreeCollapseEvent, j as TreeTickleEvent, k as TreeSelectEvent, n as TreeActivateEvent, o as TreeComponentEventMap, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent } from "./tree-component-BE7OEIiH.js";
2
2
  import { a as TreeItem, n as TreeExclusivity, o as TreeNode, r as TreeFilterPredicate, s as TreeSelectionFilter, t as LoadChildrenCallback } from "./types-6hpXRKt7.js";
3
3
  import { a as ViewStateBase, n as ScrollState, t as GetViewStateOptions } from "./types-16GC5k1z.js";
4
4
  import { m as ListSelectKeysDetail, u as ListSelectIntentDetail } from "./list-selection-types-CKTt7Rrw.js";
5
5
  import "./index-Cdcek1Oj.js";
6
- import { S as ListSearchController } from "./index-CRLTVAyt.js";
6
+ import { S as ListSearchController } from "./index-Db5VGFR1.js";
7
7
  import { n as TickledController } from "./tickled-controller-DSPoG551.js";
8
8
  import { LitElement, PropertyValues, TemplateResult, nothing } from "lit";
9
9
  import { CommandRegistry } from "@clinth/ui-commands";
@@ -1,10 +1,10 @@
1
- import { B as ListNativeDragStartDetail, C as TreeItemDblClickEvent, D as TreeSelectAllOptions, E as TreeSearchHost, L as ListDragPreviewRenderer, M as TreeDataModel, R as ListDragPreviewSourceResolver, _ as TreeDropTarget, a as TreeComponent, c as TreeDragContext, d as TreeDragStartEvent, h as TreeDropEvent, i as TreeCollapseEvent, j as TreeTickleEvent, k as TreeSelectEvent, l as TreeDragEndEvent, m as TreeDropDetail, n as TreeActivateEvent, o as TreeComponentEventMap, p as TreeDropContext, s as TreeDndMode, u as TreeDragOverEvent, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent } from "./tree-component-DNuzfo6R.js";
1
+ import { C as TreeItemDblClickEvent, D as TreeSelectAllOptions, E as TreeSearchHost, M as TreeDataModel, R as ListDragPreviewRenderer, V as ListNativeDragStartDetail, _ as TreeDropTarget, a as TreeComponent, c as TreeDragContext, d as TreeDragStartEvent, h as TreeDropEvent, i as TreeCollapseEvent, j as TreeTickleEvent, k as TreeSelectEvent, l as TreeDragEndEvent, m as TreeDropDetail, n as TreeActivateEvent, o as TreeComponentEventMap, p as TreeDropContext, s as TreeDndMode, u as TreeDragOverEvent, w as TreeNavigateOptions, x as TreeItemClickEvent, y as TreeExpandEvent, z as ListDragPreviewSourceResolver } from "./tree-component-BE7OEIiH.js";
2
2
  import { a as TreeItem, i as TreeInteractionMode, n as TreeExclusivity, o as TreeNode, r as TreeFilterPredicate, s as TreeSelectionFilter, t as LoadChildrenCallback } from "./types-6hpXRKt7.js";
3
3
  import { a as ViewStateBase, t as GetViewStateOptions } from "./types-16GC5k1z.js";
4
4
  import { m as ListSelectKeysDetail, p as ListSelectIntentSource, u as ListSelectIntentDetail } from "./list-selection-types-CKTt7Rrw.js";
5
5
  import "./index-Cdcek1Oj.js";
6
- import { S as ListSearchController } from "./index-CRLTVAyt.js";
7
- import { t as ListNativeDragController } from "./list-native-drag-controller-CgXKdmjr.js";
6
+ import { S as ListSearchController } from "./index-Db5VGFR1.js";
7
+ import { t as ListNativeDragController } from "./list-native-drag-controller-Cs-Tmtaa.js";
8
8
  import { n as TickledController } from "./tickled-controller-DSPoG551.js";
9
9
  import { LitElement, PropertyValues, ReactiveController, ReactiveControllerHost, TemplateResult, nothing } from "lit";
10
10
  import { CommandRegistry } from "@clinth/ui-commands";
@@ -1,4 +1,4 @@
1
- import { E as TreeSearchHost } from "./tree-component-DNuzfo6R.js";
1
+ import { E as TreeSearchHost } from "./tree-component-BE7OEIiH.js";
2
2
  import { o as TreeNode } from "./types-6hpXRKt7.js";
3
3
  import { p as ListSelectIntentSource } from "./list-selection-types-CKTt7Rrw.js";
4
4
  import "./icon-Bhz0c6Yf.js";