@ixfx/components 0.10.0 → 0.10.2

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 (110) hide show
  1. package/bundle/index.d.ts +233 -21
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +2101 -150
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +38 -85
  6. package/dist/ac-text.js +1 -1
  7. package/dist/ac-token.js +2 -2
  8. package/dist/{colour-picker-R73i0QTP.js → colour-picker-WDrPuqoO.js} +2 -2
  9. package/dist/{colour-picker-R73i0QTP.js.map → colour-picker-WDrPuqoO.js.map} +1 -1
  10. package/dist/colour-picker.js +1 -1
  11. package/dist/crumbs.d.ts +1 -1
  12. package/dist/crumbs.js +2 -2
  13. package/dist/{data-grid-C5hk_pzK.d.ts → data-grid-pv6eaJCZ.d.ts} +4 -3
  14. package/dist/data-grid-pv6eaJCZ.d.ts.map +1 -0
  15. package/dist/data-grid.d.ts +2 -2
  16. package/dist/data-grid.js +28 -10
  17. package/dist/data-grid.js.map +1 -1
  18. package/dist/defaults-kVl1t2tT.js +59 -0
  19. package/dist/defaults-kVl1t2tT.js.map +1 -0
  20. package/dist/{detail-list-CxPpv89T.d.ts → detail-list-BA3RVVCB.d.ts} +4 -4
  21. package/dist/{detail-list-CxPpv89T.d.ts.map → detail-list-BA3RVVCB.d.ts.map} +1 -1
  22. package/dist/detail-list.d.ts +3 -3
  23. package/dist/detail-list.js +4 -4
  24. package/dist/{grid-list-DSnYOGh7.js → grid-list-CIc4jo-x.js} +34 -7
  25. package/dist/grid-list-CIc4jo-x.js.map +1 -0
  26. package/dist/{grid-list-BGvoWbZz.d.ts → grid-list-DWXJoRnK.d.ts} +4 -4
  27. package/dist/{grid-list-BGvoWbZz.d.ts.map → grid-list-DWXJoRnK.d.ts.map} +1 -1
  28. package/dist/grid-list.d.ts +2 -2
  29. package/dist/grid-list.js +1 -1
  30. package/dist/handle-DAXs7kbJ.js +656 -0
  31. package/dist/handle-DAXs7kbJ.js.map +1 -0
  32. package/dist/{icon-BCJJYEpm.js → icon-1gpwtPx8.js} +10 -1
  33. package/dist/icon-1gpwtPx8.js.map +1 -0
  34. package/dist/icon-CDGprSdE.d.ts.map +1 -1
  35. package/dist/icons.d.ts +1 -1
  36. package/dist/icons.js +2 -2
  37. package/dist/{incr-search-C05WjbZh.js → incr-search-D91M4Ozq.js} +5 -4
  38. package/dist/incr-search-D91M4Ozq.js.map +1 -0
  39. package/dist/incr-search.d.ts +1 -1
  40. package/dist/incr-search.js +1 -1
  41. package/dist/index-9AhaHIT2.d.ts.map +1 -1
  42. package/dist/index-CYndvTWH.d.ts +38 -0
  43. package/dist/index-CYndvTWH.d.ts.map +1 -0
  44. package/dist/{index--5BSdbnL.d.ts → index-CsaQwNkz.d.ts} +3 -2
  45. package/dist/index-CsaQwNkz.d.ts.map +1 -0
  46. package/dist/index.d.ts +207 -11
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +1295 -40
  49. package/dist/index.js.map +1 -1
  50. package/dist/{list-native-drag-controller-D97TYjn1.js → list-native-drag-controller-B9xO0XWn.js} +6 -4
  51. package/dist/list-native-drag-controller-B9xO0XWn.js.map +1 -0
  52. package/dist/{list-native-drag-controller-DWiXQZou.d.ts → list-native-drag-controller-BAuWAtyQ.d.ts} +2 -2
  53. package/dist/{list-native-drag-controller-DWiXQZou.d.ts.map → list-native-drag-controller-BAuWAtyQ.d.ts.map} +1 -1
  54. package/dist/{menu-C8a-84S5.js → menu-B2Qv3Oiz.js} +6 -5
  55. package/dist/menu-B2Qv3Oiz.js.map +1 -0
  56. package/dist/{menu-item-DzizkMH-.js → menu-item-Woc8jJc1.js} +4 -4
  57. package/dist/menu-item-Woc8jJc1.js.map +1 -0
  58. package/dist/menu.js +2 -2
  59. package/dist/miller.d.ts +2 -2
  60. package/dist/miller.js +1 -1
  61. package/dist/narrowed-text.js +1 -1
  62. package/dist/{scroll-fade-CAs1EabA.js → scroll-fade-BrNUIYnm.js} +16 -3
  63. package/dist/scroll-fade-BrNUIYnm.js.map +1 -0
  64. package/dist/select-horiz.js +1 -1
  65. package/dist/{split-layout-3yBOEVZW.js → split-layout-BJEU1W0d.js} +2 -2
  66. package/dist/{split-layout-3yBOEVZW.js.map → split-layout-BJEU1W0d.js.map} +1 -1
  67. package/dist/split-layout.js +1 -1
  68. package/dist/style.css +38 -85
  69. package/dist/tabs.js +1 -1
  70. package/dist/{timeline-CFlBFFGZ.js → timeline-BP1Ux2EV.js} +2 -2
  71. package/dist/{timeline-CFlBFFGZ.js.map → timeline-BP1Ux2EV.js.map} +1 -1
  72. package/dist/timeline.js +1 -1
  73. package/dist/titlebar.js +1 -1
  74. package/dist/{tree-C25xYUa6.js → tree-Bm2TzTfe.js} +234 -15
  75. package/dist/tree-Bm2TzTfe.js.map +1 -0
  76. package/dist/{tree-component-mw8x-n2Y.d.ts → tree-component-DGmKBbpy.d.ts} +14 -1
  77. package/dist/tree-component-DGmKBbpy.d.ts.map +1 -0
  78. package/dist/tree.d.ts +15 -3
  79. package/dist/tree.d.ts.map +1 -1
  80. package/dist/tree.js +1 -1
  81. package/dist/{vertical-list--tFanQwM.d.ts → vertical-list-BWLqy3PJ.d.ts} +3 -3
  82. package/dist/{vertical-list--tFanQwM.d.ts.map → vertical-list-BWLqy3PJ.d.ts.map} +1 -1
  83. package/dist/vertical-list.d.ts +2 -2
  84. package/dist/vertical-list.js +2 -2
  85. package/docs-user/README.md +1 -0
  86. package/docs-user/icons.md +24 -10
  87. package/docs-user/index.json +8 -3
  88. package/docs-user/llms.txt +2 -1
  89. package/docs-user/multicol-list.md +128 -0
  90. package/docs-user/tree.md +12 -0
  91. package/docs-user/vertical-list.md +65 -9
  92. package/llms.txt +2 -1
  93. package/package.json +1 -1
  94. package/dist/data-grid-C5hk_pzK.d.ts.map +0 -1
  95. package/dist/defaults-BJwDsMH4.js +0 -86
  96. package/dist/defaults-BJwDsMH4.js.map +0 -1
  97. package/dist/grid-list-DSnYOGh7.js.map +0 -1
  98. package/dist/handle-BPOxBOKf.js +0 -219
  99. package/dist/handle-BPOxBOKf.js.map +0 -1
  100. package/dist/icon-BCJJYEpm.js.map +0 -1
  101. package/dist/incr-search-C05WjbZh.js.map +0 -1
  102. package/dist/index--5BSdbnL.d.ts.map +0 -1
  103. package/dist/index-CS9yM8L-.d.ts +0 -47
  104. package/dist/index-CS9yM8L-.d.ts.map +0 -1
  105. package/dist/list-native-drag-controller-D97TYjn1.js.map +0 -1
  106. package/dist/menu-C8a-84S5.js.map +0 -1
  107. package/dist/menu-item-DzizkMH-.js.map +0 -1
  108. package/dist/scroll-fade-CAs1EabA.js.map +0 -1
  109. package/dist/tree-C25xYUa6.js.map +0 -1
  110. package/dist/tree-component-mw8x-n2Y.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -5,42 +5,42 @@ import { t as themeFallbacks } from "./fallbacks-DQ_5OsmR.js";
5
5
  import { t as popupSurfaceStyles } from "./popup-D80sj2QC.js";
6
6
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
7
7
  import { a as iconBus, c as setIconFont, i as hasIcon, l as svgToDataUri, n as getIconEntry, o as registerFontIcon, r as getIconFont, s as registerIcon, t as getIcon } from "./registry-BEtb8_wB.js";
8
- import { t as IxfxIconElement } from "./icon-BCJJYEpm.js";
8
+ import { t as IxfxIconElement } from "./icon-1gpwtPx8.js";
9
9
  import { AcTextElement } from "./ac-text.js";
10
10
  import { t as DataController } from "./data-controller-DOlmqNKb.js";
11
- import { a as LIST_SEARCH_COMMAND_IDS, c as createElementListSearchAdapter, d as createDataListSearchAdapter, f as IncrSearchTreeController, h as createFuzzySearch, i as ListSearchController, l as KeyedElementIndex, m as createAcCompletionProvider, n as listSearchStyles, o as registerListSearchCommands, p as createIncrSearch, r as LIST_SEARCH_MODES, s as createElementIncrSearch, t as createTreeListSearchAdapter, u as keyForElement } from "./incr-search-C05WjbZh.js";
11
+ import { a as LIST_SEARCH_COMMAND_IDS, c as createElementListSearchAdapter, d as createDataListSearchAdapter, f as IncrSearchTreeController, h as createFuzzySearch, i as ListSearchController, l as KeyedElementIndex, m as createAcCompletionProvider, n as listSearchStyles, o as registerListSearchCommands, p as createIncrSearch, r as LIST_SEARCH_MODES, s as createElementIncrSearch, t as createTreeListSearchAdapter, u as keyForElement } from "./incr-search-D91M4Ozq.js";
12
12
  import { AcTokenElement } from "./ac-token.js";
13
- import { t as handleStyles } from "./handle-BPOxBOKf.js";
13
+ import { t as handleStyles } from "./handle-DAXs7kbJ.js";
14
14
  import { TitlebarElement } from "./titlebar.js";
15
- import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-BJwDsMH4.js";
15
+ import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-kVl1t2tT.js";
16
16
  import "./icons.js";
17
17
  import { t as prominenceStyles } from "./prominence-DlFShic3.js";
18
18
  import { n as buttonStyles, t as ButtonElement } from "./button-DsFbV4XD.js";
19
- import { n as captionForEntry, r as createDefaultListDragPreview, t as ListNativeDragController } from "./list-native-drag-controller-D97TYjn1.js";
19
+ import { n as captionForEntry, r as createDefaultListDragPreview, t as ListNativeDragController } from "./list-native-drag-controller-B9xO0XWn.js";
20
20
  import { n as isMultiMode, r as ListDragSelectController, t as ListSelectionController } from "./list-selection-controller-SA4piSBi.js";
21
21
  import { a as prefersReducedMotion, i as listItemFadeKeyframes, n as animateListItemIn, o as startListItemOutAnimation, r as animateListItemOut, t as LIST_ITEM_MOTION_MS } from "./list-item-animation-BUoEKi5s.js";
22
22
  import "./interaction-BskmlA9t.js";
23
- import "./menu-item-DzizkMH-.js";
23
+ import "./menu-item-Woc8jJc1.js";
24
24
  import { Checkbox } from "./checkbox.js";
25
- import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-R73i0QTP.js";
25
+ import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-WDrPuqoO.js";
26
26
  import { LabelledRangeInput } from "./labelled-range-input.js";
27
27
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
28
- import { a as TreeDataModel, c as pruneDraggedDescendants, i as TreeDropController, n as TreeListElement, o as applyTreeDrop, r as TreeBaseElement, s as dropTargetFor, t as TreeController } from "./tree-C25xYUa6.js";
29
- import { t as scrollFadeStyles } from "./scroll-fade-CAs1EabA.js";
28
+ import { a as TreeDataModel, c as pruneDraggedDescendants, i as TreeDropController, n as TreeListElement, o as applyTreeDrop, r as TreeBaseElement, s as dropTargetFor, t as TreeController } from "./tree-Bm2TzTfe.js";
29
+ import { t as scrollFadeStyles } from "./scroll-fade-BrNUIYnm.js";
30
30
  import { NarrowedTextElement } from "./narrowed-text.js";
31
31
  import { CrumbNavigationElement } from "./crumbs.js";
32
32
  import { DataDisplayComponent } from "./data-display.js";
33
33
  import { t as createDragGhost } from "./drag-ghost-DtSDvjri.js";
34
- import { t as menu_exports } from "./menu-C8a-84S5.js";
34
+ import { a as menuFromTreeToElements, t as menu_exports } from "./menu-B2Qv3Oiz.js";
35
35
  import { t as PanTextElement } from "./pan-text-CqtvjPyK.js";
36
36
  import { DataGridElement } from "./data-grid.js";
37
37
  import { DetailListElement } from "./detail-list.js";
38
- import { a as distribute, c as toSnapshot, i as buildModel, l as walk, n as SplitPanelElement, o as normalise, r as applySnapshot, s as resolveTracks, t as SplitLayoutElement } from "./split-layout-3yBOEVZW.js";
38
+ import { a as distribute, c as toSnapshot, i as buildModel, l as walk, n as SplitPanelElement, o as normalise, r as applySnapshot, s as resolveTracks, t as SplitLayoutElement } from "./split-layout-BJEU1W0d.js";
39
39
  import { TabListElement } from "./tabs.js";
40
40
  import { EditableLabel } from "./editable-label.js";
41
41
  import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider-input-CF2RtzgG.js";
42
42
  import { t as FormElement } from "./form-CsXJX15p.js";
43
- import { t as GridListElement } from "./grid-list-DSnYOGh7.js";
43
+ import { t as GridListElement } from "./grid-list-CIc4jo-x.js";
44
44
  import { PanelElement } from "./panel.js";
45
45
  import { GroupedItemListerElement } from "./grouped-item-lister.js";
46
46
  import { VerticalListElement } from "./vertical-list.js";
@@ -60,7 +60,7 @@ import { SelectHorizElement } from "./select-horiz.js";
60
60
  import { SnackbarElement } from "./snackbar.js";
61
61
  import { SnapContainer } from "./snap-container.js";
62
62
  import { SwipeElement } from "./swipe.js";
63
- import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-CFlBFFGZ.js";
63
+ import { a as resolveCssVars, i as attachTimelineInteractions, n as TimelineTrackTabElement, o as resolveGrid, r as timelineStyles, s as TimelineController, t as IxfxTimelineElement } from "./timeline-BP1Ux2EV.js";
64
64
  import { TransitoryLabelElement } from "./transitory-label.js";
65
65
  import { XyPad } from "./xy-pad.js";
66
66
  import { LitElement, css, html, nothing } from "lit";
@@ -6487,6 +6487,974 @@ __decorate([state()], IcicleTreeListElement.prototype, "_zoomKey", void 0);
6487
6487
  __decorate([query(`#icicle-tooltip`)], IcicleTreeListElement.prototype, "_tooltipEl", void 0);
6488
6488
  IcicleTreeListElement = __decorate([safeCustomElement(`ixfx-icicletree-list`)], IcicleTreeListElement);
6489
6489
  //#endregion
6490
+ //#region src/multicol-list/types.ts
6491
+ const ALL_KEY = `__all__`;
6492
+ //#endregion
6493
+ //#region src/multicol-list/column.ts
6494
+ /** Sorts by label, honouring direction. 'All' lives outside the list, so it is not special-cased. */
6495
+ function sortItems(items, direction) {
6496
+ const dir = direction === `desc` ? -1 : 1;
6497
+ return [...items].sort((a, b) => dir * a.label.localeCompare(b.label, void 0, {
6498
+ sensitivity: `base`,
6499
+ numeric: true
6500
+ }));
6501
+ }
6502
+ /**
6503
+ * Nearest-gap math for header drag-reorder (per data-grid's `_beginHeaderDrag`).
6504
+ *
6505
+ * `offsets` is a prefix-sum of column widths (length = count + 1). `x` is the
6506
+ * pointer position in content space (already adjusted for scroll). Returns the
6507
+ * final insertion index once the source column is removed (`insert`), plus the
6508
+ * un-normalised gap offset for the drop caret (`caretOffset`).
6509
+ */
6510
+ function computeDropGap(offsets, x, count, from) {
6511
+ if (count === 0) return {
6512
+ insert: 0,
6513
+ caretOffset: 0
6514
+ };
6515
+ let bestDist = Number.MAX_SAFE_INTEGER;
6516
+ let caretGap = from;
6517
+ for (let i = 0; i < count; i++) {
6518
+ if (i === from) continue;
6519
+ const left = offsets[i];
6520
+ const right = offsets[i + 1] ?? offsets[offsets.length - 1];
6521
+ const mid = (left + right) / 2;
6522
+ const dist = Math.abs(x - (x < mid ? left : right));
6523
+ if (dist < bestDist) {
6524
+ bestDist = dist;
6525
+ caretGap = x < mid ? i : i + 1;
6526
+ }
6527
+ }
6528
+ const insert = caretGap > from ? caretGap - 1 : caretGap;
6529
+ return {
6530
+ insert: Math.max(0, Math.min(count - 1, insert)),
6531
+ caretOffset: offsets[caretGap] ?? offsets[offsets.length - 1]
6532
+ };
6533
+ }
6534
+ var MulticolColumnController = class {
6535
+ #category;
6536
+ #categoryDefaults;
6537
+ #selectionMode;
6538
+ #dataProvider;
6539
+ #onSelectionChange;
6540
+ #onRequestData;
6541
+ #abortController = void 0;
6542
+ #host;
6543
+ #allRow;
6544
+ #listerEl;
6545
+ #selectedValues = [];
6546
+ #allSelected = true;
6547
+ #lastItems = [];
6548
+ #syncingSelection = false;
6549
+ #state;
6550
+ constructor(options) {
6551
+ this.id = options.id;
6552
+ this.#category = options.category;
6553
+ this.#categoryDefaults = options.categoryDefaults;
6554
+ this.#selectionMode = options.selectionMode;
6555
+ this.#dataProvider = options.dataProvider;
6556
+ this.#onSelectionChange = options.onSelectionChange;
6557
+ this.#onRequestData = options.onRequestData;
6558
+ this.#state = {
6559
+ id: options.id,
6560
+ categoryKey: options.category.key,
6561
+ sort: options.categoryDefaults?.sort ?? `asc`,
6562
+ grouped: options.categoryDefaults?.grouped ?? false,
6563
+ width: 220
6564
+ };
6565
+ }
6566
+ get state() {
6567
+ return this.getState();
6568
+ }
6569
+ /** Always derived from the live category so a swap is visible everywhere. */
6570
+ get categoryKey() {
6571
+ return this.#category.key;
6572
+ }
6573
+ getState() {
6574
+ return { ...this.#state };
6575
+ }
6576
+ updateState(partial) {
6577
+ const sortChanged = partial.sort !== void 0 && partial.sort !== this.#state.sort;
6578
+ const groupedChanged = partial.grouped !== void 0 && partial.grouped !== this.#state.grouped;
6579
+ this.#state = {
6580
+ ...this.#state,
6581
+ ...partial
6582
+ };
6583
+ if (sortChanged) this.#repush();
6584
+ if (groupedChanged) this.#syncGrouping();
6585
+ }
6586
+ setWidth(width) {
6587
+ this.#state = {
6588
+ ...this.#state,
6589
+ width: Math.max(80, Math.min(480, Math.round(width)))
6590
+ };
6591
+ }
6592
+ setSort(sort) {
6593
+ if (sort === this.#state.sort) return;
6594
+ this.#state = {
6595
+ ...this.#state,
6596
+ sort
6597
+ };
6598
+ this.#repush();
6599
+ }
6600
+ setGrouped(grouped) {
6601
+ if (grouped === this.#state.grouped) return;
6602
+ this.#state = {
6603
+ ...this.#state,
6604
+ grouped
6605
+ };
6606
+ this.#syncGrouping();
6607
+ }
6608
+ setSelectionMode(mode) {
6609
+ if (mode === this.#selectionMode) return;
6610
+ this.#selectionMode = mode;
6611
+ for (const sub of this.#subComponents()) sub.selectionMode = mode;
6612
+ }
6613
+ setCategory(category) {
6614
+ this.#category = category;
6615
+ this.#categoryDefaults = category.defaults;
6616
+ this.#state = {
6617
+ ...this.#state,
6618
+ categoryKey: category.key,
6619
+ sort: category.defaults?.sort ?? `asc`,
6620
+ grouped: category.defaults?.grouped ?? false
6621
+ };
6622
+ this.clearSelection();
6623
+ this.#syncGrouping();
6624
+ }
6625
+ get listerHost() {
6626
+ return this.#host;
6627
+ }
6628
+ get isMounted() {
6629
+ return this.#host !== void 0;
6630
+ }
6631
+ setDataProvider(provider) {
6632
+ this.#dataProvider = provider;
6633
+ }
6634
+ mount(host) {
6635
+ if (this.#host) return;
6636
+ this.#host = host;
6637
+ const allRow = document.createElement(`div`);
6638
+ allRow.className = `all-row`;
6639
+ allRow.dataset.key = ALL_KEY;
6640
+ allRow.setAttribute(`role`, `button`);
6641
+ allRow.setAttribute(`tabindex`, `0`);
6642
+ const allLabel = document.createElement(`span`);
6643
+ allLabel.className = `all-label`;
6644
+ allRow.appendChild(allLabel);
6645
+ const applyAll = () => {
6646
+ if (this.#allSelected) return;
6647
+ this.#setAllSelection();
6648
+ };
6649
+ allRow.addEventListener(`click`, applyAll);
6650
+ allRow.addEventListener(`keydown`, (e) => {
6651
+ if (e.key === `Enter` || e.key === ` `) {
6652
+ e.preventDefault();
6653
+ applyAll();
6654
+ }
6655
+ });
6656
+ this.#allRow = allRow;
6657
+ const lister = document.createElement(`ixfx-grouped-item-lister`);
6658
+ lister.crossGroupSelection = true;
6659
+ lister.factory = () => createVerticalListAdapter(renderItem, {
6660
+ selectionMode: this.#selectionMode,
6661
+ interactionMode: `standard`
6662
+ });
6663
+ lister.addEventListener(`select`, this.#handleSelect);
6664
+ this.#listerEl = lister;
6665
+ this.#syncGrouping();
6666
+ this.#syncAllRow();
6667
+ host.append(allRow, lister);
6668
+ if (this.#lastItems.length > 0) {
6669
+ this.#pushItems();
6670
+ this.#restoreAfterSync();
6671
+ }
6672
+ }
6673
+ unmount() {
6674
+ this.#abortPending();
6675
+ this.#allRow?.remove();
6676
+ this.#listerEl?.remove();
6677
+ this.#allRow = void 0;
6678
+ this.#listerEl = void 0;
6679
+ this.#host = void 0;
6680
+ }
6681
+ requestData(query) {
6682
+ if (!this.#dataProvider) return;
6683
+ this.#abortPending();
6684
+ const controller = new AbortController();
6685
+ this.#abortController = controller;
6686
+ const { signal } = controller;
6687
+ this.#onRequestData(this.id, query, signal);
6688
+ Promise.resolve().then(async () => {
6689
+ const result = this.#dataProvider(query, signal);
6690
+ const items = await collectDataResult(result, signal);
6691
+ if (signal.aborted) return;
6692
+ this.#applyItems(items);
6693
+ }).catch(() => {});
6694
+ }
6695
+ #applyItems(items) {
6696
+ this.#lastItems = items;
6697
+ const valid = this.#selectedValues.filter((v) => items.some((i) => i.key === v));
6698
+ const changed = valid.length !== this.#selectedValues.length;
6699
+ this.#selectedValues = valid;
6700
+ if (valid.length === 0) this.#allSelected = true;
6701
+ if (!this.#listerEl) {
6702
+ if (changed) this.#onSelectionChange(this.id, valid);
6703
+ return;
6704
+ }
6705
+ this.#pushItems();
6706
+ this.#restoreAfterSync();
6707
+ if (changed) this.#onSelectionChange(this.id, valid);
6708
+ }
6709
+ #pushItems() {
6710
+ if (!this.#listerEl) return;
6711
+ const sorted = sortItems(this.#lastItems, this.#state.sort);
6712
+ this.#listerEl.provider = () => sorted;
6713
+ }
6714
+ #repush() {
6715
+ if (!this.#listerEl || this.#lastItems.length === 0) return;
6716
+ this.#pushItems();
6717
+ this.#restoreAfterSync();
6718
+ }
6719
+ /** Grouping config from category defaults; grouping without groupBy is a no-op. */
6720
+ #syncGrouping() {
6721
+ if (!this.#listerEl) return;
6722
+ const groupBy = this.#categoryDefaults?.groupBy;
6723
+ this.#listerEl.groupBy = groupBy;
6724
+ this.#listerEl.grouped = this.#state.grouped && groupBy !== void 0;
6725
+ if (this.#lastItems.length > 0) this.#restoreAfterSync();
6726
+ }
6727
+ #subComponents() {
6728
+ if (!this.#listerEl) return [];
6729
+ return this.#listerEl.querySelectorAll(`:scope > .ungrouped-host > *, :scope > ixfx-panel > *`);
6730
+ }
6731
+ #handleSelect = () => {
6732
+ if (this.#syncingSelection) return;
6733
+ const values = [...this.#listerEl?.selectedItems ?? []].map((i) => i.key).filter((k) => k !== ALL_KEY);
6734
+ if (values.length === this.#selectedValues.length && values.every((v) => this.#selectedValues.includes(v))) {
6735
+ this.#syncAllRow();
6736
+ return;
6737
+ }
6738
+ this.#selectedValues = values;
6739
+ this.#allSelected = values.length === 0;
6740
+ this.#syncAllRow();
6741
+ this.#onSelectionChange(this.id, values);
6742
+ };
6743
+ #setAllSelection() {
6744
+ const previous = this.#selectedValues;
6745
+ this.#syncingSelection = true;
6746
+ try {
6747
+ this.#selectedValues = [];
6748
+ this.#allSelected = true;
6749
+ for (const sub of this.#subComponents()) sub.clearSelection();
6750
+ } finally {
6751
+ this.#syncingSelection = false;
6752
+ }
6753
+ this.#syncAllRow();
6754
+ if (previous.length > 0) this.#onSelectionChange(this.id, []);
6755
+ }
6756
+ clearSelection() {
6757
+ this.#setAllSelection();
6758
+ }
6759
+ get selectedValues() {
6760
+ return this.#selectedValues;
6761
+ }
6762
+ #restoreAfterSync() {
6763
+ if (!this.#listerEl) return;
6764
+ this.#listerEl.updateComplete.then(() => {
6765
+ if (!this.#listerEl || !this.#host) return;
6766
+ this.#syncingSelection = true;
6767
+ try {
6768
+ const wanted = this.#selectedValues;
6769
+ for (const list of this.#listerEl.querySelectorAll(`ixfx-vertical-list`)) list.selectKeys(wanted);
6770
+ const selected = [...this.#listerEl.selectedItems].map((i) => i.key).filter((k) => k !== ALL_KEY);
6771
+ this.#selectedValues = selected;
6772
+ this.#allSelected = selected.length === 0;
6773
+ } finally {
6774
+ this.#syncingSelection = false;
6775
+ }
6776
+ this.#syncAllRow();
6777
+ });
6778
+ }
6779
+ #syncAllRow() {
6780
+ if (!this.#allRow) return;
6781
+ const label = this.#categoryDefaults?.allLabel ?? `All`;
6782
+ const labelEl = this.#allRow.querySelector(`.all-label`);
6783
+ if (labelEl) labelEl.textContent = label;
6784
+ this.#allRow.toggleAttribute(`data-selected`, this.#allSelected);
6785
+ }
6786
+ #abortPending() {
6787
+ if (this.#abortController) {
6788
+ this.#abortController.abort();
6789
+ this.#abortController = void 0;
6790
+ }
6791
+ }
6792
+ };
6793
+ function renderItem(item) {
6794
+ const li = document.createElement(`li`);
6795
+ li.dataset.key = item.key;
6796
+ const labelSpan = document.createElement(`span`);
6797
+ labelSpan.className = `item-label`;
6798
+ labelSpan.textContent = item.label;
6799
+ li.appendChild(labelSpan);
6800
+ if (item.count !== void 0) {
6801
+ const countSpan = document.createElement(`span`);
6802
+ countSpan.className = `count`;
6803
+ countSpan.textContent = String(item.count);
6804
+ li.appendChild(countSpan);
6805
+ }
6806
+ return li;
6807
+ }
6808
+ //#endregion
6809
+ //#region src/multicol-list/multicol-list.ts
6810
+ registerIcon(`menu`, `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16"/><path d="M4 18h16"/><path d="M4 6h16"/></svg>`);
6811
+ const DEFAULT_COLUMN_WIDTH = 220;
6812
+ const MIN_COLUMN_WIDTH = 80;
6813
+ const MAX_COLUMN_WIDTH = 480;
6814
+ const DRAG_THRESHOLD = 5;
6815
+ let MulticolListElement = class MulticolListElement extends LitElement {
6816
+ constructor(..._args) {
6817
+ super(..._args);
6818
+ this.categories = [];
6819
+ this.selectionMode = `multiple`;
6820
+ this.minColumns = 1;
6821
+ this.maxColumns = 5;
6822
+ this._columns = [];
6823
+ this._colOffsets = [0];
6824
+ this._resizingColumnId = void 0;
6825
+ this._draggingColumnId = void 0;
6826
+ this._dropCaretX = void 0;
6827
+ this._idCounter = 0;
6828
+ this._autoSeeded = false;
6829
+ this._drag = {
6830
+ pointerId: -1,
6831
+ from: -1,
6832
+ startX: 0,
6833
+ startY: 0,
6834
+ active: false,
6835
+ ghost: null,
6836
+ insert: -1
6837
+ };
6838
+ }
6839
+ static {
6840
+ this.styles = [
6841
+ themeFallbacks,
6842
+ handleStyles,
6843
+ css`
6844
+ :host {
6845
+ --multicol-list-bg: var(--surface-3);
6846
+ --multicol-list-header-bg: var(--surface-2);
6847
+ --multicol-list-header-text: var(--surface-3-text);
6848
+ --multicol-list-border: var(--border);
6849
+ --multicol-list-min-column-width: ${MIN_COLUMN_WIDTH}px;
6850
+ --multicol-list-max-column-width: ${MAX_COLUMN_WIDTH}px;
6851
+
6852
+ display: block;
6853
+ overflow: hidden;
6854
+ background: var(--multicol-list-bg);
6855
+ color: var(--surface-3-text);
6856
+ font-family: var(--font-family);
6857
+ }
6858
+ #container {
6859
+ display: flex;
6860
+ flex-direction: row;
6861
+ align-items: stretch;
6862
+ overflow-x: auto;
6863
+ overflow-y: hidden;
6864
+ position: relative;
6865
+ height: 100%;
6866
+ }
6867
+ .column {
6868
+ flex-shrink: 0;
6869
+ display: flex;
6870
+ flex-direction: column;
6871
+ border-right: var(--multicol-list-border);
6872
+ min-width: var(--multicol-list-min-column-width);
6873
+ max-width: var(--multicol-list-max-column-width);
6874
+ background: var(--surface-3);
6875
+ }
6876
+ .column-header {
6877
+ display: flex;
6878
+ align-items: center;
6879
+ gap: var(--space-xs);
6880
+ height: 32px;
6881
+ background: var(--multicol-list-header-bg);
6882
+ color: var(--multicol-list-header-text);
6883
+ border-bottom: var(--border);
6884
+ position: relative;
6885
+ user-select: none;
6886
+ min-width: var(--multicol-list-min-column-width);
6887
+ box-sizing: border-box;
6888
+ }
6889
+ .column-header[data-dragging] {
6890
+ opacity: 0.4;
6891
+ }
6892
+ .reorder-handle {
6893
+ cursor: grab;
6894
+ opacity: 0;
6895
+ display: inline-flex;
6896
+ align-items: center;
6897
+ flex-shrink: 0;
6898
+ padding-left: var(--space-xs);
6899
+ touch-action: none;
6900
+ transition: opacity var(--transition, 0.15s ease-out);
6901
+ }
6902
+ .column-header:hover .reorder-handle, .column-header:focus-within .reorder-handle, .column-header[data-dragging] .reorder-handle { opacity: var(--ixfx-handle-opacity, 0.5); }
6903
+ .reorder-handle:active {
6904
+ cursor: grabbing;
6905
+ }
6906
+ .reorder-handle .ixfx-handle {
6907
+ --ixfx-handle-length: 14px;
6908
+ --ixfx-handle-thickness: var(--multicol-list-reorder-handle-width, 10px);
6909
+ --ixfx-handle-dot-size: 3px;
6910
+ }
6911
+ .column-label {
6912
+ flex: 1;
6913
+ overflow: hidden;
6914
+ text-overflow: ellipsis;
6915
+ white-space: nowrap;
6916
+ padding: 0 var(--space-s);
6917
+ font-size: var(--text-m);
6918
+ font-weight: 600;
6919
+ background: transparent;
6920
+ border: none;
6921
+ color: inherit;
6922
+ cursor: pointer;
6923
+ text-align: left;
6924
+ min-width: 0;
6925
+ }
6926
+ .column-label:hover {
6927
+ text-decoration: underline;
6928
+ }
6929
+ .burger-btn {
6930
+ flex-shrink: 0;
6931
+ width: 28px;
6932
+ height: 28px;
6933
+ display: flex;
6934
+ align-items: center;
6935
+ justify-content: center;
6936
+ background: transparent;
6937
+ border: none;
6938
+ cursor: pointer;
6939
+ color: var(--surface-3-text);
6940
+ opacity: 0;
6941
+ transition: opacity var(--transition);
6942
+ border-radius: var(--radius-s);
6943
+ }
6944
+ .column:hover .burger-btn,
6945
+ .column-header:focus-within .burger-btn {
6946
+ opacity: 1;
6947
+ }
6948
+ .burger-btn:hover {
6949
+ background: var(--surface-4);
6950
+ }
6951
+ .resize-handle {
6952
+ position: absolute;
6953
+ right: -4px;
6954
+ top: 0;
6955
+ bottom: 0;
6956
+ width: 8px;
6957
+ cursor: col-resize;
6958
+ z-index: 1;
6959
+ display: flex;
6960
+ align-items: stretch;
6961
+ justify-content: center;
6962
+ touch-action: none;
6963
+ }
6964
+ .resize-handle::before {
6965
+ content: '';
6966
+ width: 2px;
6967
+ margin: 2px 0;
6968
+ border-radius: 1px;
6969
+ background: transparent;
6970
+ transition: background-color var(--transition);
6971
+ }
6972
+ .resize-handle:hover::before,
6973
+ .resize-handle[data-active]::before {
6974
+ background: var(--accent);
6975
+ }
6976
+ .lister-host {
6977
+ flex: 1;
6978
+ overflow-y: auto;
6979
+ overflow-x: hidden;
6980
+ position: relative;
6981
+ display: flex;
6982
+ flex-direction: column;
6983
+ }
6984
+ .all-row {
6985
+ display: flex;
6986
+ align-items: center;
6987
+ padding: var(--space-xs) var(--space-s);
6988
+ cursor: pointer;
6989
+ user-select: none;
6990
+ min-height: 28px;
6991
+ box-sizing: border-box;
6992
+ outline: 1px solid transparent;
6993
+ background: var(--surface-3);
6994
+ }
6995
+ .all-row:hover,
6996
+ .all-row[data-selected] {
6997
+ background: var(--surface-5);
6998
+ }
6999
+ .all-row[data-selected] {
7000
+ outline-color: var(--accent);
7001
+ font-weight: 600;
7002
+ }
7003
+ ixfx-grouped-item-lister {
7004
+ display: block;
7005
+ }
7006
+ .drop-caret {
7007
+ position: absolute;
7008
+ top: 0;
7009
+ bottom: 0;
7010
+ width: 2px;
7011
+ background: var(--accent);
7012
+ border-radius: 1px;
7013
+ pointer-events: none;
7014
+ z-index: 10;
7015
+ }
7016
+ .item-label {
7017
+ flex: 1;
7018
+ }
7019
+ .count {
7020
+ opacity: 0.6;
7021
+ margin-left: var(--space-s);
7022
+ font-size: var(--text-s);
7023
+ }
7024
+ `
7025
+ ];
7026
+ }
7027
+ get columns() {
7028
+ return this._columns.map((c) => c.getState());
7029
+ }
7030
+ setColumns(states) {
7031
+ const existingMap = new Map(this._columns.map((c) => [c.id, c]));
7032
+ const newColumns = [];
7033
+ for (const colState of states) {
7034
+ const existing = existingMap.get(colState.id);
7035
+ if (existing) {
7036
+ if (existing.categoryKey !== colState.categoryKey) {
7037
+ const newCategory = this.categories.find((c) => c.key === colState.categoryKey);
7038
+ if (newCategory) existing.setCategory(newCategory);
7039
+ }
7040
+ existing.updateState(colState);
7041
+ newColumns.push(existing);
7042
+ existingMap.delete(colState.id);
7043
+ continue;
7044
+ }
7045
+ const category = this.categories.find((c) => c.key === colState.categoryKey);
7046
+ if (!category) continue;
7047
+ const controller = this.#createController(colState.id, category);
7048
+ controller.updateState(colState);
7049
+ newColumns.push(controller);
7050
+ }
7051
+ for (const col of existingMap.values()) col.unmount();
7052
+ this._columns = newColumns;
7053
+ this._updateColOffsets();
7054
+ this._emitColumnsChange(`add`);
7055
+ this._requeryAllColumns();
7056
+ this.requestUpdate();
7057
+ }
7058
+ addColumn(categoryKey, position) {
7059
+ if (this.maxColumns > 0 && this._columns.length >= this.maxColumns) return;
7060
+ const category = this.categories.find((c) => c.key === categoryKey);
7061
+ if (!category) return;
7062
+ const id = `col-${++this._idCounter}`;
7063
+ const controller = this.#createController(id, category);
7064
+ if (position !== void 0 && position >= 0 && position < this._columns.length) this._columns.splice(position, 0, controller);
7065
+ else this._columns.push(controller);
7066
+ this._updateColOffsets();
7067
+ this._emitColumnsChange(`add`);
7068
+ this._requeryAllColumns();
7069
+ this.requestUpdate();
7070
+ }
7071
+ removeColumn(columnId) {
7072
+ if (this._columns.length <= this.minColumns) return;
7073
+ const idx = this._columns.findIndex((c) => c.id === columnId);
7074
+ if (idx < 0) return;
7075
+ this._columns[idx].unmount();
7076
+ this._columns.splice(idx, 1);
7077
+ this._updateColOffsets();
7078
+ this._emitColumnsChange(`remove`);
7079
+ this._requeryAllColumns();
7080
+ this.requestUpdate();
7081
+ }
7082
+ getSelection() {
7083
+ return this._columns.map((c) => ({
7084
+ columnId: c.id,
7085
+ categoryKey: c.categoryKey,
7086
+ values: c.selectedValues
7087
+ }));
7088
+ }
7089
+ clearSelection() {
7090
+ for (const col of this._columns) col.clearSelection();
7091
+ this.requestUpdate();
7092
+ }
7093
+ render() {
7094
+ return html`
7095
+ <div id="container">
7096
+ ${repeat(this._columns, (col) => col.id, (col, idx) => this._renderColumn(col, idx))}
7097
+ ${this._dropCaretX !== void 0 ? html`<div class="drop-caret" style="left: ${this._dropCaretX}px"></div>` : nothing}
7098
+ </div>
7099
+ `;
7100
+ }
7101
+ updated(changedProperties) {
7102
+ if (!this._autoSeeded && this._columns.length === 0 && this.categories.length > 0) {
7103
+ this._autoSeeded = true;
7104
+ this.addColumn(this.categories[0].key);
7105
+ }
7106
+ if (changedProperties.has(`selectionMode`)) for (const col of this._columns) col.setSelectionMode(this.selectionMode);
7107
+ if (changedProperties.has(`dataProvider`)) for (const col of this._columns) col.setDataProvider(this.dataProvider);
7108
+ for (const col of this._columns) if (!col.isMounted) {
7109
+ const hostEl = this.shadowRoot?.querySelector(`[data-col-id="${col.id}"] .lister-host`);
7110
+ if (hostEl) col.mount(hostEl);
7111
+ }
7112
+ if (changedProperties.has(`categories`)) this._syncColumnsWithCategories();
7113
+ if (changedProperties.has(`categories`) || changedProperties.has(`dataProvider`)) this._requeryAllColumns();
7114
+ this._updateColOffsets();
7115
+ }
7116
+ _renderColumn(col, idx) {
7117
+ const width = col.getState().width ?? DEFAULT_COLUMN_WIDTH;
7118
+ return html`
7119
+ <div
7120
+ class="column"
7121
+ data-col-id="${col.id}"
7122
+ style="width: ${width}px"
7123
+ >
7124
+ <div
7125
+ class="column-header"
7126
+ ?data-dragging=${this._draggingColumnId === col.id}
7127
+ data-col-idx=${idx}
7128
+ >
7129
+ <span
7130
+ class="reorder-handle"
7131
+ data-tooltip="Drag to reorder"
7132
+ @pointerdown=${(e) => this._onHeaderPointerDown(e, col, idx)}
7133
+ ><span class="ixfx-handle" data-handle="dotted" data-shape="vertical" part="reorder-handle"></span></span>
7134
+ <button
7135
+ class="column-label"
7136
+ data-tooltip="Change category"
7137
+ @click=${(e) => {
7138
+ e.stopPropagation();
7139
+ this._openCategoryPicker(col, e.currentTarget);
7140
+ }}
7141
+ >${this._getCategoryLabel(col.categoryKey)}</button>
7142
+ <button
7143
+ class="burger-btn"
7144
+ data-tooltip="Column options"
7145
+ @click=${(e) => {
7146
+ e.stopPropagation();
7147
+ this._openBurgerMenu(col, e.currentTarget);
7148
+ }}
7149
+ >
7150
+ <ixfx-icon name="menu" size="14"></ixfx-icon>
7151
+ </button>
7152
+ <span
7153
+ class="resize-handle"
7154
+ ?data-active=${this._resizingColumnId === col.id}
7155
+ @pointerdown=${(e) => this._onResizePointerDown(e, col)}
7156
+ @click=${(e) => e.stopPropagation()}
7157
+ ></span>
7158
+ </div>
7159
+ <div class="lister-host"></div>
7160
+ </div>
7161
+ `;
7162
+ }
7163
+ _getCategoryLabel(key) {
7164
+ return this.categories.find((c) => c.key === key)?.label ?? key;
7165
+ }
7166
+ #createController(id, category) {
7167
+ return new MulticolColumnController({
7168
+ id,
7169
+ category,
7170
+ categoryDefaults: category.defaults,
7171
+ selectionMode: this.selectionMode,
7172
+ dataProvider: this.dataProvider,
7173
+ onSelectionChange: this._onColumnSelectionChange.bind(this),
7174
+ onRequestData: this._onColumnRequestData.bind(this)
7175
+ });
7176
+ }
7177
+ _onHeaderPointerDown(e, col, idx) {
7178
+ e.stopPropagation();
7179
+ this._drag = {
7180
+ pointerId: e.pointerId,
7181
+ from: idx,
7182
+ startX: e.clientX,
7183
+ startY: e.clientY,
7184
+ active: false,
7185
+ ghost: null,
7186
+ insert: idx
7187
+ };
7188
+ const onMove = (ev) => {
7189
+ if (ev.pointerId !== this._drag.pointerId) return;
7190
+ const dx = ev.clientX - this._drag.startX;
7191
+ const dy = ev.clientY - this._drag.startY;
7192
+ if (!this._drag.active) {
7193
+ if (Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
7194
+ this._drag.active = true;
7195
+ this._draggingColumnId = col.id;
7196
+ const headerEl = this.shadowRoot?.querySelector(`[data-col-id="${col.id}"] .column-header`);
7197
+ const content = document.createElement(`span`);
7198
+ content.textContent = this._getCategoryLabel(col.categoryKey);
7199
+ try {
7200
+ if (headerEl) {
7201
+ this._drag.ghost = createDragGhost({
7202
+ anchor: headerEl,
7203
+ content
7204
+ });
7205
+ this._drag.ghost.move(ev.clientX, ev.clientY);
7206
+ }
7207
+ } catch {}
7208
+ try {
7209
+ this._containerEl?.setPointerCapture(ev.pointerId);
7210
+ } catch {}
7211
+ }
7212
+ this._drag.ghost?.move(ev.clientX, ev.clientY);
7213
+ const containerEl = this._containerEl;
7214
+ if (!containerEl) return;
7215
+ const rect = containerEl.getBoundingClientRect();
7216
+ const x = ev.clientX - rect.left + containerEl.scrollLeft;
7217
+ const gap = computeDropGap(this._colOffsets, x, this._columns.length, this._drag.from);
7218
+ this._drag.insert = gap.insert;
7219
+ this._dropCaretX = gap.caretOffset;
7220
+ this.requestUpdate();
7221
+ };
7222
+ const finish = (ev) => {
7223
+ if (ev.pointerId !== this._drag.pointerId) return;
7224
+ const wasActive = this._drag.active;
7225
+ const from = this._drag.from;
7226
+ const insert = this._drag.insert;
7227
+ this._drag.ghost?.destroy();
7228
+ this._drag.ghost = null;
7229
+ this._draggingColumnId = void 0;
7230
+ this._dropCaretX = void 0;
7231
+ try {
7232
+ this._containerEl?.releasePointerCapture(ev.pointerId);
7233
+ } catch {}
7234
+ window.removeEventListener(`pointermove`, onMove);
7235
+ window.removeEventListener(`pointerup`, finish);
7236
+ window.removeEventListener(`pointercancel`, finish);
7237
+ if (wasActive && insert !== from) {
7238
+ const [moved] = this._columns.splice(from, 1);
7239
+ this._columns.splice(insert, 0, moved);
7240
+ this._updateColOffsets();
7241
+ this._emitColumnsChange(`reorder`);
7242
+ this.requestUpdate();
7243
+ }
7244
+ };
7245
+ window.addEventListener(`pointermove`, onMove);
7246
+ window.addEventListener(`pointerup`, finish);
7247
+ window.addEventListener(`pointercancel`, finish);
7248
+ }
7249
+ _onResizePointerDown(e, col) {
7250
+ e.preventDefault();
7251
+ e.stopPropagation();
7252
+ const startX = e.clientX;
7253
+ const startW = col.getState().width ?? DEFAULT_COLUMN_WIDTH;
7254
+ this._resizingColumnId = col.id;
7255
+ const applyWidth = (clientX) => {
7256
+ const w = Math.max(MIN_COLUMN_WIDTH, Math.min(MAX_COLUMN_WIDTH, startW + clientX - startX));
7257
+ col.setWidth(w);
7258
+ return w;
7259
+ };
7260
+ const onMove = (ev) => {
7261
+ if (ev.pointerId !== e.pointerId) return;
7262
+ applyWidth(ev.clientX);
7263
+ this._updateColOffsets();
7264
+ this.requestUpdate();
7265
+ };
7266
+ const finish = (ev) => {
7267
+ window.removeEventListener(`pointermove`, onMove);
7268
+ window.removeEventListener(`pointerup`, finish);
7269
+ window.removeEventListener(`pointercancel`, finish);
7270
+ applyWidth(ev.type === `pointercancel` ? startX : ev.clientX);
7271
+ this._resizingColumnId = void 0;
7272
+ this._updateColOffsets();
7273
+ this._emitColumnsChange(`resize`);
7274
+ this.requestUpdate();
7275
+ };
7276
+ window.addEventListener(`pointermove`, onMove);
7277
+ window.addEventListener(`pointerup`, finish);
7278
+ window.addEventListener(`pointercancel`, finish);
7279
+ }
7280
+ /** Floats a dropdown menu trigger over `anchorEl` and opens it immediately. */
7281
+ #openMenuAt(anchorEl, placement, buildMenu) {
7282
+ const rect = anchorEl.getBoundingClientRect();
7283
+ const trigger = document.createElement(`ixfx-menu-trigger`);
7284
+ trigger.mode = `dropdown`;
7285
+ trigger.tabStop = false;
7286
+ trigger.placement = placement;
7287
+ trigger.style.position = `fixed`;
7288
+ trigger.style.left = `${rect.left}px`;
7289
+ trigger.style.top = `${rect.bottom}px`;
7290
+ const container = document.createElement(`ixfx-menu-container`);
7291
+ container.setAttribute(`slot`, `menu`);
7292
+ buildMenu(container);
7293
+ trigger.appendChild(container);
7294
+ trigger.addEventListener(`menu-trigger-close`, () => trigger.remove(), { once: true });
7295
+ document.body.appendChild(trigger);
7296
+ trigger.updateComplete.then(() => trigger.openMenu());
7297
+ }
7298
+ #categoryToNode(cat) {
7299
+ return {
7300
+ item: {
7301
+ key: cat.key,
7302
+ label: cat.label
7303
+ },
7304
+ children: cat.children && cat.children.length > 0 ? cat.children.map((c) => this.#categoryToNode(c)) : void 0
7305
+ };
7306
+ }
7307
+ _openCategoryPicker(col, anchorEl) {
7308
+ this.#openMenuAt(anchorEl, `bottom-start`, (container) => {
7309
+ const items = menuFromTreeToElements(this.categories.map((c) => this.#categoryToNode(c)), { onCommand: (detail) => {
7310
+ if (detail.command === void 0) return;
7311
+ this._changeColumnCategory(col, detail.command);
7312
+ } });
7313
+ for (const el of items) container.appendChild(el);
7314
+ for (const item of container.querySelectorAll(`ixfx-menu-item`)) if (item.getAttribute(`command`) === col.categoryKey) item.setAttribute(`disabled`, ``);
7315
+ });
7316
+ }
7317
+ #menuItem(label, command, onCommand, iconName) {
7318
+ const el = document.createElement(`ixfx-menu-item`);
7319
+ el.setAttribute(`command`, command);
7320
+ el.setAttribute(`label`, label);
7321
+ if (iconName) el.setAttribute(`icon-name`, iconName);
7322
+ if (onCommand) el.addEventListener(`command`, () => onCommand());
7323
+ return el;
7324
+ }
7325
+ _openBurgerMenu(col, anchorEl) {
7326
+ this.#openMenuAt(anchorEl, `bottom-end`, (container) => {
7327
+ const removeItem = this.#menuItem(`Remove this column`, `remove`, () => this.removeColumn(col.id));
7328
+ removeItem.toggleAttribute(`disabled`, this._columns.length <= this.minColumns);
7329
+ container.appendChild(removeItem);
7330
+ const separator = document.createElement(`ixfx-menu-separator`);
7331
+ container.appendChild(separator);
7332
+ const atMax = this.maxColumns > 0 && this._columns.length >= this.maxColumns;
7333
+ const usedCats = new Set(this._columns.map((c) => c.categoryKey));
7334
+ const unused = this.categories.filter((c) => !usedCats.has(c.key));
7335
+ const canAdd = !atMax && unused.length > 0;
7336
+ const addSub = document.createElement(`ixfx-menu-sub-trigger`);
7337
+ addSub.setAttribute(`label`, `Add column`);
7338
+ const addContainer = document.createElement(`ixfx-menu-container`);
7339
+ addContainer.setAttribute(`slot`, `submenu`);
7340
+ const idx = this._columns.findIndex((c) => c.id === col.id);
7341
+ for (const [label, offset] of [[`Left`, -1], [`Right`, 1]]) {
7342
+ const item = this.#menuItem(label, `add-${label.toLowerCase()}`, () => {
7343
+ this.#insertColumn(unused[0].key, Math.max(0, idx + Math.max(0, offset)));
7344
+ });
7345
+ item.toggleAttribute(`disabled`, !canAdd);
7346
+ addContainer.appendChild(item);
7347
+ }
7348
+ addSub.appendChild(addContainer);
7349
+ container.appendChild(addSub);
7350
+ const sortSub = document.createElement(`ixfx-menu-sub-trigger`);
7351
+ sortSub.setAttribute(`label`, `Sort`);
7352
+ const sortContainer = document.createElement(`ixfx-menu-container`);
7353
+ sortContainer.setAttribute(`slot`, `submenu`);
7354
+ sortContainer.appendChild(this.#menuItem(`Ascending`, `sort-asc`, () => {
7355
+ col.setSort(`asc`);
7356
+ this._emitColumnsChange(`sort`);
7357
+ this.requestUpdate();
7358
+ }, col.getState().sort === `asc` ? `check` : void 0));
7359
+ sortContainer.appendChild(this.#menuItem(`Descending`, `sort-desc`, () => {
7360
+ col.setSort(`desc`);
7361
+ this._emitColumnsChange(`sort`);
7362
+ this.requestUpdate();
7363
+ }, col.getState().sort === `desc` ? `check` : void 0));
7364
+ sortSub.appendChild(sortContainer);
7365
+ container.appendChild(sortSub);
7366
+ const grouped = col.getState().grouped;
7367
+ container.appendChild(this.#menuItem(grouped ? `Ungroup` : `Group`, `toggle-group`, () => {
7368
+ col.setGrouped(!grouped);
7369
+ this._emitColumnsChange(`grouping`);
7370
+ this.requestUpdate();
7371
+ }, grouped ? `check` : void 0));
7372
+ });
7373
+ }
7374
+ #insertColumn(categoryKey, position) {
7375
+ this.addColumn(categoryKey, position);
7376
+ }
7377
+ _changeColumnCategory(col, categoryKey) {
7378
+ const category = this.categories.find((c) => c.key === categoryKey);
7379
+ if (!category) return;
7380
+ col.setCategory(category);
7381
+ this._emitColumnsChange(`category`);
7382
+ this._requeryAllColumns();
7383
+ this.requestUpdate();
7384
+ }
7385
+ _onColumnSelectionChange(columnId, _values) {
7386
+ if (!this._columns.find((c) => c.id === columnId)) return;
7387
+ for (const otherCol of this._columns) if (otherCol.id !== columnId) otherCol.requestData(this._buildQuery(otherCol));
7388
+ const detail = {
7389
+ columnId,
7390
+ columns: this.getSelection()
7391
+ };
7392
+ this.dispatchEvent(new CustomEvent(`multicol-select`, {
7393
+ detail,
7394
+ bubbles: true,
7395
+ composed: true
7396
+ }));
7397
+ this.requestUpdate();
7398
+ }
7399
+ _onColumnRequestData(_columnId, _query, _signal) {}
7400
+ _buildQuery(col) {
7401
+ const otherSelections = /* @__PURE__ */ new Map();
7402
+ for (const c of this._columns) if (c.id !== col.id) otherSelections.set(c.id, c.selectedValues);
7403
+ return {
7404
+ columnId: col.id,
7405
+ categoryKey: col.categoryKey,
7406
+ otherSelections
7407
+ };
7408
+ }
7409
+ _requeryAllColumns() {
7410
+ for (const col of this._columns) col.requestData(this._buildQuery(col));
7411
+ }
7412
+ _syncColumnsWithCategories() {
7413
+ let changed = false;
7414
+ for (const col of this._columns) {
7415
+ if (this.categories.some((c) => c.key === col.categoryKey)) continue;
7416
+ if (this.categories.length === 0) continue;
7417
+ col.setCategory(this.categories[0]);
7418
+ changed = true;
7419
+ }
7420
+ if (changed) this._emitColumnsChange(`category`);
7421
+ }
7422
+ _updateColOffsets() {
7423
+ const offsets = [0];
7424
+ let sum = 0;
7425
+ for (const col of this._columns) {
7426
+ sum += col.getState().width ?? DEFAULT_COLUMN_WIDTH;
7427
+ offsets.push(sum);
7428
+ }
7429
+ if (!(offsets.length === this._colOffsets.length && offsets.every((v, i) => v === this._colOffsets[i]))) this._colOffsets = offsets;
7430
+ }
7431
+ _emitColumnsChange(reason) {
7432
+ this.dispatchEvent(new CustomEvent(`multicol-columns-change`, {
7433
+ detail: {
7434
+ columns: this.columns,
7435
+ reason
7436
+ },
7437
+ bubbles: true,
7438
+ composed: true
7439
+ }));
7440
+ }
7441
+ };
7442
+ __decorate([property({ attribute: false })], MulticolListElement.prototype, "categories", void 0);
7443
+ __decorate([property({ attribute: false })], MulticolListElement.prototype, "dataProvider", void 0);
7444
+ __decorate([property({
7445
+ type: String,
7446
+ attribute: `selection-mode`
7447
+ })], MulticolListElement.prototype, "selectionMode", void 0);
7448
+ __decorate([property({ type: Number })], MulticolListElement.prototype, "minColumns", void 0);
7449
+ __decorate([property({ type: Number })], MulticolListElement.prototype, "maxColumns", void 0);
7450
+ __decorate([state()], MulticolListElement.prototype, "_columns", void 0);
7451
+ __decorate([state()], MulticolListElement.prototype, "_colOffsets", void 0);
7452
+ __decorate([state()], MulticolListElement.prototype, "_resizingColumnId", void 0);
7453
+ __decorate([state()], MulticolListElement.prototype, "_draggingColumnId", void 0);
7454
+ __decorate([state()], MulticolListElement.prototype, "_dropCaretX", void 0);
7455
+ __decorate([query(`#container`)], MulticolListElement.prototype, "_containerEl", void 0);
7456
+ MulticolListElement = __decorate([customElement(`ixfx-multicol-list`)], MulticolListElement);
7457
+ //#endregion
6490
7458
  //#region src/notifier/pill-renderer.ts
6491
7459
  const ROW_SPACING = 8;
6492
7460
  const DEFAULT_ROW_HEIGHT = 40;
@@ -9655,12 +10623,25 @@ function squarifyInto(items, box) {
9655
10623
  }
9656
10624
  return out;
9657
10625
  }
10626
+ /** Clamp a raw cascade offset fraction to a sane range. */
10627
+ function normaliseOffset(raw) {
10628
+ return typeof raw === `number` && Number.isFinite(raw) && raw > 0 ? Math.min(raw, 1) : 0;
10629
+ }
9658
10630
  /**
9659
10631
  * Subdivide `box` among `weights` (same length as the child list) using
9660
10632
  * `method` at `relativeDepth`. Returns one absolute box per weight, in order.
9661
10633
  * Zero-share children get degenerate (zero-area) boxes at the box origin.
10634
+ * Degenerate (zero/negative-extent) containers also yield zero-area boxes
10635
+ * rather than `NaN` — this matters for cascaded layouts where deep insets
10636
+ * can consume the whole box.
9662
10637
  */
9663
10638
  function subdivide(box, weights, method, relativeDepth) {
10639
+ if (box.width <= 0 || box.height <= 0) return weights.map(() => ({
10640
+ x: box.x,
10641
+ y: box.y,
10642
+ width: 0,
10643
+ height: 0
10644
+ }));
9664
10645
  const total = weights.reduce((a, b) => a + b, 0);
9665
10646
  const shares = total > 0 ? weights.map((w) => w / total) : weights.map(() => 1 / weights.length);
9666
10647
  const dice = method === `dice` || method === `slice-dice` && relativeDepth % 2 === 0;
@@ -9727,16 +10708,24 @@ function subdivide(box, weights, method, relativeDepth) {
9727
10708
  * @param options `valueAccessor` (default equal weights), `maxDepth` (nesting
9728
10709
  * levels, default unlimited), `zoomKey` (visual root, default true root;
9729
10710
  * unknown keys fall back to the true root), `tilingMethod` (default
9730
- * `'squarify'`).
10711
+ * `'squarify'`), `presentation` (default `'nested'`) plus `cascadeOffsetX/Y`
10712
+ * (per-level shift as a viewport fraction, cascaded only).
9731
10713
  */
9732
10714
  function computeTreemapLayout(root, options = {}) {
9733
10715
  if (!root?.children?.length) return [];
9734
- const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, tilingMethod = `squarify` } = options;
10716
+ const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, tilingMethod = `squarify`, hideLeaves = false, presentation = `nested`, cascadeOffsetX: rawOx, cascadeOffsetY: rawOy } = options;
9735
10717
  if (maxDepth <= 0) return [];
10718
+ const cascaded = presentation === `cascaded`;
10719
+ const ox = cascaded ? normaliseOffset(rawOx) : 0;
10720
+ const oy = cascaded ? normaliseOffset(rawOy) : 0;
10721
+ const visibleChildren = (node) => {
10722
+ const children = node.children ?? [];
10723
+ return hideLeaves ? children.filter((n) => n.item.isLeaf !== true) : children;
10724
+ };
9736
10725
  const zoomNode = zoomKey === void 0 ? root : findTreemapNode(root, zoomKey) ?? root;
9737
10726
  const zoomPath = findTreemapPath(root, zoomNode.item.key);
9738
10727
  const zoomDepth = zoomPath ? zoomPath.length - 2 : -1;
9739
- const siblings = zoomNode.children ?? [];
10728
+ const siblings = visibleChildren(zoomNode);
9740
10729
  if (siblings.length === 0) return [];
9741
10730
  const rects = [];
9742
10731
  const layoutLevel = (nodes, box, depth, relativeDepth, parentKey) => {
@@ -9745,7 +10734,7 @@ function computeTreemapLayout(root, options = {}) {
9745
10734
  const setSize = nodes.length;
9746
10735
  nodes.forEach((node, index) => {
9747
10736
  const childBox = boxes[index];
9748
- const children = node.children ?? [];
10737
+ const children = visibleChildren(node);
9749
10738
  rects.push({
9750
10739
  node,
9751
10740
  depth,
@@ -9759,7 +10748,15 @@ function computeTreemapLayout(root, options = {}) {
9759
10748
  setSize,
9760
10749
  hasChildren: children.length > 0 || node.children === void 0 && node.item.isLeaf !== true
9761
10750
  });
9762
- if (children.length > 0) layoutLevel(children, childBox, depth + 1, relativeDepth + 1, node.item.key);
10751
+ if (children.length > 0) {
10752
+ const contentBox = ox <= 0 && oy <= 0 ? childBox : {
10753
+ x: childBox.x + ox,
10754
+ y: childBox.y + oy,
10755
+ width: Math.max(0, childBox.width - ox),
10756
+ height: Math.max(0, childBox.height - oy)
10757
+ };
10758
+ layoutLevel(children, contentBox, depth + 1, relativeDepth + 1, node.item.key);
10759
+ }
9763
10760
  });
9764
10761
  };
9765
10762
  layoutLevel(siblings, {
@@ -9779,9 +10776,14 @@ let TreemapListElement = class TreemapListElement extends LitElement {
9779
10776
  this.selectionFilter = `all`;
9780
10777
  this.interactionMode = `standard`;
9781
10778
  this.tilingMethod = `squarify`;
10779
+ this.presentation = `nested`;
10780
+ this.cascadeOffset = 6;
9782
10781
  this.maxDepth = 4;
10782
+ this.hideLeaves = false;
9783
10783
  this.minLabelArea = 1600;
10784
+ this.minTileWidth = 24;
9784
10785
  this.padding = 4;
10786
+ this.minChildArea = 400;
9785
10787
  this.valueAccessor = () => 1;
9786
10788
  this._selectedNodes = /* @__PURE__ */ new Set();
9787
10789
  this.disableKeyboardNavigation = false;
@@ -9815,6 +10817,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
9815
10817
  });
9816
10818
  this.#pendingKeys = /* @__PURE__ */ new Set();
9817
10819
  this.#aborters = /* @__PURE__ */ new Map();
10820
+ this.#wheelCooldownUntil = 0;
9818
10821
  }
9819
10822
  get selectedNodes() {
9820
10823
  return this._selectedNodes;
@@ -9831,17 +10834,43 @@ let TreemapListElement = class TreemapListElement extends LitElement {
9831
10834
  #ownedRegistry;
9832
10835
  #unregisterSearchCommands;
9833
10836
  #resizeObserver;
10837
+ #pendingFlip;
10838
+ /** `performance.now()` timestamp before which further Cmd+wheel zoom steps are ignored. */
10839
+ #wheelCooldownUntil;
9834
10840
  get #effectiveRoot() {
9835
10841
  return this.model?.root ?? this.root;
9836
10842
  }
9837
10843
  #rects() {
10844
+ return this.#rectsForZoom(this._zoomKey);
10845
+ }
10846
+ #rectsForZoom(zoomKey) {
9838
10847
  return computeTreemapLayout(this.#effectiveRoot, {
9839
10848
  valueAccessor: this.valueAccessor,
9840
10849
  maxDepth: this.maxDepth,
9841
- zoomKey: this._zoomKey,
9842
- tilingMethod: this.tilingMethod
10850
+ zoomKey,
10851
+ tilingMethod: this.tilingMethod,
10852
+ hideLeaves: this.hideLeaves,
10853
+ presentation: this.presentation,
10854
+ ...this.#cascadeFractions()
9843
10855
  });
9844
10856
  }
10857
+ /**
10858
+ * Pixel `cascadeOffset` as viewport fractions for the current host size.
10859
+ * Returns `{}` when nested, unmeasured, or non-positive — layout then falls
10860
+ * back to classic nesting for that pass (the `ResizeObserver` re-renders
10861
+ * once measured).
10862
+ */
10863
+ #cascadeFractions() {
10864
+ if (this.presentation !== `cascaded`) return {};
10865
+ if (!Number.isFinite(this.cascadeOffset) || this.cascadeOffset <= 0) return {};
10866
+ const w = this.clientWidth || 0;
10867
+ const h = this.clientHeight || 0;
10868
+ if (w <= 0 || h <= 0) return {};
10869
+ return {
10870
+ cascadeOffsetX: this.cascadeOffset / w,
10871
+ cascadeOffsetY: this.cascadeOffset / h
10872
+ };
10873
+ }
9845
10874
  connectedCallback() {
9846
10875
  super.connectedCallback();
9847
10876
  this.setAttribute(`data-input-mode`, `mouse`);
@@ -9915,8 +10944,14 @@ let TreemapListElement = class TreemapListElement extends LitElement {
9915
10944
  if (changedProps.has(`searchModes`)) this.#syncSearchCommands();
9916
10945
  if (this._zoomKey !== void 0 && !findTreemapNode(this.#effectiveRoot, this._zoomKey)) this._zoomKey = void 0;
9917
10946
  this.#ensureVisibleChildren();
10947
+ if (this.#pendingFlip) {
10948
+ const flip = this.#pendingFlip;
10949
+ this.#pendingFlip = void 0;
10950
+ this.#applyFlip(flip);
10951
+ }
9918
10952
  }
9919
10953
  #resetViewState() {
10954
+ this.#pendingFlip = void 0;
9920
10955
  this.#clearSelectionInternal();
9921
10956
  this.tickled.clearTickled();
9922
10957
  this._zoomKey = void 0;
@@ -10029,6 +11064,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10029
11064
  */
10030
11065
  zoomTo(node) {
10031
11066
  if (this._zoomKey === node.item.key) return;
11067
+ this.#pendingFlip = this.#planFlip(node.item.key);
10032
11068
  this._zoomKey = node.item.key;
10033
11069
  this.tickled.clearTickled();
10034
11070
  const depth = findTreemapPath(this.#effectiveRoot, node.item.key)?.length;
@@ -10057,6 +11093,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10057
11093
  */
10058
11094
  zoomOut() {
10059
11095
  if (this._zoomKey === void 0) return;
11096
+ this.#pendingFlip = this.#planFlip(void 0);
10060
11097
  const previous = this.focusedNode;
10061
11098
  const path = this._zoomKey === void 0 ? void 0 : findTreemapPath(this.#effectiveRoot, this._zoomKey);
10062
11099
  const absoluteDepth = path === void 0 ? -1 : path.length - 2;
@@ -10080,9 +11117,66 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10080
11117
  }));
10081
11118
  this.requestUpdate();
10082
11119
  }
11120
+ /**
11121
+ * Work out (before `_zoomKey` changes) whether the upcoming zoom should
11122
+ * animate, and how — see `FlipPlan`. Returns `undefined` to skip the
11123
+ * animation: reduced-motion is requested, or the node needed to anchor it
11124
+ * isn't in either the old or new layout's visible window.
11125
+ */
11126
+ #planFlip(targetKey) {
11127
+ if (typeof matchMedia === `function` && matchMedia(`(prefers-reduced-motion: reduce)`).matches) return void 0;
11128
+ if (targetKey !== void 0) {
11129
+ const visible = this.#rects().find((r) => r.node.item.key === targetKey);
11130
+ if (visible) return {
11131
+ direction: `in`,
11132
+ rect: {
11133
+ x: visible.x,
11134
+ y: visible.y,
11135
+ width: visible.width,
11136
+ height: visible.height
11137
+ }
11138
+ };
11139
+ }
11140
+ const fromKey = this._zoomKey;
11141
+ if (fromKey === void 0) return void 0;
11142
+ const landing = this.#rectsForZoom(targetKey).find((r) => r.node.item.key === fromKey);
11143
+ if (!landing) return void 0;
11144
+ return {
11145
+ direction: `out`,
11146
+ rect: {
11147
+ x: landing.x,
11148
+ y: landing.y,
11149
+ width: landing.width,
11150
+ height: landing.height
11151
+ }
11152
+ };
11153
+ }
11154
+ /** Apply a planned FLIP animation once the new layout has rendered — see `FlipPlan`. */
11155
+ #applyFlip(flip) {
11156
+ const inner = this.renderRoot.querySelector(`.viewport-inner`);
11157
+ const viewport = this.renderRoot.querySelector(`.viewport`);
11158
+ if (!(inner instanceof HTMLElement) || !(viewport instanceof HTMLElement)) return;
11159
+ const vw = viewport.clientWidth;
11160
+ const vh = viewport.clientHeight;
11161
+ if (vw <= 0 || vh <= 0) return;
11162
+ const { rect, direction } = flip;
11163
+ const startTransform = direction === `in` ? `translate(${rect.x * vw}px, ${rect.y * vh}px) scale(${Math.max(rect.width, 1e-4)}, ${Math.max(rect.height, 1e-4)})` : (() => {
11164
+ const sx = rect.width > 0 ? 1 / rect.width : 1;
11165
+ const sy = rect.height > 0 ? 1 / rect.height : 1;
11166
+ return `translate(${-rect.x * sx * vw}px, ${-rect.y * sy * vh}px) scale(${sx}, ${sy})`;
11167
+ })();
11168
+ inner.classList.remove(`flipping`);
11169
+ inner.style.transform = startTransform;
11170
+ inner.offsetWidth;
11171
+ requestAnimationFrame(() => {
11172
+ inner.classList.add(`flipping`);
11173
+ inner.style.transform = `none`;
11174
+ });
11175
+ inner.addEventListener(`transitionend`, () => inner.classList.remove(`flipping`), { once: true });
11176
+ }
10083
11177
  #canZoom(node) {
10084
11178
  if (node.item.isLeaf === true) return false;
10085
- if (node.children !== void 0) return node.children.length > 0;
11179
+ if (node.children !== void 0) return this.hideLeaves ? node.children.some((n) => n.item.isLeaf !== true) : node.children.length > 0;
10086
11180
  return this.model !== void 0 || this.loadChildren !== void 0;
10087
11181
  }
10088
11182
  /**
@@ -10309,6 +11403,39 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10309
11403
  }
10310
11404
  }
10311
11405
  }
11406
+ /**
11407
+ * Cmd+wheel zooms: scrolling backward (deltaY < 0, towards the user) zooms
11408
+ * into the tile under the pointer — the same as clicking it; scrolling
11409
+ * forward (deltaY > 0, away from the user) zooms out one level at a time
11410
+ * (see `#zoomOutOneStep`), not straight to the root. Plain wheel (no Cmd)
11411
+ * is left alone for normal page scroll. A short cooldown after each step
11412
+ * keeps a single trackpad gesture (which fires many small wheel events)
11413
+ * from firing a cascade of zoom steps.
11414
+ */
11415
+ #handleWheel(event) {
11416
+ if (!event.metaKey || event.deltaY === 0) return;
11417
+ event.preventDefault();
11418
+ if (performance.now() < this.#wheelCooldownUntil) return;
11419
+ if (event.deltaY > 0) {
11420
+ if (this._zoomKey === void 0) return;
11421
+ this.#wheelCooldownUntil = performance.now() + 260;
11422
+ this.#zoomOutOneStep();
11423
+ return;
11424
+ }
11425
+ const key = (event.target?.closest(`.tile`))?.getAttribute(`data-key`) ?? void 0;
11426
+ if (key === void 0) return;
11427
+ const rect = this.#rects().find((r) => r.node.item.key === key);
11428
+ if (!rect || !this.#canZoom(rect.node)) return;
11429
+ this.#wheelCooldownUntil = performance.now() + 260;
11430
+ this.zoomTo(rect.node);
11431
+ }
11432
+ /** Zoom to the current zoom node's parent, or fully out when it's a direct child of the root. */
11433
+ #zoomOutOneStep() {
11434
+ const path = this._zoomKey === void 0 ? void 0 : findTreemapPath(this.#effectiveRoot, this._zoomKey);
11435
+ const parent = path && path.length > 2 ? path[path.length - 2] : void 0;
11436
+ if (parent) this.zoomTo(parent);
11437
+ else this.zoomOut();
11438
+ }
10312
11439
  #renderBreadcrumb() {
10313
11440
  const zoomNode = this.focusedNode;
10314
11441
  if (zoomNode === void 0) return nothing;
@@ -10338,25 +11465,64 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10338
11465
  if (node.item.key === this.#effectiveRoot?.item.key) this.zoomOut();
10339
11466
  else this.zoomTo(node);
10340
11467
  }
10341
- #hideLabel(rect) {
11468
+ /** On-screen size (px) of `rect`, or `undefined` before the host has been measured. */
11469
+ #pixelSize(rect) {
10342
11470
  const hostWidth = this.clientWidth || 0;
10343
11471
  const hostHeight = this.clientHeight || 0;
10344
- if (hostWidth <= 0 || hostHeight <= 0) return false;
10345
- return rect.width * hostWidth * rect.height * hostHeight < this.minLabelArea;
11472
+ if (hostWidth <= 0 || hostHeight <= 0) return void 0;
11473
+ return {
11474
+ width: rect.width * hostWidth,
11475
+ height: rect.height * hostHeight
11476
+ };
10346
11477
  }
10347
- #renderTile(rect, positionStyle, children, byParent, nested) {
11478
+ /** Hide when too small by area, or too narrow to fit any readable text even truncated. */
11479
+ #hideLabel(rect) {
11480
+ const size = this.#pixelSize(rect);
11481
+ if (size === void 0) return false;
11482
+ return size.width * size.height < this.minLabelArea || size.width < this.minTileWidth;
11483
+ }
11484
+ /** Whether `rect` is large enough on-screen for its own children to be subdivided and drawn. */
11485
+ #canDescend(rect) {
11486
+ const size = this.#pixelSize(rect);
11487
+ if (size === void 0) return true;
11488
+ const offset = this.presentation === `cascaded` && Number.isFinite(this.cascadeOffset) && this.cascadeOffset > 0 ? this.cascadeOffset : 0;
11489
+ const w = size.width - offset;
11490
+ const h = size.height - offset;
11491
+ if (w <= 0 || h <= 0) return false;
11492
+ return w * h >= this.minChildArea && w >= this.minTileWidth;
11493
+ }
11494
+ /** Slugify a category name into a CSS custom-property-safe token. */
11495
+ #categorySlug(category) {
11496
+ return category.replace(/[^\w-]/g, `-`);
11497
+ }
11498
+ /**
11499
+ * Inline colour overrides for `node`'s category, or `undefined` for none.
11500
+ * Set as real `background-color`/`color` (not custom properties) so they
11501
+ * simply win over `.tile`'s CSS-variable-driven defaults by specificity —
11502
+ * no risk of an unresolvable `var()` chain leaving the property invalid.
11503
+ */
11504
+ #categoryStyle(node) {
11505
+ const category = this.categoryAccessor?.(node.item);
11506
+ if (!category) return void 0;
11507
+ const slug = this.#categorySlug(category);
11508
+ return `background-color:var(--treemap-category-${slug}-bg, var(--treemap-tile-bg));color:var(--treemap-category-${slug}-text, var(--treemap-tile-text));`;
11509
+ }
11510
+ #renderTileBox(rect, positionStyle, hasVisibleChildren, childrenContent) {
10348
11511
  const { node } = rect;
10349
11512
  const selected = this._selectedNodes.has(node);
10350
11513
  const tickled = this.tickled.isTickled(node.item.key);
10351
11514
  const filtered = !this.#matchesFilter(node, rect.depth);
10352
11515
  const pending = this.#pendingKeys.has(node.item.key);
10353
11516
  const hideLabel = this.#hideLabel(rect);
10354
- const showHeader = children.length > 0 && !hideLabel;
11517
+ const showHeader = hasVisibleChildren && !hideLabel;
11518
+ const category = this.categoryAccessor?.(node.item);
11519
+ const categoryStyle = this.#categoryStyle(node);
10355
11520
  return html`
10356
11521
  <div
10357
- class="item tile ${nested ? `nested` : ``} ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${filtered ? `filtered` : ``} ${pending ? `loading` : ``} ${rect.width <= 0 || rect.height <= 0 ? `empty` : ``}"
11522
+ class="item tile ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${filtered ? `filtered` : ``} ${pending ? `loading` : ``} ${rect.width <= 0 || rect.height <= 0 ? `empty` : ``}"
10358
11523
  data-key=${node.item.key}
10359
11524
  data-depth=${rect.relativeDepth}
11525
+ data-category=${category ?? nothing}
10360
11526
  role="treeitem"
10361
11527
  tabindex="-1"
10362
11528
  aria-level=${rect.depth + 1}
@@ -10366,7 +11532,7 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10366
11532
  aria-label=${node.item.label}
10367
11533
  title=${node.item.label}
10368
11534
  part="tile"
10369
- style=${positionStyle}
11535
+ style=${categoryStyle ? `${positionStyle};${categoryStyle}` : positionStyle}
10370
11536
  @click=${(e) => {
10371
11537
  e.stopPropagation();
10372
11538
  this.#handleItemClick(rect, this.#rects().findIndex((r) => r.node.item.key === node.item.key), e);
@@ -10378,23 +11544,46 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10378
11544
  @pointerenter=${() => this.tickled.handlePointerEnter(node.item.key)}
10379
11545
  >
10380
11546
  ${showHeader ? html`<div class="tile-header" part="tile-header"><span class="treemap-label" part="label">${node.item.label}</span></div>` : html`<span class="treemap-label ${hideLabel ? `hide-label` : ``}" part="label">${node.item.label}</span>`}
10381
- ${children.length > 0 ? html`
10382
- <div class="tile-children" role="group">
10383
- ${repeat(children, (r) => r.node.item.key, (r) => this.#renderNestedTile(r, rect, byParent))}
10384
- </div>
10385
- ` : nothing}
11547
+ ${childrenContent}
10386
11548
  </div>
10387
11549
  `;
10388
11550
  }
11551
+ /**
11552
+ * Render `rect` plus (if it's large enough to descend into — see
11553
+ * `#canDescend`) a `.tile-children` holding its own children, each
11554
+ * positioned relative to `rect` itself and recursing the same way.
11555
+ *
11556
+ * Each level gets its own real `.tile-header` + `.tile-children` box, so a
11557
+ * header reserves its own space via normal box-model layout (flex column:
11558
+ * header, then the remaining space for children) at *every* level — not
11559
+ * just the top one. That matters because layout rects are purely
11560
+ * geometric (no allowance for header height), so a folder whose one child
11561
+ * fills ~100% of its area gets a child rect nearly identical to its own;
11562
+ * positioning that child against its direct parent (not some flattened
11563
+ * shared ancestor) is what keeps the parent's header from being painted
11564
+ * over by an opaque, near-identically-sized child box.
11565
+ */
11566
+ #renderTile(rect, positionStyle, byParent) {
11567
+ const children = rect.hasChildren && this.#canDescend(rect) ? byParent.get(rect.node.item.key) ?? [] : [];
11568
+ const childrenContent = children.length > 0 ? html`
11569
+ <div class="tile-children" role="group">
11570
+ ${repeat(children, (r) => r.node.item.key, (r) => this.#renderNestedTile(r, rect, byParent))}
11571
+ </div>
11572
+ ` : nothing;
11573
+ return this.#renderTileBox(rect, positionStyle, children.length > 0, childrenContent);
11574
+ }
11575
+ /** A child tile, positioned as a percentage of `parent`'s own box. */
10389
11576
  #renderNestedTile(rect, parent, byParent) {
10390
11577
  const relX = parent.width > 0 ? (rect.x - parent.x) / parent.width : 0;
10391
11578
  const relY = parent.height > 0 ? (rect.y - parent.y) / parent.height : 0;
10392
11579
  const relW = parent.width > 0 ? rect.width / parent.width : 0;
10393
11580
  const relH = parent.height > 0 ? rect.height / parent.height : 0;
10394
- return this.#renderTile(rect, `left:${(relX * 100).toFixed(4)}%;top:${(relY * 100).toFixed(4)}%;width:${(relW * 100).toFixed(4)}%;height:${(relH * 100).toFixed(4)}%`, byParent.get(rect.node.item.key) ?? [], byParent, true);
11581
+ const style = `left:${(relX * 100).toFixed(4)}%;top:${(relY * 100).toFixed(4)}%;width:${(relW * 100).toFixed(4)}%;height:${(relH * 100).toFixed(4)}%`;
11582
+ return this.#renderTile(rect, style, byParent);
10395
11583
  }
10396
11584
  #renderTopTile(rect, byParent) {
10397
- return this.#renderTile(rect, `left:${(rect.x * 100).toFixed(4)}%;top:${(rect.y * 100).toFixed(4)}%;width:${(rect.width * 100).toFixed(4)}%;height:${(rect.height * 100).toFixed(4)}%`, byParent.get(rect.node.item.key) ?? [], byParent, false);
11585
+ const style = `left:${(rect.x * 100).toFixed(4)}%;top:${(rect.y * 100).toFixed(4)}%;width:${(rect.width * 100).toFixed(4)}%;height:${(rect.height * 100).toFixed(4)}%`;
11586
+ return this.#renderTile(rect, style, byParent);
10398
11587
  }
10399
11588
  render() {
10400
11589
  const rects = this.#rects();
@@ -10412,15 +11601,19 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10412
11601
  class="treemap"
10413
11602
  role="tree"
10414
11603
  tabindex="0"
11604
+ data-presentation=${this.presentation}
10415
11605
  data-input-mode=${this.tickled.inputMode}
10416
11606
  style=${`--treemap-padding:${this.padding}px`}
10417
11607
  @keydown=${(e) => this.#handleKeyDown(e)}
10418
11608
  @pointerleave=${() => this.tickled.clearTickled()}
11609
+ @wheel=${(e) => this.#handleWheel(e)}
10419
11610
  >
10420
11611
  ${this.#renderBreadcrumb()}
10421
11612
  ${rects.length === 0 ? html`<div class="empty-state">No data</div>` : html`
10422
11613
  <div class="viewport" part="viewport">
10423
- ${repeat(topLevel, (r) => r.node.item.key, (r) => this.#renderTopTile(r, byParent))}
11614
+ <div class="viewport-inner">
11615
+ ${repeat(topLevel, (r) => r.node.item.key, (r) => this.#renderTopTile(r, byParent))}
11616
+ </div>
10424
11617
  </div>
10425
11618
  `}
10426
11619
  </div>
@@ -10443,11 +11636,18 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10443
11636
  --treemap-tile-border: var(--border-subtle);
10444
11637
  --treemap-header-bg: rgb(0 0 0 / 0.12);
10445
11638
  --treemap-font-size: var(--text-s);
11639
+ --treemap-zoom-duration: 220ms;
10446
11640
 
10447
11641
  display: block;
10448
- overflow: auto;
11642
+ overflow: hidden;
10449
11643
  }
10450
11644
 
11645
+ /* Per-category tile colours (set categoryAccessor to opt in): define
11646
+ --treemap-category-SLUG-bg / -text at whatever scope suits (:host
11647
+ here, or globally) for each category your accessor can return —
11648
+ e.g. --treemap-category-urgent-bg: oklch(55% 0.18 25). A category
11649
+ with no matching pair falls back to --treemap-tile-bg/-text. */
11650
+
10451
11651
  .treemap {
10452
11652
  display: flex;
10453
11653
  flex-direction: column;
@@ -10476,18 +11676,44 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10476
11676
  .viewport {
10477
11677
  position: relative;
10478
11678
  width: 100%;
10479
- height: var(--treemap-height);
10480
- flex-shrink: 0;
11679
+ /* flex-basis of --treemap-height (its size when nothing forces a
11680
+ different one — the common case of an auto-height host) but
11681
+ allowed to grow/shrink like any flex item, so it shares the
11682
+ .treemap column's height with the breadcrumb instead of a plain
11683
+ fixed height always claiming that full amount regardless of what
11684
+ else needs space — which is what let the breadcrumb push the
11685
+ host past its own height and scroll once a zoom made it appear. */
11686
+ flex: 1 1 var(--treemap-height);
11687
+ min-height: 0;
10481
11688
  overflow: hidden;
10482
11689
  border-radius: var(--radius-m);
10483
11690
  }
10484
11691
 
11692
+ /* Transform target for the zoom-in/zoom-out FLIP animation (see
11693
+ #planFlip/#applyFlip) — kept separate from .viewport so the
11694
+ transform never fights that element's own sizing/overflow. */
11695
+ .viewport-inner {
11696
+ position: absolute;
11697
+ inset: 0;
11698
+ transform-origin: 0 0;
11699
+ }
11700
+
11701
+ .viewport-inner.flipping {
11702
+ transition: transform var(--treemap-zoom-duration, 220ms) ease-out;
11703
+ }
11704
+
10485
11705
  .tile {
10486
11706
  position: absolute;
10487
11707
  box-sizing: border-box;
10488
11708
  overflow: hidden;
10489
11709
  display: flex;
10490
11710
  flex-direction: column;
11711
+ /* Override the shared .item class's align-items:center (built for
11712
+ icon+label rows) — tiles need their flex children to stretch to
11713
+ full width, or .tile-children collapses to its (empty) content
11714
+ width and every nested tile collapses with it. */
11715
+ align-items: stretch;
11716
+ white-space: normal;
10491
11717
  background: var(--treemap-tile-bg);
10492
11718
  color: var(--treemap-tile-text);
10493
11719
  border: var(--treemap-tile-border);
@@ -10506,6 +11732,14 @@ let TreemapListElement = class TreemapListElement extends LitElement {
10506
11732
  margin-top: 0;
10507
11733
  }
10508
11734
 
11735
+ /* Cascaded presentation (Lü & Fogarty 2008): the geometric inset is
11736
+ already in the layout rects — this adds the stack-of-cards depth
11737
+ cue on top. Parent tiles read as cards sitting behind their
11738
+ children. */
11739
+ .treemap[data-presentation="cascaded"] .tile {
11740
+ box-shadow: 2px 2px 0 rgb(0 0 0 / 0.25);
11741
+ }
11742
+
10509
11743
  .tile-header {
10510
11744
  flex-shrink: 0;
10511
11745
  padding: 1px var(--space-xs);
@@ -10576,16 +11810,37 @@ __decorate([property({
10576
11810
  type: String,
10577
11811
  attribute: `tiling-method`
10578
11812
  })], TreemapListElement.prototype, "tilingMethod", void 0);
11813
+ __decorate([property({
11814
+ type: String,
11815
+ attribute: `presentation`
11816
+ })], TreemapListElement.prototype, "presentation", void 0);
11817
+ __decorate([property({
11818
+ type: Number,
11819
+ attribute: `cascade-offset`
11820
+ })], TreemapListElement.prototype, "cascadeOffset", void 0);
10579
11821
  __decorate([property({
10580
11822
  type: Number,
10581
11823
  attribute: `max-depth`
10582
11824
  })], TreemapListElement.prototype, "maxDepth", void 0);
11825
+ __decorate([property({
11826
+ type: Boolean,
11827
+ attribute: `hide-leaves`
11828
+ })], TreemapListElement.prototype, "hideLeaves", void 0);
10583
11829
  __decorate([property({
10584
11830
  type: Number,
10585
11831
  attribute: `min-label-area`
10586
11832
  })], TreemapListElement.prototype, "minLabelArea", void 0);
11833
+ __decorate([property({
11834
+ type: Number,
11835
+ attribute: `min-tile-width`
11836
+ })], TreemapListElement.prototype, "minTileWidth", void 0);
10587
11837
  __decorate([property({ type: Number })], TreemapListElement.prototype, "padding", void 0);
11838
+ __decorate([property({
11839
+ type: Number,
11840
+ attribute: `min-child-area`
11841
+ })], TreemapListElement.prototype, "minChildArea", void 0);
10588
11842
  __decorate([property({ attribute: false })], TreemapListElement.prototype, "valueAccessor", void 0);
11843
+ __decorate([property({ attribute: false })], TreemapListElement.prototype, "categoryAccessor", void 0);
10589
11844
  __decorate([property({ attribute: false })], TreemapListElement.prototype, "selectedNode", void 0);
10590
11845
  __decorate([state()], TreemapListElement.prototype, "_selectedNodes", void 0);
10591
11846
  __decorate([property({ attribute: false })], TreemapListElement.prototype, "filterPredicate", void 0);
@@ -11244,6 +12499,6 @@ function init() {
11244
12499
  console.log(`Init`);
11245
12500
  }
11246
12501
  //#endregion
11247
- export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findIcicleNode, findIciclePath, findNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
12502
+ export { AcTextElement, AcTokenElement, BottomDrawerElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DataTableElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GridListElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IcicleTreeListElement, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, MulticolListElement, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeDropController, TreeKeyboardNavController, TreeListElement, TreemapListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findIcicleNode, findIciclePath, findNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
11248
12503
 
11249
12504
  //# sourceMappingURL=index.js.map