@ixfx/components 0.8.8 → 0.8.9

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 (64) hide show
  1. package/bundle/index.d.ts +232 -42
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +1102 -37
  4. package/bundle/index.js.map +1 -1
  5. package/dist/crumbs.d.ts +1 -1
  6. package/dist/{data-grid-BKa9i86q.d.ts → data-grid-C588pTgt.d.ts} +3 -3
  7. package/dist/{data-grid-BKa9i86q.d.ts.map → data-grid-C588pTgt.d.ts.map} +1 -1
  8. package/dist/data-grid.d.ts +2 -2
  9. package/dist/data-grid.js +1 -1
  10. package/dist/{detail-list-CHTomlbR.d.ts → detail-list-IKl76Wnp.d.ts} +4 -4
  11. package/dist/{detail-list-CHTomlbR.d.ts.map → detail-list-IKl76Wnp.d.ts.map} +1 -1
  12. package/dist/detail-list.d.ts +3 -3
  13. package/dist/detail-list.js +1 -1
  14. package/dist/{grid-list-CsZcXxMC.d.ts → grid-list-BUlUnisU.d.ts} +7 -55
  15. package/dist/grid-list-BUlUnisU.d.ts.map +1 -0
  16. package/dist/{grid-list-C8oMxLl-.js → grid-list-D18FNJRH.js} +2 -2
  17. package/dist/{grid-list-C8oMxLl-.js.map → grid-list-D18FNJRH.js.map} +1 -1
  18. package/dist/grid-list.d.ts +2 -2
  19. package/dist/grid-list.js +1 -1
  20. package/dist/incr-search.d.ts +1 -1
  21. package/dist/{index-Dgrx-DIA.d.ts → index--qnhBWZJ.d.ts} +2 -2
  22. package/dist/{index-Dgrx-DIA.d.ts.map → index--qnhBWZJ.d.ts.map} +1 -1
  23. package/dist/index.d.ts +30 -9
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +9 -9
  26. package/dist/index.js.map +1 -1
  27. package/dist/{labelled-slider-input-BCH9968c.js → labelled-slider-input-aEYDvW2S.js} +2 -2
  28. package/dist/{labelled-slider-input-BCH9968c.js.map → labelled-slider-input-aEYDvW2S.js.map} +1 -1
  29. package/dist/labelled-slider-input.js +1 -1
  30. package/dist/list-native-drag-controller-CFyrkKUj.d.ts +61 -0
  31. package/dist/list-native-drag-controller-CFyrkKUj.d.ts.map +1 -0
  32. package/dist/{list-native-drag-controller-DrY3qeJM.js → list-native-drag-controller-DxD6Yjci.js} +14 -2
  33. package/dist/list-native-drag-controller-DxD6Yjci.js.map +1 -0
  34. package/dist/miller.d.ts +2 -2
  35. package/dist/plots.js +1 -1
  36. package/dist/slider-input-BxURAAmD.d.ts.map +1 -1
  37. package/dist/{slider-input-WR8_RwHg.js → slider-input-Cb5uSV42.js} +78 -11
  38. package/dist/slider-input-Cb5uSV42.js.map +1 -0
  39. package/dist/slider-input.js +1 -1
  40. package/dist/{tree-DSMn566I.js → tree-a14n9y7i.js} +1006 -19
  41. package/dist/tree-a14n9y7i.js.map +1 -0
  42. package/dist/{tree-component-nPP5Y-WS.d.ts → tree-component-BW2iCFq9.d.ts} +107 -3
  43. package/dist/tree-component-BW2iCFq9.d.ts.map +1 -0
  44. package/dist/tree.d.ts +102 -4
  45. package/dist/tree.d.ts.map +1 -1
  46. package/dist/tree.js +2 -2
  47. package/dist/{vertical-list-A6oWfivZ.d.ts → vertical-list-CHrXmmQ3.d.ts} +3 -3
  48. package/dist/{vertical-list-A6oWfivZ.d.ts.map → vertical-list-CHrXmmQ3.d.ts.map} +1 -1
  49. package/dist/vertical-list.d.ts +2 -2
  50. package/dist/vertical-list.js +1 -1
  51. package/dist/{xy-axis-CrrVdDFe.js → xy-axis-COKw338Q.js} +2 -2
  52. package/dist/xy-axis-COKw338Q.js.map +1 -0
  53. package/dist/xy-axis-DQqd2yXJ.d.ts.map +1 -1
  54. package/docs-user/index.json +2 -2
  55. package/docs-user/tree.md +75 -0
  56. package/package.json +1 -1
  57. package/dist/grid-list-CsZcXxMC.d.ts.map +0 -1
  58. package/dist/list-drag-types-kpaXz2pZ.d.ts +0 -42
  59. package/dist/list-drag-types-kpaXz2pZ.d.ts.map +0 -1
  60. package/dist/list-native-drag-controller-DrY3qeJM.js.map +0 -1
  61. package/dist/slider-input-WR8_RwHg.js.map +0 -1
  62. package/dist/tree-DSMn566I.js.map +0 -1
  63. package/dist/tree-component-nPP5Y-WS.d.ts.map +0 -1
  64. package/dist/xy-axis-CrrVdDFe.js.map +0 -1
package/bundle/index.js CHANGED
@@ -6049,7 +6049,7 @@ const DEFAULT_THRESHOLD = 4;
6049
6049
  /** Pointer distance (px) from an edge that triggers auto-scroll. */
6050
6050
  const EDGE_ZONE = 28;
6051
6051
  /** Max auto-scroll speed in px per frame. */
6052
- const MAX_SCROLL_SPEED = 16;
6052
+ const MAX_SCROLL_SPEED$1 = 16;
6053
6053
  /**
6054
6054
  * Shared pointer-drag (marquee / rubber-band) selection for list components.
6055
6055
  *
@@ -6315,10 +6315,10 @@ var ListDragSelectController = class {
6315
6315
  const py = this.#currentClientY - box.top;
6316
6316
  let dx = 0;
6317
6317
  let dy = 0;
6318
- if (px < EDGE_ZONE) dx = -Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, px) / EDGE_ZONE));
6319
- else if (px > box.width - EDGE_ZONE) dx = Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, box.width - px) / EDGE_ZONE));
6320
- if (py < EDGE_ZONE) dy = -Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, py) / EDGE_ZONE));
6321
- else if (py > box.height - EDGE_ZONE) dy = Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, box.height - py) / EDGE_ZONE));
6318
+ if (px < EDGE_ZONE) dx = -Math.ceil(MAX_SCROLL_SPEED$1 * (1 - Math.max(0, px) / EDGE_ZONE));
6319
+ else if (px > box.width - EDGE_ZONE) dx = Math.ceil(MAX_SCROLL_SPEED$1 * (1 - Math.max(0, box.width - px) / EDGE_ZONE));
6320
+ if (py < EDGE_ZONE) dy = -Math.ceil(MAX_SCROLL_SPEED$1 * (1 - Math.max(0, py) / EDGE_ZONE));
6321
+ else if (py > box.height - EDGE_ZONE) dy = Math.ceil(MAX_SCROLL_SPEED$1 * (1 - Math.max(0, box.height - py) / EDGE_ZONE));
6322
6322
  if (dx === 0 && dy === 0) return;
6323
6323
  const autoScroll = this.#config.autoScroll;
6324
6324
  if (!autoScroll) return;
@@ -6521,6 +6521,10 @@ var ListNativeDragController = class {
6521
6521
  } catch {}
6522
6522
  this.refreshDraggable();
6523
6523
  }
6524
+ /** `renderRoot` does not exist yet at `hostConnected` for a shadow-DOM host — rebind once it does. */
6525
+ hostUpdated() {
6526
+ this.#bind();
6527
+ }
6524
6528
  hostDisconnected() {
6525
6529
  this.#unbind();
6526
6530
  try {
@@ -6558,7 +6562,6 @@ var ListNativeDragController = class {
6558
6562
  #onDragStart = (event) => {
6559
6563
  if (!(event instanceof DragEvent)) return;
6560
6564
  if (this.#seenDragStarts.has(event)) return;
6561
- this.#seenDragStarts.add(event);
6562
6565
  let enabled = false;
6563
6566
  try {
6564
6567
  enabled = this.#config.isEnabled();
@@ -6572,6 +6575,7 @@ var ListNativeDragController = class {
6572
6575
  } catch {
6573
6576
  return;
6574
6577
  }
6578
+ if (originKey) this.#seenDragStarts.add(event);
6575
6579
  if (!originKey) return;
6576
6580
  let prepared;
6577
6581
  try {
@@ -6630,6 +6634,14 @@ var ListNativeDragController = class {
6630
6634
  notCancelled = true;
6631
6635
  }
6632
6636
  if (notCancelled) {
6637
+ if (event.dataTransfer) {
6638
+ try {
6639
+ if (event.dataTransfer.effectAllowed === `none` || event.dataTransfer.effectAllowed === `uninitialized`) event.dataTransfer.effectAllowed = `copyMove`;
6640
+ } catch {}
6641
+ try {
6642
+ this.#config.writeDataTransfer?.(event.dataTransfer, detail);
6643
+ } catch {}
6644
+ }
6633
6645
  const hotspot = preview.hotspot ?? {
6634
6646
  x: 16,
6635
6647
  y: 16
@@ -9736,15 +9748,138 @@ async function collectDataResult(result, signal) {
9736
9748
  return result;
9737
9749
  }
9738
9750
  //#endregion
9739
- //#region src/common/tree-data-model.ts
9751
+ //#region src/common/tree-drop-apply.ts
9740
9752
  function findNode$1(root, key) {
9741
9753
  if (root.item.key === key) return root;
9742
- if (!root.children) return void 0;
9743
- for (const child of root.children) {
9754
+ for (const child of root.children ?? []) {
9744
9755
  const found = findNode$1(child, key);
9745
9756
  if (found) return found;
9746
9757
  }
9747
9758
  }
9759
+ function findParent(root, key, parent = void 0) {
9760
+ for (const child of root.children ?? []) {
9761
+ if (child.item.key === key) return parent === void 0 ? root : parent;
9762
+ const found = findParent(child, key, child);
9763
+ if (found) return found;
9764
+ }
9765
+ }
9766
+ /** True when `key` is `ancestorKey`, or a descendant of it. */
9767
+ function isSelfOrDescendant(root, ancestorKey, key) {
9768
+ const ancestor = findNode$1(root, ancestorKey);
9769
+ return ancestor !== void 0 && findNode$1(ancestor, key) !== void 0;
9770
+ }
9771
+ /** Remove every node whose key is in `keys` (with its whole subtree), in one pass. */
9772
+ function removeKeys(node, keys) {
9773
+ if (!node.children) return node;
9774
+ return {
9775
+ ...node,
9776
+ children: node.children.filter((c) => !keys.has(c.item.key)).map((c) => removeKeys(c, keys))
9777
+ };
9778
+ }
9779
+ function childrenOf(root, parentKey) {
9780
+ if (parentKey === void 0) return root.children ?? [];
9781
+ return findNode$1(root, parentKey)?.children ?? [];
9782
+ }
9783
+ /** Return a new root with `parentKey`'s children replaced (root itself when `parentKey` is undefined). */
9784
+ function withChildren(node, parentKey, children) {
9785
+ if (parentKey === void 0) return {
9786
+ ...node,
9787
+ children
9788
+ };
9789
+ if (node.item.key === parentKey) return {
9790
+ ...node,
9791
+ children
9792
+ };
9793
+ if (!node.children) return node;
9794
+ return {
9795
+ ...node,
9796
+ children: node.children.map((c) => withChildren(c, parentKey, children))
9797
+ };
9798
+ }
9799
+ function clamp$5(n, min, max) {
9800
+ return Math.max(min, Math.min(max, n));
9801
+ }
9802
+ /**
9803
+ * Drop keys whose ancestor is also being dragged — only the top-most selected
9804
+ * nodes move; their subtrees travel with them. Preserves input order.
9805
+ */
9806
+ function pruneDraggedDescendants(root, keys) {
9807
+ const set = new Set(keys);
9808
+ return keys.filter((key) => {
9809
+ let parent = findParent(root, key);
9810
+ while (parent) {
9811
+ if (set.has(parent.item.key)) return false;
9812
+ parent = findParent(root, parent.item.key);
9813
+ }
9814
+ return true;
9815
+ });
9816
+ }
9817
+ /**
9818
+ * Framework-agnostic drop application. Given the current immutable `root` and a
9819
+ * resolved drop context, returns a **new** root with the drop applied, or the
9820
+ * unchanged `root` when the drop is invalid (dragged node into its own subtree,
9821
+ * missing reference, empty payload). Never throws, never mutates.
9822
+ *
9823
+ * The insertion point is re-derived from `target.referenceKey` + `target.position`
9824
+ * against the post-removal tree, so same-parent reorders are off-by-one-safe and
9825
+ * multi-node drops land as siblings in drag order. `target.index` is honoured only
9826
+ * for `position: 'inside'` (0 = first child, large = append).
9827
+ */
9828
+ function applyTreeDrop(root, ctx) {
9829
+ const { target, source } = ctx;
9830
+ let nodes;
9831
+ let removeSet = /* @__PURE__ */ new Set();
9832
+ if (source === `internal`) {
9833
+ const keys = pruneDraggedDescendants(root, [...ctx.draggedKeys]);
9834
+ if (keys.length === 0) return root;
9835
+ if (target.parentKey !== void 0) {
9836
+ for (const key of keys) if (isSelfOrDescendant(root, key, target.parentKey)) return root;
9837
+ }
9838
+ if (target.position !== `inside`) {
9839
+ for (const key of keys) if (isSelfOrDescendant(root, key, target.referenceKey)) return root;
9840
+ }
9841
+ const resolved = keys.map((k) => findNode$1(root, k));
9842
+ if (resolved.includes(void 0)) return root;
9843
+ nodes = resolved;
9844
+ removeSet = new Set(keys);
9845
+ } else {
9846
+ nodes = (ctx.dragged ?? []).map((n) => ({ ...n }));
9847
+ if (nodes.length === 0) return root;
9848
+ }
9849
+ const afterRemoval = removeSet.size > 0 ? removeKeys(root, removeSet) : root;
9850
+ let parentKey;
9851
+ let index;
9852
+ if (target.position === `inside`) {
9853
+ if (findNode$1(afterRemoval, target.referenceKey) === void 0) return root;
9854
+ parentKey = target.referenceKey;
9855
+ const kids = childrenOf(afterRemoval, parentKey);
9856
+ index = clamp$5(target.index, 0, kids.length);
9857
+ } else {
9858
+ parentKey = findParent(afterRemoval, target.referenceKey)?.item.key;
9859
+ const refIdx = childrenOf(afterRemoval, parentKey).findIndex((c) => c.item.key === target.referenceKey);
9860
+ if (refIdx < 0) return root;
9861
+ index = target.position === `before` ? refIdx : refIdx + 1;
9862
+ }
9863
+ const kids = [...childrenOf(afterRemoval, parentKey)];
9864
+ const next = [
9865
+ ...kids.slice(0, index),
9866
+ ...nodes,
9867
+ ...kids.slice(index)
9868
+ ];
9869
+ return withChildren(afterRemoval, parentKey, next);
9870
+ }
9871
+ /** Build a synthetic `TreeDropTarget` for programmatic moves (see `TreeDataModel`). */
9872
+ function dropTargetFor(referenceKey, position, index = position === `inside` ? Number.MAX_SAFE_INTEGER : 0) {
9873
+ return {
9874
+ referenceKey,
9875
+ position,
9876
+ index,
9877
+ parentKey: position === `inside` ? referenceKey : void 0,
9878
+ depth: 0
9879
+ };
9880
+ }
9881
+ //#endregion
9882
+ //#region src/common/tree-data-model.ts
9748
9883
  /** Return a new root with the node at `key` replaced by `replacer(node)`. */
9749
9884
  function mapNode(root, key, replacer) {
9750
9885
  if (root.item.key === key) return replacer(root);
@@ -9769,11 +9904,23 @@ function removeNodeFrom(root, key) {
9769
9904
  children: root.children.filter((c) => c.item.key !== key).map((c) => removeNodeFrom(c, key))
9770
9905
  };
9771
9906
  }
9772
- /** Return a new root with the node at `key` moved to become a child of `newParentKey`. */
9773
- function moveNodeTo(root, key, newParentKey) {
9774
- const target = findNode$1(root, key);
9775
- if (!target) return root;
9776
- return addChildTo(removeNodeFrom(root, key), newParentKey, target);
9907
+ /** Return a new root with `newChild` inserted at `index` among the children of `parentKey`. */
9908
+ function insertChildAt(root, parentKey, newChild, index) {
9909
+ return mapNode(root, parentKey, (parent) => {
9910
+ const children = parent.children ?? [];
9911
+ const clampedIndex = Math.max(0, Math.min(index, children.length));
9912
+ return {
9913
+ item: parent.item,
9914
+ children: [
9915
+ ...children.slice(0, clampedIndex),
9916
+ newChild,
9917
+ ...children.slice(clampedIndex)
9918
+ ]
9919
+ };
9920
+ });
9921
+ }
9922
+ function getRootChildren(root) {
9923
+ return root.children ?? [];
9777
9924
  }
9778
9925
  /**
9779
9926
  * Manages tree data for tree-like components.
@@ -9901,10 +10048,80 @@ var TreeDataModel = class {
9901
10048
  }
9902
10049
  /**
9903
10050
  * Moves the node with the given key to become a child of `newParentKey`.
10051
+ * When `index` is provided, inserts at that position; otherwise appends.
10052
+ * Returns the new root (connected components are notified automatically).
10053
+ */
10054
+ moveNode(key, newParentKey, index) {
10055
+ const next = applyTreeDrop(this.#root, {
10056
+ source: `internal`,
10057
+ draggedKeys: [key],
10058
+ target: dropTargetFor(newParentKey, `inside`, index ?? Number.MAX_SAFE_INTEGER)
10059
+ });
10060
+ if (next !== this.#root) {
10061
+ this.#root = next;
10062
+ this.#notify({
10063
+ type: `root`,
10064
+ root: this.#root
10065
+ });
10066
+ }
10067
+ return this.#root;
10068
+ }
10069
+ /**
10070
+ * Moves the node with the given key to become a sibling of `referenceKey`,
10071
+ * positioned `before` or `after` it. A no-op (returns the unchanged root) when
10072
+ * `key` is `referenceKey`, an ancestor of it, or either is missing.
10073
+ * Returns the new root (connected components are notified automatically).
10074
+ */
10075
+ moveNodeRelative(key, referenceKey, position) {
10076
+ const next = applyTreeDrop(this.#root, {
10077
+ source: `internal`,
10078
+ draggedKeys: [key],
10079
+ target: dropTargetFor(referenceKey, position)
10080
+ });
10081
+ if (next !== this.#root) {
10082
+ this.#root = next;
10083
+ this.#notify({
10084
+ type: `root`,
10085
+ root: this.#root
10086
+ });
10087
+ }
10088
+ return this.#root;
10089
+ }
10090
+ /**
10091
+ * Applies a resolved drop (from `ixfx-tree-list`'s `tree-drop` event or a
10092
+ * hand-built context) to the current root. No-op when the drop is invalid.
10093
+ * Returns the new root (connected components are notified automatically).
10094
+ */
10095
+ applyDrop(ctx) {
10096
+ const next = applyTreeDrop(this.#root, ctx);
10097
+ if (next !== this.#root) {
10098
+ this.#root = next;
10099
+ this.#notify({
10100
+ type: `root`,
10101
+ root: this.#root
10102
+ });
10103
+ }
10104
+ return this.#root;
10105
+ }
10106
+ /**
10107
+ * Inserts `node` as a child of `parentKey` (or at the root level when `parentKey` is undefined).
10108
+ * When `index` is provided, inserts at that position; otherwise appends.
9904
10109
  * Returns the new root (connected components are notified automatically).
9905
10110
  */
9906
- moveNode(key, newParentKey) {
9907
- this.#root = moveNodeTo(this.#root, key, newParentKey);
10111
+ insertNode(parentKey, node, index) {
10112
+ if (parentKey === void 0) {
10113
+ const children = getRootChildren(this.#root);
10114
+ const clampedIndex = Math.max(0, Math.min(index ?? children.length, children.length));
10115
+ this.#root = {
10116
+ ...this.#root,
10117
+ children: [
10118
+ ...children.slice(0, clampedIndex),
10119
+ node,
10120
+ ...children.slice(clampedIndex)
10121
+ ]
10122
+ };
10123
+ } else if (index !== void 0) this.#root = insertChildAt(this.#root, parentKey, node, index);
10124
+ else this.#root = addChildTo(this.#root, parentKey, node);
9908
10125
  this.#notify({
9909
10126
  type: `root`,
9910
10127
  root: this.#root
@@ -15244,6 +15461,7 @@ let DataTableElement = class DataTableElement extends i {
15244
15461
  this.styles = [
15245
15462
  tickledStyles,
15246
15463
  tickledItemStyles,
15464
+ popupSurfaceStyles,
15247
15465
  i$3`
15248
15466
  :host {
15249
15467
  display: block;
@@ -15383,7 +15601,6 @@ let DataTableElement = class DataTableElement extends i {
15383
15601
  width: max-content;
15384
15602
  max-width: 100cqi;
15385
15603
  padding: var(--space-xs);
15386
- background: var(--surface-2);
15387
15604
  visibility: hidden;
15388
15605
  transform: translateY(-4px);
15389
15606
  pointer-events: none;
@@ -15462,7 +15679,7 @@ let DataTableElement = class DataTableElement extends i {
15462
15679
  ?data-full=${r.fullWidth}
15463
15680
  @pointerenter=${() => this.#handlePointerEnter(i)}
15464
15681
  @click=${() => this.#select(i)}
15465
- ><div class="key">${r.label}</div><div class="value"><span class="value-text">${typeof r.value === `boolean` ? r.value ? `Yes` : `No` : r.value}</span>${r.detail === void 0 ? A : b`<div class="detail" part="detail">${r.detail}</div>`}</div></div>`)}</div>`;
15682
+ ><div class="key">${r.label}</div><div class="value"><span class="value-text">${typeof r.value === `boolean` ? r.value ? `Yes` : `No` : r.value}</span>${r.detail === void 0 ? A : b`<div class="detail popup-surface" part="detail">${r.detail}</div>`}</div></div>`)}</div>`;
15466
15683
  }
15467
15684
  };
15468
15685
  __decorate([property({
@@ -24552,6 +24769,360 @@ __decorate([property({
24552
24769
  })], GroupedItemListerElement.prototype, "crossGroupSelection", void 0);
24553
24770
  GroupedItemListerElement = __decorate([safeCustomElement(`ixfx-grouped-item-lister`)], GroupedItemListerElement);
24554
24771
  //#endregion
24772
+ //#region src/tree/tree-drag-registry.ts
24773
+ const TREE_DRAG_MIME = `application/x-ixfx-tree`;
24774
+ const registry = /* @__PURE__ */ new Map();
24775
+ const weakRefs = /* @__PURE__ */ new Map();
24776
+ /**
24777
+ * The source id of the drag currently in flight, if any. There is only ever one
24778
+ * native drag at a time, so a drop target can resolve the dragged nodes during
24779
+ * `dragover` — when `DataTransfer.getData()` is unreadable (protected mode) — by
24780
+ * looking this up in the registry.
24781
+ */
24782
+ let currentSourceId;
24783
+ let sourceIdCounter = 0;
24784
+ function treeDragGenerateSourceId() {
24785
+ return `tree-drag-${++sourceIdCounter}-${Date.now()}`;
24786
+ }
24787
+ function treeDragRegister(sourceId, element, nodes, keys) {
24788
+ registry.set(sourceId, {
24789
+ sourceId,
24790
+ nodes,
24791
+ keys
24792
+ });
24793
+ weakRefs.set(sourceId, new WeakRef(element));
24794
+ currentSourceId = sourceId;
24795
+ }
24796
+ function treeDragUnregister(sourceId) {
24797
+ registry.delete(sourceId);
24798
+ weakRefs.delete(sourceId);
24799
+ if (currentSourceId === sourceId) currentSourceId = void 0;
24800
+ }
24801
+ /** The in-flight drag's `{ keys, nodes, element }`, or `undefined` when nothing is dragging. */
24802
+ function treeDragCurrent() {
24803
+ if (currentSourceId === void 0) return void 0;
24804
+ const entry = registry.get(currentSourceId);
24805
+ if (!entry) return void 0;
24806
+ return {
24807
+ sourceId: currentSourceId,
24808
+ keys: entry.keys,
24809
+ nodes: entry.nodes,
24810
+ element: weakRefs.get(currentSourceId)?.deref()
24811
+ };
24812
+ }
24813
+ //#endregion
24814
+ //#region src/tree/tree-drop-controller.ts
24815
+ const EDGE_ZONE_PX$1 = 24;
24816
+ const MAX_SCROLL_SPEED = 16;
24817
+ function clamp$4(value, min, max) {
24818
+ return Math.max(min, Math.min(max, value));
24819
+ }
24820
+ var TreeDropController = class {
24821
+ #host;
24822
+ #config;
24823
+ #active = false;
24824
+ #current;
24825
+ #source = `internal`;
24826
+ #dragKeys = [];
24827
+ #dragNodes = [];
24828
+ #expandTimer;
24829
+ #expandPendingKey;
24830
+ #scrollRaf = 0;
24831
+ #pointerX = 0;
24832
+ #pointerY = 0;
24833
+ #boundContainer;
24834
+ constructor(host, config) {
24835
+ this.#host = host;
24836
+ this.#config = config;
24837
+ host.addController(this);
24838
+ }
24839
+ /** A drag is currently over this tree. */
24840
+ get isDragging() {
24841
+ return this.#active;
24842
+ }
24843
+ /** A drag is over this tree but the current position is not a valid drop. */
24844
+ get isRejected() {
24845
+ return this.#active && this.#current === void 0;
24846
+ }
24847
+ get dropState() {
24848
+ return this.#current;
24849
+ }
24850
+ hostConnected() {
24851
+ this.#bind();
24852
+ }
24853
+ /** Bind once the shadow `#container` exists (it does not yet at `hostConnected`). */
24854
+ hostUpdated() {
24855
+ this.#bind();
24856
+ }
24857
+ #bind() {
24858
+ const container = this.#config.getScrollContainer();
24859
+ if (!container || container === this.#boundContainer) return;
24860
+ this.#unbind();
24861
+ this.#boundContainer = container;
24862
+ container.addEventListener(`dragenter`, this.#onDragEnter);
24863
+ container.addEventListener(`dragover`, this.#onDragOver);
24864
+ container.addEventListener(`dragleave`, this.#onDragLeave);
24865
+ container.addEventListener(`drop`, this.#onDrop);
24866
+ }
24867
+ #unbind() {
24868
+ const c = this.#boundContainer;
24869
+ if (!c) return;
24870
+ c.removeEventListener(`dragenter`, this.#onDragEnter);
24871
+ c.removeEventListener(`dragover`, this.#onDragOver);
24872
+ c.removeEventListener(`dragleave`, this.#onDragLeave);
24873
+ c.removeEventListener(`drop`, this.#onDrop);
24874
+ this.#boundContainer = void 0;
24875
+ }
24876
+ hostDisconnected() {
24877
+ this.#unbind();
24878
+ this.#clearExpand();
24879
+ this.#stopScroll();
24880
+ this.#active = false;
24881
+ this.#current = void 0;
24882
+ }
24883
+ #onDragEnter = (event) => {
24884
+ if (this.#config.getDndMode() === `none` || !event.dataTransfer) return;
24885
+ if (this.#config.resolveDrag(event.dataTransfer, `hover`) === void 0) return;
24886
+ event.preventDefault();
24887
+ if (!this.#active) {
24888
+ this.#active = true;
24889
+ this.#config.onActiveChange(true);
24890
+ }
24891
+ };
24892
+ #onDragOver = (event) => {
24893
+ if (this.#config.getDndMode() === `none` || !event.dataTransfer) return;
24894
+ this.#pointerX = event.clientX;
24895
+ this.#pointerY = event.clientY;
24896
+ const drag = this.#config.resolveDrag(event.dataTransfer, `hover`);
24897
+ if (!drag) {
24898
+ this.#reject(event);
24899
+ return;
24900
+ }
24901
+ if (!this.#active) {
24902
+ this.#active = true;
24903
+ this.#config.onActiveChange(true);
24904
+ }
24905
+ this.#source = drag.source;
24906
+ this.#dragKeys = drag.keys;
24907
+ this.#dragNodes = drag.nodes;
24908
+ const rows = this.#config.getVisibleRows();
24909
+ this.#handleExpandHover(this.#rowAtPointer(rows, event.clientY));
24910
+ this.#kickScroll();
24911
+ const target = this.#resolveIntent(event, rows, drag.source);
24912
+ if (!target) {
24913
+ this.#reject(event, false);
24914
+ return;
24915
+ }
24916
+ const ctx = {
24917
+ source: drag.source,
24918
+ dragged: drag.nodes.length > 0 ? drag.nodes : void 0,
24919
+ draggedKeys: drag.keys,
24920
+ target,
24921
+ dataTransfer: event.dataTransfer
24922
+ };
24923
+ if (!this.#config.vet(ctx)) {
24924
+ this.#reject(event, false);
24925
+ return;
24926
+ }
24927
+ event.preventDefault();
24928
+ event.dataTransfer.dropEffect = drag.source === `internal` ? `move` : `copy`;
24929
+ this.#setDropState(target);
24930
+ };
24931
+ /** Not a valid drop here: keep the drag active for feedback but accept nothing. */
24932
+ #reject(event, clearHover = true) {
24933
+ if (event.dataTransfer) event.dataTransfer.dropEffect = `none`;
24934
+ this.#setDropState(void 0);
24935
+ if (clearHover) this.#clearExpand();
24936
+ }
24937
+ #onDragLeave = (event) => {
24938
+ const container = this.#config.getScrollContainer();
24939
+ const related = event.relatedTarget;
24940
+ if (container && related && container.contains(related)) return;
24941
+ this.#endHover();
24942
+ };
24943
+ #onDrop = (event) => {
24944
+ if (!event.dataTransfer) {
24945
+ this.#endHover();
24946
+ return;
24947
+ }
24948
+ event.preventDefault();
24949
+ this.#stopScroll();
24950
+ this.#clearExpand();
24951
+ const finish = (dropped) => {
24952
+ this.#current = void 0;
24953
+ this.#active = false;
24954
+ this.#config.onDropStateChange(void 0);
24955
+ this.#config.onActiveChange(false);
24956
+ this.#config.onDragEnd(dropped);
24957
+ };
24958
+ if (this.#config.getDndMode() === `none`) {
24959
+ finish(false);
24960
+ return;
24961
+ }
24962
+ const drag = this.#config.resolveDrag(event.dataTransfer, `drop`);
24963
+ if (!drag) {
24964
+ finish(false);
24965
+ return;
24966
+ }
24967
+ this.#dragKeys = drag.keys;
24968
+ this.#dragNodes = drag.nodes;
24969
+ const target = this.#resolveIntent(event, this.#config.getVisibleRows(), drag.source);
24970
+ if (!target) {
24971
+ finish(false);
24972
+ return;
24973
+ }
24974
+ const ctx = {
24975
+ source: drag.source,
24976
+ dragged: drag.nodes.length > 0 ? drag.nodes : void 0,
24977
+ draggedKeys: drag.keys,
24978
+ target,
24979
+ dataTransfer: event.dataTransfer
24980
+ };
24981
+ if (!this.#config.vet(ctx)) {
24982
+ finish(false);
24983
+ return;
24984
+ }
24985
+ const detail = {
24986
+ ...ctx,
24987
+ external: drag.source === `external` ? drag.nodes : void 0
24988
+ };
24989
+ finish(this.#config.commitDrop(detail));
24990
+ };
24991
+ #endHover() {
24992
+ this.#clearExpand();
24993
+ this.#stopScroll();
24994
+ if (this.#current !== void 0) {
24995
+ this.#current = void 0;
24996
+ this.#config.onDropStateChange(void 0);
24997
+ }
24998
+ if (this.#active) {
24999
+ this.#active = false;
25000
+ this.#config.onActiveChange(false);
25001
+ }
25002
+ }
25003
+ #rowAtPointer(rows, clientY) {
25004
+ if (rows.length === 0) return void 0;
25005
+ if (clientY < rows[0].rect.top) return rows[0];
25006
+ if (clientY > rows[rows.length - 1].rect.bottom) return rows[rows.length - 1];
25007
+ return rows.find((r) => clientY >= r.rect.top && clientY <= r.rect.bottom) ?? rows[rows.length - 1];
25008
+ }
25009
+ #parentRow(rows, index) {
25010
+ const target = rows[index];
25011
+ for (let i = index - 1; i >= 0; i--) if (rows[i].depth === target.depth - 1) return rows[i];
25012
+ }
25013
+ #resolveIntent(event, rows, source) {
25014
+ if (rows.length === 0) return void 0;
25015
+ const row = this.#rowAtPointer(rows, event.clientY);
25016
+ if (!row) return void 0;
25017
+ const rowIndex = rows.indexOf(row);
25018
+ const f = clamp$4((event.clientY - row.rect.top) / row.rect.height, 0, 1);
25019
+ let position = f < .25 ? `before` : f > .75 ? `after` : `inside`;
25020
+ const isLeaf = row.node.item.isLeaf === true;
25021
+ if (position === `inside` && isLeaf) position = `after`;
25022
+ let insideFromExpandedAfter = false;
25023
+ if (position === `after` && !isLeaf && this.#config.isExpanded(row.key)) {
25024
+ position = `inside`;
25025
+ insideFromExpandedAfter = true;
25026
+ }
25027
+ let parentKey;
25028
+ let referenceKey;
25029
+ let depth;
25030
+ let index;
25031
+ if (position === `inside`) {
25032
+ parentKey = row.key;
25033
+ referenceKey = row.key;
25034
+ depth = row.depth + 1;
25035
+ index = insideFromExpandedAfter ? 0 : row.node.children?.length ?? 0;
25036
+ } else {
25037
+ const indent = this.#config.getIndentPx() || 1;
25038
+ const treeLeft = rows[0].rect.left;
25039
+ const effDepth = clamp$4(Math.round((event.clientX - treeLeft) / indent), 0, row.depth);
25040
+ let anchorIndex = rowIndex;
25041
+ for (let up = row.depth - effDepth; up > 0; up--) {
25042
+ const parent = this.#parentRow(rows, anchorIndex);
25043
+ if (!parent) break;
25044
+ anchorIndex = rows.indexOf(parent);
25045
+ }
25046
+ const anchor = rows[anchorIndex];
25047
+ referenceKey = anchor.key;
25048
+ depth = anchor.depth;
25049
+ const parent = this.#parentRow(rows, anchorIndex);
25050
+ parentKey = parent?.key;
25051
+ const refIdx = (parent ? parent.node.children ?? [] : rows.filter((r) => r.depth === 0).map((r) => r.node)).findIndex((n) => n.item.key === anchor.key);
25052
+ index = (refIdx < 0 ? 0 : refIdx) + (position === `after` ? 1 : 0);
25053
+ }
25054
+ if (source === `internal`) {
25055
+ for (const key of this.#dragKeys) {
25056
+ if (key === parentKey || key === referenceKey) return void 0;
25057
+ if (parentKey !== void 0 && this.#config.isSelfOrDescendant(key, parentKey)) return void 0;
25058
+ if (position !== `inside` && this.#config.isSelfOrDescendant(key, referenceKey)) return void 0;
25059
+ }
25060
+ if (this.#dragKeys.length > 0 && !this.#config.isReorderAllowed()) {
25061
+ if (!this.#dragKeys.some((k) => this.#config.getParentKey(k) !== parentKey)) return void 0;
25062
+ }
25063
+ }
25064
+ return {
25065
+ parentKey,
25066
+ index,
25067
+ referenceKey,
25068
+ position,
25069
+ depth
25070
+ };
25071
+ }
25072
+ #handleExpandHover(row) {
25073
+ if (!row || row.node.item.isLeaf === true || this.#config.isExpanded(row.key)) {
25074
+ this.#clearExpand();
25075
+ return;
25076
+ }
25077
+ if (row.key === this.#expandPendingKey) return;
25078
+ this.#clearExpand();
25079
+ const key = this.#expandPendingKey = row.key;
25080
+ this.#expandTimer = setTimeout(() => {
25081
+ this.#expandTimer = void 0;
25082
+ if (this.#expandPendingKey === key) {
25083
+ this.#expandPendingKey = void 0;
25084
+ this.#config.expandKey(key);
25085
+ }
25086
+ }, Math.max(0, this.#config.getExpandHoverMs()));
25087
+ }
25088
+ #clearExpand() {
25089
+ if (this.#expandTimer !== void 0) {
25090
+ clearTimeout(this.#expandTimer);
25091
+ this.#expandTimer = void 0;
25092
+ }
25093
+ this.#expandPendingKey = void 0;
25094
+ }
25095
+ #kickScroll() {
25096
+ if (this.#scrollRaf === 0) this.#scrollRaf = requestAnimationFrame(this.#scrollTick);
25097
+ }
25098
+ #scrollTick = () => {
25099
+ this.#scrollRaf = 0;
25100
+ if (!this.#active) return;
25101
+ const container = this.#config.getScrollContainer();
25102
+ if (!container) return;
25103
+ const rect = container.getBoundingClientRect();
25104
+ const y = this.#pointerY - rect.top;
25105
+ let dy = 0;
25106
+ if (y < EDGE_ZONE_PX$1) dy = -Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, y) / EDGE_ZONE_PX$1));
25107
+ else if (y > rect.height - EDGE_ZONE_PX$1) dy = Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, rect.height - y) / EDGE_ZONE_PX$1));
25108
+ if (dy !== 0 && this.#pointerX >= rect.left && this.#pointerX <= rect.right) {
25109
+ container.scrollTop += dy;
25110
+ this.#kickScroll();
25111
+ }
25112
+ };
25113
+ #stopScroll() {
25114
+ if (this.#scrollRaf !== 0) {
25115
+ cancelAnimationFrame(this.#scrollRaf);
25116
+ this.#scrollRaf = 0;
25117
+ }
25118
+ }
25119
+ #setDropState(state) {
25120
+ const unchanged = state === void 0 ? this.#current === void 0 : state.referenceKey === this.#current?.referenceKey && state.position === this.#current?.position && state.depth === this.#current?.depth && state.index === this.#current?.index;
25121
+ this.#current = state;
25122
+ if (!unchanged || this.#active) this.#config.onDropStateChange(state);
25123
+ }
25124
+ };
25125
+ //#endregion
24555
25126
  //#region src/tree/tree-base.ts
24556
25127
  /** Above this many rows entering / leaving at once, skip the animation entirely. */
24557
25128
  const MAX_ANIMATED_ROWS = 50;
@@ -24564,6 +25135,10 @@ let TreeBaseElement = class TreeBaseElement extends i {
24564
25135
  this._selectedNodes = /* @__PURE__ */ new Set();
24565
25136
  this.disableKeyboardNavigation = false;
24566
25137
  this.registry = void 0;
25138
+ this.itemDnd = `none`;
25139
+ this.dndExpandHoverMs = 500;
25140
+ this.reorderable = true;
25141
+ this.applyInternalDrop = true;
24567
25142
  this._expandedKeys = /* @__PURE__ */ new Set();
24568
25143
  this.tickled = new TickledController(this, {
24569
25144
  getItems: () => {
@@ -24572,6 +25147,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
24572
25147
  enabled: true
24573
25148
  }));
24574
25149
  },
25150
+ hoverDisabled: () => this.#drop?.isDragging === true || this.#nativeDrag?.isDragging === true,
24575
25151
  onStateChange: () => {
24576
25152
  this.setAttribute(`data-input-mode`, this.tickled.inputMode);
24577
25153
  }
@@ -24588,6 +25164,12 @@ let TreeBaseElement = class TreeBaseElement extends i {
24588
25164
  this.#leaving = /* @__PURE__ */ new Map();
24589
25165
  this.#leavingAnimations = /* @__PURE__ */ new Map();
24590
25166
  this.#treeAnimReady = false;
25167
+ this.#dragSourceId = ``;
25168
+ this.#nativeDragKeys = /* @__PURE__ */ new Set();
25169
+ this.#internalDropHandled = false;
25170
+ this.#onContainerScroll = () => {
25171
+ this.#rowsCache = void 0;
25172
+ };
24591
25173
  this.#onKeyDown = (event) => {
24592
25174
  if (this.search.isOpen) return;
24593
25175
  const nodes = this.#getAllNodes();
@@ -24741,6 +25323,28 @@ let TreeBaseElement = class TreeBaseElement extends i {
24741
25323
  #leaving;
24742
25324
  #leavingAnimations;
24743
25325
  #treeAnimReady;
25326
+ #dragSourceId;
25327
+ #postDragSuppressTimer;
25328
+ #dropState;
25329
+ #drop;
25330
+ #nativeDrag;
25331
+ /** Keys of the nodes currently being dragged out (for `.dragging` styling). */
25332
+ #nativeDragKeys;
25333
+ /** Set by `commitDrop` for a same-tree internal drop, read by the native `onEnd` to avoid a duplicate `tree-drag-end`. */
25334
+ #internalDropHandled;
25335
+ /** Per-drag cache of measured rows; invalidated on scroll / update. */
25336
+ #rowsCache;
25337
+ #onContainerScroll;
25338
+ get nativeDrag() {
25339
+ return this.#nativeDrag;
25340
+ }
25341
+ get dropState() {
25342
+ return this.#dropState;
25343
+ }
25344
+ /** Keys of the nodes currently being dragged out of this tree. */
25345
+ get nativeDragKeys() {
25346
+ return this.#nativeDragKeys;
25347
+ }
24744
25348
  #cancelLeavingAnimation(key) {
24745
25349
  this.#leavingAnimations.get(key)?.cancel();
24746
25350
  this.#leavingAnimations.delete(key);
@@ -24852,6 +25456,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
24852
25456
  this.#treeAnimReady = true;
24853
25457
  }
24854
25458
  updated(changedProps) {
25459
+ this.#rowsCache = void 0;
24855
25460
  if (changedProps.has(`root`) && this.root) {
24856
25461
  this.#abortPending();
24857
25462
  this._expandedKeys.clear();
@@ -24908,6 +25513,291 @@ let TreeBaseElement = class TreeBaseElement extends i {
24908
25513
  });
24909
25514
  this.registry = registry;
24910
25515
  this.#syncSearchCommands();
25516
+ this.#initDnd();
25517
+ }
25518
+ #initDnd() {
25519
+ this.#dragSourceId = treeDragGenerateSourceId();
25520
+ this.#nativeDrag = new ListNativeDragController(this, {
25521
+ source: `tree-list`,
25522
+ isEnabled: () => this.itemDnd !== `none` && this.#anyRowDraggable(),
25523
+ resolveEventToKey: (target) => {
25524
+ if (!(target instanceof Element)) return void 0;
25525
+ return target.closest(`li[data-key]`)?.getAttribute(`data-key`) ?? void 0;
25526
+ },
25527
+ prepareSelection: (originKey) => {
25528
+ const allNodes = this.#getAllNodes();
25529
+ const originEntry = allNodes.find((n) => n.node.item.key === originKey);
25530
+ if (!originEntry) return void 0;
25531
+ const selectedNodes = new Set(this._selectedNodes);
25532
+ if (!selectedNodes.has(originEntry.node)) selectedNodes.clear();
25533
+ selectedNodes.add(originEntry.node);
25534
+ const orderedKeys = allNodes.filter((n) => selectedNodes.has(n.node)).map((n) => n.node.item.key);
25535
+ const topKeys = new Set(this.root ? pruneDraggedDescendants(this.root, orderedKeys) : orderedKeys);
25536
+ const selected = allNodes.filter((n) => topKeys.has(n.node.item.key)).map((n, i) => ({
25537
+ key: n.node.item.key,
25538
+ index: i,
25539
+ item: n.node,
25540
+ element: this.shadowRoot?.querySelector(`li[data-key="${CSS.escape(n.node.item.key)}"]`) ?? void 0
25541
+ }));
25542
+ const origin = selected.find((e) => e.key === originKey) ?? {
25543
+ key: originKey,
25544
+ index: 0,
25545
+ item: originEntry.node,
25546
+ element: void 0
25547
+ };
25548
+ if (!selected.some((e) => e.key === origin.key)) selected.unshift(origin);
25549
+ return {
25550
+ origin,
25551
+ selected
25552
+ };
25553
+ },
25554
+ getMetrics: () => ({ rowHeight: this.#getItemHeight() }),
25555
+ getRenderer: () => this.dragPreviewRenderer,
25556
+ dispatch: (detail) => {
25557
+ const keys = detail.selected.map((e) => e.key);
25558
+ const nodes = detail.selected.map((e) => e.item);
25559
+ const evt = new CustomEvent(`list-native-drag-start`, {
25560
+ detail,
25561
+ bubbles: true,
25562
+ composed: true,
25563
+ cancelable: true
25564
+ });
25565
+ const notCancelled = this.dispatchEvent(evt);
25566
+ if (notCancelled) {
25567
+ this.#nativeDragKeys = new Set(keys);
25568
+ this.#internalDropHandled = false;
25569
+ if (this.itemDnd === `internal` || this.itemDnd === `both`) treeDragRegister(this.#dragSourceId, this, nodes, keys);
25570
+ this.dispatchEvent(new CustomEvent(`tree-drag-start`, {
25571
+ detail: {
25572
+ nodes,
25573
+ keys
25574
+ },
25575
+ bubbles: true,
25576
+ composed: true
25577
+ }));
25578
+ }
25579
+ return notCancelled;
25580
+ },
25581
+ writeDataTransfer: (dataTransfer, detail) => {
25582
+ if (this.itemDnd !== `internal` && this.itemDnd !== `both`) return;
25583
+ const keys = detail.selected.map((e) => e.key);
25584
+ const nodes = detail.selected.map((e) => e.item);
25585
+ try {
25586
+ dataTransfer.setData(TREE_DRAG_MIME, JSON.stringify({
25587
+ sourceId: this.#dragSourceId,
25588
+ keys,
25589
+ nodes
25590
+ }));
25591
+ dataTransfer.setData(`text/plain`, nodes.map((n) => n.item.label).join(`\n`));
25592
+ } catch {}
25593
+ },
25594
+ onActiveChange: (active) => {
25595
+ this.toggleAttribute(`data-native-dragging`, active);
25596
+ if (!active) this.#nativeDragKeys = /* @__PURE__ */ new Set();
25597
+ this.requestUpdate();
25598
+ },
25599
+ onEnd: () => {
25600
+ treeDragUnregister(this.#dragSourceId);
25601
+ this.#nativeDragKeys = /* @__PURE__ */ new Set();
25602
+ this.#postDragSuppressTimer = setTimeout(() => {
25603
+ this.#postDragSuppressTimer = void 0;
25604
+ }, 150);
25605
+ if (!this.#internalDropHandled) this.dispatchEvent(new CustomEvent(`tree-drag-end`, {
25606
+ detail: { dropped: false },
25607
+ bubbles: true,
25608
+ composed: true
25609
+ }));
25610
+ this.#internalDropHandled = false;
25611
+ }
25612
+ });
25613
+ this.#drop = new TreeDropController(this, {
25614
+ getDndMode: () => this.itemDnd,
25615
+ getExpandHoverMs: () => this.dndExpandHoverMs,
25616
+ getVisibleRows: () => this.#getVisibleRows(),
25617
+ getIndentPx: () => this.#getIndentPx(),
25618
+ getScrollContainer: () => this.#container(),
25619
+ isSelfOrDescendant: (ancestorKey, key) => this.#isSelfOrDescendant(ancestorKey, key),
25620
+ isExpanded: (key) => this._expandedKeys.has(key),
25621
+ isReorderAllowed: () => this.reorderable,
25622
+ getParentKey: (key) => this.#findParentByKey(key)?.item.key,
25623
+ resolveDrag: (dataTransfer, phase) => this.#resolveDrag(dataTransfer, phase),
25624
+ vet: (ctx) => {
25625
+ if (this.canDrop && !this.canDrop(ctx)) return false;
25626
+ const evt = new CustomEvent(`tree-drag-over`, {
25627
+ detail: ctx,
25628
+ bubbles: true,
25629
+ composed: true,
25630
+ cancelable: true
25631
+ });
25632
+ return this.dispatchEvent(evt);
25633
+ },
25634
+ expandKey: (key) => this.#springLoadExpand(key),
25635
+ onDropStateChange: (state) => {
25636
+ this.#dropState = state;
25637
+ this.toggleAttribute(`data-drop-rejected`, this.#drop.isDragging && state === void 0);
25638
+ this.requestUpdate();
25639
+ },
25640
+ onActiveChange: (active) => {
25641
+ if (active) {
25642
+ this.#rowsCache = void 0;
25643
+ this.#container()?.addEventListener(`scroll`, this.#onContainerScroll, { passive: true });
25644
+ } else {
25645
+ this.#container()?.removeEventListener(`scroll`, this.#onContainerScroll);
25646
+ this.#rowsCache = void 0;
25647
+ this.toggleAttribute(`data-drop-rejected`, false);
25648
+ }
25649
+ this.requestUpdate();
25650
+ },
25651
+ commitDrop: (detail) => {
25652
+ if (!this.dispatchEvent(new CustomEvent(`tree-drop`, {
25653
+ detail,
25654
+ bubbles: true,
25655
+ composed: true,
25656
+ cancelable: true
25657
+ }))) return false;
25658
+ if (this.applyInternalDrop && detail.source === `internal` && this.model) this.model.applyDrop({
25659
+ source: `internal`,
25660
+ draggedKeys: detail.draggedKeys,
25661
+ target: detail.target
25662
+ });
25663
+ this.#internalDropHandled = true;
25664
+ return true;
25665
+ },
25666
+ onDragEnd: (dropped) => {
25667
+ this.#dropState = void 0;
25668
+ this.toggleAttribute(`data-drop-rejected`, false);
25669
+ this.requestUpdate();
25670
+ this.dispatchEvent(new CustomEvent(`tree-drag-end`, {
25671
+ detail: { dropped },
25672
+ bubbles: true,
25673
+ composed: true
25674
+ }));
25675
+ }
25676
+ });
25677
+ }
25678
+ #container() {
25679
+ return this.shadowRoot?.querySelector(`#container`) ?? void 0;
25680
+ }
25681
+ #getIndentPx() {
25682
+ const parsed = Number.parseInt(getComputedStyle(this).getPropertyValue(`--tree-indent`), 10);
25683
+ return Number.isNaN(parsed) ? 20 : parsed;
25684
+ }
25685
+ #getItemHeight() {
25686
+ const parsed = Number.parseInt(getComputedStyle(this).getPropertyValue(`--tree-item-height`), 10);
25687
+ return Number.isNaN(parsed) ? 30 : parsed;
25688
+ }
25689
+ /** Measured rows, cached for the duration of a drag and invalidated on scroll / update. */
25690
+ #getVisibleRows() {
25691
+ if (this.#rowsCache) return this.#rowsCache;
25692
+ const rows = [];
25693
+ for (const { node, depth } of this.#getAllNodes()) {
25694
+ const li = this.shadowRoot?.querySelector(`li[data-key="${CSS.escape(node.item.key)}"]`);
25695
+ if (li) rows.push({
25696
+ key: node.item.key,
25697
+ node,
25698
+ depth,
25699
+ rect: li.getBoundingClientRect()
25700
+ });
25701
+ }
25702
+ this.#rowsCache = rows;
25703
+ return rows;
25704
+ }
25705
+ /** Route spring-load through the real expand path so lazy children load and `expand` fires with the right depth. */
25706
+ #springLoadExpand(key) {
25707
+ if (this._expandedKeys.has(key)) return;
25708
+ const entry = this.#getAllNodes().find((n) => n.node.item.key === key);
25709
+ if (!entry || entry.node.item.isLeaf === true) return;
25710
+ this.#toggleExpand(entry.node, entry.depth);
25711
+ this.#rowsCache = void 0;
25712
+ this.requestUpdate();
25713
+ }
25714
+ #isSelfOrDescendant(ancestorKey, key) {
25715
+ if (ancestorKey === key) return true;
25716
+ let node = this.#getAllNodes().find((n) => n.node.item.key === key)?.node;
25717
+ let parent = node ? this.#findParentByKey(node.item.key) : void 0;
25718
+ while (parent) {
25719
+ if (parent.item.key === ancestorKey) return true;
25720
+ node = parent;
25721
+ parent = this.#findParentByKey(node.item.key);
25722
+ }
25723
+ return false;
25724
+ }
25725
+ #findParentByKey(key) {
25726
+ for (const { node } of this.#getAllNodes()) if (node.children?.some((c) => c.item.key === key)) return node;
25727
+ }
25728
+ /**
25729
+ * Decide whether a DataTransfer is acceptable and resolve the dragged set.
25730
+ * During `hover` the DataTransfer is read-protected, so an internal drag is
25731
+ * recovered from the module-level drag registry (there is only one at a time).
25732
+ */
25733
+ #resolveDrag(dataTransfer, phase) {
25734
+ const mode = this.itemDnd;
25735
+ if (mode === `none`) return void 0;
25736
+ const canInternal = mode === `internal` || mode === `both`;
25737
+ const canExternal = mode === `external` || mode === `both`;
25738
+ let types = [];
25739
+ try {
25740
+ types = Array.from(dataTransfer.types);
25741
+ } catch {}
25742
+ const current = treeDragCurrent();
25743
+ const looksInternal = types.includes(TREE_DRAG_MIME) || current !== void 0;
25744
+ if (canInternal && looksInternal) {
25745
+ if (current && current.keys.length > 0) {
25746
+ const keys = this.root ? pruneDraggedDescendants(this.root, current.keys) : current.keys;
25747
+ return {
25748
+ source: `internal`,
25749
+ keys,
25750
+ nodes: keys.map((k) => this.#getAllNodes().find((n) => n.node.item.key === k)?.node).filter((n) => n !== void 0)
25751
+ };
25752
+ }
25753
+ if (phase === `drop`) try {
25754
+ const raw = dataTransfer.getData(TREE_DRAG_MIME);
25755
+ if (raw) {
25756
+ const payload = JSON.parse(raw);
25757
+ return {
25758
+ source: `internal`,
25759
+ keys: payload.keys ?? [],
25760
+ nodes: payload.nodes ?? []
25761
+ };
25762
+ }
25763
+ } catch {}
25764
+ return {
25765
+ source: `internal`,
25766
+ keys: [],
25767
+ nodes: []
25768
+ };
25769
+ }
25770
+ if (canExternal && !looksInternal) {
25771
+ if (this.acceptDropTypes !== void 0) {
25772
+ const accepted = this.acceptDropTypes.trim().split(/\s+/).filter(Boolean);
25773
+ const present = Array.from(dataTransfer.types);
25774
+ if (accepted.length > 0 && !accepted.some((t) => present.includes(t))) return void 0;
25775
+ }
25776
+ if (phase === `drop`) {
25777
+ const nodes = this.parseExternalDrop?.(dataTransfer);
25778
+ if (!nodes || nodes.length === 0) return void 0;
25779
+ return {
25780
+ source: `external`,
25781
+ keys: nodes.map((n) => n.item.key),
25782
+ nodes
25783
+ };
25784
+ }
25785
+ return this.parseExternalDrop ? {
25786
+ source: `external`,
25787
+ keys: [],
25788
+ nodes: []
25789
+ } : void 0;
25790
+ }
25791
+ }
25792
+ #anyRowDraggable() {
25793
+ if (this.itemDnd === `none`) return false;
25794
+ const allNodes = this.#getAllNodes();
25795
+ if (allNodes.length === 0) return false;
25796
+ if (!this.canDrag) return true;
25797
+ return allNodes.some(({ node }) => this.canDrag({
25798
+ nodes: [node],
25799
+ keys: [node.item.key]
25800
+ }));
24911
25801
  }
24912
25802
  disconnectedCallback() {
24913
25803
  super.disconnectedCallback();
@@ -24918,6 +25808,12 @@ let TreeBaseElement = class TreeBaseElement extends i {
24918
25808
  this.#modelUnsubscribe = void 0;
24919
25809
  this.#unregisterSearchCommands?.();
24920
25810
  this.#unregisterSearchCommands = void 0;
25811
+ if (this.#postDragSuppressTimer !== void 0) {
25812
+ clearTimeout(this.#postDragSuppressTimer);
25813
+ this.#postDragSuppressTimer = void 0;
25814
+ }
25815
+ this.#container()?.removeEventListener(`scroll`, this.#onContainerScroll);
25816
+ treeDragUnregister(this.#dragSourceId);
24921
25817
  if (this.#ownedRegistry) {
24922
25818
  this.#ownedRegistry.unregister(`select-all`);
24923
25819
  this.#ownedRegistry.unregister(`deselect-all`);
@@ -25092,6 +25988,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25092
25988
  `;
25093
25989
  }
25094
25990
  _handleItemClick(node, depth, event) {
25991
+ if (this.#drop?.isDragging || this.#nativeDrag?.isDragging || this.#postDragSuppressTimer !== void 0) return;
25095
25992
  if (event && event.detail >= 2) return;
25096
25993
  if (this.#pendingNode && this._expandedKeys.has(this.#pendingNode.item.key)) this.#abortPending();
25097
25994
  this.tickled.handlePointerEnter(node.item.key);
@@ -25526,6 +26423,23 @@ let TreeBaseElement = class TreeBaseElement extends i {
25526
26423
  </ul>
25527
26424
  `;
25528
26425
  }
26426
+ /** Shared drag-and-drop render state for a row, used by every `_renderNode` variant. */
26427
+ _dndRowState(node) {
26428
+ const draggable = this.itemDnd !== `none` && (this.root?.children?.length ?? 0) > 0 && (this.itemDnd === `internal` || this.itemDnd === `both` || this.itemDnd === `external`) && (this.canDrag?.({
26429
+ nodes: [node],
26430
+ keys: [node.item.key]
26431
+ }) ?? true);
26432
+ const dragging = this.#nativeDragKeys.has(node.item.key);
26433
+ const state = this.#dropState;
26434
+ const dropTarget = state !== void 0 && state.referenceKey === node.item.key;
26435
+ return {
26436
+ draggable,
26437
+ dragging,
26438
+ dropTarget,
26439
+ dropPosition: dropTarget ? state.position : void 0,
26440
+ dropDepth: dropTarget ? state.depth : void 0
26441
+ };
26442
+ }
25529
26443
  _renderNode(node, depth) {
25530
26444
  const selected = this._isSelected(node);
25531
26445
  const tickled = this._isFocused(node);
@@ -25534,9 +26448,10 @@ let TreeBaseElement = class TreeBaseElement extends i {
25534
26448
  const isPending = this.#pendingNode === node;
25535
26449
  const isFiltered = this._isFilteredOut(node, depth);
25536
26450
  const isLeaving = this._isLeaving(node);
26451
+ const dnd = this._dndRowState(node);
25537
26452
  return b`
25538
26453
  <li
25539
- class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${isFiltered ? `filtered` : ``} ${isLeaving ? `leaving` : ``}"
26454
+ class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${isFiltered ? `filtered` : ``} ${isLeaving ? `leaving` : ``} ${dnd.dragging ? `dragging` : ``} ${dnd.dropTarget && dnd.dropPosition === `inside` ? `drop-into` : ``}"
25540
26455
  role="treeitem"
25541
26456
  aria-selected=${selected}
25542
26457
  aria-expanded=${isBranch ? isExpanded : A}
@@ -25544,6 +26459,8 @@ let TreeBaseElement = class TreeBaseElement extends i {
25544
26459
  aria-level=${depth + 1}
25545
26460
  data-key=${node.item.key}
25546
26461
  style=${`--depth: ${depth}`}
26462
+ draggable=${dnd.draggable ? `true` : A}
26463
+ part=${dnd.dropTarget ? `drop-target` : A}
25547
26464
  @click=${(e) => this._handleItemClick(node, depth, e)}
25548
26465
  @pointerenter=${() => {
25549
26466
  this.tickled.handlePointerEnter(node.item.key);
@@ -25557,6 +26474,11 @@ let TreeBaseElement = class TreeBaseElement extends i {
25557
26474
  }));
25558
26475
  }}
25559
26476
  >
26477
+ ${dnd.dropTarget && (dnd.dropPosition === `before` || dnd.dropPosition === `after`) ? b`<div
26478
+ class="drop-line drop-line-${dnd.dropPosition}"
26479
+ style="--drop-depth: ${dnd.dropDepth ?? depth}"
26480
+ part="drop-indicator"
26481
+ ></div>` : A}
25560
26482
  ${this.renderNodeContent(node, depth)}
25561
26483
  ${isPending ? this.renderLoadingIndicator() : A}
25562
26484
  </li>
@@ -25577,6 +26499,10 @@ let TreeBaseElement = class TreeBaseElement extends i {
25577
26499
  --tree-item-height: 30px;
25578
26500
  --tree-caret-size: 30px;
25579
26501
  --tree-radius: var(--radius-s);
26502
+ --tree-drop-line: var(--accent);
26503
+ --tree-drop-nub-size: 5px;
26504
+ --tree-drop-into-outline: 2px solid var(--accent);
26505
+ --tree-drop-into-bg: color-mix(in srgb, var(--accent) 14%, transparent);
25580
26506
 
25581
26507
  position: relative;
25582
26508
  display: block;
@@ -25604,6 +26530,7 @@ let TreeBaseElement = class TreeBaseElement extends i {
25604
26530
  }
25605
26531
 
25606
26532
  .item {
26533
+ position: relative; /* anchor for the .drop-line before/after indicator */
25607
26534
  display: flex;
25608
26535
  align-items: center;
25609
26536
  height: var(--tree-item-height);
@@ -25679,11 +26606,49 @@ let TreeBaseElement = class TreeBaseElement extends i {
25679
26606
  overflow: hidden;
25680
26607
  }
25681
26608
 
25682
- ::highlight(incr-search-highlight) {
25683
- background: var(--search-highlight-bg, var(--accent));
25684
- color: var(--search-highlight-color, var(--accent-text, #fff));
25685
- border-radius: 2px;
25686
- padding: 0 1px;
26609
+ /* Drag and drop styles */
26610
+ .item.dragging {
26611
+ opacity: 0.4;
26612
+ }
26613
+
26614
+ .item.drop-into {
26615
+ outline: var(--tree-drop-into-outline);
26616
+ outline-offset: -2px;
26617
+ background: var(--tree-drop-into-bg);
26618
+ }
26619
+
26620
+ .drop-line {
26621
+ position: absolute;
26622
+ left: calc(var(--tree-indent) * var(--drop-depth, 0) + var(--space-xs));
26623
+ right: var(--space-xs);
26624
+ height: 2px;
26625
+ background: var(--tree-drop-line);
26626
+ pointer-events: none;
26627
+ z-index: 10;
26628
+ }
26629
+
26630
+ /* Nub at the left end of the insertion line (VS Code style). */
26631
+ .drop-line::before {
26632
+ content: "";
26633
+ position: absolute;
26634
+ left: calc(-1 * var(--tree-drop-nub-size) / 2);
26635
+ top: calc(50% - var(--tree-drop-nub-size) / 2);
26636
+ width: var(--tree-drop-nub-size);
26637
+ height: var(--tree-drop-nub-size);
26638
+ border-radius: 50%;
26639
+ background: var(--tree-drop-line);
26640
+ }
26641
+
26642
+ .drop-line-before {
26643
+ top: -1px;
26644
+ }
26645
+
26646
+ .drop-line-after {
26647
+ bottom: -1px;
26648
+ }
26649
+
26650
+ :host([data-drop-rejected]) {
26651
+ cursor: not-allowed;
25687
26652
  }
25688
26653
  `
25689
26654
  ];
@@ -25717,6 +26682,31 @@ __decorate([property({
25717
26682
  attribute: `search-modes`,
25718
26683
  reflect: true
25719
26684
  })], TreeBaseElement.prototype, "searchModes", void 0);
26685
+ __decorate([property({
26686
+ reflect: true,
26687
+ attribute: `item-dnd`
26688
+ })], TreeBaseElement.prototype, "itemDnd", void 0);
26689
+ __decorate([property({
26690
+ type: String,
26691
+ attribute: `accept-drop-types`
26692
+ })], TreeBaseElement.prototype, "acceptDropTypes", void 0);
26693
+ __decorate([property({
26694
+ type: Number,
26695
+ attribute: `dnd-expand-hover-ms`
26696
+ })], TreeBaseElement.prototype, "dndExpandHoverMs", void 0);
26697
+ __decorate([property({
26698
+ reflect: true,
26699
+ attribute: `reorderable`,
26700
+ converter: {
26701
+ fromAttribute: (value) => value !== `false`,
26702
+ toAttribute: (value) => value ? null : `false`
26703
+ }
26704
+ })], TreeBaseElement.prototype, "reorderable", void 0);
26705
+ __decorate([property({ attribute: false })], TreeBaseElement.prototype, "dragPreviewRenderer", void 0);
26706
+ __decorate([property({ attribute: false })], TreeBaseElement.prototype, "canDrag", void 0);
26707
+ __decorate([property({ attribute: false })], TreeBaseElement.prototype, "canDrop", void 0);
26708
+ __decorate([property({ attribute: false })], TreeBaseElement.prototype, "parseExternalDrop", void 0);
26709
+ __decorate([property({ attribute: false })], TreeBaseElement.prototype, "applyInternalDrop", void 0);
25720
26710
  __decorate([state()], TreeBaseElement.prototype, "_expandedKeys", void 0);
25721
26711
  __decorate([state()], TreeBaseElement.prototype, "_focusedDepth", void 0);
25722
26712
  TreeBaseElement = __decorate([safeCustomElement(`ixfx-tree-base`)], TreeBaseElement);
@@ -25798,9 +26788,10 @@ let TreeListElement = class TreeListElement extends TreeBaseElement {
25798
26788
  const hasIconAtDepth = this.#depthsWithIcons.has(depth);
25799
26789
  const isLeaving = this._isLeaving(node);
25800
26790
  const isFiltered = this._isFilteredOut(node, depth);
26791
+ const dnd = this._dndRowState(node);
25801
26792
  return b`
25802
26793
  <li
25803
- class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${hasIconAtDepth ? `has-icon-at-depth` : ``} ${isLeaving ? `leaving` : ``} ${isFiltered ? `filtered` : ``}"
26794
+ class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${hasIconAtDepth ? `has-icon-at-depth` : ``} ${isLeaving ? `leaving` : ``} ${isFiltered ? `filtered` : ``} ${dnd.dragging ? `dragging` : ``} ${dnd.dropTarget && dnd.dropPosition === `inside` ? `drop-into` : ``}"
25804
26795
  data-key=${node.item.key}
25805
26796
  role="treeitem"
25806
26797
  aria-selected=${selected}
@@ -25808,9 +26799,16 @@ let TreeListElement = class TreeListElement extends TreeBaseElement {
25808
26799
  aria-hidden=${isLeaving ? `true` : A}
25809
26800
  aria-level=${depth + 1}
25810
26801
  style=${`--depth: ${depth}`}
26802
+ draggable=${dnd.draggable ? `true` : A}
26803
+ part=${dnd.dropTarget ? `drop-target` : A}
25811
26804
  @click=${(e) => this._handleItemClick(node, depth, e)}
25812
26805
  @pointerenter=${() => this.tickled.handlePointerEnter(node.item.key)}
25813
26806
  >
26807
+ ${dnd.dropTarget && (dnd.dropPosition === `before` || dnd.dropPosition === `after`) ? b`<div
26808
+ class="drop-line drop-line-${dnd.dropPosition}"
26809
+ style="--drop-depth: ${dnd.dropDepth ?? depth}"
26810
+ part="drop-indicator"
26811
+ ></div>` : A}
25814
26812
  ${this.renderNodeContent(node, depth)}
25815
26813
  ${isPending ? this.renderLoadingIndicator() : A}
25816
26814
  </li>
@@ -29348,6 +30346,77 @@ function valueToRelative(value, min, max) {
29348
30346
  const HANDLE_HIT_RADIUS = .06;
29349
30347
  const DEFAULT_VALUE_MIN_FRACTION = .01;
29350
30348
  const CHANGE_DEBOUNCE_MS = 150;
30349
+ /**
30350
+ * Evaluate a simple arithmetic expression (decimal numbers, `+ - * /` and
30351
+ * parentheses). Returns `undefined` when the string contains anything else.
30352
+ * Used for CSS `calc()`-derived values — a safe substitute for `new Function`.
30353
+ */
30354
+ function evaluateArithmetic(source) {
30355
+ let pos = 0;
30356
+ const skipSpaces = () => {
30357
+ while (pos < source.length) {
30358
+ const c = source[pos];
30359
+ if (c !== ` ` && c !== `\t` && c !== `\n` && c !== `\r`) break;
30360
+ pos++;
30361
+ }
30362
+ };
30363
+ function parseNumber() {
30364
+ skipSpaces();
30365
+ const match = /^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/i.exec(source.slice(pos));
30366
+ if (!match) return void 0;
30367
+ pos += match[0].length;
30368
+ return Number.parseFloat(match[0]);
30369
+ }
30370
+ function parseFactor() {
30371
+ skipSpaces();
30372
+ const c = source[pos];
30373
+ if (c === `+` || c === `-`) {
30374
+ pos++;
30375
+ const value = parseFactor();
30376
+ return value === void 0 ? void 0 : c === `-` ? -value : value;
30377
+ }
30378
+ if (c === `(`) {
30379
+ pos++;
30380
+ const value = parseSum();
30381
+ if (value === void 0) return void 0;
30382
+ skipSpaces();
30383
+ if (source[pos] !== `)`) return void 0;
30384
+ pos++;
30385
+ return value;
30386
+ }
30387
+ return parseNumber();
30388
+ }
30389
+ function parseProduct() {
30390
+ let value = parseFactor();
30391
+ if (value === void 0) return void 0;
30392
+ while (true) {
30393
+ skipSpaces();
30394
+ const op = source[pos];
30395
+ if (op !== `*` && op !== `/`) return value;
30396
+ pos++;
30397
+ const rhs = parseFactor();
30398
+ if (rhs === void 0) return void 0;
30399
+ value = op === `*` ? value * rhs : value / rhs;
30400
+ }
30401
+ }
30402
+ function parseSum() {
30403
+ let value = parseProduct();
30404
+ if (value === void 0) return void 0;
30405
+ while (true) {
30406
+ skipSpaces();
30407
+ const op = source[pos];
30408
+ if (op !== `+` && op !== `-`) return value;
30409
+ pos++;
30410
+ const rhs = parseProduct();
30411
+ if (rhs === void 0) return void 0;
30412
+ value = op === `+` ? value + rhs : value - rhs;
30413
+ }
30414
+ }
30415
+ const value = parseSum();
30416
+ if (value === void 0) return void 0;
30417
+ skipSpaces();
30418
+ return pos === source.length ? value : void 0;
30419
+ }
29351
30420
  let SliderInputElement = class SliderInputElement extends WheelNudgeMixin(i) {
29352
30421
  #lanes;
29353
30422
  /** Raw pole values: independent of which is "low" or "high". */
@@ -30261,14 +31330,10 @@ let SliderInputElement = class SliderInputElement extends WheelNudgeMixin(i) {
30261
31330
  const parsed = Number.parseFloat(val.replace(/[^0-9.-]/g, ``));
30262
31331
  return Number.isNaN(parsed) ? defaultValue : parsed;
30263
31332
  }
30264
- const evalStr = val.replace(/var\(--value-relative\)/g, valueRelative);
30265
- try {
30266
- const result = new Function(`return ${evalStr.replace(/calc\s*\(([^)]+)\)/g, `$1`)}`)();
30267
- return typeof result === `number` && !Number.isNaN(result) ? result : defaultValue;
30268
- } catch {
30269
- const parsed = Number.parseFloat(val.replace(/[^0-9.-]/g, ``));
30270
- return Number.isNaN(parsed) ? defaultValue : parsed;
30271
- }
31333
+ const result = evaluateArithmetic(val.replace(/var\(--value-relative\)/g, valueRelative).replace(/calc\s*\(([^)]+)\)/g, `$1`));
31334
+ if (result !== void 0) return Number.isNaN(result) ? defaultValue : result;
31335
+ const parsed = Number.parseFloat(val.replace(/[^0-9.-]/g, ``));
31336
+ return Number.isNaN(parsed) ? defaultValue : parsed;
30272
31337
  }
30273
31338
  const parsed = Number.parseFloat(val);
30274
31339
  return Number.isNaN(parsed) ? defaultValue : parsed;
@@ -30345,10 +31410,10 @@ let SliderInputElement = class SliderInputElement extends WheelNudgeMixin(i) {
30345
31410
  proposedHigh = clamp$1(proposedHigh, this.min, this.max);
30346
31411
  }
30347
31412
  const lowKey = this.#lengthDragLowKey ?? this.#lowKey();
30348
- this.#lengthDragHighKey ?? this.#highKey();
31413
+ const highKey = this.#lengthDragHighKey ?? this.#highKey();
30349
31414
  const previous = this.#poles();
30350
31415
  const newPoleA = lowKey === `a` ? proposedLow : proposedHigh;
30351
- const newPoleB = lowKey === `b` ? proposedLow : proposedHigh;
31416
+ const newPoleB = highKey === `b` ? proposedHigh : proposedLow;
30352
31417
  this.#poleA = newPoleA;
30353
31418
  this.#poleB = newPoleB;
30354
31419
  if (this.valueMode === `triple` && this.#poleC !== void 0) {
@@ -33967,7 +35032,7 @@ function getScaleSteps(palette) {
33967
35032
  function resolveCssVariable(el, prop) {
33968
35033
  const style = getComputedStyle(el);
33969
35034
  let value = style.getPropertyValue(prop).trim();
33970
- const varRegex = /var\((--[\w-]+)(?:,\s*(.*))?\)/g;
35035
+ const varRegex = /var\((--[\w-]+)(?:,(.*))?\)/g;
33971
35036
  for (let i = 0; i < 5 && value.includes(`var(`); i++) value = value.replace(varRegex, (_, varName, fallback) => {
33972
35037
  const resolved = style.getPropertyValue(varName).trim();
33973
35038
  if (resolved) return resolved;
@@ -43393,6 +44458,6 @@ function init() {
43393
44458
  console.log(`Init`);
43394
44459
  }
43395
44460
  //#endregion
43396
- 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, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeKeyboardNavController, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, normalize, panelGapIndex, parseColourScaleAttr, parseLayout, pointerOverAnyHost, prefersReducedMotion, readBaseColour, registerFontIcon, registerIcon, registerListSearchCommands, removePanelFromStack, resolveCssVars, resolveGrid, resolveLeafPath, resolveTracks, serializeLayout, setActive, setIconFont, startListItemOutAnimation, svgToDataUri, swapLeaves, tickledItemStyles, tickledStyles, timelineStyles, toSnapshot, walk, wrapRoot };
44461
+ 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, IncrSearchTreeController as IncrSearchMillerController, IncrSearchTreeController, IxfxHexEditorElement, IxfxIconElement, IxfxTimelineElement, KeyedElementIndex, LIST_ITEM_MOTION_MS, LIST_SEARCH_COMMAND_IDS, LIST_SEARCH_MODES, LabelledRadialInput, LabelledRangeInput, LabelledSliderInput, LedElement, ListDragSelectController, ListNativeDragController, ListSearchController, ListSelectionController, menu_exports as Menu, MillerBaseElement, MillerListElement, MillerTreeController, NarrowedTextElement, NotificationManager, NotificationPillElement, PanTextElement, PanelElement, PanelGroupElement, PlotDataSeries, PlotHistogram, PlotMultiAxis, PlotSingleAxis, PlotXyAxis, PolarPad, RadialInputElement, RadioGroup, RangeElement, RangeInput, RangeMultiElement, RatingElement, SelectHorizElement, SliderInputElement, SlidingNumberElement, SnackbarElement, SnapContainer, SplitButton, SplitLayoutElement, SplitPanelElement, SwipeElement, TabController, TabListElement, TabListItemElement, TabPanelElement, TabPanelsElement, TextShimmerElement, TickledController, TimelineController, TimelineTrackTabElement, TitlebarElement, ToolbarElement, ToolbarGroupElement, TooltipElement, TransitoryLabelElement, TreeBaseElement, TreeController, TreeDataModel, TreeDropController, TreeKeyboardNavController, TreeListElement, TwoSplitLayoutElement, VerticalListElement, XyPad, addPanelToStack, animateListItemIn, animateListItemOut, applyAgeModification, applyHighlights, applySnapshot, applyTreeDrop, attachTimelineInteractions, bottomDrawerCommandId, buildHighlightTargets, buildModel, captionForEntry, clearHighlights, collectContainerNames, collectDataResult, collectPanelIds, collectStackPaths, computeColour, computeLeafGeoms, createAcCompletionProvider, createDataListSearchAdapter, createDefaultListDragPreview, createElementIncrSearch, createElementListSearchAdapter, createEmptyLayout, createEmptyStack, createFuzzySearch, createIncrSearch, createPillRenderer, createSplit, createStack, createTreeListAdapter, createTreeListSearchAdapter, createVerticalListAdapter, distribute, dropTargetFor, extractStack, findNode, findParentOf, findStackOf, findStackPathByName, getActiveDragPanelId, getIcon, getIconEntry, getIconFont, getLeafNeighbours, hasIcon, iconBus, init, insertBeside, isDragging, isMultiMode, isSplit, isStack, keyForElement, listItemFadeKeyframes, listSearchStyles, monitorIndeterminate, moveLeafNodeToEdge, moveLeafStep, normalise, 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, walk, wrapRoot };
43397
44462
 
43398
44463
  //# sourceMappingURL=index.js.map