@ixfx/components 0.7.0 → 0.7.1

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 (86) hide show
  1. package/bundle/index.d.ts +235 -27
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +799 -124
  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-BAa6ke09.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
  8. package/dist/{ac-token-BAa6ke09.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 +1 -1
  11. package/dist/{button-Dat2yHAU.js → button-DsFbV4XD.js} +3 -3
  12. package/dist/{button-Dat2yHAU.js.map → button-DsFbV4XD.js.map} +1 -1
  13. package/dist/button.d.ts.map +1 -1
  14. package/dist/button.js +1 -1
  15. package/dist/{colour-picker-BSDBL-QL.js → colour-picker-Ddsk-7E_.js} +2 -2
  16. package/dist/{colour-picker-BSDBL-QL.js.map → colour-picker-Ddsk-7E_.js.map} +1 -1
  17. package/dist/colour-picker.js +1 -1
  18. package/dist/crumbs.d.ts +1 -1
  19. package/dist/crumbs.js +1 -1
  20. package/dist/{data-grid-C8qIo1-u.d.ts → data-grid-Bh4YrQGK.d.ts} +2 -2
  21. package/dist/{data-grid-C8qIo1-u.d.ts.map → data-grid-Bh4YrQGK.d.ts.map} +1 -1
  22. package/dist/data-grid.d.ts +1 -1
  23. package/dist/data-grid.js +1 -1
  24. package/dist/{defaults-BkWCPJFL.js → defaults-BJwDsMH4.js} +26 -2
  25. package/dist/defaults-BJwDsMH4.js.map +1 -0
  26. package/dist/{hex-editor-Bk6rxhfg.js → hex-editor-BiRfwTz1.js} +2 -2
  27. package/dist/{hex-editor-Bk6rxhfg.js.map → hex-editor-BiRfwTz1.js.map} +1 -1
  28. package/dist/hex.js +1 -1
  29. package/dist/{icon-DpA9x2Ve.d.ts → icon-CDGprSdE.d.ts} +1 -12
  30. package/dist/icon-CDGprSdE.d.ts.map +1 -0
  31. package/dist/{icon-CvnPanhA.js → icon-DcEEGQa_.js} +37 -8
  32. package/dist/icon-DcEEGQa_.js.map +1 -0
  33. package/dist/icons.d.ts +3 -3
  34. package/dist/icons.js +4 -4
  35. package/dist/icons.js.map +1 -1
  36. package/dist/{index-CKtLhgYj.d.ts → index-9AhaHIT2.d.ts} +3 -3
  37. package/dist/{index-CKtLhgYj.d.ts.map → index-9AhaHIT2.d.ts.map} +1 -1
  38. package/dist/{index-BtGFYfaK.d.ts → index-CS9yM8L-.d.ts} +14 -4
  39. package/dist/index-CS9yM8L-.d.ts.map +1 -0
  40. package/dist/index.d.ts +223 -23
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +674 -106
  43. package/dist/index.js.map +1 -1
  44. package/dist/{menu-BjRvlgPy.js → menu-CXDFJxNm.js} +3 -3
  45. package/dist/{menu-BjRvlgPy.js.map → menu-CXDFJxNm.js.map} +1 -1
  46. package/dist/{menu-item-Bs2MYyHq.d.ts → menu-item-CZi9vy5O.d.ts} +4 -2
  47. package/dist/menu-item-CZi9vy5O.d.ts.map +1 -0
  48. package/dist/{menu-item-B-zYrTTi.js → menu-item-D2S4i8u1.js} +16 -4
  49. package/dist/menu-item-D2S4i8u1.js.map +1 -0
  50. package/dist/menu.d.ts +2 -2
  51. package/dist/menu.js +2 -2
  52. package/dist/notification-pill-DyZydXoZ.d.ts.map +1 -1
  53. package/dist/notifier.js +2 -2
  54. package/dist/notifier.js.map +1 -1
  55. package/dist/panel.d.ts +1 -1
  56. package/dist/plots.js +1 -1
  57. package/dist/registry-BEtb8_wB.js +46 -0
  58. package/dist/registry-BEtb8_wB.js.map +1 -0
  59. package/dist/{tab-list-MPwq_1Jj.d.ts → tab-list-CGyPt07Z.d.ts} +9 -2
  60. package/dist/tab-list-CGyPt07Z.d.ts.map +1 -0
  61. package/dist/tabs.d.ts +1 -1
  62. package/dist/tabs.js +32 -13
  63. package/dist/tabs.js.map +1 -1
  64. package/dist/{titlebar-DaCfpliv.d.ts → titlebar-Bj5pfdw_.d.ts} +2 -2
  65. package/dist/{titlebar-DaCfpliv.d.ts.map → titlebar-Bj5pfdw_.d.ts.map} +1 -1
  66. package/dist/titlebar.d.ts +1 -1
  67. package/dist/titlebar.js +1 -1
  68. package/dist/tooltip-BlvBUQxx.d.ts.map +1 -1
  69. package/dist/{xy-axis-CxHC8z5E.js → xy-axis-DWizs0bt.js} +3 -3
  70. package/dist/xy-axis-DWizs0bt.js.map +1 -0
  71. package/docs-user/dock.md +166 -15
  72. package/docs-user/icons.md +4 -0
  73. package/docs-user/index.json +2 -2
  74. package/docs-user/tabs.md +20 -0
  75. package/docs-user/user-theming.md +109 -0
  76. package/package.json +1 -1
  77. package/dist/defaults-BkWCPJFL.js.map +0 -1
  78. package/dist/icon-CvnPanhA.js.map +0 -1
  79. package/dist/icon-DpA9x2Ve.d.ts.map +0 -1
  80. package/dist/index-BtGFYfaK.d.ts.map +0 -1
  81. package/dist/menu-item-B-zYrTTi.js.map +0 -1
  82. package/dist/menu-item-Bs2MYyHq.d.ts.map +0 -1
  83. package/dist/registry-CkW7q09Q.js +0 -21
  84. package/dist/registry-CkW7q09Q.js.map +0 -1
  85. package/dist/tab-list-MPwq_1Jj.d.ts.map +0 -1
  86. package/dist/xy-axis-CxHC8z5E.js.map +0 -1
package/dist/index.js CHANGED
@@ -3,21 +3,21 @@ import { t as TickledController } from "./tickled-controller-h9GmJ_bU.js";
3
3
  import { t as themeFallbacks } from "./fallbacks-DNI9xt0F.js";
4
4
  import { t as popupSurfaceStyles } from "./popup-D80sj2QC.js";
5
5
  import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
6
- import { a as svgToDataUri, i as registerIcon, n as hasIcon, r as iconBus, t as getIcon } from "./registry-CkW7q09Q.js";
7
- import { t as IxfxIconElement } from "./icon-CvnPanhA.js";
6
+ 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";
7
+ import { t as IxfxIconElement } from "./icon-DcEEGQa_.js";
8
8
  import { AcTextElement } from "./ac-text.js";
9
9
  import { t as DataController } from "./data-controller-DOlmqNKb.js";
10
10
  import { n as createIncrSearch, r as createFuzzySearch, t as createElementIncrSearch } from "./element-search-Y8SRfPGM.js";
11
11
  import { n as createAcCompletionProvider, t as IncrSearchTreeController } from "./incr-search-vCzuao-2.js";
12
12
  import { AcTokenElement } from "./ac-token.js";
13
- import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-BkWCPJFL.js";
13
+ import { i as ICON_CLOSE, n as ICON_CHECK, r as ICON_CHEVRON_DOWN, t as ICON_CARET_RIGHT } from "./defaults-BJwDsMH4.js";
14
14
  import "./icons.js";
15
15
  import { t as prominenceStyles } from "./prominence-DlFShic3.js";
16
- import { n as buttonStyles, t as ButtonElement } from "./button-Dat2yHAU.js";
16
+ import { n as buttonStyles, t as ButtonElement } from "./button-DsFbV4XD.js";
17
17
  import { n as ListSelectionController, t as VerticalListElement } from "./vertical-list-ClnqTkF3.js";
18
- import "./menu-item-B-zYrTTi.js";
18
+ import "./menu-item-D2S4i8u1.js";
19
19
  import { Checkbox } from "./checkbox.js";
20
- import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-BSDBL-QL.js";
20
+ import { n as ColourPicker, t as ColourPickerPopup } from "./colour-picker-Ddsk-7E_.js";
21
21
  import { LabelledRangeInput } from "./labelled-range-input.js";
22
22
  import { t as collectDataResult } from "./data-provider-35TyWclX.js";
23
23
  import { i as TreeDataModel, n as TreeListElement, r as TreeBaseElement, t as TreeController } from "./tree-Ch4W8qXQ.js";
@@ -26,7 +26,7 @@ import { NarrowedTextElement } from "./narrowed-text.js";
26
26
  import { CrumbNavigationElement } from "./crumbs.js";
27
27
  import { DataDisplayComponent } from "./data-display.js";
28
28
  import { t as createDragGhost } from "./drag-ghost-DtSDvjri.js";
29
- import { t as menu_exports } from "./menu-BjRvlgPy.js";
29
+ import { t as menu_exports } from "./menu-CXDFJxNm.js";
30
30
  import { DataGridElement } from "./data-grid.js";
31
31
  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-BFSbUZQv.js";
32
32
  import { TabListElement } from "./tabs.js";
@@ -36,14 +36,14 @@ import { n as EditableNumber, t as LabelledSliderInput } from "./labelled-slider
36
36
  import { t as FormElement } from "./form-CsXJX15p.js";
37
37
  import { PanelElement } from "./panel.js";
38
38
  import { GroupedItemListerElement } from "./grouped-item-lister.js";
39
- import { t as IxfxHexEditorElement } from "./hex-editor-Bk6rxhfg.js";
39
+ import { t as IxfxHexEditorElement } from "./hex-editor-BiRfwTz1.js";
40
40
  import { t as RadialInputElement } from "./radial-input-Dp5qz0ly.js";
41
41
  import { LabelledRadialInput } from "./labelled-radial-input.js";
42
42
  import { t as SliderInputElement } from "./slider-input-De4eoT11.js";
43
43
  import { LedElement } from "./led.js";
44
44
  import { MillerBaseElement, MillerListElement, MillerTreeController } from "./miller.js";
45
45
  import { NotificationPillElement } from "./notifier.js";
46
- import { a as TooltipElement, c as computeColour, i as PlotMultiAxis, l as parseColourScaleAttr, n as PlotSingleAxis, o as PlotDataSeries, r as PlotHistogram, s as applyAgeModification, t as PlotXyAxis, u as readBaseColour } from "./xy-axis-CxHC8z5E.js";
46
+ import { a as TooltipElement, c as computeColour, i as PlotMultiAxis, l as parseColourScaleAttr, n as PlotSingleAxis, o as PlotDataSeries, r as PlotHistogram, s as applyAgeModification, t as PlotXyAxis, u as readBaseColour } from "./xy-axis-DWizs0bt.js";
47
47
  import { PolarPad } from "./polar-pad.js";
48
48
  import { t as tooltipValueStyles } from "./tooltip-CJt3WLmN.js";
49
49
  import { RangeInput } from "./range-input.js";
@@ -2526,10 +2526,11 @@ function unregisterDockHost(host) {
2526
2526
  * Begin a dock-panel drag. Called by hosts in response to their own
2527
2527
  * `dock-panel-drag-start` events (titlebar or tab-item handles).
2528
2528
  */
2529
- function startDrag(panelId, sourceHost, pointerId, clientX, clientY) {
2529
+ function startDrag(panelId, sourceHost, pointerId, clientX, clientY, kind) {
2530
2530
  if (activeDrag !== null);
2531
2531
  activeDrag = {
2532
2532
  panelId,
2533
+ kind,
2533
2534
  sourceHost,
2534
2535
  pointerId,
2535
2536
  ghost: createGhostForPanel(sourceHost, panelId),
@@ -2602,7 +2603,7 @@ function onKeyDown(event) {
2602
2603
  }
2603
2604
  function findDropZone(drag, clientX, clientY) {
2604
2605
  for (const host of dragHosts) {
2605
- const zone = host.computeDropZone(clientX, clientY, drag.panelId);
2606
+ const zone = host.computeDropZone(clientX, clientY, drag.panelId, drag.kind);
2606
2607
  if (zone !== null) return zone;
2607
2608
  }
2608
2609
  return null;
@@ -2690,12 +2691,15 @@ function createEmptyLayout() {
2690
2691
  root: createEmptyStack()
2691
2692
  };
2692
2693
  }
2693
- function createStack(panels, active) {
2694
- return {
2694
+ function createStack(panels, active, name) {
2695
+ const stack = {
2695
2696
  kind: `stack`,
2696
2697
  panels: [...panels],
2697
2698
  active: active ?? panels[0] ?? ``
2698
2699
  };
2700
+ const trimmed = name?.trim();
2701
+ if (trimmed) stack.name = trimmed;
2702
+ return stack;
2699
2703
  }
2700
2704
  function createSplit(direction, children, sizes) {
2701
2705
  const mean = children.length > 0 ? 1 / children.length : 1;
@@ -2709,7 +2713,8 @@ function createSplit(direction, children, sizes) {
2709
2713
  /**
2710
2714
  * Runs after every mutation:
2711
2715
  * - stack `active` fixed to a member of `panels` (or `''` when empty)
2712
- * - empty stacks removed from their parent split (and their `sizes` entry)
2716
+ * - empty *unnamed* stacks removed from their parent split (and their
2717
+ * `sizes` entry); named empty stacks are kept so the name stays addressable
2713
2718
  * - splits with ≤1 child replaced by that child (spliced into the parent)
2714
2719
  * - a child split whose direction equals its parent's is flattened into it,
2715
2720
  * spreading its sizes across the slot it vacated
@@ -2718,13 +2723,14 @@ function createSplit(direction, children, sizes) {
2718
2723
  */
2719
2724
  function normalize(root) {
2720
2725
  if (isStack(root)) {
2726
+ sanitizeStackName(root);
2721
2727
  if (!root.panels.includes(root.active)) root.active = root.panels[0] ?? ``;
2722
2728
  return root;
2723
2729
  }
2724
2730
  for (let i = root.children.length - 1; i >= 0; i--) {
2725
2731
  normalize(root.children[i]);
2726
2732
  const child = root.children[i];
2727
- if (isStack(child) && child.panels.length === 0) {
2733
+ if (isStack(child) && child.panels.length === 0 && !child.name) {
2728
2734
  root.children.splice(i, 1);
2729
2735
  root.sizes.splice(i, 1);
2730
2736
  continue;
@@ -2758,17 +2764,36 @@ function replaceNodeContents(target, source) {
2758
2764
  const t = target;
2759
2765
  t.panels = source.panels;
2760
2766
  t.active = source.active;
2767
+ if (source.name !== void 0) t.name = source.name;
2768
+ else delete t.name;
2769
+ if (source.hideLabels !== void 0) t.hideLabels = source.hideLabels;
2770
+ else delete t.hideLabels;
2761
2771
  delete t.collapsed;
2762
2772
  delete t.preCollapseSize;
2773
+ if (source.collapsed !== void 0) t.collapsed = source.collapsed;
2774
+ if (source.preCollapseSize !== void 0) t.preCollapseSize = source.preCollapseSize;
2763
2775
  } else {
2764
2776
  target.kind = `split`;
2765
2777
  const t = target;
2766
2778
  t.direction = source.direction;
2767
2779
  t.children = source.children;
2768
2780
  t.sizes = source.sizes;
2781
+ const stale = t;
2782
+ delete stale.panels;
2783
+ delete stale.active;
2784
+ delete stale.name;
2785
+ delete stale.collapsed;
2786
+ delete stale.preCollapseSize;
2769
2787
  }
2770
2788
  return target;
2771
2789
  }
2790
+ /** Trim `name`; drop it when empty / non-string so lookups stay predictable. */
2791
+ function sanitizeStackName(stack) {
2792
+ if (stack.name === void 0) return;
2793
+ const trimmed = typeof stack.name === `string` ? stack.name.trim() : ``;
2794
+ if (trimmed) stack.name = trimmed;
2795
+ else delete stack.name;
2796
+ }
2772
2797
  function findNode(root, path) {
2773
2798
  let current = root;
2774
2799
  for (const index of path) {
@@ -2802,6 +2827,36 @@ function collectPanelIds(root) {
2802
2827
  return root.children.flatMap(collectPanelIds);
2803
2828
  }
2804
2829
  /**
2830
+ * Path of the first stack (tree order) whose `name` matches, or null.
2831
+ * Names are expected to be unique per layout; duplicates resolve first-wins.
2832
+ */
2833
+ function findStackPathByName(root, name) {
2834
+ const wanted = name.trim();
2835
+ if (!wanted) return null;
2836
+ return findStackPathByNameInner(root, wanted, []);
2837
+ }
2838
+ function findStackPathByNameInner(node, name, path) {
2839
+ if (isStack(node)) return node.name === name ? path : null;
2840
+ for (let i = 0; i < node.children.length; i++) {
2841
+ const found = findStackPathByNameInner(node.children[i], name, [...path, i]);
2842
+ if (found !== null) return found;
2843
+ }
2844
+ return null;
2845
+ }
2846
+ /** Names of every named stack leaf, in tree order. */
2847
+ function collectContainerNames(root) {
2848
+ const out = [];
2849
+ const visit = (node) => {
2850
+ if (isStack(node)) {
2851
+ if (node.name) out.push(node.name);
2852
+ return;
2853
+ }
2854
+ node.children.forEach(visit);
2855
+ };
2856
+ visit(root);
2857
+ return out;
2858
+ }
2859
+ /**
2805
2860
  * Paths of every stack leaf, in tree order. `[]` is the root itself when it
2806
2861
  * is a stack.
2807
2862
  */
@@ -2916,6 +2971,251 @@ function extractStack(root, stackPath, fallbackStack) {
2916
2971
  normalize(root);
2917
2972
  return stack;
2918
2973
  }
2974
+ /** Tolerance for edge-touch comparisons in unit-square geometry. */
2975
+ const GEOM_EPS = 1e-9;
2976
+ function pathsEqual(a, b) {
2977
+ return a.length === b.length && a.every((v, i) => v === b[i]);
2978
+ }
2979
+ /**
2980
+ * Resolve a {@link DockLeafRef} to a stack path. Strings match container
2981
+ * `name` first-wins; arrays must index an existing stack leaf. Returns null
2982
+ * when unresolvable.
2983
+ */
2984
+ function resolveLeafPath(root, ref) {
2985
+ if (typeof ref === `string`) return findStackPathByName(root, ref);
2986
+ if (!Array.isArray(ref)) return null;
2987
+ let current = root;
2988
+ for (const index of ref) {
2989
+ if (!Number.isInteger(index) || index < 0) return null;
2990
+ if (!isSplit(current)) return null;
2991
+ const next = current.children[index];
2992
+ if (!next) return null;
2993
+ current = next;
2994
+ }
2995
+ return isStack(current) ? [...ref] : null;
2996
+ }
2997
+ /** Absolute (unit-square) rect of every stack leaf, in tree order. */
2998
+ function computeLeafGeoms(root) {
2999
+ const out = [];
3000
+ const visit = (node, path, rect) => {
3001
+ if (isStack(node)) {
3002
+ out.push({
3003
+ path,
3004
+ name: node.name ?? null,
3005
+ rect
3006
+ });
3007
+ return;
3008
+ }
3009
+ const total = node.sizes.reduce((sum, w) => sum + w, 0);
3010
+ const safe = total > 0 ? total : node.children.length || 1;
3011
+ let offset = 0;
3012
+ node.children.forEach((child, i) => {
3013
+ const frac = (node.sizes[i] ?? safe / node.children.length) / safe;
3014
+ if (node.direction === `row`) {
3015
+ const w = rect.w * frac;
3016
+ visit(child, [...path, i], {
3017
+ x: rect.x + offset,
3018
+ y: rect.y,
3019
+ w,
3020
+ h: rect.h
3021
+ });
3022
+ offset += w;
3023
+ } else {
3024
+ const h = rect.h * frac;
3025
+ visit(child, [...path, i], {
3026
+ x: rect.x,
3027
+ y: rect.y + offset,
3028
+ w: rect.w,
3029
+ h
3030
+ });
3031
+ offset += h;
3032
+ }
3033
+ });
3034
+ };
3035
+ visit(root, [], {
3036
+ x: 0,
3037
+ y: 0,
3038
+ w: 1,
3039
+ h: 1
3040
+ });
3041
+ return out;
3042
+ }
3043
+ function intervalOverlap(a0, a1, b0, b1) {
3044
+ return Math.min(a1, b1) - Math.max(a0, b0);
3045
+ }
3046
+ /**
3047
+ * Geometric neighbours of a leaf — what the user sees above / below / left /
3048
+ * right of it. Each list holds `{ name, path }` (name is null for unnamed
3049
+ * leaves), ordered most-overlapping first. Returns null when `ref` is
3050
+ * unresolvable.
3051
+ */
3052
+ function getLeafNeighbours(root, ref) {
3053
+ const path = resolveLeafPath(root, ref);
3054
+ if (path === null) return null;
3055
+ const geoms = computeLeafGeoms(root);
3056
+ const self = geoms.find((g) => pathsEqual(g.path, path));
3057
+ if (!self) return null;
3058
+ const s = self.rect;
3059
+ const above = [];
3060
+ const below = [];
3061
+ const left = [];
3062
+ const right = [];
3063
+ geoms.forEach((g, order) => {
3064
+ if (g === self) return;
3065
+ const r = g.rect;
3066
+ const info = {
3067
+ name: g.name,
3068
+ path: [...g.path]
3069
+ };
3070
+ if (Math.abs(r.y + r.h - s.y) < GEOM_EPS) {
3071
+ const o = intervalOverlap(r.x, r.x + r.w, s.x, s.x + s.w);
3072
+ if (o > GEOM_EPS) above.push({
3073
+ info,
3074
+ overlap: o,
3075
+ order
3076
+ });
3077
+ }
3078
+ if (Math.abs(s.y + s.h - r.y) < GEOM_EPS) {
3079
+ const o = intervalOverlap(r.x, r.x + r.w, s.x, s.x + s.w);
3080
+ if (o > GEOM_EPS) below.push({
3081
+ info,
3082
+ overlap: o,
3083
+ order
3084
+ });
3085
+ }
3086
+ if (Math.abs(r.x + r.w - s.x) < GEOM_EPS) {
3087
+ const o = intervalOverlap(r.y, r.y + r.h, s.y, s.y + s.h);
3088
+ if (o > GEOM_EPS) left.push({
3089
+ info,
3090
+ overlap: o,
3091
+ order
3092
+ });
3093
+ }
3094
+ if (Math.abs(s.x + s.w - r.x) < GEOM_EPS) {
3095
+ const o = intervalOverlap(r.y, r.y + r.h, s.y, s.y + s.h);
3096
+ if (o > GEOM_EPS) right.push({
3097
+ info,
3098
+ overlap: o,
3099
+ order
3100
+ });
3101
+ }
3102
+ });
3103
+ const rank = (hits) => hits.sort((a, b) => b.overlap - a.overlap || a.order - b.order).map((h) => h.info);
3104
+ return {
3105
+ above: rank(above),
3106
+ below: rank(below),
3107
+ left: rank(left),
3108
+ right: rank(right)
3109
+ };
3110
+ }
3111
+ /**
3112
+ * Exchange two leaves' positions in the tree, each carrying its size slot so
3113
+ * the remaining structure and proportions are untouched. Returns false when
3114
+ * either path is not a stack leaf.
3115
+ */
3116
+ function swapLeaves(root, pathA, pathB) {
3117
+ if (pathsEqual(pathA, pathB)) return false;
3118
+ const nodeA = findNode(root, pathA);
3119
+ const nodeB = findNode(root, pathB);
3120
+ if (nodeA === null || nodeB === null || !isStack(nodeA) || !isStack(nodeB)) return false;
3121
+ const parentA = findParentOf(root, pathA);
3122
+ const parentB = findParentOf(root, pathB);
3123
+ if (parentA === null || parentB === null) return false;
3124
+ const indexA = pathA[pathA.length - 1];
3125
+ const indexB = pathB[pathB.length - 1];
3126
+ if (parentA === parentB) {
3127
+ const p = parentA;
3128
+ [p.children[indexA], p.children[indexB]] = [p.children[indexB], p.children[indexA]];
3129
+ [p.sizes[indexA], p.sizes[indexB]] = [p.sizes[indexB] ?? 1, p.sizes[indexA] ?? 1];
3130
+ return true;
3131
+ }
3132
+ const carriedNode = parentA.children[indexA];
3133
+ const carriedSize = parentA.sizes[indexA] ?? 1;
3134
+ parentA.children[indexA] = parentB.children[indexB];
3135
+ parentA.sizes[indexA] = parentB.sizes[indexB] ?? 1;
3136
+ parentB.children[indexB] = carriedNode;
3137
+ parentB.sizes[indexB] = carriedSize;
3138
+ return true;
3139
+ }
3140
+ /**
3141
+ * Move a leaf one position in `direction`, swapping with the neighbour it
3142
+ * shares the longest edge with. Returns false when `ref` is unresolvable or
3143
+ * nothing adjoins in that direction. Run `normalize()` afterwards.
3144
+ */
3145
+ function moveLeafStep(root, ref, direction) {
3146
+ const path = resolveLeafPath(root, ref);
3147
+ if (path === null) return false;
3148
+ const neighbours = getLeafNeighbours(root, ref);
3149
+ if (neighbours === null) return false;
3150
+ const list = direction === `up` ? neighbours.above : direction === `down` ? neighbours.below : direction === `left` ? neighbours.left : neighbours.right;
3151
+ if (list.length === 0) return false;
3152
+ return swapLeaves(root, path, list[0].path);
3153
+ }
3154
+ /**
3155
+ * Move a leaf to an edge of the overall layout, keeping the rest of the
3156
+ * tree intact as a single subtree and preserving the leaf's absolute size
3157
+ * along the target axis. Returns false when `ref` is unresolvable or the
3158
+ * layout holds a single leaf. Run `normalize()` afterwards (also safe to
3159
+ * call it twice — the host's commit does).
3160
+ */
3161
+ function moveLeafNodeToEdge(root, ref, edge) {
3162
+ const path = resolveLeafPath(root, ref);
3163
+ if (path === null || path.length === 0) return false;
3164
+ const self = computeLeafGeoms(root).find((g) => pathsEqual(g.path, path));
3165
+ if (!self) return false;
3166
+ const horizontal = edge === `left` || edge === `right`;
3167
+ const frac = Math.min(Math.max(horizontal ? self.rect.w : self.rect.h, .05), .95);
3168
+ if (!(frac > 0) || frac >= 1) return false;
3169
+ const parent = findParentOf(root, path);
3170
+ if (parent === null) return false;
3171
+ const [node] = parent.children.splice(path[path.length - 1], 1);
3172
+ parent.sizes.splice(path[path.length - 1], 1);
3173
+ if (!node) return false;
3174
+ normalize(root);
3175
+ const atStart = edge === `left` || edge === `top`;
3176
+ const direction = horizontal ? `row` : `column`;
3177
+ if (isStack(root)) {
3178
+ const rest = root;
3179
+ const remaining = {
3180
+ kind: `stack`,
3181
+ panels: [...rest.panels],
3182
+ active: rest.active
3183
+ };
3184
+ if (rest.name !== void 0) remaining.name = rest.name;
3185
+ if (rest.collapsed !== void 0) remaining.collapsed = rest.collapsed;
3186
+ if (rest.preCollapseSize !== void 0) remaining.preCollapseSize = rest.preCollapseSize;
3187
+ replaceNodeContents(root, {
3188
+ kind: `split`,
3189
+ direction,
3190
+ children: atStart ? [node, remaining] : [remaining, node],
3191
+ sizes: atStart ? [frac, 1 - frac] : [1 - frac, frac]
3192
+ });
3193
+ return true;
3194
+ }
3195
+ if (isSplit(root) && root.direction === direction) {
3196
+ const size = frac * (root.sizes.reduce((total, w) => total + w, 0) || root.children.length || 1) / (1 - frac);
3197
+ const at = atStart ? 0 : root.children.length;
3198
+ root.children.splice(at, 0, node);
3199
+ root.sizes.splice(at, 0, size);
3200
+ return true;
3201
+ }
3202
+ if (isSplit(root)) {
3203
+ const inner = {
3204
+ kind: `split`,
3205
+ direction: root.direction,
3206
+ children: root.children,
3207
+ sizes: root.sizes
3208
+ };
3209
+ replaceNodeContents(root, {
3210
+ kind: `split`,
3211
+ direction,
3212
+ children: atStart ? [node, inner] : [inner, node],
3213
+ sizes: atStart ? [frac, 1 - frac] : [1 - frac, frac]
3214
+ });
3215
+ return true;
3216
+ }
3217
+ return false;
3218
+ }
2919
3219
  function serializeLayout(root) {
2920
3220
  return {
2921
3221
  version: 1,
@@ -2929,6 +3229,8 @@ function serializeNode(node) {
2929
3229
  panels: [...node.panels],
2930
3230
  active: node.active
2931
3231
  };
3232
+ if (node.name !== void 0) out.name = node.name;
3233
+ if (node.hideLabels !== void 0) out.hideLabels = node.hideLabels;
2932
3234
  if (node.collapsed !== void 0) out.collapsed = node.collapsed;
2933
3235
  if (node.preCollapseSize !== void 0) out.preCollapseSize = node.preCollapseSize;
2934
3236
  return out;
@@ -2971,9 +3273,13 @@ let TabListItemElement = class TabListItemElement extends LitElement {
2971
3273
  this.registry = void 0;
2972
3274
  this._compact = false;
2973
3275
  this._hasToolbarContent = false;
3276
+ this._labelObserver = null;
2974
3277
  this._onToolbarSlotChange = () => {
2975
3278
  this._updateToolbarContent();
2976
3279
  };
3280
+ this._onLabelSlotChange = () => {
3281
+ this._syncLabelSizer();
3282
+ };
2977
3283
  }
2978
3284
  connectedCallback() {
2979
3285
  super.connectedCallback();
@@ -2982,6 +3288,13 @@ let TabListItemElement = class TabListItemElement extends LitElement {
2982
3288
  });
2983
3289
  this._resizeObserver.observe(this);
2984
3290
  (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.addEventListener(`slotchange`, this._onToolbarSlotChange);
3291
+ (this.shadowRoot?.querySelector(`slot:not([name])`))?.addEventListener(`slotchange`, this._onLabelSlotChange);
3292
+ this._labelObserver = new MutationObserver(() => this._syncLabelSizer());
3293
+ this._labelObserver.observe(this, {
3294
+ childList: true,
3295
+ characterData: true,
3296
+ subtree: true
3297
+ });
2985
3298
  }
2986
3299
  disconnectedCallback() {
2987
3300
  super.disconnectedCallback();
@@ -2989,7 +3302,10 @@ let TabListItemElement = class TabListItemElement extends LitElement {
2989
3302
  this._resizeObserver = void 0;
2990
3303
  this._commandCleanup?.();
2991
3304
  this._commandCleanup = void 0;
3305
+ this._labelObserver?.disconnect();
3306
+ this._labelObserver = null;
2992
3307
  (this.shadowRoot?.querySelector(`slot[name="toolbar"]`))?.removeEventListener(`slotchange`, this._onToolbarSlotChange);
3308
+ (this.shadowRoot?.querySelector(`slot:not([name])`))?.removeEventListener(`slotchange`, this._onLabelSlotChange);
2993
3309
  }
2994
3310
  updated(changed) {
2995
3311
  super.updated(changed);
@@ -3012,12 +3328,25 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3012
3328
  if (id === this.commandActive) this.click();
3013
3329
  });
3014
3330
  }
3331
+ /**
3332
+ * Mirror the default-slot text into `.label[data-label]` for the `::after`
3333
+ * width sizer. Slotted toolbar content is excluded.
3334
+ */
3335
+ _syncLabelSizer() {
3336
+ const slot = this.shadowRoot?.querySelector(`slot:not([name])`);
3337
+ const label = this.shadowRoot?.querySelector(`.label`);
3338
+ if (slot === null || slot === void 0 || label === null || label === void 0) return;
3339
+ const text = slot.assignedNodes().filter((node) => !(node instanceof HTMLElement && node.hasAttribute(`slot`))).map((node) => node.textContent ?? ``).join(``);
3340
+ if (text) label.setAttribute(`data-label`, text);
3341
+ else label.removeAttribute(`data-label`);
3342
+ }
3015
3343
  _updateToolbarContent() {
3016
3344
  const slot = this.shadowRoot?.querySelector(`slot[name="toolbar"]`);
3017
3345
  this._hasToolbarContent = (slot?.assignedElements().length ?? 0) > 0;
3018
3346
  }
3019
3347
  firstUpdated() {
3020
3348
  this._updateToolbarContent();
3349
+ this._syncLabelSizer();
3021
3350
  }
3022
3351
  render() {
3023
3352
  const showLabel = !this.hideLabels || !this.iconName;
@@ -3059,15 +3388,21 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3059
3388
  css`
3060
3389
  :host {
3061
3390
  --selected-tab-color: var(--ixfx-selected-tab-color, var(--surface-2-text));
3391
+ --selected-tab-icon-color: var(--ixfx-selected-tab-icon-color, var(--accent));
3062
3392
  --selected-tab-border-width: var(--ixfx-selected-tab-border-width, 1px);
3063
3393
  --selected-tab-weight: var(--ixfx-selected-tab-weight, bold);
3394
+ --selected-tab-text-decoration: var(--ixfx-selected-tab-text-decoration, none);
3395
+ --selected-tab-text-decoration-color: var(--ixfx-selected-tab-text-decoration-color, var(--accent));
3396
+ --selected-tab-text-decoration-thickness: var(--ixfx-selected-tab-text-decoration-thickness, 0px);
3397
+ --selected-tab-text-decoration-offset: var(--ixfx-selected-tab-text-decoration-offset, 2px);
3064
3398
  --selected-background: var(--ixfx-tab-selected-background, var(--surface-5));
3065
3399
  --tab-padding: var(--ixfx-tab-padding, var(--space-s));
3066
3400
  display: inline-flex;
3067
3401
  min-width: 0;
3068
3402
  user-select: none;
3069
3403
  box-sizing: border-box;
3070
- font-size: var(--text-xs);
3404
+ font-size: var(--text-m);
3405
+ color: inherit;
3071
3406
  /* No explicit height: items stretch (align-self: stretch via the
3072
3407
  list's flex container) so every tab in a strip shares one height
3073
3408
  even when toolbars give some items taller content. */
@@ -3082,7 +3417,18 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3082
3417
  font-weight: 500;
3083
3418
  border: var(--selected-tab-border-width) solid transparent;
3084
3419
  gap: var(--space-s);
3420
+ transition: background var(--transition, 0.15s);
3421
+ }
3422
+
3423
+ /* Hover ("tickle") background. When --ixfx-tab-hover-background is
3424
+ unset each state keeps its resting background, so existing
3425
+ consumers see no change. */
3426
+ :host(:hover:not([selected])) > div {
3427
+ background: var(--ixfx-tab-hover-background, transparent);
3428
+ }
3085
3429
 
3430
+ :host([selected]:hover) > div {
3431
+ background: var(--ixfx-tab-hover-background, var(--selected-background));
3086
3432
  }
3087
3433
 
3088
3434
  :host([selected]) > div {
@@ -3096,6 +3442,13 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3096
3442
  border-radius:var(--radius-m);
3097
3443
  }
3098
3444
 
3445
+ :host([selected]) .label {
3446
+ text-decoration: var(--selected-tab-text-decoration);
3447
+ text-decoration-color: var(--selected-tab-text-decoration-color);
3448
+ text-decoration-thickness: var(--selected-tab-text-decoration-thickness);
3449
+ text-decoration-offset: var(--selected-tab-text-decoration-offset);
3450
+ }
3451
+
3099
3452
  .label {
3100
3453
  overflow: var(--allow-overflow, hidden);
3101
3454
  text-overflow: ellipsis;
@@ -3104,10 +3457,29 @@ let TabListItemElement = class TabListItemElement extends LitElement {
3104
3457
  flex: 1 1 auto;
3105
3458
  }
3106
3459
 
3460
+ /* Width sizer: an invisible copy of the label, always set at the
3461
+ selected weight, so activating a tab (bold) never shifts the strip.
3462
+ Text is mirrored from the default slot via the data-label attribute
3463
+ (see _syncLabelSizer). */
3464
+ .label::after {
3465
+ content: attr(data-label);
3466
+ display: block;
3467
+ height: 0;
3468
+ overflow: hidden;
3469
+ visibility: hidden;
3470
+ font-weight: var(--selected-tab-weight);
3471
+ }
3472
+
3107
3473
  ixfx-icon {
3108
3474
  flex-shrink: 0;
3109
3475
  }
3110
3476
 
3477
+ /* Leading icon (direct child — not close/toolbar icons) picks up the
3478
+ accent when selected, so icon-only tabs read as active. */
3479
+ :host([selected]) > div > ixfx-icon {
3480
+ color: var(--selected-tab-icon-color);
3481
+ }
3482
+
3111
3483
  .actions {
3112
3484
  display: flex;
3113
3485
  align-items: center;
@@ -3203,6 +3575,7 @@ let DockPanelElement = class DockPanelElement extends LitElement {
3203
3575
  this.iconName = ``;
3204
3576
  this.closable = false;
3205
3577
  this.collapsible = false;
3578
+ this.kind = `any`;
3206
3579
  this.accepts = ``;
3207
3580
  this.presentation = `solo`;
3208
3581
  this._collapsed = false;
@@ -3256,6 +3629,10 @@ let DockPanelElement = class DockPanelElement extends LitElement {
3256
3629
  }
3257
3630
  connectedCallback() {
3258
3631
  super.connectedCallback();
3632
+ if (this.hasAttribute(`title`)) {
3633
+ if (!this.hasAttribute(`label`)) this.title = this.getAttribute(`title`) ?? ``;
3634
+ this.removeAttribute(`title`);
3635
+ }
3259
3636
  this.addEventListener(`pointerdown`, this._onPointerDown);
3260
3637
  }
3261
3638
  disconnectedCallback() {
@@ -3347,13 +3724,20 @@ __decorate([property({
3347
3724
  attribute: `panel-id`,
3348
3725
  reflect: true
3349
3726
  })], DockPanelElement.prototype, "panelId", void 0);
3350
- __decorate([property({ type: String })], DockPanelElement.prototype, "title", void 0);
3727
+ __decorate([property({
3728
+ type: String,
3729
+ attribute: `label`
3730
+ })], DockPanelElement.prototype, "title", void 0);
3351
3731
  __decorate([property({
3352
3732
  type: String,
3353
3733
  attribute: `icon-name`
3354
3734
  })], DockPanelElement.prototype, "iconName", void 0);
3355
3735
  __decorate([property({ type: Boolean })], DockPanelElement.prototype, "closable", void 0);
3356
3736
  __decorate([property({ type: Boolean })], DockPanelElement.prototype, "collapsible", void 0);
3737
+ __decorate([property({
3738
+ type: String,
3739
+ reflect: true
3740
+ })], DockPanelElement.prototype, "kind", void 0);
3357
3741
  __decorate([property({
3358
3742
  type: String,
3359
3743
  attribute: `accepts`
@@ -3385,13 +3769,16 @@ let DockHostElement = class DockHostElement extends LitElement {
3385
3769
  this._dragActive = false;
3386
3770
  this._junctions = [];
3387
3771
  this._toolbarsOut = /* @__PURE__ */ new Map();
3772
+ this._leafContentRules = /* @__PURE__ */ new Map();
3388
3773
  this._tabDragPending = null;
3389
3774
  this._junctionsKey = ``;
3390
3775
  this._junctionsRaf = null;
3391
3776
  this._hostResizeObserver = null;
3777
+ this._toolbarSlots = /* @__PURE__ */ new Set();
3778
+ this._toolbarObserver = null;
3392
3779
  this._onDragStart = (event) => {
3393
3780
  const { panelId, pointerId, clientX, clientY } = event.detail;
3394
- startDrag(panelId, this, pointerId, clientX, clientY);
3781
+ startDrag(panelId, this, pointerId, clientX, clientY, this._findPanelEl(panelId)?.kind);
3395
3782
  };
3396
3783
  this._onPoolSlotChange = () => {
3397
3784
  this._syncPool();
@@ -3438,11 +3825,12 @@ let DockHostElement = class DockHostElement extends LitElement {
3438
3825
  const pathStr = this.shadowRoot?.getElementById(detail.id)?.getAttribute(`data-dock-path`);
3439
3826
  if (pathStr === null || pathStr === void 0) return;
3440
3827
  const path = parsePath(pathStr);
3441
- const paths = collectStackPaths(this._model).filter((p) => p.join(`-`) !== path.join(`-`));
3442
- const fallbackNode = paths.length > 0 ? findNode(this._model, paths[0]) : null;
3443
- const fallback = fallbackNode !== null && isStack(fallbackNode) ? fallbackNode : void 0;
3828
+ const closing = findNode(this._model, path);
3829
+ if (closing === null || !isStack(closing)) return;
3830
+ const moving = [...closing.panels];
3444
3831
  this._returnAllToolbars();
3445
- extractStack(this._model, path, fallback);
3832
+ extractStack(this._model, path);
3833
+ for (const panelId of moving) addPanelToStack(this._firstStackAllowing(this._panelKind(panelId)), panelId);
3446
3834
  this._commit();
3447
3835
  };
3448
3836
  this._onTabChange = (event, path) => {
@@ -3507,11 +3895,21 @@ let DockHostElement = class DockHostElement extends LitElement {
3507
3895
  this.addEventListener(`dock-panel-drag-start`, this._onDragStart);
3508
3896
  this._hostResizeObserver = new ResizeObserver(() => this._scheduleJunctions());
3509
3897
  this._hostResizeObserver.observe(this);
3898
+ this._scanToolbarSlots();
3899
+ this._toolbarObserver = new MutationObserver(() => this._scanToolbarSlots());
3900
+ this._toolbarObserver.observe(this, {
3901
+ childList: true,
3902
+ subtree: true,
3903
+ attributes: true,
3904
+ attributeFilter: [`slot`]
3905
+ });
3510
3906
  }
3511
3907
  disconnectedCallback() {
3512
3908
  super.disconnectedCallback();
3513
3909
  unregisterDockHost(this);
3514
3910
  this.removeEventListener(`dock-panel-drag-start`, this._onDragStart);
3911
+ this._toolbarObserver?.disconnect();
3912
+ this._toolbarObserver = null;
3515
3913
  this._hostResizeObserver?.disconnect();
3516
3914
  this._hostResizeObserver = null;
3517
3915
  if (this._junctionsRaf !== null) {
@@ -3564,6 +3962,19 @@ let DockHostElement = class DockHostElement extends LitElement {
3564
3962
  _scanPanels() {
3565
3963
  return Array.from(this.children).filter((el) => el instanceof HTMLElement && el.tagName === `IXFX-DOCK-PANEL` && Boolean(el.panelId));
3566
3964
  }
3965
+ /** Refresh the set of provided `toolbar-<name>` slots; re-render on change. */
3966
+ _scanToolbarSlots() {
3967
+ const found = /* @__PURE__ */ new Set();
3968
+ for (const child of this.children) {
3969
+ if (!(child instanceof HTMLElement)) continue;
3970
+ const slot = child.getAttribute(`slot`) ?? ``;
3971
+ if (slot.startsWith(`toolbar-`) && slot.length > `toolbar-`.length) found.add(slot);
3972
+ }
3973
+ if (found.size !== this._toolbarSlots.size || [...found].some((s) => !this._toolbarSlots.has(s))) {
3974
+ this._toolbarSlots = found;
3975
+ this.requestUpdate();
3976
+ }
3977
+ }
3567
3978
  _findPanelEl(panelId) {
3568
3979
  return this._pool.find((p) => p.panelId === panelId) ?? this._scanPanels().find((p) => p.panelId === panelId);
3569
3980
  }
@@ -3577,7 +3988,33 @@ let DockHostElement = class DockHostElement extends LitElement {
3577
3988
  return fresh;
3578
3989
  }
3579
3990
  _appendPanelToFirstStack(panelId) {
3580
- addPanelToStack(this._model.kind === `stack` ? this._model : this._firstStack(), panelId);
3991
+ const kind = this._panelKind(panelId);
3992
+ if (this._model.kind === `stack` && this._stackAllowsKind(this._model, kind)) {
3993
+ addPanelToStack(this._model, panelId);
3994
+ return;
3995
+ }
3996
+ addPanelToStack(this._firstStackAllowing(kind), panelId);
3997
+ }
3998
+ /** Normalized content kind of a panel (`'any'` when unknown/unset). */
3999
+ _panelKind(panelId) {
4000
+ return normalizeKind(this._findPanelEl(panelId)?.kind);
4001
+ }
4002
+ /** Whether `kind` may live in `stack` under the current leaf rules. */
4003
+ _stackAllowsKind(stack, kind) {
4004
+ if (stack.name === void 0) return true;
4005
+ const rules = this._leafContentRules.get(stack.name);
4006
+ if (rules === void 0) return true;
4007
+ if (rules.deny.has(kind)) return false;
4008
+ return rules.allow === null || rules.allow.has(kind);
4009
+ }
4010
+ /** First stack (tree order) whose rules admit `kind`, else the first stack. */
4011
+ _firstStackAllowing(kind) {
4012
+ for (const path of collectStackPaths(this._model)) {
4013
+ const node = findNode(this._model, path);
4014
+ if (node !== null && isStack(node) && this._stackAllowsKind(node, kind)) return node;
4015
+ }
4016
+ console.warn(`[ixfx-dock-host] no leaf admits kind "${kind}", using first stack`);
4017
+ return this._firstStack();
3581
4018
  }
3582
4019
  _syncPool() {
3583
4020
  const current = this._scanPanels();
@@ -3619,7 +4056,34 @@ let DockHostElement = class DockHostElement extends LitElement {
3619
4056
  this.requestUpdate();
3620
4057
  this._emitChange();
3621
4058
  }
4059
+ /**
4060
+ * Dock a panel. Returns false (without touching the DOM) when the
4061
+ * explicitly targeted container denies the panel's `kind`.
4062
+ */
3622
4063
  addPanel(panel, target) {
4064
+ const kind = panel instanceof HTMLElement ? normalizeKind(panel.kind) : normalizeKind(panel.kind);
4065
+ const op = target?.op ?? `tabs`;
4066
+ let stackPath = null;
4067
+ let splitTarget = null;
4068
+ if (target?.container !== void 0) {
4069
+ const namedPath = findStackPathByName(this._model, target.container);
4070
+ if (namedPath === null) console.warn(`[ixfx-dock-host] addPanel: unknown container "${target.container}", appending to first admitting stack`);
4071
+ else if (op === `tabs` && !this._stackAllowsKindAt(namedPath, kind)) {
4072
+ console.warn(`[ixfx-dock-host] addPanel: container "${target.container}" does not admit kind "${kind}"`);
4073
+ return false;
4074
+ } else stackPath = namedPath;
4075
+ } else if (target?.stack) {
4076
+ const found = findStackOf(this._model, target.stack);
4077
+ if (found === null) console.warn(`[ixfx-dock-host] addPanel: unknown stack panel "${target.stack}", appending to first admitting stack`);
4078
+ else if (op === `tabs` && !this._stackAllowsKindAt(found, kind)) {
4079
+ console.warn(`[ixfx-dock-host] addPanel: target stack does not admit kind "${kind}"`);
4080
+ return false;
4081
+ } else stackPath = found;
4082
+ }
4083
+ if (stackPath !== null && op !== `tabs`) {
4084
+ splitTarget = stackPath;
4085
+ stackPath = null;
4086
+ }
3623
4087
  let el;
3624
4088
  if (panel instanceof HTMLElement) el = panel;
3625
4089
  else {
@@ -3629,19 +4093,16 @@ let DockHostElement = class DockHostElement extends LitElement {
3629
4093
  if (panel.iconName !== void 0) el.iconName = panel.iconName;
3630
4094
  if (panel.closable !== void 0) el.closable = panel.closable;
3631
4095
  if (panel.collapsible !== void 0) el.collapsible = panel.collapsible;
4096
+ if (panel.kind !== void 0) el.kind = panel.kind;
3632
4097
  }
3633
4098
  if (el.parentElement !== this) this.appendChild(el);
3634
4099
  if (!this._pool.some((p) => p.panelId === el.panelId)) this._pool = [...this._pool, el];
3635
4100
  this._returnAllToolbars();
3636
- const op = target?.op ?? `tabs`;
3637
- if (target?.stack) {
3638
- const stackPath = findStackOf(this._model, target.stack);
3639
- if (stackPath !== null) {
3640
- if (op === `tabs`) {
3641
- const stack = findNode(this._model, stackPath);
3642
- if (stack !== null && isStack(stack)) addPanelToStack(stack, el.panelId, target.index);
3643
- } else insertBeside(this._model, stackPath, opToDirection(op), createStack([el.panelId]), `after`);
3644
- }
4101
+ if (collectPanelIds(this._model).includes(el.panelId)) this._removeFromModel(el.panelId);
4102
+ if (splitTarget !== null) insertBeside(this._model, splitTarget, opToDirection(op), createStack([el.panelId]), `after`);
4103
+ else if (stackPath !== null) {
4104
+ const stack = findNode(this._model, stackPath);
4105
+ if (stack !== null && isStack(stack)) addPanelToStack(stack, el.panelId, target?.index);
3645
4106
  } else this._appendPanelToFirstStack(el.panelId);
3646
4107
  normalize(this._model);
3647
4108
  this.requestUpdate();
@@ -3651,6 +4112,12 @@ let DockHostElement = class DockHostElement extends LitElement {
3651
4112
  composed: true
3652
4113
  }));
3653
4114
  this._emitChange();
4115
+ return true;
4116
+ }
4117
+ /** Whether the stack at `stackPath` admits `kind` under the leaf rules. */
4118
+ _stackAllowsKindAt(stackPath, kind) {
4119
+ const stack = findNode(this._model, stackPath);
4120
+ return stack !== null && isStack(stack) && this._stackAllowsKind(stack, kind);
3654
4121
  }
3655
4122
  removePanel(panelId) {
3656
4123
  if (!collectPanelIds(this._model).includes(panelId)) return false;
@@ -3686,6 +4153,123 @@ let DockHostElement = class DockHostElement extends LitElement {
3686
4153
  getPanelIds() {
3687
4154
  return collectPanelIds(this._model);
3688
4155
  }
4156
+ /** Names of every named stack leaf, in tree order. */
4157
+ getContainerNames() {
4158
+ return collectContainerNames(this._model);
4159
+ }
4160
+ /**
4161
+ * Snapshot of a named container (`{ name, panels, active }`), or null when
4162
+ * no stack carries that name. First match wins when duplicated.
4163
+ */
4164
+ getContainer(name) {
4165
+ const path = findStackPathByName(this._model, name);
4166
+ if (path === null) return null;
4167
+ const node = findNode(this._model, path);
4168
+ if (node === null || !isStack(node) || node.name === void 0) return null;
4169
+ return {
4170
+ name: node.name,
4171
+ panels: [...node.panels],
4172
+ active: node.active
4173
+ };
4174
+ }
4175
+ /** Panel-ids in a named container, in tab order (`[]` when unknown/empty). */
4176
+ getContainerPanels(name) {
4177
+ return this.getContainer(name)?.panels ?? [];
4178
+ }
4179
+ /** Panel elements in a named container, in tab order — for iterating children. */
4180
+ getContainerElements(name) {
4181
+ return this.getContainerPanels(name).map((id) => this._findPanelEl(id)).filter((el) => el !== void 0);
4182
+ }
4183
+ /**
4184
+ * Restrict a named container to only the given panel kinds — e.g.
4185
+ * `setLeafExclusiveContents('editor', ['document'])`. `tabs` drops,
4186
+ * `addPanel`, and re-homing into the leaf then refuse other kinds, while
4187
+ * edge splits beside the leaf stay allowed (they create a new leaf).
4188
+ * Pass `[]` to seal the leaf (nothing admitted). Warns when no stack
4189
+ * currently carries `name`, but the rule is still stored and applies once
4190
+ * one appears. Rules are host policy: kept across `loadLayout()`, never
4191
+ * serialized.
4192
+ */
4193
+ setLeafExclusiveContents(name, kinds) {
4194
+ const key = name.trim();
4195
+ if (!key) {
4196
+ console.warn(`[ixfx-dock-host] setLeafExclusiveContents: empty container name`);
4197
+ return;
4198
+ }
4199
+ const allow = new Set(kinds.map((k) => k.trim()).filter((k) => k.length > 0));
4200
+ const entry = this._leafContentRules.get(key) ?? {
4201
+ allow: null,
4202
+ deny: /* @__PURE__ */ new Set()
4203
+ };
4204
+ entry.allow = allow;
4205
+ this._leafContentRules.set(key, entry);
4206
+ if (findStackPathByName(this._model, key) === null) console.warn(`[ixfx-dock-host] setLeafExclusiveContents: no container named "${key}" yet; rule stored`);
4207
+ }
4208
+ /**
4209
+ * Forbid the given panel kinds in a named container — e.g.
4210
+ * `setLeafDenyContents('footer', ['files', 'document'])`. Everything else
4211
+ * stays admitted. Pass `[]` to lift the denial. See
4212
+ * {@link setLeafExclusiveContents} for scope/ordering notes.
4213
+ */
4214
+ setLeafDenyContents(name, kinds) {
4215
+ const key = name.trim();
4216
+ if (!key) {
4217
+ console.warn(`[ixfx-dock-host] setLeafDenyContents: empty container name`);
4218
+ return;
4219
+ }
4220
+ const deny = new Set(kinds.map((k) => k.trim()).filter((k) => k.length > 0));
4221
+ const entry = this._leafContentRules.get(key) ?? {
4222
+ allow: null,
4223
+ deny: /* @__PURE__ */ new Set()
4224
+ };
4225
+ entry.deny = deny;
4226
+ if (entry.allow === null && entry.deny.size === 0) this._leafContentRules.delete(key);
4227
+ else this._leafContentRules.set(key, entry);
4228
+ if (findStackPathByName(this._model, key) === null) console.warn(`[ixfx-dock-host] setLeafDenyContents: no container named "${key}" yet; rule stored`);
4229
+ }
4230
+ /** Remove every content rule for a named container. */
4231
+ clearLeafContentRestrictions(name) {
4232
+ this._leafContentRules.delete(name.trim());
4233
+ }
4234
+ /** Copy of a container's rules, or null when unrestricted. */
4235
+ getLeafContentRestrictions(name) {
4236
+ const rules = this._leafContentRules.get(name.trim());
4237
+ if (rules === void 0) return null;
4238
+ return {
4239
+ allow: rules.allow === null ? null : [...rules.allow],
4240
+ deny: [...rules.deny]
4241
+ };
4242
+ }
4243
+ /**
4244
+ * Geometric neighbours of a leaf (`name` or numeric `path`) — what sits
4245
+ * above / below / left / right of it on screen. Each entry is
4246
+ * `{ name, path }` (`name` is null for unnamed leaves), ordered
4247
+ * most-overlapping first. Returns null when the leaf is unknown.
4248
+ */
4249
+ getNeighbours(leaf) {
4250
+ return getLeafNeighbours(this._model, leaf);
4251
+ }
4252
+ /**
4253
+ * Move a leaf one position in `direction`, swapping with the neighbour it
4254
+ * shares the longest edge with (both keep the remaining structure intact).
4255
+ * Returns false when the leaf is unknown or nothing adjoins that way.
4256
+ */
4257
+ moveLeaf(leaf, direction) {
4258
+ if (!moveLeafStep(this._model, leaf, direction)) return false;
4259
+ this._commit();
4260
+ return true;
4261
+ }
4262
+ /**
4263
+ * Move a leaf to an edge of the overall layout (e.g. toggle a sidebar from
4264
+ * `left` to `right`). The rest of the layout stays intact as a single
4265
+ * subtree and the leaf keeps its absolute size along the target axis.
4266
+ * Returns false when the leaf is unknown or the layout holds one leaf.
4267
+ */
4268
+ moveLeafToEdge(leaf, edge) {
4269
+ if (!moveLeafNodeToEdge(this._model, leaf, edge)) return false;
4270
+ this._commit();
4271
+ return true;
4272
+ }
3689
4273
  /**
3690
4274
  * Capture a structured-clone-safe {@link DockPanelSnapshot} of a panel
3691
4275
  * (identity, chrome attributes, and a best-effort `innerHTML`). Returns
@@ -3700,6 +4284,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3700
4284
  iconName: el.iconName,
3701
4285
  closable: el.closable,
3702
4286
  collapsible: el.collapsible,
4287
+ kind: normalizeKind(el.kind),
3703
4288
  accepts: el.accepts,
3704
4289
  contentHTML: el.innerHTML
3705
4290
  };
@@ -3723,10 +4308,11 @@ let DockHostElement = class DockHostElement extends LitElement {
3723
4308
  * `accepts` / `canAccept`. Pure query: no model mutation, no overlay.
3724
4309
  *
3725
4310
  * `panelId` is passed to `canAccept`; use any stable id for an external
3726
- * panel (defaults to `"__external__"`).
4311
+ * panel (defaults to `"__external__"`). `kind` covers leaf content rules
4312
+ * for panels unknown to this host (defaults to `'any'`).
3727
4313
  */
3728
- queryDropTarget(clientX, clientY, panelId = `__external__`) {
3729
- const zone = this.computeDropZone(clientX, clientY, panelId);
4314
+ queryDropTarget(clientX, clientY, panelId = `__external__`, kind) {
4315
+ const zone = this.computeDropZone(clientX, clientY, panelId, kind);
3730
4316
  return zone === null ? null : zoneToTarget(zone);
3731
4317
  }
3732
4318
  /**
@@ -3735,9 +4321,9 @@ let DockHostElement = class DockHostElement extends LitElement {
3735
4321
  * one. Call on every pointer update from the outer coordinator, then
3736
4322
  * {@link endExternalDrop} when the drag leaves or ends.
3737
4323
  */
3738
- previewExternalDrop(clientX, clientY, panelId = `__external__`) {
4324
+ previewExternalDrop(clientX, clientY, panelId = `__external__`, kind) {
3739
4325
  this.setDragActive(true);
3740
- const zone = this.computeDropZone(clientX, clientY, panelId);
4326
+ const zone = this.computeDropZone(clientX, clientY, panelId, kind);
3741
4327
  this.setDropZone(zone);
3742
4328
  return zone === null ? null : zoneToTarget(zone);
3743
4329
  }
@@ -3750,8 +4336,9 @@ let DockHostElement = class DockHostElement extends LitElement {
3750
4336
  * Recreate a panel from a {@link DockPanelSnapshot} (or a bare
3751
4337
  * {@link DockPanelInit}) and dock it. With `at` viewport coordinates the
3752
4338
  * panel lands where a drop there would put it (respecting `accepts` /
3753
- * `canAccept`); without them, or when the point misses the host, it goes
3754
- * into the first stack. Returns the created element, or null when a panel
4339
+ * `canAccept` and leaf content rules); without them, or when the point
4340
+ * misses the host, it goes into the first stack admitting its kind.
4341
+ * Returns the created element, or null when a panel
3755
4342
  * with that id is already docked here.
3756
4343
  */
3757
4344
  acceptExternalPanel(snapshot, at) {
@@ -3762,6 +4349,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3762
4349
  if (snapshot.iconName !== void 0) el.iconName = snapshot.iconName;
3763
4350
  if (snapshot.closable !== void 0) el.closable = snapshot.closable;
3764
4351
  if (snapshot.collapsible !== void 0) el.collapsible = snapshot.collapsible;
4352
+ if (`kind` in snapshot && snapshot.kind !== void 0) el.kind = snapshot.kind;
3765
4353
  if (`accepts` in snapshot && snapshot.accepts) el.setAttribute(`accepts`, snapshot.accepts);
3766
4354
  if (`contentHTML` in snapshot && snapshot.contentHTML) el.innerHTML = snapshot.contentHTML;
3767
4355
  this._returnAllToolbars();
@@ -3787,9 +4375,10 @@ let DockHostElement = class DockHostElement extends LitElement {
3787
4375
  * a zone with rects relative to the host, or null when the pointer is
3788
4376
  * outside the host or the candidate zone is disallowed.
3789
4377
  */
3790
- computeDropZone(clientX, clientY, panelId) {
4378
+ computeDropZone(clientX, clientY, panelId, kind) {
3791
4379
  const hostRect = this.getBoundingClientRect();
3792
4380
  if (clientX < hostRect.left || clientX > hostRect.right || clientY < hostRect.top || clientY > hostRect.bottom) return null;
4381
+ const resolvedKind = kind?.trim() ? kind.trim() : this._panelKind(panelId);
3793
4382
  const rel = (r) => ({
3794
4383
  x: r.left - hostRect.left,
3795
4384
  y: r.top - hostRect.top,
@@ -3817,7 +4406,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3817
4406
  rect: rel(leafRect),
3818
4407
  caretRect: this._stripCaretRect(strip, gapIndex, hostRect)
3819
4408
  };
3820
- return this._zoneAllowed(panelId, zone) ? zone : null;
4409
+ return this._zoneAllowed(panelId, zone, resolvedKind) ? zone : null;
3821
4410
  }
3822
4411
  }
3823
4412
  const relX = (clientX - leafRect.left) / Math.max(leafRect.width, 1);
@@ -3831,7 +4420,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3831
4420
  gapIndex: stack.panels.length,
3832
4421
  rect: rel(leafRect)
3833
4422
  };
3834
- return this._zoneAllowed(panelId, zone) ? zone : null;
4423
+ return this._zoneAllowed(panelId, zone, resolvedKind) ? zone : null;
3835
4424
  }
3836
4425
  const r = rel(leafRect);
3837
4426
  let operation;
@@ -3877,7 +4466,7 @@ let DockHostElement = class DockHostElement extends LitElement {
3877
4466
  side,
3878
4467
  rect: zoneRect
3879
4468
  };
3880
- return this._zoneAllowed(panelId, zone) ? zone : null;
4469
+ return this._zoneAllowed(panelId, zone, resolvedKind) ? zone : null;
3881
4470
  }
3882
4471
  const fromLeft = clientX - hostRect.left;
3883
4472
  const fromRight = hostRect.right - clientX;
@@ -3933,15 +4522,18 @@ let DockHostElement = class DockHostElement extends LitElement {
3933
4522
  side,
3934
4523
  rect: zoneRect
3935
4524
  };
3936
- return this._zoneAllowed(panelId, zone) ? zone : null;
4525
+ return this._zoneAllowed(panelId, zone, resolvedKind) ? zone : null;
3937
4526
  }
3938
- _zoneAllowed(panelId, zone) {
4527
+ _zoneAllowed(panelId, zone, kind) {
3939
4528
  if (!tokenAllows(this.accepts, operationToToken(zone.operation))) return false;
3940
4529
  const stack = findNode(this._model, zone.targetPath);
3941
4530
  if (stack !== null && isStack(stack) && stack.panels.length === 1) {
3942
4531
  const target = this._findPanelEl(stack.panels[0]);
3943
4532
  if (target && !panelAllows(target.accepts, operationToToken(zone.operation))) return false;
3944
4533
  }
4534
+ if (zone.operation === `tabs` && stack !== null && isStack(stack)) {
4535
+ if (!this._stackAllowsKind(stack, kind?.trim() ? kind.trim() : this._panelKind(panelId))) return false;
4536
+ }
3945
4537
  if (this.canAccept && !this.canAccept(panelId, zone.operation)) return false;
3946
4538
  return true;
3947
4539
  }
@@ -3956,22 +4548,32 @@ let DockHostElement = class DockHostElement extends LitElement {
3956
4548
  this._appendPanelToFirstStack(panelId);
3957
4549
  normalize(this._model);
3958
4550
  }
3959
- this._applyZone(panelId, zone);
4551
+ this._applyZone(panelId, zone, sourceHost === void 0 || sourceHost === this);
3960
4552
  this._commit();
3961
4553
  }
3962
4554
  /**
3963
4555
  * Move `panelId` (already present somewhere in the model) to the position
3964
4556
  * described by `zone`. Shared by in-page drops and external panel adoption.
3965
4557
  */
3966
- _applyZone(panelId, zone) {
4558
+ _applyZone(panelId, zone, transferName = false) {
3967
4559
  const sourcePath = findStackOf(this._model, panelId);
4560
+ let vacated = null;
3968
4561
  if (sourcePath !== null) {
3969
4562
  const source = findNode(this._model, sourcePath);
3970
- if (source !== null && isStack(source)) removePanelFromStack(source, panelId);
4563
+ if (source !== null && isStack(source)) {
4564
+ removePanelFromStack(source, panelId);
4565
+ if (source.panels.length === 0) vacated = source;
4566
+ }
3971
4567
  }
3972
4568
  if (zone.operation === `tabs`) {
3973
4569
  const target = findNode(this._model, zone.targetPath);
3974
- if (target !== null && isStack(target)) addPanelToStack(target, panelId, zone.gapIndex);
4570
+ if (target !== null && isStack(target)) {
4571
+ addPanelToStack(target, panelId, zone.gapIndex);
4572
+ if (transferName && vacated !== null && vacated !== target && vacated.name !== void 0 && target.name === void 0) {
4573
+ target.name = vacated.name;
4574
+ delete vacated.name;
4575
+ }
4576
+ }
3975
4577
  } else insertBeside(this._model, zone.targetPath, opToDirection(zone.operation), createStack([panelId]), zone.side);
3976
4578
  }
3977
4579
  /**
@@ -4107,16 +4709,6 @@ let DockHostElement = class DockHostElement extends LitElement {
4107
4709
  };
4108
4710
  window.addEventListener(`click`, swallow, true);
4109
4711
  }
4110
- _splitStack(path, op) {
4111
- const stack = findNode(this._model, path);
4112
- if (stack === null || !isStack(stack) || stack.panels.length === 0) return;
4113
- const activeId = stack.active;
4114
- this._returnAllToolbars();
4115
- removePanelFromStack(stack, activeId);
4116
- normalize(this._model);
4117
- insertBeside(this._model, path, opToDirection(op), createStack([activeId]), `after`);
4118
- this._commit();
4119
- }
4120
4712
  _removeFromModel(panelId) {
4121
4713
  const stackPath = findStackOf(this._model, panelId);
4122
4714
  if (stackPath === null) return;
@@ -4247,6 +4839,7 @@ let DockHostElement = class DockHostElement extends LitElement {
4247
4839
  id=${`dock-leaf-${pathStr}`}
4248
4840
  class="leaf"
4249
4841
  data-dock-path=${pathStr}
4842
+ data-dock-name=${stack.name ?? nothing}
4250
4843
  size=${size === void 0 ? nothing : String(size)}
4251
4844
  min=${collapsible ? `1px` : nothing}
4252
4845
  when-small=${collapsible ? `collapse` : nothing}
@@ -4258,26 +4851,19 @@ let DockHostElement = class DockHostElement extends LitElement {
4258
4851
  <slot name="empty"><span>Drop panels here</span></slot>
4259
4852
  </div>
4260
4853
  `);
4854
+ const toolbarSlot = stack.name !== void 0 && this._toolbarSlots.has(`toolbar-${stack.name}`) ? html`<slot name="toolbar-${stack.name}" slot="toolbar"></slot>` : nothing;
4261
4855
  return leafAttrs(html`
4262
4856
  <ixfx-tab-list
4263
4857
  class="strip"
4264
4858
  orientation="horizontal"
4859
+ scrollable
4860
+ shrink
4861
+ ?hide-labels=${stack.hideLabels === true}
4265
4862
  @change=${(e) => this._onTabChange(e, path)}
4266
4863
  @pointerdown=${this._onStripPointerDown}
4267
4864
  >
4268
4865
  ${repeat(stack.panels, (id) => id, (id) => this._renderTabItem(stack, id))}
4269
- <div slot="toolbar" class="group-toolbar">
4270
- <button
4271
- class="chrome-btn"
4272
- title="Split horizontally (top/bottom)"
4273
- @click=${() => this._splitStack(path, `split-horizontal`)}
4274
- >↕</button>
4275
- <button
4276
- class="chrome-btn"
4277
- title="Split vertically (left/right)"
4278
- @click=${() => this._splitStack(path, `split-vertical`)}
4279
- >↔</button>
4280
- </div>
4866
+ ${toolbarSlot}
4281
4867
  </ixfx-tab-list>
4282
4868
  <div class="leaf-body">
4283
4869
  <slot name="dock-panel-${stack.active}"></slot>
@@ -4357,9 +4943,14 @@ let DockHostElement = class DockHostElement extends LitElement {
4357
4943
  .strip {
4358
4944
  flex-shrink: 0;
4359
4945
  border: 0;
4360
- /* The leaf background shows through selected tabs; the accent
4361
- underline indicator carries the selection. */
4946
+ /* The leaf background shows through selected tabs; a text underline
4947
+ (not the border indicator) carries the selection. */
4362
4948
  --ixfx-tab-selected-background: transparent;
4949
+ --ixfx-selected-tab-border-width: 0;
4950
+ --ixfx-selected-tab-text-decoration: underline;
4951
+ --ixfx-selected-tab-text-decoration-thickness: 2px;
4952
+ --ixfx-selected-tab-text-decoration-offset: 4px;
4953
+ --ixfx-tab-hover-background: var(--surface-4);
4363
4954
  }
4364
4955
 
4365
4956
  /* Uniform tab height: a panel toolbar button would otherwise inflate
@@ -4368,6 +4959,11 @@ let DockHostElement = class DockHostElement extends LitElement {
4368
4959
  height: var(--dock-tab-height, 30px);
4369
4960
  }
4370
4961
 
4962
+ /* Breathing room between strip toolbars and the leaf edge. */
4963
+ .strip::part(list-toolbar) {
4964
+ padding-right: var(--space-xs);
4965
+ }
4966
+
4371
4967
  .leaf-body {
4372
4968
  flex: 1;
4373
4969
  min-height: 0;
@@ -4389,38 +4985,6 @@ let DockHostElement = class DockHostElement extends LitElement {
4389
4985
  margin: var(--space-s);
4390
4986
  }
4391
4987
 
4392
- .group-toolbar {
4393
- display: flex;
4394
- gap: 2px;
4395
- padding: 0 var(--space-xs);
4396
- }
4397
-
4398
- .chrome-btn {
4399
- display: inline-flex;
4400
- align-items: center;
4401
- justify-content: center;
4402
- width: 1.6em;
4403
- height: 1.6em;
4404
- padding: 0;
4405
- background: none;
4406
- border: none;
4407
- border-radius: var(--radius-s);
4408
- color: inherit;
4409
- cursor: pointer;
4410
- opacity: var(--prominence-idle-opacity);
4411
- transition: background var(--transition), opacity var(--transition);
4412
- }
4413
-
4414
- .chrome-btn:hover {
4415
- background: var(--surface-5);
4416
- opacity: var(--prominence-tickled-opacity);
4417
- }
4418
-
4419
- .chrome-btn:focus-visible {
4420
- outline: 2px solid var(--accent);
4421
- outline-offset: 1px;
4422
- }
4423
-
4424
4988
  .overlay {
4425
4989
  position: absolute;
4426
4990
  inset: 0;
@@ -4537,6 +5101,10 @@ function zoneToTarget(zone) {
4537
5101
  function cloneNode(node) {
4538
5102
  return JSON.parse(JSON.stringify(node));
4539
5103
  }
5104
+ /** Panel content kind, normalized (`'any'` when unset/blank). */
5105
+ function normalizeKind(kind) {
5106
+ return (kind?.trim() ?? ``) || `any`;
5107
+ }
4540
5108
  function parsePath(pathStr) {
4541
5109
  return pathStr.length === 0 ? [] : pathStr.split(`-`).filter((s) => s.length > 0).map(Number);
4542
5110
  }
@@ -7900,6 +8468,6 @@ function init() {
7900
8468
  console.log(`Init`);
7901
8469
  }
7902
8470
  //#endregion
7903
- export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, 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, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, buildHighlightTargets, buildModel, clearHighlights, collectDataResult, collectPanelIds, collectStackPaths, computeColour, createAcCompletionProvider, createElementIncrSearch, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, getActiveDragPanelId, getIcon, hasIcon, iconBus, init, insertBeside, isDragging, isSplit, isStack, monitorIndeterminate, normalise, normalize, parseColourScaleAttr, parseLayout, pointerOverAnyHost, readBaseColour, registerIcon, removePanelFromStack, resolveCssVars, resolveGrid, resolveTracks, serializeLayout, setActive, svgToDataUri, timelineStyles, toSnapshot, walk, wrapRoot };
8471
+ export { AcTextElement, AcTokenElement, ButtonElement, Checkbox, ColourPicker, ColourPickerPopup, CrumbNavigationElement, CrumbPathController, CrumbPathElement, DataController, DataDisplayComponent, DataGridElement, DetailListElement, DockHostElement, DockPanelElement, EditableLabel, EditableNumber, FormElement, FormGroupElement, FormPartElement, GroupedItemListerElement, ICON_CARET_RIGHT, ICON_CHECK, ICON_CHEVRON_DOWN, ICON_CLOSE, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, 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, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, buildHighlightTargets, buildModel, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createElementIncrSearch, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isSplit, isStack, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normalize, parseColourScaleAttr, parseLayout, pointerOverAnyHost, readBaseColour, registerFontIcon, registerIcon, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, svgToDataUri, swapLeaves, timelineStyles, toSnapshot, walk, wrapRoot };
7904
8472
 
7905
8473
  //# sourceMappingURL=index.js.map