@ixfx/components 0.10.7 → 0.10.8

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 (89) hide show
  1. package/bundle/index.d.ts +403 -1
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +1459 -158
  4. package/bundle/index.js.map +1 -1
  5. package/dist/ac-text.d.ts +1 -1
  6. package/dist/{ac-token-TCLAZeVg.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
  7. package/dist/{ac-token-TCLAZeVg.d.ts.map → ac-token--_vCHXWw.d.ts.map} +1 -1
  8. package/dist/ac-token.d.ts +1 -1
  9. package/dist/{button-CTL45aBl.d.ts → button-BYuf72aR.d.ts} +2 -2
  10. package/dist/{button-CTL45aBl.d.ts.map → button-BYuf72aR.d.ts.map} +1 -1
  11. package/dist/button.d.ts +1 -1
  12. package/dist/colour-picker.d.ts +1 -1
  13. package/dist/crumbs.d.ts +3 -3
  14. package/dist/{data-grid-BDNjQv3Q.d.ts → data-grid-3yIylIH-.d.ts} +5 -5
  15. package/dist/{data-grid-BDNjQv3Q.d.ts.map → data-grid-3yIylIH-.d.ts.map} +1 -1
  16. package/dist/data-grid.d.ts +2 -2
  17. package/dist/{detail-list-BdLuOwQj.d.ts → detail-list-ccWFyhEc.d.ts} +5 -5
  18. package/dist/{detail-list-BdLuOwQj.d.ts.map → detail-list-ccWFyhEc.d.ts.map} +1 -1
  19. package/dist/detail-list.d.ts +3 -3
  20. package/dist/{grid-list-DyphX9Fv.d.ts → grid-list-BnOVgtLI.d.ts} +4 -4
  21. package/dist/{grid-list-DyphX9Fv.d.ts.map → grid-list-BnOVgtLI.d.ts.map} +1 -1
  22. package/dist/grid-list.d.ts +2 -2
  23. package/dist/{grouped-item-lister-Bhyo-dkH.d.ts → grouped-item-lister-DETte0Dh.d.ts} +2 -2
  24. package/dist/{grouped-item-lister-Bhyo-dkH.d.ts.map → grouped-item-lister-DETte0Dh.d.ts.map} +1 -1
  25. package/dist/grouped-item-lister.d.ts +1 -1
  26. package/dist/{icon-DR_3rSyZ.d.ts → icon-CDGprSdE.d.ts} +2 -2
  27. package/dist/icon-CDGprSdE.d.ts.map +1 -0
  28. package/dist/icons.d.ts +2 -2
  29. package/dist/incr-search.d.ts +1 -1
  30. package/dist/{index-BXafRK-_.d.ts → index-5-cwYpmx.d.ts} +4 -4
  31. package/dist/{index-BXafRK-_.d.ts.map → index-5-cwYpmx.d.ts.map} +1 -1
  32. package/dist/{index-garxxqgV.d.ts → index-CYndvTWH.d.ts} +2 -2
  33. package/dist/{index-garxxqgV.d.ts.map → index-CYndvTWH.d.ts.map} +1 -1
  34. package/dist/{index-BUB5SICW.d.ts → index-CoqtMSd9.d.ts} +2 -2
  35. package/dist/{index-BUB5SICW.d.ts.map → index-CoqtMSd9.d.ts.map} +1 -1
  36. package/dist/{index-C59-JEPl.d.ts → index-RImMNo0r.d.ts} +4 -4
  37. package/dist/{index-C59-JEPl.d.ts.map → index-RImMNo0r.d.ts.map} +1 -1
  38. package/dist/{index-CJ5fshD3.d.ts → index-UvnoZUAo.d.ts} +2 -2
  39. package/dist/{index-CJ5fshD3.d.ts.map → index-UvnoZUAo.d.ts.map} +1 -1
  40. package/dist/{index-BOUaDIW-.d.ts → index-tq6f8007.d.ts} +2 -2
  41. package/dist/{index-BOUaDIW-.d.ts.map → index-tq6f8007.d.ts.map} +1 -1
  42. package/dist/index.d.ts +417 -22
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1299 -40
  45. package/dist/index.js.map +1 -1
  46. package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-DiTme1JO.d.ts} +2 -2
  47. package/dist/{labelled-input-base-Dp_9KP0G.d.ts.map → labelled-input-base-DiTme1JO.d.ts.map} +1 -1
  48. package/dist/labelled-radial-input.d.ts +2 -2
  49. package/dist/labelled-radial-input.d.ts.map +1 -1
  50. package/dist/labelled-range-input.d.ts +1 -1
  51. package/dist/labelled-slider-input.d.ts +1 -1
  52. package/dist/{list-native-drag-controller-BAuWAtyQ.d.ts → list-native-drag-controller-B9reY4uM.d.ts} +2 -2
  53. package/dist/{list-native-drag-controller-BAuWAtyQ.d.ts.map → list-native-drag-controller-B9reY4uM.d.ts.map} +1 -1
  54. package/dist/{menu-item-ZmkXNjek.d.ts → menu-item-CZi9vy5O.d.ts} +2 -2
  55. package/dist/{menu-item-ZmkXNjek.d.ts.map → menu-item-CZi9vy5O.d.ts.map} +1 -1
  56. package/dist/menu.d.ts +2 -2
  57. package/dist/miller.d.ts +3 -3
  58. package/dist/panel.d.ts +1 -1
  59. package/dist/{split-layout-BJEU1W0d.js → split-layout-CXotkdbx.js} +46 -4
  60. package/dist/split-layout-CXotkdbx.js.map +1 -0
  61. package/dist/{split-layout-C5SYbDrq.d.ts → split-layout-JK3xWVX2.d.ts} +2 -2
  62. package/dist/{split-layout-C5SYbDrq.d.ts.map → split-layout-JK3xWVX2.d.ts.map} +1 -1
  63. package/dist/split-layout.d.ts +1 -1
  64. package/dist/split-layout.js +1 -1
  65. package/dist/{tab-list-v8mKX7Fu.d.ts → tab-list-pqfKaVAE.d.ts} +2 -2
  66. package/dist/{tab-list-v8mKX7Fu.d.ts.map → tab-list-pqfKaVAE.d.ts.map} +1 -1
  67. package/dist/tabs.d.ts +1 -1
  68. package/dist/{titlebar-B5zSTZnF.d.ts → titlebar-Tqu-VvMU.d.ts} +2 -2
  69. package/dist/{titlebar-B5zSTZnF.d.ts.map → titlebar-Tqu-VvMU.d.ts.map} +1 -1
  70. package/dist/titlebar.d.ts +1 -1
  71. package/dist/{tree-component-DGmKBbpy.d.ts → tree-component-CMGeqyjZ.d.ts} +2 -2
  72. package/dist/{tree-component-DGmKBbpy.d.ts.map → tree-component-CMGeqyjZ.d.ts.map} +1 -1
  73. package/dist/tree.d.ts +4 -4
  74. package/dist/{types-Bc23SI94.d.ts → types-3Jfcaxvo.d.ts} +8 -1
  75. package/dist/types-3Jfcaxvo.d.ts.map +1 -0
  76. package/dist/{vertical-list-C03PN6lx.d.ts → vertical-list-9dJ1R1hU.d.ts} +3 -3
  77. package/dist/{vertical-list-C03PN6lx.d.ts.map → vertical-list-9dJ1R1hU.d.ts.map} +1 -1
  78. package/dist/vertical-list.d.ts +2 -2
  79. package/docs-user/README.md +1 -0
  80. package/docs-user/data-grid.md +11 -2
  81. package/docs-user/hyperbolic-tree.md +282 -0
  82. package/docs-user/index.json +7 -2
  83. package/docs-user/llms.txt +1 -0
  84. package/docs-user/tree.md +1 -0
  85. package/llms.txt +1 -0
  86. package/package.json +1 -1
  87. package/dist/icon-DR_3rSyZ.d.ts.map +0 -1
  88. package/dist/split-layout-BJEU1W0d.js.map +0 -1
  89. package/dist/types-Bc23SI94.d.ts.map +0 -1
package/bundle/index.js CHANGED
@@ -19133,6 +19133,44 @@ function collectWeights(snapshot, weights, collapsed) {
19133
19133
  if (snapshot.collapsed !== void 0) collapsed.set(snapshot.id, snapshot.collapsed);
19134
19134
  } else if (snapshot.children) for (const child of snapshot.children) collectWeights(child, weights, collapsed);
19135
19135
  }
19136
+ function setPanelRestoreWeight(group, id, restoreWeight) {
19137
+ const children = group.children.map((child) => {
19138
+ if (child.kind === `panel`) return child.id === id ? {
19139
+ ...child,
19140
+ restoreWeight
19141
+ } : child;
19142
+ return setPanelRestoreWeight(child, id, restoreWeight);
19143
+ });
19144
+ return {
19145
+ ...group,
19146
+ children
19147
+ };
19148
+ }
19149
+ function preserveRestoreWeights(previous, next) {
19150
+ if (!previous) return next;
19151
+ const previousById = new Map(previous.children.map((child) => [child.id, child]));
19152
+ const children = next.children.map((child) => {
19153
+ const match = previousById.get(child.id);
19154
+ if (!match || match.kind !== child.kind) return child;
19155
+ if (child.kind === `panel` && match.kind === `panel`) return {
19156
+ ...child,
19157
+ restoreWeight: match.restoreWeight
19158
+ };
19159
+ return preserveRestoreWeights(match, child);
19160
+ });
19161
+ return {
19162
+ ...next,
19163
+ children
19164
+ };
19165
+ }
19166
+ function findPanelNode(group, id) {
19167
+ for (const child of group.children) if (child.kind === `panel`) {
19168
+ if (child.id === id) return child;
19169
+ } else {
19170
+ const found = findPanelNode(child, id);
19171
+ if (found) return found;
19172
+ }
19173
+ }
19136
19174
  function walk(group, visitor) {
19137
19175
  walkInner(group, [], visitor);
19138
19176
  }
@@ -19265,7 +19303,7 @@ let SplitLayoutElement = class SplitLayoutElement extends i {
19265
19303
  _rebuildModel() {
19266
19304
  this._reindexSlots();
19267
19305
  const normalized = normalise(buildModel(this));
19268
- this._model = normalized;
19306
+ this._model = preserveRestoreWeights(this._model, normalized);
19269
19307
  this.requestUpdate();
19270
19308
  }
19271
19309
  get panels() {
@@ -19387,6 +19425,7 @@ let SplitLayoutElement = class SplitLayoutElement extends i {
19387
19425
  if (!panel || panel.collapsed === collapsed) return;
19388
19426
  this._applyingOwnMutation = true;
19389
19427
  if (collapsed) {
19428
+ if (this._model) this._model = setPanelRestoreWeight(this._model, panel.id, panel.weight);
19390
19429
  panel.el.setAttribute(`collapsed`, ``);
19391
19430
  panel.el.setAttribute(`data-collapsed`, ``);
19392
19431
  } else {
@@ -19394,7 +19433,10 @@ let SplitLayoutElement = class SplitLayoutElement extends i {
19394
19433
  panel.el.removeAttribute(`data-collapsed`);
19395
19434
  }
19396
19435
  this._rebuildModel();
19397
- if (!collapsed && revealWeight !== void 0) this._setFlexibleWeight(panel.id, revealWeight);
19436
+ if (!collapsed) {
19437
+ const restoreWeight = revealWeight ?? (this._model ? findPanelNode(this._model, panel.id)?.restoreWeight : void 0);
19438
+ if (restoreWeight !== void 0) this._setFlexibleWeight(panel.id, restoreWeight);
19439
+ }
19398
19440
  this.requestUpdate();
19399
19441
  this._observer?.takeRecords();
19400
19442
  this._applyingOwnMutation = false;
@@ -20987,6 +21029,7 @@ let DockHostElement = class DockHostElement extends i {
20987
21029
  this._junctionsKey = ``;
20988
21030
  this._junctionsRaf = null;
20989
21031
  this._hostResizeObserver = null;
21032
+ this._loadGeneration = 0;
20990
21033
  this._toolbarSlots = /* @__PURE__ */ new Set();
20991
21034
  this._toolbarObserver = null;
20992
21035
  this._panelObservers = /* @__PURE__ */ new Map();
@@ -21304,6 +21347,7 @@ let DockHostElement = class DockHostElement extends i {
21304
21347
  }
21305
21348
  loadLayout(layout) {
21306
21349
  this._returnAllToolbars();
21350
+ this._loadGeneration++;
21307
21351
  this._model = normalize(cloneNode(layout.root));
21308
21352
  this._mergePoolIntoModel();
21309
21353
  this.requestUpdate();
@@ -22005,12 +22049,18 @@ let DockHostElement = class DockHostElement extends i {
22005
22049
  const splits = this.shadowRoot?.querySelectorAll(`ixfx-split-layout[data-dock-path]`);
22006
22050
  if (splits === void 0) return;
22007
22051
  for (const el of splits) {
22052
+ if (el.getAttribute(`data-dock-gen`) !== String(this._loadGeneration)) continue;
22008
22053
  const pathStr = el.getAttribute(`data-dock-path`);
22009
22054
  if (pathStr === null) continue;
22010
22055
  const node = findNode(this._model, parsePath(pathStr));
22011
22056
  if (node === null || !isSplit(node)) continue;
22012
22057
  const live = Object.values(el.getSizes());
22013
- if (live.length === node.children.length && !weightsEqual(live, node.sizes)) node.sizes = live;
22058
+ if (live.length === node.children.length && !weightsEqual(live, node.sizes)) {
22059
+ node.sizes = live;
22060
+ Array.from(el.children).forEach((child, i) => {
22061
+ if (child instanceof HTMLElement && node.sizes[i] !== void 0) child.setAttribute(`size`, String(node.sizes[i]));
22062
+ });
22063
+ }
22014
22064
  }
22015
22065
  }
22016
22066
  _teardownTabDragListeners() {
@@ -22139,6 +22189,7 @@ let DockHostElement = class DockHostElement extends i {
22139
22189
  size=${size === void 0 ? A : String(size)}
22140
22190
  style=${`--split-gutter-size: var(--dock-split-bar-size, 2px); --split-collapsed-size: var(--dock-collapsed-size, 40px)`}
22141
22191
  data-dock-path=${pathStr}
22192
+ data-dock-gen=${this._loadGeneration}
22142
22193
  @ixfx-split-resize=${this._onSplitWeightsChanged}
22143
22194
  @ixfx-split-change=${this._onSplitWeightsChanged}
22144
22195
  @ixfx-split-collapse=${(e) => this._onSplitCollapsed(e, true)}
@@ -31264,17 +31315,117 @@ __decorate([state()], IxfxHexEditorElement.prototype, "_shadeMap", void 0);
31264
31315
  __decorate([state()], IxfxHexEditorElement.prototype, "_focusSide", void 0);
31265
31316
  IxfxHexEditorElement = __decorate([safeCustomElement(`ixfx-hex-editor`)], IxfxHexEditorElement);
31266
31317
  //#endregion
31267
- //#region src/icicle-tree/layout.ts
31268
- /** Coerce a raw accessor result to a non-negative finite weight. */
31269
- function normaliseValue(raw) {
31270
- return typeof raw === `number` && Number.isFinite(raw) && raw > 0 ? raw : 0;
31318
+ //#region src/hyperbolic-tree/poincare-math.ts
31319
+ const EPSILON = 1e-9;
31320
+ function complexMul(a, b) {
31321
+ return {
31322
+ x: a.x * b.x - a.y * b.y,
31323
+ y: a.x * b.y + a.y * b.x
31324
+ };
31325
+ }
31326
+ function complexConjugate(a) {
31327
+ return {
31328
+ x: a.x,
31329
+ y: -a.y
31330
+ };
31331
+ }
31332
+ function complexAdd(a, b) {
31333
+ return {
31334
+ x: a.x + b.x,
31335
+ y: a.y + b.y
31336
+ };
31337
+ }
31338
+ function complexSub(a, b) {
31339
+ return {
31340
+ x: a.x - b.x,
31341
+ y: a.y - b.y
31342
+ };
31343
+ }
31344
+ function complexScale(a, s) {
31345
+ return {
31346
+ x: a.x * s,
31347
+ y: a.y * s
31348
+ };
31349
+ }
31350
+ function complexDiv(a, b) {
31351
+ const denominator = b.x * b.x + b.y * b.y;
31352
+ if (denominator < EPSILON) return {
31353
+ x: 0,
31354
+ y: 0
31355
+ };
31356
+ return complexScale(complexMul(a, complexConjugate(b)), 1 / denominator);
31357
+ }
31358
+ /** Euclidean norm (`|z|`) of a point. */
31359
+ function norm(a) {
31360
+ return Math.hypot(a.x, a.y);
31361
+ }
31362
+ /** Clamp a point to stay strictly inside the unit disk (the Poincaré model's boundary is never reached). */
31363
+ function clampToDisk(p, maxNorm = .999999) {
31364
+ const n = norm(p);
31365
+ if (n <= maxNorm) return p;
31366
+ return complexScale(p, maxNorm / n);
31367
+ }
31368
+ /**
31369
+ * Möbius transform that translates `a` to the origin: `(z - a) / (1 - conj(a) * z)`.
31370
+ * A hyperbolic isometry — preserves all pairwise Poincaré distances.
31371
+ */
31372
+ function mobiusToOrigin(z, a) {
31373
+ return clampToDisk(complexDiv(complexSub(z, a), complexSub({
31374
+ x: 1,
31375
+ y: 0
31376
+ }, complexMul(complexConjugate(a), z))));
31271
31377
  }
31378
+ /**
31379
+ * Inverse of {@link mobiusToOrigin}: translates the origin back to `a`, i.e.
31380
+ * `(z + a) / (1 + conj(a) * z)`.
31381
+ */
31382
+ function mobiusFromOrigin(z, a) {
31383
+ return clampToDisk(complexDiv(complexAdd(z, a), complexAdd({
31384
+ x: 1,
31385
+ y: 0
31386
+ }, complexMul(complexConjugate(a), z))));
31387
+ }
31388
+ /**
31389
+ * Möbius addition (gyrogroup composition) of two disk-translations: the
31390
+ * canonical-space point reached by translating the origin to `a`, then
31391
+ * translating that local frame's origin by `b`.
31392
+ */
31393
+ function mobiusAdd(a, b) {
31394
+ return mobiusFromOrigin(b, a);
31395
+ }
31396
+ /** Euclidean Poincaré-disk radius corresponding to hyperbolic distance `d` from the origin. */
31397
+ function euclideanRadiusForHyperbolicDistance(d) {
31398
+ return Math.tanh(d / 2);
31399
+ }
31400
+ /** Hyperbolic distance from the origin corresponding to Euclidean disk radius `r`. */
31401
+ function hyperbolicDistanceForEuclideanRadius(r) {
31402
+ return 2 * Math.atanh(Math.min(Math.max(r, 0), .999999));
31403
+ }
31404
+ /** Hyperbolic (Poincaré) distance between two points in the unit disk. */
31405
+ function poincareDistance(p, q) {
31406
+ return hyperbolicDistanceForEuclideanRadius(norm(mobiusToOrigin(q, p)));
31407
+ }
31408
+ /**
31409
+ * Point at parameter `t` (0–1) along the hyperbolic geodesic from `a` to `b`.
31410
+ * `t=0` yields `a`, `t=1` yields `b`; intermediate values move at constant
31411
+ * hyperbolic speed along the geodesic (not the Euclidean straight line).
31412
+ */
31413
+ function geodesicInterpolate(a, b, t) {
31414
+ if (t <= 0) return a;
31415
+ if (t >= 1) return b;
31416
+ const bLocal = mobiusToOrigin(b, a);
31417
+ const localNorm = norm(bLocal);
31418
+ if (localNorm < EPSILON) return a;
31419
+ return mobiusFromOrigin(complexScale(complexScale(bLocal, 1 / localNorm), euclideanRadiusForHyperbolicDistance(hyperbolicDistanceForEuclideanRadius(localNorm) * t)), a);
31420
+ }
31421
+ //#endregion
31422
+ //#region src/hyperbolic-tree/layout.ts
31272
31423
  /** Depth-first search for the node with `key`. Returns `undefined` when absent. */
31273
- function findIcicleNode(root, key) {
31424
+ function findHyperbolicNode(root, key) {
31274
31425
  if (!root) return void 0;
31275
31426
  if (root.item.key === key) return root;
31276
31427
  for (const child of root.children ?? []) {
31277
- const hit = findIcicleNode(child, key);
31428
+ const hit = findHyperbolicNode(child, key);
31278
31429
  if (hit) return hit;
31279
31430
  }
31280
31431
  }
@@ -31282,92 +31433,289 @@ function findIcicleNode(root, key) {
31282
31433
  * Chain of nodes from `root` down to (and including) the node with `key`.
31283
31434
  * Returns `undefined` when the key is absent. The first entry is always `root`.
31284
31435
  */
31285
- function findIciclePath(root, key) {
31436
+ function findHyperbolicPath(root, key) {
31286
31437
  if (!root) return void 0;
31287
31438
  if (root.item.key === key) return [root];
31288
31439
  for (const child of root.children ?? []) {
31289
- const hit = findIciclePath(child, key);
31440
+ const hit = findHyperbolicPath(child, key);
31290
31441
  if (hit) return [root, ...hit];
31291
31442
  }
31292
31443
  }
31293
31444
  /**
31294
- * Compute the visible rectangles for an icicle view.
31445
+ * Number of nodes in `node`'s subtree, counting `node` itself, up to
31446
+ * `remainingDepth` further levels (matching the canonical-position recursion's
31447
+ * own `maxDepth` cutoff, so weighting stays consistent with what's actually
31448
+ * laid out).
31449
+ */
31450
+ function subtreeSize(node, remainingDepth) {
31451
+ if (remainingDepth <= 0) return 1;
31452
+ const children = node.children ?? [];
31453
+ if (children.length === 0) return 1;
31454
+ let total = 1;
31455
+ for (const child of children) total += subtreeSize(child, remainingDepth - 1);
31456
+ return total;
31457
+ }
31458
+ /**
31459
+ * Angle (as seen from `localOrigin`, i.e. after translating `localOrigin` to
31460
+ * the disk's center) of the disk-boundary point that currently sits at angle
31461
+ * `theta` from the true origin. Möbius translation is conformal but not
31462
+ * angle-preserving in the naive sense — a wedge boundary doesn't just shift
31463
+ * by a constant offset when reparented to a new local frame, its exact
31464
+ * transformed angle depends on how far off-center `localOrigin` is. Used to
31465
+ * carry a node's *own* angular wedge (inherited from its parent) into the
31466
+ * local frame of each of its children, rather than approximating it as
31467
+ * "the opposite direction ± half the width" — the same technique used by
31468
+ * reference hyperbolic-tree-browser implementations (e.g. d3-hypertree's
31469
+ * `wedgeTranslate`) to keep the recursive layout accurate at any depth/width.
31470
+ */
31471
+ function boundaryAngleInLocalFrame(theta, localOrigin) {
31472
+ const transformed = mobiusToOrigin({
31473
+ x: Math.cos(theta),
31474
+ y: Math.sin(theta)
31475
+ }, localOrigin);
31476
+ return Math.atan2(transformed.y, transformed.x);
31477
+ }
31478
+ /** Deterministic pseudo-random value in `[-1, 1]` derived from `key`, stable across renders. */
31479
+ function stableUnitJitter(key) {
31480
+ let hash = 0;
31481
+ for (let i = 0; i < key.length; i++) hash = Math.imul(hash, 31) + key.charCodeAt(i) | 0;
31482
+ return (hash >>> 0) % 1e3 / 1e3 * 2 - 1;
31483
+ }
31484
+ /**
31485
+ * A single unbranching child (no siblings to fan against) would otherwise sit
31486
+ * at the exact bisector of its inherited wedge — i.e. dead-center, continuing
31487
+ * in a perfectly straight line from its own parent's edge. For a chain of
31488
+ * such nodes (a deeply-nested path with no branching), that reads as one
31489
+ * unbroken line cutting across the disk rather than a legible sequence of
31490
+ * edges. Nudging by a small, key-derived (so stable across re-renders) angle
31491
+ * breaks that up — the same purpose served by the small per-node offsets in
31492
+ * reference hyperbolic-tree-browser implementations (e.g. d3-hypertree's
31493
+ * `layoutBergé`, which staggers leaf nodes rather than stacking them exactly
31494
+ * radially).
31495
+ */
31496
+ const CHAIN_JITTER_RADIANS = .22;
31497
+ /**
31498
+ * Canonical (true-root-anchored) hyperbolic position of every currently-loaded
31499
+ * node, keyed by node key. Positions never depend on the current focus —
31500
+ * refocusing is purely a Möbius re-projection of these fixed coordinates, so
31501
+ * the tree never needs to be re-laid-out when the focus changes.
31295
31502
  *
31296
- * Bands start at the zoom node's **children** (the zoom node itself is shown in
31297
- * the breadcrumb strip, never as a rect — matching `TreeComponent.getNodes()`,
31298
- * where the root is never listed). Each band spans 0–1; a rect's `x`/`width`
31299
- * are fractions of its band, proportional to `valueAccessor` shares among
31300
- * siblings. Siblings whose weights all normalise to `0` split the band equally.
31503
+ * Each node holds an angular wedge — inherited from its parent, expressed in
31504
+ * its *own* local frame (root starts with the full `[-π, π]`) — across which
31505
+ * its children are placed at hyperbolic distance `curvature` (default `1`).
31506
+ * That wedge is partitioned among the children, weighted by each child's own
31507
+ * subtree size rather than split evenly, and each child's own share is
31508
+ * carried into its local frame via {@link boundaryAngleInLocalFrame} before
31509
+ * recursing. This is a strict partition (slices never overlap and always sum
31510
+ * to the parent's own wedge), which is what guarantees sibling subtrees never
31511
+ * spatially cross regardless of how deep or bushy they are.
31301
31512
  *
31302
- * @param root True tree root. `undefined` (or a root without children) yields `[]`.
31303
- * @param options `valueAccessor` (default equal weights), `maxDepth` (band count,
31304
- * default unlimited), `zoomKey` (visual root, default true root; unknown keys
31305
- * fall back to the true root).
31513
+ * `curvature` scales how far apart (in hyperbolic distance) each generation
31514
+ * sits. Raising it pushes each generation further out, so the Poincaré
31515
+ * metric's own `tanh` compression crowds distant generations toward the
31516
+ * boundary faster — a stronger fisheye, which is why it reads as "zooming
31517
+ * in" on the focus. Lowering it spreads generations out more evenly,
31518
+ * flattening the view toward a Euclidean-feeling layout.
31306
31519
  */
31307
- function computeIcicleLayout(root, options = {}) {
31308
- if (!root?.children?.length) return [];
31309
- const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, hideLeaves = false } = options;
31310
- if (maxDepth <= 0) return [];
31311
- const zoomNode = zoomKey === void 0 ? root : findIcicleNode(root, zoomKey) ?? root;
31312
- const zoomPath = findIciclePath(root, zoomNode.item.key);
31313
- const zoomDepth = zoomPath ? zoomPath.length - 2 : -1;
31314
- const siblings = zoomNode.children ?? [];
31315
- if (siblings.length === 0) return [];
31316
- const isLeaf = (node) => node.item.isLeaf === true || node.children !== void 0 && node.children.length === 0;
31317
- const rects = [];
31318
- const layoutLevel = (nodes, depth, relativeDepth, offset, span, parentKey) => {
31319
- const visible = hideLeaves ? nodes.filter((n) => !isLeaf(n)) : nodes;
31320
- if (visible.length === 0 || relativeDepth >= maxDepth) return;
31321
- const weights = visible.map((n) => normaliseValue(valueAccessor(n.item)));
31322
- const total = weights.reduce((a, b) => a + b, 0);
31323
- const setSize = visible.length;
31324
- let cursor = offset;
31325
- visible.forEach((node, index) => {
31326
- const width = span * (total > 0 ? weights[index] / total : 1 / setSize);
31327
- const children = node.children ?? [];
31328
- rects.push({
31329
- node,
31330
- depth,
31331
- relativeDepth,
31332
- x: cursor,
31333
- width,
31334
- parentKey,
31335
- index,
31336
- setSize,
31337
- hasChildren: children.length > 0 || node.children === void 0 && node.item.isLeaf !== true
31520
+ function computeCanonicalPositions(root, maxDepth = 24, curvature = 1) {
31521
+ const map = /* @__PURE__ */ new Map();
31522
+ if (!root) return map;
31523
+ const origin = {
31524
+ x: 0,
31525
+ y: 0
31526
+ };
31527
+ map.set(root.item.key, {
31528
+ node: root,
31529
+ depth: 0,
31530
+ parentKey: void 0,
31531
+ position: origin,
31532
+ angularShare: 2 * Math.PI
31533
+ });
31534
+ const place = (node, position, wedgeStart, wedgeEnd, depth) => {
31535
+ if (depth >= maxDepth) return;
31536
+ const children = node.children ?? [];
31537
+ const n = children.length;
31538
+ if (n === 0) return;
31539
+ const r0 = euclideanRadiusForHyperbolicDistance(curvature);
31540
+ const angularWidth = wedgeEnd - wedgeStart;
31541
+ const weights = children.map((child) => subtreeSize(child, maxDepth - depth - 1));
31542
+ const totalWeight = weights.reduce((a, b) => a + b, 0);
31543
+ let cursor = wedgeStart;
31544
+ children.forEach((child, index) => {
31545
+ const share = n === 1 ? angularWidth : angularWidth * weights[index] / totalWeight;
31546
+ const childStart = cursor;
31547
+ const childEnd = cursor + share;
31548
+ cursor = childEnd;
31549
+ const theta = (childStart + childEnd) / 2 + (n === 1 ? stableUnitJitter(child.item.key) * Math.min(CHAIN_JITTER_RADIANS, share * .4) : 0);
31550
+ const local = {
31551
+ x: r0 * Math.cos(theta),
31552
+ y: r0 * Math.sin(theta)
31553
+ };
31554
+ const canonicalPosition = mobiusFromOrigin(local, position);
31555
+ map.set(child.item.key, {
31556
+ node: child,
31557
+ depth: depth + 1,
31558
+ parentKey: node.item.key,
31559
+ position: canonicalPosition,
31560
+ angularShare: share
31338
31561
  });
31339
- if (children.length > 0) layoutLevel(children, depth + 1, relativeDepth + 1, cursor, width, node.item.key);
31340
- cursor += width;
31562
+ const localStart = boundaryAngleInLocalFrame(childStart, local);
31563
+ let localWidth = boundaryAngleInLocalFrame(childEnd, local) - localStart;
31564
+ if (localWidth <= 0) localWidth += 2 * Math.PI;
31565
+ place(child, canonicalPosition, localStart, localStart + localWidth, depth + 1);
31341
31566
  });
31342
31567
  };
31343
- layoutLevel(siblings, zoomDepth + 1, 0, 0, 1, zoomNode.item.key);
31344
- return rects;
31568
+ place(root, origin, -Math.PI, Math.PI, 0);
31569
+ return map;
31570
+ }
31571
+ /** Nodes within `maxRadius` tree-graph steps of `focusedKey`, mapped to their step distance. */
31572
+ function ringDistances(canonical, focusedKey, maxRadius) {
31573
+ const ring = /* @__PURE__ */ new Map();
31574
+ if (!canonical.has(focusedKey)) return ring;
31575
+ ring.set(focusedKey, 0);
31576
+ let frontier = [focusedKey];
31577
+ for (let distance = 1; distance <= maxRadius && frontier.length > 0; distance++) {
31578
+ const next = [];
31579
+ for (const key of frontier) {
31580
+ const entry = canonical.get(key);
31581
+ if (!entry) continue;
31582
+ const neighbours = [];
31583
+ if (entry.parentKey !== void 0) neighbours.push(entry.parentKey);
31584
+ for (const child of entry.node.children ?? []) neighbours.push(child.item.key);
31585
+ for (const neighbour of neighbours) if (!ring.has(neighbour) && canonical.has(neighbour)) {
31586
+ ring.set(neighbour, distance);
31587
+ next.push(neighbour);
31588
+ }
31589
+ }
31590
+ frontier = next;
31591
+ }
31592
+ return ring;
31593
+ }
31594
+ /**
31595
+ * Compute the visible nodes/edges of a hyperbolic tree view: every
31596
+ * currently-loaded node within `maxRadius` tree-graph steps of the focused
31597
+ * node, projected onto the Poincaré disk with the focus at its center.
31598
+ *
31599
+ * @param root True tree root. `undefined` yields an empty layout.
31600
+ * @param options `focusedKey` (default the true root; unknown keys fall back
31601
+ * to the true root), `maxRadius` (default unlimited), `maxDepth` (safety
31602
+ * cap on canonical-position recursion depth, default 24), `centerOverride`
31603
+ * (project around this canonical-space point instead of the focus node's
31604
+ * own position — used to animate smoothly between foci).
31605
+ */
31606
+ function computeHyperbolicLayout(root, options = {}) {
31607
+ if (!root) return {
31608
+ nodes: [],
31609
+ edges: []
31610
+ };
31611
+ const { maxRadius = Number.POSITIVE_INFINITY, maxDepth = 24, curvature = 1 } = options;
31612
+ const canonical = computeCanonicalPositions(root, maxDepth, curvature);
31613
+ const focusedKey = options.focusedKey !== void 0 && canonical.has(options.focusedKey) ? options.focusedKey : root.item.key;
31614
+ const focusEntry = canonical.get(focusedKey);
31615
+ if (!focusEntry) return {
31616
+ nodes: [],
31617
+ edges: []
31618
+ };
31619
+ const projectionCenter = options.centerOverride ?? focusEntry.position;
31620
+ const ring = ringDistances(canonical, focusedKey, maxRadius);
31621
+ const rawWeights = [...ring.keys()].map((key) => canonical.get(key).node.item.weight).filter((w) => typeof w === `number`);
31622
+ const minWeight = rawWeights.length > 0 ? Math.min(...rawWeights) : void 0;
31623
+ const maxWeight = rawWeights.length > 0 ? Math.max(...rawWeights) : void 0;
31624
+ const normalizeWeight = (weight) => {
31625
+ if (weight === void 0 || minWeight === void 0 || maxWeight === void 0 || maxWeight === minWeight) return .5;
31626
+ return (weight - minWeight) / (maxWeight - minWeight);
31627
+ };
31628
+ const nodes = [...ring.entries()].map(([key, distance]) => {
31629
+ const entry = canonical.get(key);
31630
+ const weight = entry.node.item.weight;
31631
+ return {
31632
+ node: entry.node,
31633
+ key,
31634
+ depth: entry.depth,
31635
+ ring: distance,
31636
+ parentKey: entry.parentKey,
31637
+ position: mobiusToOrigin(entry.position, projectionCenter),
31638
+ angularShare: entry.angularShare,
31639
+ weight,
31640
+ weightNormalized: normalizeWeight(weight)
31641
+ };
31642
+ }).sort((a, b) => a.ring - b.ring);
31643
+ const byKey = new Map(nodes.map((n) => [n.key, n]));
31644
+ const edges = [];
31645
+ for (const n of nodes) {
31646
+ if (n.parentKey === void 0) continue;
31647
+ const parent = byKey.get(n.parentKey);
31648
+ if (!parent) continue;
31649
+ edges.push({
31650
+ fromKey: parent.key,
31651
+ toKey: n.key,
31652
+ from: parent.position,
31653
+ to: n.position,
31654
+ weightNormalized: (parent.weightNormalized + n.weightNormalized) / 2
31655
+ });
31656
+ }
31657
+ return {
31658
+ nodes,
31659
+ edges
31660
+ };
31345
31661
  }
31346
31662
  //#endregion
31347
- //#region src/icicle-tree/icicletree-list.ts
31348
- let IcicleTreeListElement = class IcicleTreeListElement extends i {
31663
+ //#region src/hyperbolic-tree/hyperbolictree-list.ts
31664
+ /**
31665
+ * The Poincaré disk's math operates in a `-1..1` unit radius, but rendering
31666
+ * an SVG `viewBox` at that literal scale (then letting CSS stretch it to a
31667
+ * few hundred device pixels) is an extreme, unusual upscale factor that has
31668
+ * been observed to trigger a Chromium GPU-rasterization glitch — a `fill:
31669
+ * none` shape painting as solid-filled, matching its computed style exactly
31670
+ * but not what's on screen. Rendering in a "normal"-magnitude SVG coordinate
31671
+ * system (viewBox radius {@link RENDER_SCALE} instead of `1`) avoids it.
31672
+ */
31673
+ const RENDER_SCALE = 500;
31674
+ /**
31675
+ * Sanitizes a node key into a token safe to use inside a `part` attribute /
31676
+ * `::part()` selector — arbitrary key characters (spaces, quotes, etc.)
31677
+ * would otherwise produce a token CSS can't select without bespoke escaping.
31678
+ */
31679
+ function partToken(key) {
31680
+ return key.replace(/[^\w-]/g, `-`);
31681
+ }
31682
+ /** Angular distance (radians, 0–π) of a layout node from screen-"up" (−π/2). */
31683
+ function angleDistanceFromUp(n) {
31684
+ const angle = Math.atan2(n.position.y, n.position.x);
31685
+ let diff = Math.abs(angle - -Math.PI / 2);
31686
+ if (diff > Math.PI) diff = 2 * Math.PI - diff;
31687
+ return diff;
31688
+ }
31689
+ let HyperbolicTreeListElement = class HyperbolicTreeListElement extends i {
31349
31690
  constructor(..._args) {
31350
31691
  super(..._args);
31351
31692
  this.exclusivity = `none`;
31352
31693
  this.selectionFilter = `all`;
31353
31694
  this.interactionMode = `standard`;
31354
- this.orientation = `horizontal`;
31355
- this.maxDepth = 4;
31356
- this.minLabelWidth = 40;
31357
- this.minVerticalLabelWidth = 16;
31358
- this.hideLeaves = false;
31359
- this.valueAccessor = () => 1;
31695
+ this.maxRadius = 4;
31696
+ this.nodeRadius = .05;
31697
+ this.minNodeRadius = .015;
31698
+ this.minWeightScale = .6;
31699
+ this.maxWeightScale = 1.6;
31700
+ this.zoom = 1;
31701
+ this.curvature = 1;
31702
+ this.focusAnimationDuration = 400;
31360
31703
  this._selectedNodes = /* @__PURE__ */ new Set();
31361
31704
  this.disableKeyboardNavigation = false;
31362
31705
  this.registry = void 0;
31363
- this._zoomKey = void 0;
31706
+ this._focusKey = void 0;
31707
+ this._animCenter = void 0;
31708
+ this._panOffset = {
31709
+ x: 0,
31710
+ y: 0
31711
+ };
31364
31712
  this.search = new ListSearchController(this, { adapter: createTreeListSearchAdapter(this, {
31365
- labelSelector: `.icicle-label`,
31713
+ labelSelector: `.hyperbolictree-label`,
31366
31714
  highlightKey: `incr-search-highlight`
31367
31715
  }) });
31368
31716
  this.tickled = new TickledController(this, {
31369
- getItems: () => this.#rects().map((r) => ({
31370
- id: r.node.item.key,
31717
+ getItems: () => this.#layout().nodes.map((n) => ({
31718
+ id: n.key,
31371
31719
  enabled: true
31372
31720
  })),
31373
31721
  onStateChange: () => {
@@ -31375,12 +31723,12 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31375
31723
  },
31376
31724
  onTickle: (id) => {
31377
31725
  if (id === void 0) return;
31378
- const rect = this.#rects().find((r) => r.node.item.key === id);
31379
- if (!rect) return;
31726
+ const n = this.#layout().nodes.find((n) => n.key === id);
31727
+ if (!n) return;
31380
31728
  this.dispatchEvent(new CustomEvent(`tickle`, {
31381
31729
  detail: {
31382
- node: rect.node,
31383
- depth: rect.depth
31730
+ node: n.node,
31731
+ depth: n.depth
31384
31732
  },
31385
31733
  bubbles: true,
31386
31734
  composed: true
@@ -31399,29 +31747,40 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31399
31747
  get selectedNodes() {
31400
31748
  return this._selectedNodes;
31401
31749
  }
31402
- /** Current zoom root. `undefined` when showing the full tree. Pure view-state — `root` is never mutated. */
31750
+ /** The node currently centered on the disk. Pure view-state — `root` is never mutated by focus changes. */
31403
31751
  get focusedNode() {
31404
- if (this._zoomKey === void 0) return void 0;
31405
- return findIcicleNode(this.#effectiveRoot, this._zoomKey);
31752
+ if (this._focusKey === void 0) return this.#effectiveRoot;
31753
+ return findHyperbolicNode(this.#effectiveRoot, this._focusKey) ?? this.#effectiveRoot;
31406
31754
  }
31407
31755
  #modelUnsubscribe;
31408
31756
  #pendingKeys;
31409
31757
  #aborters;
31410
- #anchorIndex;
31411
31758
  #ownedRegistry;
31412
31759
  #unregisterSearchCommands;
31413
- #resizeObserver;
31760
+ #animFrame;
31761
+ #panStart;
31414
31762
  get #effectiveRoot() {
31415
31763
  return this.model?.root ?? this.root;
31416
31764
  }
31417
- #rects() {
31418
- return computeIcicleLayout(this.#effectiveRoot, {
31419
- valueAccessor: this.valueAccessor,
31420
- maxDepth: this.maxDepth,
31421
- zoomKey: this._zoomKey,
31422
- hideLeaves: this.hideLeaves
31765
+ #layout() {
31766
+ return computeHyperbolicLayout(this.#effectiveRoot, {
31767
+ focusedKey: this._focusKey,
31768
+ maxRadius: this.maxRadius,
31769
+ curvature: this.curvature,
31770
+ centerOverride: this._panOffset.x === 0 && this._panOffset.y === 0 && this._animCenter === void 0 ? void 0 : this.#effectiveCenter()
31423
31771
  });
31424
31772
  }
31773
+ #effectiveCenter() {
31774
+ const canonical = computeCanonicalPositions(this.#effectiveRoot, 24, this.curvature);
31775
+ const focusKey = this._focusKey ?? this.#effectiveRoot?.item.key;
31776
+ const base = this._animCenter ?? (focusKey === void 0 ? void 0 : canonical.get(focusKey)?.position);
31777
+ if (base === void 0) return void 0;
31778
+ if (this._panOffset.x === 0 && this._panOffset.y === 0) return base;
31779
+ return clampToDisk({
31780
+ x: base.x + this._panOffset.x,
31781
+ y: base.y + this._panOffset.y
31782
+ }, .95);
31783
+ }
31425
31784
  connectedCallback() {
31426
31785
  super.connectedCallback();
31427
31786
  this.setAttribute(`data-input-mode`, `mouse`);
@@ -31440,10 +31799,6 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31440
31799
  });
31441
31800
  this.registry = registry;
31442
31801
  this.#syncSearchCommands();
31443
- if (typeof ResizeObserver !== `undefined`) {
31444
- this.#resizeObserver = new ResizeObserver(() => this.requestUpdate());
31445
- this.#resizeObserver.observe(this);
31446
- }
31447
31802
  }
31448
31803
  disconnectedCallback() {
31449
31804
  super.disconnectedCallback();
@@ -31452,8 +31807,10 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31452
31807
  for (const aborter of this.#aborters.values()) aborter.abort();
31453
31808
  this.#aborters.clear();
31454
31809
  this.#pendingKeys.clear();
31455
- this.#resizeObserver?.disconnect();
31456
- this.#resizeObserver = void 0;
31810
+ if (this.#animFrame !== void 0) {
31811
+ cancelAnimationFrame(this.#animFrame);
31812
+ this.#animFrame = void 0;
31813
+ }
31457
31814
  if (this.#ownedRegistry) {
31458
31815
  this.#ownedRegistry.unregister(`select-all`);
31459
31816
  this.#ownedRegistry.unregister(`deselect-all`);
@@ -31488,74 +31845,34 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31488
31845
  this.#resetViewState();
31489
31846
  }
31490
31847
  }
31491
- if (changedProps.has(`interactionMode`)) {
31492
- this.#anchorIndex = void 0;
31493
- this.clearSelection();
31494
- }
31848
+ if (changedProps.has(`interactionMode`)) this.clearSelection();
31495
31849
  if (changedProps.has(`searchModes`)) this.#syncSearchCommands();
31496
- if (this._zoomKey !== void 0 && !findIcicleNode(this.#effectiveRoot, this._zoomKey)) this._zoomKey = void 0;
31850
+ if (this._focusKey !== void 0 && !findHyperbolicNode(this.#effectiveRoot, this._focusKey)) {
31851
+ this._focusKey = void 0;
31852
+ this._animCenter = void 0;
31853
+ }
31497
31854
  this.#ensureVisibleChildren();
31498
- this.#syncTooltip();
31499
- }
31500
- /** The host's own (viewport) extent — width in horizontal orientation, height in vertical. */
31501
- #hostExtent() {
31502
- return (this.orientation === `vertical` ? this.clientHeight : this.clientWidth) || 0;
31503
- }
31504
- /**
31505
- * Whether `rect`'s label should be rotated or hidden for lack of space, per
31506
- * {@link minLabelWidth} / {@link minVerticalLabelWidth}. `orientation="vertical"`
31507
- * rects never rotate — hides outright at `minLabelWidth` instead, same as before.
31508
- */
31509
- #labelMode(rect) {
31510
- const hostExtent = this.#hostExtent();
31511
- if (hostExtent === 0) return {
31512
- hidden: false,
31513
- rotated: false
31514
- };
31515
- const vertical = this.orientation === `vertical`;
31516
- const pixelWidth = rect.width * hostExtent;
31517
- if (vertical) return {
31518
- hidden: pixelWidth < this.minLabelWidth,
31519
- rotated: false
31520
- };
31521
- if (pixelWidth < this.minVerticalLabelWidth) return {
31522
- hidden: true,
31523
- rotated: false
31524
- };
31525
- return {
31526
- hidden: false,
31527
- rotated: pixelWidth < this.minLabelWidth
31528
- };
31529
- }
31530
- /** Anchor the shared tooltip popover to the tickled rect, if its label needs one. */
31531
- #syncTooltip() {
31532
- const popover = this._tooltipEl;
31533
- if (!popover?.popover) return;
31534
- const key = this.tickled.tickledId;
31535
- const rect = key === void 0 ? void 0 : this.#rects().find((r) => r.node.item.key === key);
31536
- const mode = rect ? this.#labelMode(rect) : void 0;
31537
- const isOpen = popover.matches(`:popover-open`);
31538
- if (rect && mode && (mode.hidden || mode.rotated)) {
31539
- popover.textContent = rect.node.item.label;
31540
- if (!isOpen) try {
31541
- popover.showPopover();
31542
- } catch {}
31543
- } else if (isOpen) try {
31544
- popover.hidePopover();
31545
- } catch {}
31546
31855
  }
31547
31856
  #resetViewState() {
31548
31857
  this.#clearSelectionInternal();
31549
31858
  this.tickled.clearTickled();
31550
- this._zoomKey = void 0;
31551
- this.#anchorIndex = void 0;
31859
+ this._focusKey = void 0;
31860
+ this._animCenter = void 0;
31861
+ this._panOffset = {
31862
+ x: 0,
31863
+ y: 0
31864
+ };
31865
+ if (this.#animFrame !== void 0) {
31866
+ cancelAnimationFrame(this.#animFrame);
31867
+ this.#animFrame = void 0;
31868
+ }
31552
31869
  }
31553
31870
  #ensureVisibleChildren() {
31554
31871
  if (!this.model && !this.loadChildren) return;
31555
- for (const rect of this.#rects()) {
31556
- const { node } = rect;
31872
+ for (const n of this.#layout().nodes) {
31873
+ const { node } = n;
31557
31874
  if (node.children !== void 0 || this.#pendingKeys.has(node.item.key)) continue;
31558
- this.#loadChildren(node, rect.depth);
31875
+ this.#loadChildren(node, n.depth);
31559
31876
  }
31560
31877
  }
31561
31878
  async #loadChildren(node, depth) {
@@ -31628,9 +31945,9 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31628
31945
  }
31629
31946
  selectAll() {
31630
31947
  const prev = new Set(this._selectedNodes);
31631
- for (const rect of this.#rects()) {
31632
- if (!this.#canSelect(rect.node)) continue;
31633
- this._selectedNodes.add(rect.node);
31948
+ for (const n of this.#layout().nodes) {
31949
+ if (!this.#canSelect(n.node)) continue;
31950
+ this._selectedNodes.add(n.node);
31634
31951
  }
31635
31952
  this.selectedNode = [...this._selectedNodes].at(-1);
31636
31953
  this.#dispatchSelect(prev);
@@ -31651,11 +31968,987 @@ let IcicleTreeListElement = class IcicleTreeListElement extends i {
31651
31968
  this.requestUpdate();
31652
31969
  }
31653
31970
  /**
31654
- * Drill down so `node` becomes the visual root (ancestors move to the
31655
- * breadcrumb strip). Pure view-state — `root` is never mutated.
31656
- * Fires `zoom` and the semantic `expand` event.
31971
+ * Re-center the disk on `node` (an animated Möbius transform of the fixed
31972
+ * layout — `root` is never mutated). Fires `focus`, plus the semantic
31973
+ * `expand`/`collapse` event when the new focus is a descendant/ancestor of
31974
+ * the previous one, for interop with generic `TreeComponent` listeners.
31657
31975
  */
31658
- zoomTo(node) {
31976
+ focusOn(node) {
31977
+ const targetKey = node.item.key;
31978
+ const currentFocusKey = this._focusKey ?? this.#effectiveRoot?.item.key;
31979
+ if (currentFocusKey === targetKey) return;
31980
+ const previousNode = currentFocusKey === void 0 ? void 0 : findHyperbolicNode(this.#effectiveRoot, currentFocusKey);
31981
+ const canonical = computeCanonicalPositions(this.#effectiveRoot, 24, this.curvature);
31982
+ const fromPosition = (currentFocusKey === void 0 ? void 0 : canonical.get(currentFocusKey)?.position) ?? {
31983
+ x: 0,
31984
+ y: 0
31985
+ };
31986
+ const toPosition = canonical.get(targetKey)?.position ?? {
31987
+ x: 0,
31988
+ y: 0
31989
+ };
31990
+ this._focusKey = targetKey;
31991
+ this._panOffset = {
31992
+ x: 0,
31993
+ y: 0
31994
+ };
31995
+ this.#animateTo(fromPosition, toPosition);
31996
+ this.dispatchEvent(new CustomEvent(`focus`, {
31997
+ detail: {
31998
+ node,
31999
+ previous: previousNode
32000
+ },
32001
+ bubbles: true,
32002
+ composed: true
32003
+ }));
32004
+ if (previousNode) {
32005
+ if (findHyperbolicNode(previousNode, targetKey)) {
32006
+ const depth = (findHyperbolicPath(this.#effectiveRoot, targetKey)?.length ?? 1) - 1;
32007
+ this.dispatchEvent(new CustomEvent(`expand`, {
32008
+ detail: {
32009
+ node,
32010
+ depth
32011
+ },
32012
+ bubbles: true,
32013
+ composed: true
32014
+ }));
32015
+ } else if (findHyperbolicNode(node, previousNode.item.key)) {
32016
+ const depth = (findHyperbolicPath(this.#effectiveRoot, previousNode.item.key)?.length ?? 1) - 1;
32017
+ this.dispatchEvent(new CustomEvent(`collapse`, {
32018
+ detail: {
32019
+ node: previousNode,
32020
+ depth
32021
+ },
32022
+ bubbles: true,
32023
+ composed: true
32024
+ }));
32025
+ }
32026
+ }
32027
+ this.requestUpdate();
32028
+ }
32029
+ #prefersReducedMotion() {
32030
+ return typeof matchMedia === `function` && matchMedia(`(prefers-reduced-motion: reduce)`).matches;
32031
+ }
32032
+ #animateTo(from, to) {
32033
+ if (this.#animFrame !== void 0) {
32034
+ cancelAnimationFrame(this.#animFrame);
32035
+ this.#animFrame = void 0;
32036
+ }
32037
+ if (this.focusAnimationDuration <= 0 || this.#prefersReducedMotion() || typeof requestAnimationFrame !== `function`) {
32038
+ this._animCenter = void 0;
32039
+ return;
32040
+ }
32041
+ const start = performance.now();
32042
+ const duration = this.focusAnimationDuration;
32043
+ const step = (now) => {
32044
+ const t = Math.min(1, (now - start) / duration);
32045
+ this._animCenter = t >= 1 ? void 0 : geodesicInterpolate(from, to, t);
32046
+ this.requestUpdate();
32047
+ this.#animFrame = t < 1 ? requestAnimationFrame(step) : void 0;
32048
+ };
32049
+ this.#animFrame = requestAnimationFrame(step);
32050
+ }
32051
+ #focusAndMaybeSelect(node) {
32052
+ this.focusOn(node);
32053
+ this.tickled.setTickled(node.item.key);
32054
+ if (this.interactionMode === `implicit`) this.select(node);
32055
+ }
32056
+ /** Focus + select the node at `keys` (path from the root's children). Returns `true` if found. */
32057
+ navigateTo(keys) {
32058
+ const root = this.#effectiveRoot;
32059
+ if (!root?.children) return false;
32060
+ let current = root;
32061
+ for (const key of keys) {
32062
+ const found = current.children?.find((n) => n.item.key === key);
32063
+ if (!found) return false;
32064
+ current = found;
32065
+ }
32066
+ this.focusOn(current);
32067
+ this.select(current);
32068
+ this.tickled.setTickled(current.item.key);
32069
+ this.requestUpdate();
32070
+ return true;
32071
+ }
32072
+ /** Focus + select the first node for which `predicate` returns `true`. Returns `true` if found. */
32073
+ navigateToNode(predicate) {
32074
+ const root = this.#effectiveRoot;
32075
+ if (!root?.children) return false;
32076
+ const keyPath = this.#findKeyPath(root.children, predicate);
32077
+ if (!keyPath) return false;
32078
+ return this.navigateTo(keyPath);
32079
+ }
32080
+ /**
32081
+ * Bring the node with `key` into the visible window and move the keyboard
32082
+ * cursor to it, without changing the selection. Used by incremental-search
32083
+ * "navigate" mode.
32084
+ */
32085
+ revealKey(key) {
32086
+ const node = findHyperbolicNode(this.#effectiveRoot, key);
32087
+ if (!node) return false;
32088
+ if (!this.#layout().nodes.some((n) => n.key === key)) this.focusOn(node);
32089
+ this.tickled.setTickled(key);
32090
+ this.requestUpdate();
32091
+ return true;
32092
+ }
32093
+ #findKeyPath(nodes, predicate, prefix = []) {
32094
+ for (const node of nodes) {
32095
+ const path = [...prefix, node.item.key];
32096
+ if (predicate(node)) return path;
32097
+ if (node.children?.length) {
32098
+ const hit = this.#findKeyPath(node.children, predicate, path);
32099
+ if (hit) return hit;
32100
+ }
32101
+ }
32102
+ }
32103
+ /**
32104
+ * All nodes currently laid out on the disk (within `maxRadius` of the
32105
+ * focus), in render (ring-major) order. Unlike `ixfx-icicletree-list`, the
32106
+ * focused node itself is included — it is literally rendered, at the
32107
+ * center.
32108
+ */
32109
+ getNodes() {
32110
+ return this.#layout().nodes.map((n) => ({
32111
+ node: n.node,
32112
+ depth: n.depth
32113
+ }));
32114
+ }
32115
+ #matchesFilter(node, depth) {
32116
+ if (!this.filterPredicate) return true;
32117
+ if (this.filterPredicate(node, depth)) return true;
32118
+ return node.children?.some((child) => this.#matchesFilter(child, depth + 1)) ?? false;
32119
+ }
32120
+ #handleItemClick(n, event) {
32121
+ this.dispatchEvent(new CustomEvent(`item-click`, {
32122
+ detail: {
32123
+ node: n.node,
32124
+ depth: n.depth
32125
+ },
32126
+ bubbles: true,
32127
+ composed: true
32128
+ }));
32129
+ if (this.interactionMode === `standard` && (event.ctrlKey || event.metaKey)) {
32130
+ if (this._selectedNodes.has(n.node)) this.deselect(n.node);
32131
+ else if (this.#canSelect(n.node)) {
32132
+ const prev = new Set(this._selectedNodes);
32133
+ this._selectedNodes.add(n.node);
32134
+ this.selectedNode = n.node;
32135
+ this.#dispatchSelect(prev);
32136
+ this.requestUpdate();
32137
+ }
32138
+ } else if (this.interactionMode !== `manual`) this.select(n.node);
32139
+ this.tickled.setTickled(n.key);
32140
+ this.focusOn(n.node);
32141
+ }
32142
+ #handleItemDblClick(n) {
32143
+ this.dispatchEvent(new CustomEvent(`item-dblclick`, {
32144
+ detail: {
32145
+ node: n.node,
32146
+ depth: n.depth
32147
+ },
32148
+ bubbles: true,
32149
+ composed: true
32150
+ }));
32151
+ this.dispatchEvent(new CustomEvent(`activate`, {
32152
+ detail: {
32153
+ node: n.node,
32154
+ depth: n.depth
32155
+ },
32156
+ bubbles: true,
32157
+ composed: true
32158
+ }));
32159
+ }
32160
+ #handleKeyDown(event) {
32161
+ if (this.disableKeyboardNavigation) return;
32162
+ const root = this.#effectiveRoot;
32163
+ const { nodes } = this.#layout();
32164
+ if (!root || nodes.length === 0) return;
32165
+ const focusNode = findHyperbolicNode(root, this._focusKey ?? root.item.key);
32166
+ if (!focusNode) return;
32167
+ switch (event.key) {
32168
+ case `ArrowUp`: {
32169
+ event.preventDefault();
32170
+ const children = nodes.filter((n) => n.parentKey === focusNode.item.key);
32171
+ if (children.length === 0) return;
32172
+ const best = children.reduce((a, b) => angleDistanceFromUp(a) < angleDistanceFromUp(b) ? a : b);
32173
+ this.#focusAndMaybeSelect(best.node);
32174
+ return;
32175
+ }
32176
+ case `ArrowDown`: {
32177
+ event.preventDefault();
32178
+ const path = findHyperbolicPath(root, focusNode.item.key);
32179
+ const parent = path && path.length >= 2 ? path[path.length - 2] : void 0;
32180
+ if (parent) this.#focusAndMaybeSelect(parent);
32181
+ return;
32182
+ }
32183
+ case `ArrowLeft`:
32184
+ case `ArrowRight`: {
32185
+ event.preventDefault();
32186
+ const path = findHyperbolicPath(root, focusNode.item.key);
32187
+ const siblings = (path && path.length >= 2 ? path[path.length - 2] : void 0)?.children ?? (focusNode === root ? [focusNode] : []);
32188
+ const index = siblings.findIndex((n) => n.item.key === focusNode.item.key);
32189
+ if (index === -1 || siblings.length <= 1) return;
32190
+ const next = siblings[(index + (event.key === `ArrowRight` ? 1 : -1) + siblings.length) % siblings.length];
32191
+ this.#focusAndMaybeSelect(next);
32192
+ return;
32193
+ }
32194
+ case `Enter`: {
32195
+ event.preventDefault();
32196
+ if (this.interactionMode !== `manual`) this.select(focusNode);
32197
+ const depth = (findHyperbolicPath(root, focusNode.item.key)?.length ?? 1) - 1;
32198
+ this.dispatchEvent(new CustomEvent(`activate`, {
32199
+ detail: {
32200
+ node: focusNode,
32201
+ depth
32202
+ },
32203
+ bubbles: true,
32204
+ composed: true
32205
+ }));
32206
+ return;
32207
+ }
32208
+ case `Escape`: if (this._focusKey !== void 0 && this._focusKey !== root.item.key) {
32209
+ event.preventDefault();
32210
+ this.focusOn(root);
32211
+ }
32212
+ }
32213
+ }
32214
+ #isBackgroundTarget(event) {
32215
+ const target = event.target;
32216
+ return target === event.currentTarget || target?.classList.contains(`disk-boundary`) === true;
32217
+ }
32218
+ #handleBackgroundPointerDown(event) {
32219
+ if (!this.#isBackgroundTarget(event)) return;
32220
+ event.currentTarget.setPointerCapture(event.pointerId);
32221
+ this.#panStart = {
32222
+ pointerId: event.pointerId,
32223
+ startClient: {
32224
+ x: event.clientX,
32225
+ y: event.clientY
32226
+ },
32227
+ baseOffset: this._panOffset
32228
+ };
32229
+ }
32230
+ #handleBackgroundPointerMove(event) {
32231
+ if (!this.#panStart || event.pointerId !== this.#panStart.pointerId) return;
32232
+ const rect = event.currentTarget.getBoundingClientRect();
32233
+ const scale = 2.1 / (Math.min(rect.width, rect.height) || 1);
32234
+ const dx = (event.clientX - this.#panStart.startClient.x) * scale;
32235
+ const dy = (event.clientY - this.#panStart.startClient.y) * scale;
32236
+ this._panOffset = clampToDisk({
32237
+ x: this.#panStart.baseOffset.x - dx,
32238
+ y: this.#panStart.baseOffset.y - dy
32239
+ }, .9);
32240
+ this.requestUpdate();
32241
+ }
32242
+ #handleBackgroundPointerUp(event) {
32243
+ if (this.#panStart?.pointerId === event.pointerId) this.#panStart = void 0;
32244
+ }
32245
+ #defaultEdgeRenderer(edge) {
32246
+ const steps = 8;
32247
+ let d = ``;
32248
+ for (let i = 0; i <= steps; i++) {
32249
+ const p = geodesicInterpolate(edge.from, edge.to, i / steps);
32250
+ d += `${i === 0 ? `M` : `L`}${(p.x * RENDER_SCALE).toFixed(2)},${(p.y * RENDER_SCALE).toFixed(2)} `;
32251
+ }
32252
+ return w`<path
32253
+ class="edge"
32254
+ d=${d}
32255
+ part="edge edge-to-${partToken(edge.toKey)} edge-from-${partToken(edge.fromKey)}"
32256
+ data-from=${edge.fromKey}
32257
+ data-to=${edge.toKey}
32258
+ style="--edge-weight: ${edge.weightNormalized}"
32259
+ />`;
32260
+ }
32261
+ #renderEdge(edge, byKey) {
32262
+ if (this.edgeRenderer) {
32263
+ const fromNode = byKey.get(edge.fromKey)?.node;
32264
+ const toNode = byKey.get(edge.toKey)?.node;
32265
+ if (fromNode && toNode) return w`<g transform="scale(${RENDER_SCALE})">${this.edgeRenderer({
32266
+ edge,
32267
+ fromNode,
32268
+ toNode
32269
+ })}</g>`;
32270
+ }
32271
+ return this.#defaultEdgeRenderer(edge);
32272
+ }
32273
+ /**
32274
+ * A node's rendered dot radius: shrinks with distance from focus (existing
32275
+ * behaviour), but also caps itself to the angular room {@link
32276
+ * HyperbolicLayoutNode.angularShare} actually gives it at its radius —
32277
+ * without this, a cluster of siblings squeezed into a narrow wedge (a
32278
+ * bushy ancestor elsewhere in the tree, or many siblings at this level)
32279
+ * all render at the same distance-only size and physically overlap into
32280
+ * an unreadable blob, however small {@link minNodeRadius} suppresses their
32281
+ * labels. `angularShare * distance` approximates the Euclidean arc length
32282
+ * available to the node; capping the diameter to a fraction of that keeps
32283
+ * a visible gap between crowded neighbours.
32284
+ */
32285
+ #nodeRenderRadius(n) {
32286
+ const distance = Math.hypot(n.position.x, n.position.y);
32287
+ const scale = Math.max(.2, 1 - distance);
32288
+ const weightScale = this.minWeightScale + (this.maxWeightScale - this.minWeightScale) * n.weightNormalized;
32289
+ const radius = this.nodeRadius * scale * weightScale;
32290
+ if (distance < 1e-6) return radius;
32291
+ const arcLength = n.angularShare * distance;
32292
+ return Math.min(radius, Math.max(arcLength * .35, .003));
32293
+ }
32294
+ /**
32295
+ * Which nodes get a rendered label, greedily thinned to avoid overlap: a
32296
+ * per-node radius threshold alone ({@link minNodeRadius}) still lets many
32297
+ * same-sized nodes crowded into a small angular wedge all show labels that
32298
+ * visually collide. Nodes are considered in priority order (closer ring
32299
+ * first, then larger on-screen radius) and a label is kept only if its
32300
+ * position isn't too close to an already-kept one.
32301
+ */
32302
+ #computeLabelKeys(nodes) {
32303
+ const minSpacing = .07;
32304
+ const prioritised = [...nodes.filter((n) => this.#nodeRenderRadius(n) >= this.minNodeRadius)].sort((a, b) => {
32305
+ if (a.ring !== b.ring) return a.ring - b.ring;
32306
+ return Math.hypot(a.position.x, a.position.y) - Math.hypot(b.position.x, b.position.y);
32307
+ });
32308
+ const kept = [];
32309
+ const keys = /* @__PURE__ */ new Set();
32310
+ for (const n of prioritised) if (!kept.some((k) => Math.hypot(k.position.x - n.position.x, k.position.y - n.position.y) < minSpacing)) {
32311
+ kept.push(n);
32312
+ keys.add(n.key);
32313
+ }
32314
+ return keys;
32315
+ }
32316
+ #renderNode(n, siblingGroups, labelKeys) {
32317
+ const { node, key, position } = n;
32318
+ const selected = this._selectedNodes.has(node);
32319
+ const tickled = this.tickled.isTickled(key);
32320
+ const filtered = !this.#matchesFilter(node, n.depth);
32321
+ const pending = this.#pendingKeys.has(key);
32322
+ const isFocused = n.ring === 0;
32323
+ const radius = this.#nodeRenderRadius(n);
32324
+ const showLabel = labelKeys.has(key);
32325
+ const siblings = siblingGroups.get(n.parentKey) ?? [n];
32326
+ const index = siblings.findIndex((s) => s.key === key);
32327
+ const scaledRadius = radius * RENDER_SCALE;
32328
+ const weightStyle = `--node-weight: ${n.weightNormalized};${n.weight === void 0 ? `` : ` --node-weight-raw: ${n.weight};`}`;
32329
+ return w`
32330
+ <g
32331
+ class="node ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${filtered ? `filtered` : ``} ${pending ? `loading` : ``} ${isFocused ? `focused` : ``}"
32332
+ data-key=${key}
32333
+ role="treeitem"
32334
+ tabindex="-1"
32335
+ aria-level=${n.depth + 1}
32336
+ aria-selected=${selected}
32337
+ aria-setsize=${siblings.length}
32338
+ aria-posinset=${index + 1}
32339
+ aria-label=${node.item.label}
32340
+ part="node node-${partToken(key)}"
32341
+ style=${weightStyle}
32342
+ transform="translate(${position.x * RENDER_SCALE} ${position.y * RENDER_SCALE})"
32343
+ @pointerdown=${(e) => e.stopPropagation()}
32344
+ @click=${(e) => {
32345
+ e.stopPropagation();
32346
+ this.#handleItemClick(n, e);
32347
+ }}
32348
+ @dblclick=${(e) => {
32349
+ e.stopPropagation();
32350
+ this.#handleItemDblClick(n);
32351
+ }}
32352
+ @pointerenter=${() => this.tickled.handlePointerEnter(key)}
32353
+ >
32354
+ <circle class="node-hit" r=${Math.max(scaledRadius, .035 * RENDER_SCALE)} part="hit" />
32355
+ <circle class="node-dot" r=${scaledRadius} part="dot" />
32356
+ ${showLabel ? w`<text class="hyperbolictree-label" part="label" x=${scaledRadius + .01 * RENDER_SCALE} y="0" dominant-baseline="middle">${node.item.label}</text>` : A}
32357
+ </g>
32358
+ `;
32359
+ }
32360
+ render() {
32361
+ const { nodes, edges } = this.#layout();
32362
+ const byKey = new Map(nodes.map((n) => [n.key, n]));
32363
+ const siblingGroups = /* @__PURE__ */ new Map();
32364
+ for (const n of nodes) {
32365
+ const group = siblingGroups.get(n.parentKey) ?? [];
32366
+ group.push(n);
32367
+ siblingGroups.set(n.parentKey, group);
32368
+ }
32369
+ const labelKeys = this.#computeLabelKeys(nodes);
32370
+ return b`
32371
+ <svg
32372
+ class="hyperbolictree"
32373
+ viewBox="${-1.05 * RENDER_SCALE} ${-1.05 * RENDER_SCALE} ${2.1 * RENDER_SCALE} ${2.1 * RENDER_SCALE}"
32374
+ preserveAspectRatio="xMidYMid meet"
32375
+ role="tree"
32376
+ tabindex="0"
32377
+ data-input-mode=${this.tickled.inputMode}
32378
+ @keydown=${(e) => this.#handleKeyDown(e)}
32379
+ @pointerdown=${(e) => this.#handleBackgroundPointerDown(e)}
32380
+ @pointermove=${(e) => this.#handleBackgroundPointerMove(e)}
32381
+ @pointerup=${(e) => this.#handleBackgroundPointerUp(e)}
32382
+ @pointerleave=${() => this.tickled.clearTickled()}
32383
+ >
32384
+ <g class="zoom" transform="scale(${this.zoom})">
32385
+ <circle class="disk-boundary" part="boundary" cx="0" cy="0" r=${RENDER_SCALE} />
32386
+ <g class="edges" part="edges">
32387
+ ${repeat(edges, (e) => `${e.fromKey}->${e.toKey}`, (e) => this.#renderEdge(e, byKey))}
32388
+ </g>
32389
+ <g class="nodes" part="nodes">
32390
+ ${repeat(nodes, (n) => n.key, (n) => this.#renderNode(n, siblingGroups, labelKeys))}
32391
+ </g>
32392
+ </g>
32393
+ </svg>
32394
+ ${this.search.renderField()}
32395
+ `;
32396
+ }
32397
+ static {
32398
+ this.styles = [
32399
+ themeFallbacks,
32400
+ listSearchStyles,
32401
+ i$3`
32402
+ :host {
32403
+ --hyperbolictree-node-color: var(--surface-4);
32404
+ --hyperbolictree-node-text: var(--surface-3-text);
32405
+ --hyperbolictree-edge-color: var(--surface-6);
32406
+ --hyperbolictree-boundary-color: var(--border-subtle);
32407
+ --hyperbolictree-font-size: 25px;
32408
+
32409
+ display: block;
32410
+ overflow: hidden;
32411
+ outline: none;
32412
+ overscroll-behavior: contain;
32413
+ }
32414
+
32415
+ /*
32416
+ * delegatesFocus means the host itself reports as focused whenever
32417
+ * the shadow DOM's focused descendant (the svg) is — without this,
32418
+ * the host also picks up the browser's own default focus ring/fill
32419
+ * sized to the whole box.
32420
+ */
32421
+ :host(:focus),
32422
+ :host(:focus-visible) {
32423
+ outline: none;
32424
+ }
32425
+
32426
+ .hyperbolictree {
32427
+ display: block;
32428
+ width: 100%;
32429
+ height: 100%;
32430
+ outline: none;
32431
+ touch-action: none;
32432
+ overscroll-behavior: contain;
32433
+ }
32434
+
32435
+ .disk-boundary {
32436
+ fill: none;
32437
+ stroke: var(--hyperbolictree-boundary-color);
32438
+ stroke-width: 1;
32439
+ }
32440
+
32441
+ .edge {
32442
+ fill: none;
32443
+ stroke: var(--hyperbolictree-edge-color);
32444
+ /* --edge-weight (0..1, average of the endpoint nodes' --node-weight) thickens heavier edges. */
32445
+ stroke-width: calc(1px + var(--edge-weight, 0.5) * 3px);
32446
+ }
32447
+
32448
+ .node {
32449
+ cursor: pointer;
32450
+ }
32451
+
32452
+ .node-hit {
32453
+ fill: transparent;
32454
+ pointer-events: all;
32455
+ }
32456
+
32457
+ .node-dot {
32458
+ /* --node-weight (0..1, normalized across the visible node set) tints toward --accent for heavier nodes. */
32459
+ fill: color-mix(in oklab, var(--hyperbolictree-node-color), var(--accent) calc(var(--node-weight, 0.5) * 50%));
32460
+ stroke: var(--surface-2);
32461
+ stroke-width: 1;
32462
+ pointer-events: none;
32463
+ }
32464
+
32465
+ .node.tickled .node-dot {
32466
+ fill: var(--item-bg-tickled);
32467
+ }
32468
+
32469
+ .node.selected .node-dot {
32470
+ fill: var(--item-bg-selected);
32471
+ }
32472
+
32473
+ .node.selected.tickled .node-dot {
32474
+ fill: var(--item-bg-selected-tickled);
32475
+ }
32476
+
32477
+ .node.focused .node-dot {
32478
+ stroke: var(--accent);
32479
+ stroke-width: 3;
32480
+ }
32481
+
32482
+ .node.filtered {
32483
+ opacity: 0.3;
32484
+ }
32485
+
32486
+ .node.loading .node-dot {
32487
+ opacity: 0.6;
32488
+ }
32489
+
32490
+ .hyperbolictree-label {
32491
+ font-size: var(--hyperbolictree-font-size);
32492
+ fill: var(--hyperbolictree-node-text);
32493
+ cursor: pointer;
32494
+ user-select: none;
32495
+ }
32496
+ `
32497
+ ];
32498
+ }
32499
+ };
32500
+ __decorate([property({ type: Object })], HyperbolicTreeListElement.prototype, "root", void 0);
32501
+ __decorate([property({ attribute: false })], HyperbolicTreeListElement.prototype, "model", void 0);
32502
+ __decorate([property({ attribute: false })], HyperbolicTreeListElement.prototype, "loadChildren", void 0);
32503
+ __decorate([property({
32504
+ reflect: true,
32505
+ attribute: `exclusivity`
32506
+ })], HyperbolicTreeListElement.prototype, "exclusivity", void 0);
32507
+ __decorate([property({
32508
+ reflect: true,
32509
+ attribute: `selection-filter`
32510
+ })], HyperbolicTreeListElement.prototype, "selectionFilter", void 0);
32511
+ __decorate([property({
32512
+ type: String,
32513
+ attribute: `interaction-mode`
32514
+ })], HyperbolicTreeListElement.prototype, "interactionMode", void 0);
32515
+ __decorate([property({
32516
+ type: Number,
32517
+ attribute: `max-radius`
32518
+ })], HyperbolicTreeListElement.prototype, "maxRadius", void 0);
32519
+ __decorate([property({
32520
+ type: Number,
32521
+ attribute: `node-radius`
32522
+ })], HyperbolicTreeListElement.prototype, "nodeRadius", void 0);
32523
+ __decorate([property({
32524
+ type: Number,
32525
+ attribute: `min-node-radius`
32526
+ })], HyperbolicTreeListElement.prototype, "minNodeRadius", void 0);
32527
+ __decorate([property({
32528
+ type: Number,
32529
+ attribute: `min-weight-scale`
32530
+ })], HyperbolicTreeListElement.prototype, "minWeightScale", void 0);
32531
+ __decorate([property({
32532
+ type: Number,
32533
+ attribute: `max-weight-scale`
32534
+ })], HyperbolicTreeListElement.prototype, "maxWeightScale", void 0);
32535
+ __decorate([property({ type: Number })], HyperbolicTreeListElement.prototype, "zoom", void 0);
32536
+ __decorate([property({ type: Number })], HyperbolicTreeListElement.prototype, "curvature", void 0);
32537
+ __decorate([property({
32538
+ type: Number,
32539
+ attribute: `focus-animation-duration`
32540
+ })], HyperbolicTreeListElement.prototype, "focusAnimationDuration", void 0);
32541
+ __decorate([property({ attribute: false })], HyperbolicTreeListElement.prototype, "edgeRenderer", void 0);
32542
+ __decorate([property({ attribute: false })], HyperbolicTreeListElement.prototype, "selectedNode", void 0);
32543
+ __decorate([state()], HyperbolicTreeListElement.prototype, "_selectedNodes", void 0);
32544
+ __decorate([property({ attribute: false })], HyperbolicTreeListElement.prototype, "filterPredicate", void 0);
32545
+ __decorate([property({
32546
+ type: Boolean,
32547
+ attribute: `disable-keyboard-navigation`
32548
+ })], HyperbolicTreeListElement.prototype, "disableKeyboardNavigation", void 0);
32549
+ __decorate([property({ attribute: false })], HyperbolicTreeListElement.prototype, "registry", void 0);
32550
+ __decorate([property({
32551
+ type: String,
32552
+ attribute: `search-modes`,
32553
+ reflect: true
32554
+ })], HyperbolicTreeListElement.prototype, "searchModes", void 0);
32555
+ __decorate([state()], HyperbolicTreeListElement.prototype, "_focusKey", void 0);
32556
+ __decorate([state()], HyperbolicTreeListElement.prototype, "_animCenter", void 0);
32557
+ __decorate([state()], HyperbolicTreeListElement.prototype, "_panOffset", void 0);
32558
+ HyperbolicTreeListElement = __decorate([safeCustomElement(`ixfx-hyperbolictree-list`)], HyperbolicTreeListElement);
32559
+ //#endregion
32560
+ //#region src/icicle-tree/layout.ts
32561
+ /** Coerce a raw accessor result to a non-negative finite weight. */
32562
+ function normaliseValue(raw) {
32563
+ return typeof raw === `number` && Number.isFinite(raw) && raw > 0 ? raw : 0;
32564
+ }
32565
+ /** Depth-first search for the node with `key`. Returns `undefined` when absent. */
32566
+ function findIcicleNode(root, key) {
32567
+ if (!root) return void 0;
32568
+ if (root.item.key === key) return root;
32569
+ for (const child of root.children ?? []) {
32570
+ const hit = findIcicleNode(child, key);
32571
+ if (hit) return hit;
32572
+ }
32573
+ }
32574
+ /**
32575
+ * Chain of nodes from `root` down to (and including) the node with `key`.
32576
+ * Returns `undefined` when the key is absent. The first entry is always `root`.
32577
+ */
32578
+ function findIciclePath(root, key) {
32579
+ if (!root) return void 0;
32580
+ if (root.item.key === key) return [root];
32581
+ for (const child of root.children ?? []) {
32582
+ const hit = findIciclePath(child, key);
32583
+ if (hit) return [root, ...hit];
32584
+ }
32585
+ }
32586
+ /**
32587
+ * Compute the visible rectangles for an icicle view.
32588
+ *
32589
+ * Bands start at the zoom node's **children** (the zoom node itself is shown in
32590
+ * the breadcrumb strip, never as a rect — matching `TreeComponent.getNodes()`,
32591
+ * where the root is never listed). Each band spans 0–1; a rect's `x`/`width`
32592
+ * are fractions of its band, proportional to `valueAccessor` shares among
32593
+ * siblings. Siblings whose weights all normalise to `0` split the band equally.
32594
+ *
32595
+ * @param root True tree root. `undefined` (or a root without children) yields `[]`.
32596
+ * @param options `valueAccessor` (default equal weights), `maxDepth` (band count,
32597
+ * default unlimited), `zoomKey` (visual root, default true root; unknown keys
32598
+ * fall back to the true root).
32599
+ */
32600
+ function computeIcicleLayout(root, options = {}) {
32601
+ if (!root?.children?.length) return [];
32602
+ const { maxDepth = Number.POSITIVE_INFINITY, valueAccessor = () => 1, zoomKey, hideLeaves = false } = options;
32603
+ if (maxDepth <= 0) return [];
32604
+ const zoomNode = zoomKey === void 0 ? root : findIcicleNode(root, zoomKey) ?? root;
32605
+ const zoomPath = findIciclePath(root, zoomNode.item.key);
32606
+ const zoomDepth = zoomPath ? zoomPath.length - 2 : -1;
32607
+ const siblings = zoomNode.children ?? [];
32608
+ if (siblings.length === 0) return [];
32609
+ const isLeaf = (node) => node.item.isLeaf === true || node.children !== void 0 && node.children.length === 0;
32610
+ const rects = [];
32611
+ const layoutLevel = (nodes, depth, relativeDepth, offset, span, parentKey) => {
32612
+ const visible = hideLeaves ? nodes.filter((n) => !isLeaf(n)) : nodes;
32613
+ if (visible.length === 0 || relativeDepth >= maxDepth) return;
32614
+ const weights = visible.map((n) => normaliseValue(valueAccessor(n.item)));
32615
+ const total = weights.reduce((a, b) => a + b, 0);
32616
+ const setSize = visible.length;
32617
+ let cursor = offset;
32618
+ visible.forEach((node, index) => {
32619
+ const width = span * (total > 0 ? weights[index] / total : 1 / setSize);
32620
+ const children = node.children ?? [];
32621
+ rects.push({
32622
+ node,
32623
+ depth,
32624
+ relativeDepth,
32625
+ x: cursor,
32626
+ width,
32627
+ parentKey,
32628
+ index,
32629
+ setSize,
32630
+ hasChildren: children.length > 0 || node.children === void 0 && node.item.isLeaf !== true
32631
+ });
32632
+ if (children.length > 0) layoutLevel(children, depth + 1, relativeDepth + 1, cursor, width, node.item.key);
32633
+ cursor += width;
32634
+ });
32635
+ };
32636
+ layoutLevel(siblings, zoomDepth + 1, 0, 0, 1, zoomNode.item.key);
32637
+ return rects;
32638
+ }
32639
+ //#endregion
32640
+ //#region src/icicle-tree/icicletree-list.ts
32641
+ let IcicleTreeListElement = class IcicleTreeListElement extends i {
32642
+ constructor(..._args) {
32643
+ super(..._args);
32644
+ this.exclusivity = `none`;
32645
+ this.selectionFilter = `all`;
32646
+ this.interactionMode = `standard`;
32647
+ this.orientation = `horizontal`;
32648
+ this.maxDepth = 4;
32649
+ this.minLabelWidth = 40;
32650
+ this.minVerticalLabelWidth = 16;
32651
+ this.hideLeaves = false;
32652
+ this.valueAccessor = () => 1;
32653
+ this._selectedNodes = /* @__PURE__ */ new Set();
32654
+ this.disableKeyboardNavigation = false;
32655
+ this.registry = void 0;
32656
+ this._zoomKey = void 0;
32657
+ this.search = new ListSearchController(this, { adapter: createTreeListSearchAdapter(this, {
32658
+ labelSelector: `.icicle-label`,
32659
+ highlightKey: `incr-search-highlight`
32660
+ }) });
32661
+ this.tickled = new TickledController(this, {
32662
+ getItems: () => this.#rects().map((r) => ({
32663
+ id: r.node.item.key,
32664
+ enabled: true
32665
+ })),
32666
+ onStateChange: () => {
32667
+ this.setAttribute(`data-input-mode`, this.tickled.inputMode);
32668
+ },
32669
+ onTickle: (id) => {
32670
+ if (id === void 0) return;
32671
+ const rect = this.#rects().find((r) => r.node.item.key === id);
32672
+ if (!rect) return;
32673
+ this.dispatchEvent(new CustomEvent(`tickle`, {
32674
+ detail: {
32675
+ node: rect.node,
32676
+ depth: rect.depth
32677
+ },
32678
+ bubbles: true,
32679
+ composed: true
32680
+ }));
32681
+ }
32682
+ });
32683
+ this.#pendingKeys = /* @__PURE__ */ new Set();
32684
+ this.#aborters = /* @__PURE__ */ new Map();
32685
+ }
32686
+ static {
32687
+ this.shadowRootOptions = {
32688
+ ...i.shadowRootOptions,
32689
+ delegatesFocus: true
32690
+ };
32691
+ }
32692
+ get selectedNodes() {
32693
+ return this._selectedNodes;
32694
+ }
32695
+ /** Current zoom root. `undefined` when showing the full tree. Pure view-state — `root` is never mutated. */
32696
+ get focusedNode() {
32697
+ if (this._zoomKey === void 0) return void 0;
32698
+ return findIcicleNode(this.#effectiveRoot, this._zoomKey);
32699
+ }
32700
+ #modelUnsubscribe;
32701
+ #pendingKeys;
32702
+ #aborters;
32703
+ #anchorIndex;
32704
+ #ownedRegistry;
32705
+ #unregisterSearchCommands;
32706
+ #resizeObserver;
32707
+ get #effectiveRoot() {
32708
+ return this.model?.root ?? this.root;
32709
+ }
32710
+ #rects() {
32711
+ return computeIcicleLayout(this.#effectiveRoot, {
32712
+ valueAccessor: this.valueAccessor,
32713
+ maxDepth: this.maxDepth,
32714
+ zoomKey: this._zoomKey,
32715
+ hideLeaves: this.hideLeaves
32716
+ });
32717
+ }
32718
+ connectedCallback() {
32719
+ super.connectedCallback();
32720
+ this.setAttribute(`data-input-mode`, `mouse`);
32721
+ const registry = this.#ownedRegistry = createCommandRegistry();
32722
+ registry.register({
32723
+ id: `select-all`,
32724
+ label: `Select All`,
32725
+ description: `Select all visible items`,
32726
+ execute: () => this.selectAll()
32727
+ });
32728
+ registry.register({
32729
+ id: `deselect-all`,
32730
+ label: `Deselect All`,
32731
+ description: `Clear all selection`,
32732
+ execute: () => this.deselectAll()
32733
+ });
32734
+ this.registry = registry;
32735
+ this.#syncSearchCommands();
32736
+ if (typeof ResizeObserver !== `undefined`) {
32737
+ this.#resizeObserver = new ResizeObserver(() => this.requestUpdate());
32738
+ this.#resizeObserver.observe(this);
32739
+ }
32740
+ }
32741
+ disconnectedCallback() {
32742
+ super.disconnectedCallback();
32743
+ this.#modelUnsubscribe?.();
32744
+ this.#modelUnsubscribe = void 0;
32745
+ for (const aborter of this.#aborters.values()) aborter.abort();
32746
+ this.#aborters.clear();
32747
+ this.#pendingKeys.clear();
32748
+ this.#resizeObserver?.disconnect();
32749
+ this.#resizeObserver = void 0;
32750
+ if (this.#ownedRegistry) {
32751
+ this.#ownedRegistry.unregister(`select-all`);
32752
+ this.#ownedRegistry.unregister(`deselect-all`);
32753
+ this.#ownedRegistry = void 0;
32754
+ this.registry = void 0;
32755
+ }
32756
+ }
32757
+ #effectiveSearchModes() {
32758
+ const raw = this.searchModes?.trim();
32759
+ if (raw === void 0) return [...LIST_SEARCH_MODES];
32760
+ const requested = new Set(raw.split(/\s+/));
32761
+ return LIST_SEARCH_MODES.filter((m) => requested.has(m));
32762
+ }
32763
+ #syncSearchCommands() {
32764
+ if (!this.#ownedRegistry) return;
32765
+ this.search.setModes(this.#effectiveSearchModes());
32766
+ this.#unregisterSearchCommands?.();
32767
+ this.#unregisterSearchCommands = registerListSearchCommands(this.#ownedRegistry, this.search);
32768
+ }
32769
+ updated(changedProps) {
32770
+ if (changedProps.has(`root`) && this.root) this.#resetViewState();
32771
+ if (changedProps.has(`model`)) {
32772
+ this.#modelUnsubscribe?.();
32773
+ this.#modelUnsubscribe = void 0;
32774
+ if (this.model) {
32775
+ this.#modelUnsubscribe = this.model._subscribe((event) => {
32776
+ if (event.type === `root`) {
32777
+ this.#resetViewState();
32778
+ this.requestUpdate();
32779
+ } else if (event.type === `invalidate`) this.requestUpdate();
32780
+ });
32781
+ this.#resetViewState();
32782
+ }
32783
+ }
32784
+ if (changedProps.has(`interactionMode`)) {
32785
+ this.#anchorIndex = void 0;
32786
+ this.clearSelection();
32787
+ }
32788
+ if (changedProps.has(`searchModes`)) this.#syncSearchCommands();
32789
+ if (this._zoomKey !== void 0 && !findIcicleNode(this.#effectiveRoot, this._zoomKey)) this._zoomKey = void 0;
32790
+ this.#ensureVisibleChildren();
32791
+ this.#syncTooltip();
32792
+ }
32793
+ /** The host's own (viewport) extent — width in horizontal orientation, height in vertical. */
32794
+ #hostExtent() {
32795
+ return (this.orientation === `vertical` ? this.clientHeight : this.clientWidth) || 0;
32796
+ }
32797
+ /**
32798
+ * Whether `rect`'s label should be rotated or hidden for lack of space, per
32799
+ * {@link minLabelWidth} / {@link minVerticalLabelWidth}. `orientation="vertical"`
32800
+ * rects never rotate — hides outright at `minLabelWidth` instead, same as before.
32801
+ */
32802
+ #labelMode(rect) {
32803
+ const hostExtent = this.#hostExtent();
32804
+ if (hostExtent === 0) return {
32805
+ hidden: false,
32806
+ rotated: false
32807
+ };
32808
+ const vertical = this.orientation === `vertical`;
32809
+ const pixelWidth = rect.width * hostExtent;
32810
+ if (vertical) return {
32811
+ hidden: pixelWidth < this.minLabelWidth,
32812
+ rotated: false
32813
+ };
32814
+ if (pixelWidth < this.minVerticalLabelWidth) return {
32815
+ hidden: true,
32816
+ rotated: false
32817
+ };
32818
+ return {
32819
+ hidden: false,
32820
+ rotated: pixelWidth < this.minLabelWidth
32821
+ };
32822
+ }
32823
+ /** Anchor the shared tooltip popover to the tickled rect, if its label needs one. */
32824
+ #syncTooltip() {
32825
+ const popover = this._tooltipEl;
32826
+ if (!popover?.popover) return;
32827
+ const key = this.tickled.tickledId;
32828
+ const rect = key === void 0 ? void 0 : this.#rects().find((r) => r.node.item.key === key);
32829
+ const mode = rect ? this.#labelMode(rect) : void 0;
32830
+ const isOpen = popover.matches(`:popover-open`);
32831
+ if (rect && mode && (mode.hidden || mode.rotated)) {
32832
+ popover.textContent = rect.node.item.label;
32833
+ if (!isOpen) try {
32834
+ popover.showPopover();
32835
+ } catch {}
32836
+ } else if (isOpen) try {
32837
+ popover.hidePopover();
32838
+ } catch {}
32839
+ }
32840
+ #resetViewState() {
32841
+ this.#clearSelectionInternal();
32842
+ this.tickled.clearTickled();
32843
+ this._zoomKey = void 0;
32844
+ this.#anchorIndex = void 0;
32845
+ }
32846
+ #ensureVisibleChildren() {
32847
+ if (!this.model && !this.loadChildren) return;
32848
+ for (const rect of this.#rects()) {
32849
+ const { node } = rect;
32850
+ if (node.children !== void 0 || this.#pendingKeys.has(node.item.key)) continue;
32851
+ this.#loadChildren(node, rect.depth);
32852
+ }
32853
+ }
32854
+ async #loadChildren(node, depth) {
32855
+ const key = node.item.key;
32856
+ this.#pendingKeys.add(key);
32857
+ const controller = new AbortController();
32858
+ this.#aborters.set(key, controller);
32859
+ this.requestUpdate();
32860
+ try {
32861
+ let children;
32862
+ if (this.model) children = await this.model.getChildren(node, depth, controller.signal);
32863
+ else children = [...await collectDataResult(this.loadChildren({
32864
+ node,
32865
+ depth
32866
+ }, controller.signal), controller.signal)];
32867
+ if (controller.signal.aborted) return;
32868
+ node.children = children;
32869
+ } catch {
32870
+ if (controller.signal.aborted) return;
32871
+ node.children = [];
32872
+ } finally {
32873
+ this.#pendingKeys.delete(key);
32874
+ this.#aborters.delete(key);
32875
+ if (!controller.signal.aborted) this.requestUpdate();
32876
+ }
32877
+ }
32878
+ #canSelect(node) {
32879
+ if (this.selectionFilter === `none`) return false;
32880
+ if (this.selectionFilter === `leaf`) return node.item.isLeaf === true;
32881
+ if (this.selectionFilter === `branch`) return node.item.isLeaf === false || node.children !== void 0 && node.children.length > 0;
32882
+ return true;
32883
+ }
32884
+ #clearSelectionInternal() {
32885
+ this._selectedNodes.clear();
32886
+ this.selectedNode = void 0;
32887
+ }
32888
+ #dispatchSelect(previous) {
32889
+ this.dispatchEvent(new CustomEvent(`select`, {
32890
+ detail: {
32891
+ selected: new Set(this._selectedNodes),
32892
+ previous
32893
+ },
32894
+ bubbles: true,
32895
+ composed: true
32896
+ }));
32897
+ }
32898
+ select(node) {
32899
+ if (!this.#canSelect(node)) return;
32900
+ const prev = new Set(this._selectedNodes);
32901
+ this._selectedNodes.clear();
32902
+ this._selectedNodes.add(node);
32903
+ this.selectedNode = node;
32904
+ this.#dispatchSelect(prev);
32905
+ this.requestUpdate();
32906
+ }
32907
+ deselect(node) {
32908
+ if (!this._selectedNodes.has(node)) return;
32909
+ const prev = new Set(this._selectedNodes);
32910
+ this._selectedNodes.delete(node);
32911
+ if (this.selectedNode === node) this.selectedNode = [...this._selectedNodes].at(-1);
32912
+ this.#dispatchSelect(prev);
32913
+ this.requestUpdate();
32914
+ }
32915
+ clearSelection() {
32916
+ if (this._selectedNodes.size === 0) return;
32917
+ const prev = new Set(this._selectedNodes);
32918
+ this.#clearSelectionInternal();
32919
+ this.#dispatchSelect(prev);
32920
+ this.requestUpdate();
32921
+ }
32922
+ selectAll() {
32923
+ const prev = new Set(this._selectedNodes);
32924
+ for (const rect of this.#rects()) {
32925
+ if (!this.#canSelect(rect.node)) continue;
32926
+ this._selectedNodes.add(rect.node);
32927
+ }
32928
+ this.selectedNode = [...this._selectedNodes].at(-1);
32929
+ this.#dispatchSelect(prev);
32930
+ this.requestUpdate();
32931
+ }
32932
+ deselectAll() {
32933
+ const prev = new Set(this._selectedNodes);
32934
+ this.#clearSelectionInternal();
32935
+ this.#dispatchSelect(prev);
32936
+ this.requestUpdate();
32937
+ }
32938
+ /** Replace the selection with `nodes` (subject to `selectionFilter`) — search "select" mode. */
32939
+ selectMany(nodes) {
32940
+ const prev = new Set(this._selectedNodes);
32941
+ this._selectedNodes = new Set([...nodes].filter((n) => this.#canSelect(n)));
32942
+ this.selectedNode = [...this._selectedNodes].at(-1);
32943
+ this.#dispatchSelect(prev);
32944
+ this.requestUpdate();
32945
+ }
32946
+ /**
32947
+ * Drill down so `node` becomes the visual root (ancestors move to the
32948
+ * breadcrumb strip). Pure view-state — `root` is never mutated.
32949
+ * Fires `zoom` and the semantic `expand` event.
32950
+ */
32951
+ zoomTo(node) {
31659
32952
  if (this._zoomKey === node.item.key) return;
31660
32953
  this._zoomKey = node.item.key;
31661
32954
  this.tickled.clearTickled();
@@ -37660,8 +38953,7 @@ let MulticolListElement = class MulticolListElement extends i {
37660
38953
  display: flex;
37661
38954
  flex-direction: row;
37662
38955
  align-items: stretch;
37663
- overflow-x: auto;
37664
- overflow-y: hidden;
38956
+ overflow: hidden;
37665
38957
  position: relative;
37666
38958
  height: 100%;
37667
38959
  }
@@ -38282,7 +39574,16 @@ let MulticolListElement = class MulticolListElement extends i {
38282
39574
  let headerWidth = 0;
38283
39575
  if (headerEl) {
38284
39576
  const labelBtn = headerEl.querySelector(`.column-label`);
38285
- if (labelBtn) headerWidth = measure(labelBtn.textContent ?? ``);
39577
+ if (labelBtn) {
39578
+ const labelTextWidth = measure(labelBtn.textContent ?? ``);
39579
+ const btnStyle = getComputedStyle(labelBtn);
39580
+ const labelBtnPaddingH = Number.parseFloat(btnStyle.paddingLeft) + Number.parseFloat(btnStyle.paddingRight);
39581
+ const burgerBtn = headerEl.querySelector(`.burger-btn`);
39582
+ const burgerWidth = burgerBtn ? Number.parseFloat(getComputedStyle(burgerBtn).width) : 0;
39583
+ const headerStyle = getComputedStyle(headerEl);
39584
+ const gap = Number.parseFloat(headerStyle.gap) || 0;
39585
+ headerWidth = labelTextWidth + labelBtnPaddingH + burgerWidth + gap;
39586
+ }
38286
39587
  }
38287
39588
  const neededWidth = Math.max(headerWidth, contentWidth + 24 + 16);
38288
39589
  const clampedWidth = Math.max(minWidth, Math.min(maxWidth, Math.ceil(neededWidth)));
@@ -50663,6 +51964,6 @@ function init() {
50663
51964
  console.log(`Init`);
50664
51965
  }
50665
51966
  //#endregion
50666
- 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, ShapefillValueElement, 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 };
51967
+ 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, HyperbolicTreeListElement, 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, ShapefillValueElement, 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, clampToDisk, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeCanonicalPositions, computeColour, computeHyperbolicLayout, computeIcicleLayout, computeLeafGeoms, computeTreemapLayout, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, euclideanRadiusForHyperbolicDistance, extractStack, findHyperbolicNode, findHyperbolicPath, findIcicleNode, findIciclePath, findNode, findPanelNode, findParentOf, findStackOf, findStackPathByName, findTreemapNode, findTreemapPath, geodesicInterpolate, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, hyperbolicDistanceForEuclideanRadius, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, mobiusAdd, mobiusFromOrigin, mobiusToOrigin, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, norm, normalise, normaliseValue, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, poincareDistance, pointerOverAnyHost, prefersReducedMotion, preserveRestoreWeights, pruneDraggedDescendants, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, setPanelRestoreWeight, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, toolbarGapIndex, walk, wrapRoot };
50667
51968
 
50668
51969
  //# sourceMappingURL=index.js.map