@ixfx/components 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.
Files changed (141) hide show
  1. package/bundle/index.d.ts +1355 -526
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +3277 -384
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +1 -1
  6. package/dist/ac-text.js +1 -1
  7. package/dist/{ac-token-TCLAZeVg.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
  8. package/dist/{ac-token-TCLAZeVg.d.ts.map → ac-token--_vCHXWw.d.ts.map} +1 -1
  9. package/dist/ac-token.d.ts +1 -1
  10. package/dist/ac-token.js +2 -2
  11. package/dist/button.d.ts +1 -1
  12. package/dist/button.d.ts.map +1 -1
  13. package/dist/colour-picker.d.ts +1 -1
  14. package/dist/crumbs.d.ts +6 -2
  15. package/dist/crumbs.d.ts.map +1 -1
  16. package/dist/crumbs.js +13 -3
  17. package/dist/crumbs.js.map +1 -1
  18. package/dist/{data-grid-Db4QpnII.d.ts → data-grid-CtJ35v8L.d.ts} +59 -2
  19. package/dist/data-grid-CtJ35v8L.d.ts.map +1 -0
  20. package/dist/data-grid.d.ts +1 -1
  21. package/dist/data-grid.js +268 -14
  22. package/dist/data-grid.js.map +1 -1
  23. package/dist/detail-list-BS5dRDda.d.ts +175 -0
  24. package/dist/detail-list-BS5dRDda.d.ts.map +1 -0
  25. package/dist/detail-list.d.ts +3 -0
  26. package/dist/detail-list.js +1031 -0
  27. package/dist/detail-list.js.map +1 -0
  28. package/dist/grid-list-D-GbghSH.d.ts +321 -0
  29. package/dist/grid-list-D-GbghSH.d.ts.map +1 -0
  30. package/dist/grid-list.d.ts +3 -0
  31. package/dist/grid-list.js +994 -0
  32. package/dist/grid-list.js.map +1 -0
  33. package/dist/{grouped-item-lister-BWlC9S4e.d.ts → grouped-item-lister-fdZHVxFM.d.ts} +3 -3
  34. package/dist/{grouped-item-lister-BWlC9S4e.d.ts.map → grouped-item-lister-fdZHVxFM.d.ts.map} +1 -1
  35. package/dist/grouped-item-lister.d.ts +1 -1
  36. package/dist/{icon-DR_3rSyZ.d.ts → icon-CDGprSdE.d.ts} +2 -2
  37. package/dist/icon-CDGprSdE.d.ts.map +1 -0
  38. package/dist/icons.d.ts +2 -2
  39. package/dist/incr-search-DpbSJtgj.js +962 -0
  40. package/dist/incr-search-DpbSJtgj.js.map +1 -0
  41. package/dist/incr-search.d.ts +2 -2
  42. package/dist/incr-search.js +2 -3
  43. package/dist/{index-C59-JEPl.d.ts → index-9AhaHIT2.d.ts} +3 -3
  44. package/dist/{index-C59-JEPl.d.ts.map → index-9AhaHIT2.d.ts.map} +1 -1
  45. package/dist/index-CBS4z1v-.d.ts +365 -0
  46. package/dist/index-CBS4z1v-.d.ts.map +1 -0
  47. package/dist/{index-DsjpDksO.d.ts → index-CS9yM8L-.d.ts} +2 -2
  48. package/dist/{index-DsjpDksO.d.ts.map → index-CS9yM8L-.d.ts.map} +1 -1
  49. package/dist/{index-BUB5SICW.d.ts → index-CoqtMSd9.d.ts} +2 -2
  50. package/dist/{index-BUB5SICW.d.ts.map → index-CoqtMSd9.d.ts.map} +1 -1
  51. package/dist/{index-CJ5fshD3.d.ts → index-UvnoZUAo.d.ts} +2 -2
  52. package/dist/{index-CJ5fshD3.d.ts.map → index-UvnoZUAo.d.ts.map} +1 -1
  53. package/dist/{index-BOUaDIW-.d.ts → index-tq6f8007.d.ts} +2 -2
  54. package/dist/{index-BOUaDIW-.d.ts.map → index-tq6f8007.d.ts.map} +1 -1
  55. package/dist/index.d.ts +188 -243
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +376 -1004
  58. package/dist/index.js.map +1 -1
  59. package/dist/interaction-Cr13azbM.js +3 -0
  60. package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-DiTme1JO.d.ts} +2 -2
  61. package/dist/{labelled-input-base-Dp_9KP0G.d.ts.map → labelled-input-base-DiTme1JO.d.ts.map} +1 -1
  62. package/dist/labelled-radial-input.d.ts +2 -2
  63. package/dist/labelled-radial-input.d.ts.map +1 -1
  64. package/dist/labelled-range-input.d.ts +1 -1
  65. package/dist/labelled-slider-input.d.ts +1 -1
  66. package/dist/list-item-animation-DuiwgN3l.js +112 -0
  67. package/dist/list-item-animation-DuiwgN3l.js.map +1 -0
  68. package/dist/list-selection-controller-DTFI40li.js +264 -0
  69. package/dist/list-selection-controller-DTFI40li.js.map +1 -0
  70. package/dist/{list-selection-types-DSuRNWpx.d.ts → list-selection-types-B5ioL-dG.d.ts} +6 -1
  71. package/dist/list-selection-types-B5ioL-dG.d.ts.map +1 -0
  72. package/dist/{menu-DMzjkVnK.js → menu-Bg90Qr0B.js} +3 -3
  73. package/dist/{menu-DMzjkVnK.js.map → menu-Bg90Qr0B.js.map} +1 -1
  74. package/dist/{menu-item-D2S4i8u1.js → menu-item-Bx-Fs7jq.js} +3 -3
  75. package/dist/{menu-item-D2S4i8u1.js.map → menu-item-Bx-Fs7jq.js.map} +1 -1
  76. package/dist/{menu-item-ZmkXNjek.d.ts → menu-item-CZi9vy5O.d.ts} +2 -2
  77. package/dist/{menu-item-ZmkXNjek.d.ts.map → menu-item-CZi9vy5O.d.ts.map} +1 -1
  78. package/dist/menu.d.ts +2 -2
  79. package/dist/menu.js +2 -2
  80. package/dist/miller.d.ts +82 -4
  81. package/dist/miller.d.ts.map +1 -1
  82. package/dist/miller.js +329 -70
  83. package/dist/miller.js.map +1 -1
  84. package/dist/narrowed-text.js +3 -4
  85. package/dist/narrowed-text.js.map +1 -1
  86. package/dist/panel.d.ts +1 -1
  87. package/dist/plots.js +1 -1
  88. package/dist/select-horiz.js +2 -2
  89. package/dist/{split-layout-C5SYbDrq.d.ts → split-layout-JK3xWVX2.d.ts} +2 -2
  90. package/dist/{split-layout-C5SYbDrq.d.ts.map → split-layout-JK3xWVX2.d.ts.map} +1 -1
  91. package/dist/split-layout.d.ts +1 -1
  92. package/dist/{tab-list-DbMIL520.d.ts → tab-list-CGyPt07Z.d.ts} +2 -2
  93. package/dist/{tab-list-DbMIL520.d.ts.map → tab-list-CGyPt07Z.d.ts.map} +1 -1
  94. package/dist/tabs.d.ts +1 -1
  95. package/dist/{tickled-controller-Ds1DMyG7.d.ts → tickled-controller-Bn3YdQsM.d.ts} +12 -1
  96. package/dist/{tickled-controller-Ds1DMyG7.d.ts.map → tickled-controller-Bn3YdQsM.d.ts.map} +1 -1
  97. package/dist/{tickled-controller-h9GmJ_bU.js → tickled-controller-C66DgJHl.js} +16 -1
  98. package/dist/tickled-controller-C66DgJHl.js.map +1 -0
  99. package/dist/{titlebar-B23MrIbI.d.ts → titlebar-Bj5pfdw_.d.ts} +2 -2
  100. package/dist/{titlebar-B23MrIbI.d.ts.map → titlebar-Bj5pfdw_.d.ts.map} +1 -1
  101. package/dist/titlebar.d.ts +1 -1
  102. package/dist/{tree-Ch4W8qXQ.js → tree-DAii2A1g.js} +190 -29
  103. package/dist/tree-DAii2A1g.js.map +1 -0
  104. package/dist/{tree-component-BvV4muxx.d.ts → tree-component-F6qZ0Gdv.d.ts} +9 -1
  105. package/dist/{tree-component-BvV4muxx.d.ts.map → tree-component-F6qZ0Gdv.d.ts.map} +1 -1
  106. package/dist/tree.d.ts +28 -4
  107. package/dist/tree.d.ts.map +1 -1
  108. package/dist/tree.js +1 -1
  109. package/dist/vertical-list-DwtCPy1b.d.ts +143 -0
  110. package/dist/vertical-list-DwtCPy1b.d.ts.map +1 -0
  111. package/dist/vertical-list.d.ts +3 -121
  112. package/dist/vertical-list.js +642 -1
  113. package/dist/vertical-list.js.map +1 -0
  114. package/dist/{xy-axis-DWizs0bt.js → xy-axis-VrX8dmvS.js} +2 -2
  115. package/dist/{xy-axis-DWizs0bt.js.map → xy-axis-VrX8dmvS.js.map} +1 -1
  116. package/docs-user/README.md +1 -0
  117. package/docs-user/data-grid.md +70 -2
  118. package/docs-user/detail-list.md +39 -1
  119. package/docs-user/grid-list.md +298 -0
  120. package/docs-user/incr-search.md +12 -2
  121. package/docs-user/index.json +7 -2
  122. package/docs-user/llms.txt +1 -0
  123. package/docs-user/tree.md +35 -1
  124. package/docs-user/vertical-list.md +58 -2
  125. package/llms.txt +1 -0
  126. package/package.json +17 -2
  127. package/dist/data-grid-Db4QpnII.d.ts.map +0 -1
  128. package/dist/element-search-Y8SRfPGM.js +0 -185
  129. package/dist/element-search-Y8SRfPGM.js.map +0 -1
  130. package/dist/icon-DR_3rSyZ.d.ts.map +0 -1
  131. package/dist/incr-search-vCzuao-2.js +0 -137
  132. package/dist/incr-search-vCzuao-2.js.map +0 -1
  133. package/dist/index-Cu5i8zZY.d.ts +0 -160
  134. package/dist/index-Cu5i8zZY.d.ts.map +0 -1
  135. package/dist/interaction-D5XdKzbR.js +0 -2
  136. package/dist/list-selection-types-DSuRNWpx.d.ts.map +0 -1
  137. package/dist/tickled-controller-h9GmJ_bU.js.map +0 -1
  138. package/dist/tree-Ch4W8qXQ.js.map +0 -1
  139. package/dist/vertical-list-B4w_ksJk.js +0 -814
  140. package/dist/vertical-list-B4w_ksJk.js.map +0 -1
  141. package/dist/vertical-list.d.ts.map +0 -1
@@ -1,12 +1,15 @@
1
- import { t as TickledController } from "./tickled-controller-h9GmJ_bU.js";
1
+ import { t as TickledController } from "./tickled-controller-C66DgJHl.js";
2
2
  import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-DNI9xt0F.js";
4
4
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
- import "./interaction-D5XdKzbR.js";
5
+ import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-DpbSJtgj.js";
6
+ import { n as animateListItemIn, r as animateListItemOut } from "./list-item-animation-DuiwgN3l.js";
7
+ import "./interaction-Cr13azbM.js";
6
8
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
7
9
  import { LitElement, css, html, nothing } from "lit";
8
10
  import { property, state } from "lit/decorators.js";
9
11
  import { createCommandRegistry } from "@clinth/ui-commands";
12
+ import { repeat } from "lit/directives/repeat.js";
10
13
  //#region src/common/tree-data-model.ts
11
14
  function findNode(root, key) {
12
15
  if (root.item.key === key) return root;
@@ -198,6 +201,8 @@ var TreeDataModel = class {
198
201
  };
199
202
  //#endregion
200
203
  //#region src/tree/tree-base.ts
204
+ /** Above this many rows entering / leaving at once, skip the animation entirely. */
205
+ const MAX_ANIMATED_ROWS = 50;
201
206
  let TreeBaseElement = class TreeBaseElement extends LitElement {
202
207
  constructor(..._args) {
203
208
  super(..._args);
@@ -220,8 +225,19 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
220
225
  }
221
226
  });
222
227
  this._focusedDepth = 0;
228
+ this.search = new ListSearchController(this, { adapter: createTreeListSearchAdapter(this, {
229
+ labelSelector: `.tree-label`,
230
+ highlightKey: `incr-search-highlight`
231
+ }) });
223
232
  this.#config = { indent: 20 };
233
+ this.#renderedKeys = [];
234
+ this.#lastNodeByKey = /* @__PURE__ */ new Map();
235
+ this.#enteringKeys = /* @__PURE__ */ new Set();
236
+ this.#leaving = /* @__PURE__ */ new Map();
237
+ this.#leavingAnimating = /* @__PURE__ */ new Set();
238
+ this.#treeAnimReady = false;
224
239
  this.#onKeyDown = (event) => {
240
+ if (this.search.isOpen) return;
225
241
  const nodes = this.#getAllNodes();
226
242
  if (nodes.length === 0) return;
227
243
  if ((event.ctrlKey || event.metaKey) && event.key === `a`) {
@@ -282,7 +298,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
282
298
  bubbles: true,
283
299
  composed: true
284
300
  }));
285
- } else if (current.depth > 1) {
301
+ } else if (current.depth > 0) {
286
302
  const parentDepth = current.depth - 1;
287
303
  for (let i = currentIdx - 1; i >= 0; i--) if (nodes[i].depth === parentDepth) {
288
304
  this.#setFocusedIndex(i);
@@ -342,12 +358,111 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
342
358
  get selectedNodes() {
343
359
  return this._selectedNodes;
344
360
  }
361
+ #unregisterSearchCommands;
362
+ #effectiveSearchModes() {
363
+ const raw = this.searchModes?.trim();
364
+ if (raw === void 0) return [...LIST_SEARCH_MODES];
365
+ const requested = new Set(raw.split(/\s+/));
366
+ return LIST_SEARCH_MODES.filter((m) => requested.has(m));
367
+ }
368
+ #syncSearchCommands() {
369
+ if (!this.#ownedRegistry) return;
370
+ this.search.setModes(this.#effectiveSearchModes());
371
+ this.#unregisterSearchCommands?.();
372
+ this.#unregisterSearchCommands = registerListSearchCommands(this.#ownedRegistry, this.search);
373
+ }
345
374
  #pendingNode;
346
375
  #pendingController;
347
376
  #modelUnsubscribe;
348
377
  #anchor;
349
378
  #ownedRegistry;
350
379
  #config;
380
+ #renderedKeys;
381
+ #lastNodeByKey;
382
+ #enteringKeys;
383
+ #leaving;
384
+ #leavingAnimating;
385
+ #treeAnimReady;
386
+ willUpdate(changedProps) {
387
+ super.willUpdate(changedProps);
388
+ this.#diffVisibleNodes();
389
+ }
390
+ #diffVisibleNodes() {
391
+ const nodes = this.root ? this.#getAllNodes() : [];
392
+ const nowKeys = new Set(nodes.map((n) => n.node.item.key));
393
+ this.#enteringKeys.clear();
394
+ if (this.#treeAnimReady && this.#renderedKeys.length > 0) {
395
+ const prevSet = new Set(this.#renderedKeys);
396
+ for (const { node } of nodes) if (!prevSet.has(node.item.key)) this.#enteringKeys.add(node.item.key);
397
+ if (this.#enteringKeys.size > MAX_ANIMATED_ROWS) this.#enteringKeys.clear();
398
+ for (const key of this.#renderedKeys) if (!nowKeys.has(key) && !this.#leaving.has(key)) {
399
+ const last = this.#lastNodeByKey.get(key);
400
+ if (last) this.#leaving.set(key, last);
401
+ }
402
+ }
403
+ for (const key of [...this.#leaving.keys()]) if (nowKeys.has(key)) {
404
+ this.#leaving.delete(key);
405
+ this.#leavingAnimating.delete(key);
406
+ }
407
+ if (this.#leaving.size > MAX_ANIMATED_ROWS) {
408
+ this.#leaving.clear();
409
+ this.#leavingAnimating.clear();
410
+ }
411
+ }
412
+ /** True while `node` is a fading ghost row (removed / collapsed, still animating out). */
413
+ _isLeaving(node) {
414
+ return this.#leaving.has(node.item.key);
415
+ }
416
+ /**
417
+ * True when `filterPredicate` is set and neither `node` nor any descendant
418
+ * matches — the row should carry the `filtered` class (`display: none`).
419
+ */
420
+ _isFilteredOut(node, depth) {
421
+ return this.filterPredicate !== void 0 && !this.#matchesFilter(node, depth);
422
+ }
423
+ /** Splice the fading ghost rows back into the visible list near where they were. */
424
+ #weaveLeaving(nodes) {
425
+ if (this.#leaving.size === 0) return nodes;
426
+ const result = [...nodes];
427
+ const indexOfKey = (key) => result.findIndex((e) => e.node.item.key === key);
428
+ for (const [key, entry] of this.#leaving) {
429
+ const prevIdx = this.#renderedKeys.indexOf(key);
430
+ let insertAt = result.length;
431
+ for (let j = prevIdx + 1; j < this.#renderedKeys.length; j++) {
432
+ const at = indexOfKey(this.#renderedKeys[j]);
433
+ if (at !== -1) {
434
+ insertAt = at;
435
+ break;
436
+ }
437
+ }
438
+ result.splice(insertAt, 0, entry);
439
+ }
440
+ return result;
441
+ }
442
+ #runItemAnimations() {
443
+ if (this.#enteringKeys.size > 0) {
444
+ for (const el of this.renderRoot.querySelectorAll(`.item`)) {
445
+ const key = el.dataset.key;
446
+ if (key !== void 0 && this.#enteringKeys.has(key)) animateListItemIn(el);
447
+ }
448
+ this.#enteringKeys.clear();
449
+ }
450
+ if (this.#leaving.size > 0) for (const el of this.renderRoot.querySelectorAll(`.item.leaving`)) {
451
+ const key = el.dataset.key;
452
+ if (key === void 0 || this.#leavingAnimating.has(key)) continue;
453
+ this.#leavingAnimating.add(key);
454
+ animateListItemOut(el).then(() => {
455
+ this.#leaving.delete(key);
456
+ this.#leavingAnimating.delete(key);
457
+ this.requestUpdate();
458
+ });
459
+ }
460
+ const visible = this.root ? this.#getAllNodes() : [];
461
+ this.#renderedKeys = visible.map((n) => n.node.item.key);
462
+ this.#lastNodeByKey.clear();
463
+ for (const entry of visible) this.#lastNodeByKey.set(entry.node.item.key, entry);
464
+ this.#treeAnimReady = true;
465
+ }
351
466
  updated(changedProps) {
352
467
  if (changedProps.has(`root`) && this.root) {
353
468
  this.#abortPending();
@@ -382,6 +497,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
382
497
  if (changedProps.has(`selectedNode`) && this.selectedNode) {
383
498
  if (changedProps.get(`selectedNode`) !== this.selectedNode) this.tickled.setTickled(this.selectedNode.item.key);
384
499
  }
500
+ this.#runItemAnimations();
385
501
  }
386
502
  connectedCallback() {
387
503
  super.connectedCallback();
@@ -400,11 +516,14 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
400
516
  execute: () => this.deselectAll()
401
517
  });
402
518
  this.registry = registry;
519
+ this.#syncSearchCommands();
403
520
  }
404
521
  disconnectedCallback() {
405
522
  super.disconnectedCallback();
406
523
  this.#modelUnsubscribe?.();
407
524
  this.#modelUnsubscribe = void 0;
525
+ this.#unregisterSearchCommands?.();
526
+ this.#unregisterSearchCommands = void 0;
408
527
  if (this.#ownedRegistry) {
409
528
  this.#ownedRegistry.unregister(`select-all`);
410
529
  this.#ownedRegistry.unregister(`deselect-all`);
@@ -502,6 +621,28 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
502
621
  if (!keyPath) return false;
503
622
  return this.navigateTo(keyPath);
504
623
  }
624
+ /** Expand ancestors + move the cursor to `key`, without touching the selection (search "navigate" mode). */
625
+ revealKey(key) {
626
+ if (!this.root?.children) return false;
627
+ const path = this.#findNodePath(this.root.children, (n) => n.item.key === key);
628
+ if (!path) return false;
629
+ for (let i = 0; i < path.length - 1; i++) {
630
+ this.#applyExclusivity(path[i]);
631
+ this._expandedKeys.add(path[i]);
632
+ }
633
+ this.tickled.setTickled(key);
634
+ this.requestUpdate();
635
+ this.updateComplete.then(() => this.#scrollKeyIntoView(key));
636
+ return true;
637
+ }
638
+ /** Replace the selection with `nodes` (subject to `selectionFilter`) — search "select" mode. */
639
+ selectMany(nodes) {
640
+ const prev = new Set(this._selectedNodes);
641
+ this._selectedNodes = new Set([...nodes].filter((n) => this.#canSelect(n)));
642
+ this.selectedNode = [...this._selectedNodes].at(-1);
643
+ this.#dispatchSelect(prev);
644
+ this.requestUpdate();
645
+ }
505
646
  getNodes() {
506
647
  if (!this.root?.children) return [];
507
648
  const result = [];
@@ -546,9 +687,9 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
546
687
  }
547
688
  }
548
689
  }
549
- renderNodeContent(node, _depth) {
690
+ renderNodeContent(node, depth) {
550
691
  const isBranch = node.item.isLeaf !== true;
551
- const isExpanded = this._isExpanded(node);
692
+ const isExpanded = this._isExpanded(node, depth);
552
693
  return html`
553
694
  <span class="tree-caret">
554
695
  ${isBranch ? html`<ixfx-icon class="caret-icon" name="chevron-down" .rotate=${isExpanded ? nothing : `-90deg`}></ixfx-icon>` : ``}
@@ -829,9 +970,9 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
829
970
  _isFocused(node) {
830
971
  return this.tickled.isTickled(node.item.key);
831
972
  }
832
- _isExpanded(node) {
973
+ _isExpanded(node, depth = 0) {
833
974
  if (this._expandedKeys.has(node.item.key)) return true;
834
- if (this.filterPredicate && node.children) return node.children.some((child) => this.#matchesFilter(child, 0));
975
+ if (this.filterPredicate && node.children) return node.children.some((child) => this.#matchesFilter(child, depth + 1));
835
976
  return false;
836
977
  }
837
978
  #matchesFilter(node, depth) {
@@ -905,14 +1046,14 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
905
1046
  node: n,
906
1047
  depth: d
907
1048
  });
908
- if (this._expandedKeys.has(n.item.key) && n.children) for (const child of n.children) visit(child, d + 1);
1049
+ if (n.children && this._isExpanded(n, d)) for (const child of n.children) visit(child, d + 1);
909
1050
  };
910
1051
  if (node.children) for (const child of node.children) visit(child, depth + 1);
911
1052
  return result;
912
1053
  }
913
1054
  #getAllNodes() {
914
1055
  if (!this.root) return [];
915
- return this.#getVisibleNodes(this.root, 0);
1056
+ return this.#getVisibleNodes(this.root, -1);
916
1057
  }
917
1058
  #getFocusedIndex() {
918
1059
  const nodes = this.#getAllNodes();
@@ -962,18 +1103,19 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
962
1103
  >
963
1104
  ${this.root ? this.#renderNodes(nodes) : nothing}
964
1105
  </div>
1106
+ ${this.search.renderField()}
965
1107
  `;
966
1108
  }
967
1109
  #onDblClick;
968
1110
  #renderNodes(nodes) {
969
- if (nodes.length === 0 && this.#pendingNode) return html`
1111
+ if (nodes.length === 0 && this.#pendingNode && this.#leaving.size === 0) return html`
970
1112
  <div class="tree-loading">
971
1113
  ${this.renderLoadingIndicator()}
972
1114
  </div>
973
1115
  `;
974
1116
  return html`
975
1117
  <ul class="tree-list" role="tree">
976
- ${nodes.map(({ node, depth }) => this._renderNode(node, depth))}
1118
+ ${repeat(this.#weaveLeaving(nodes), ({ node }) => node.item.key, ({ node, depth }) => this._renderNode(node, depth))}
977
1119
  </ul>
978
1120
  `;
979
1121
  }
@@ -981,15 +1123,17 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
981
1123
  const selected = this._isSelected(node);
982
1124
  const tickled = this._isFocused(node);
983
1125
  const isBranch = node.item.isLeaf !== true;
984
- const isExpanded = this._isExpanded(node);
1126
+ const isExpanded = this._isExpanded(node, depth);
985
1127
  const isPending = this.#pendingNode === node;
986
- const isFiltered = this.filterPredicate !== void 0 && !this.#matchesFilter(node, depth);
1128
+ const isFiltered = this._isFilteredOut(node, depth);
1129
+ const isLeaving = this._isLeaving(node);
987
1130
  return html`
988
1131
  <li
989
- class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${isFiltered ? `filtered` : ``}"
1132
+ class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${isFiltered ? `filtered` : ``} ${isLeaving ? `leaving` : ``}"
990
1133
  role="treeitem"
991
1134
  aria-selected=${selected}
992
1135
  aria-expanded=${isBranch ? isExpanded : nothing}
1136
+ aria-hidden=${isLeaving ? `true` : nothing}
993
1137
  aria-level=${depth + 1}
994
1138
  data-key=${node.item.key}
995
1139
  style=${`--depth: ${depth}`}
@@ -1016,6 +1160,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
1016
1160
  themeFallbacks,
1017
1161
  tickledStyles,
1018
1162
  tickledItemStyles,
1163
+ listSearchStyles,
1019
1164
  css`
1020
1165
  :host {
1021
1166
  --tree-bg: var(--surface-3);
@@ -1026,16 +1171,23 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
1026
1171
  --tree-caret-size: 10px;
1027
1172
  --tree-radius: var(--radius-s);
1028
1173
 
1174
+ position: relative;
1029
1175
  display: block;
1030
- overflow: auto;
1176
+ overflow: hidden;
1031
1177
  box-sizing: border-box;
1032
1178
  background: var(--tree-bg);
1033
1179
  color: var(--tree-text);
1034
1180
  }
1035
1181
 
1182
+ /* min-height (not height) so the tree still grows to its content when the
1183
+ host has no explicit height; when it does, this fills it and scrolls.
1184
+ The scroll lives here, not on :host, so the search popover (a sibling of
1185
+ #container, positioned against :host) stays put while the list scrolls. */
1036
1186
  #container {
1037
1187
  outline: none;
1038
1188
  min-height: 100%;
1189
+ max-height: 100%;
1190
+ overflow: auto;
1039
1191
  }
1040
1192
 
1041
1193
  .tree-list {
@@ -1110,6 +1262,12 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
1110
1262
  display: none;
1111
1263
  }
1112
1264
 
1265
+ /* Fading-out ghost row (see #runItemAnimations) — inert while it collapses. */
1266
+ .item.leaving {
1267
+ pointer-events: none;
1268
+ overflow: hidden;
1269
+ }
1270
+
1113
1271
  ::highlight(incr-search-highlight) {
1114
1272
  background: var(--search-highlight-bg, var(--accent));
1115
1273
  color: var(--search-highlight-color, var(--accent-text, #fff));
@@ -1143,6 +1301,11 @@ __decorate([property({
1143
1301
  attribute: `disable-keyboard-navigation`
1144
1302
  })], TreeBaseElement.prototype, "disableKeyboardNavigation", void 0);
1145
1303
  __decorate([property({ attribute: false })], TreeBaseElement.prototype, "registry", void 0);
1304
+ __decorate([property({
1305
+ type: String,
1306
+ attribute: `search-modes`,
1307
+ reflect: true
1308
+ })], TreeBaseElement.prototype, "searchModes", void 0);
1146
1309
  __decorate([state()], TreeBaseElement.prototype, "_expandedKeys", void 0);
1147
1310
  __decorate([state()], TreeBaseElement.prototype, "_focusedDepth", void 0);
1148
1311
  TreeBaseElement = __decorate([safeCustomElement(`ixfx-tree-base`)], TreeBaseElement);
@@ -1169,11 +1332,11 @@ let TreeListElement = class TreeListElement extends TreeBaseElement {
1169
1332
  if (node.item.icon) this.#depthsWithIcons.add(depth);
1170
1333
  if (node.children) for (const child of node.children) visit(child, depth + 1);
1171
1334
  };
1172
- if (this.root) visit(this.root, 0);
1335
+ if (this.root) visit(this.root, -1);
1173
1336
  }
1174
1337
  renderNodeContent(node, depth) {
1175
1338
  const isBranch = node.item.isLeaf !== true;
1176
- const isExpanded = this._isExpanded(node);
1339
+ const isExpanded = this._isExpanded(node, depth);
1177
1340
  const icon = node.item.icon;
1178
1341
  const tooltip = node.item.tooltip;
1179
1342
  const caretAndLabel = html`
@@ -1219,16 +1382,19 @@ let TreeListElement = class TreeListElement extends TreeBaseElement {
1219
1382
  const selected = this._isSelected(node);
1220
1383
  const tickled = this._isFocused(node);
1221
1384
  const isBranch = node.item.isLeaf !== true;
1222
- const isExpanded = this._isExpanded(node);
1385
+ const isExpanded = this._isExpanded(node, depth);
1223
1386
  const isPending = this._pendingNode === node;
1224
1387
  const hasIconAtDepth = this.#depthsWithIcons.has(depth);
1388
+ const isLeaving = this._isLeaving(node);
1389
+ const isFiltered = this._isFilteredOut(node, depth);
1225
1390
  return html`
1226
1391
  <li
1227
- class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${hasIconAtDepth ? `has-icon-at-depth` : ``}"
1392
+ class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${hasIconAtDepth ? `has-icon-at-depth` : ``} ${isLeaving ? `leaving` : ``} ${isFiltered ? `filtered` : ``}"
1228
1393
  data-key=${node.item.key}
1229
1394
  role="treeitem"
1230
1395
  aria-selected=${selected}
1231
1396
  aria-expanded=${isBranch ? isExpanded : nothing}
1397
+ aria-hidden=${isLeaving ? `true` : nothing}
1232
1398
  aria-level=${depth + 1}
1233
1399
  style=${`--depth: ${depth}`}
1234
1400
  @click=${(e) => this._handleItemClick(node, depth, e)}
@@ -1368,29 +1534,24 @@ var TreeController = class {
1368
1534
  navigateToValue(predicate) {
1369
1535
  const treePath = this.#findTreePath(this.#root, predicate);
1370
1536
  if (!treePath) return false;
1537
+ let currentColumn = this.#element.root?.children ?? [];
1371
1538
  const keys = [];
1372
1539
  for (let i = 1; i < treePath.length; i++) {
1373
1540
  const treeNode = treePath[i];
1374
1541
  const key = this.#options.valueToItem(treeNode.getValue(), treeNode).key;
1375
1542
  keys.push(key);
1376
1543
  if (i < treePath.length - 1) {
1377
- const currentChildren = i === 1 ? this.#element.root?.children ?? [] : this.#findInChildren(this.#element.root?.children ?? [], keys);
1378
- const treeNodeMap = this.#nodeToTree;
1379
- const node = currentChildren.find((n) => n.item.key === key);
1544
+ const node = currentColumn.find((n) => n.item.key === key);
1380
1545
  if (!node) return false;
1381
1546
  if (node.children === void 0) {
1382
- const mapped = treeNodeMap.get(node);
1547
+ const mapped = this.#nodeToTree.get(node);
1383
1548
  if (mapped) node.children = this.#childrenOf(mapped);
1384
1549
  }
1550
+ currentColumn = node.children ?? [];
1385
1551
  }
1386
1552
  }
1387
1553
  return this.#element.navigateTo(keys);
1388
1554
  }
1389
- #findInChildren(children, keys) {
1390
- if (keys.length === 0) return children;
1391
- const key = keys[0];
1392
- return children.find((n) => n.item.key === key)?.children ?? [];
1393
- }
1394
1555
  #childrenOf(treeNode) {
1395
1556
  return Array.from(treeNode.children(), (child) => this.#toTreeNode(child));
1396
1557
  }
@@ -1419,4 +1580,4 @@ var TreeController = class {
1419
1580
  //#endregion
1420
1581
  export { TreeDataModel as i, TreeListElement as n, TreeBaseElement as r, TreeController as t };
1421
1582
 
1422
- //# sourceMappingURL=tree-Ch4W8qXQ.js.map
1583
+ //# sourceMappingURL=tree-DAii2A1g.js.map