@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.
- package/bundle/index.d.ts +232 -42
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +1102 -37
- package/bundle/index.js.map +1 -1
- package/dist/crumbs.d.ts +1 -1
- package/dist/{data-grid-BKa9i86q.d.ts → data-grid-C588pTgt.d.ts} +3 -3
- package/dist/{data-grid-BKa9i86q.d.ts.map → data-grid-C588pTgt.d.ts.map} +1 -1
- package/dist/data-grid.d.ts +2 -2
- package/dist/data-grid.js +1 -1
- package/dist/{detail-list-CHTomlbR.d.ts → detail-list-IKl76Wnp.d.ts} +4 -4
- package/dist/{detail-list-CHTomlbR.d.ts.map → detail-list-IKl76Wnp.d.ts.map} +1 -1
- package/dist/detail-list.d.ts +3 -3
- package/dist/detail-list.js +1 -1
- package/dist/{grid-list-CsZcXxMC.d.ts → grid-list-BUlUnisU.d.ts} +7 -55
- package/dist/grid-list-BUlUnisU.d.ts.map +1 -0
- package/dist/{grid-list-C8oMxLl-.js → grid-list-D18FNJRH.js} +2 -2
- package/dist/{grid-list-C8oMxLl-.js.map → grid-list-D18FNJRH.js.map} +1 -1
- package/dist/grid-list.d.ts +2 -2
- package/dist/grid-list.js +1 -1
- package/dist/incr-search.d.ts +1 -1
- package/dist/{index-Dgrx-DIA.d.ts → index--qnhBWZJ.d.ts} +2 -2
- package/dist/{index-Dgrx-DIA.d.ts.map → index--qnhBWZJ.d.ts.map} +1 -1
- package/dist/index.d.ts +30 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/{labelled-slider-input-BCH9968c.js → labelled-slider-input-aEYDvW2S.js} +2 -2
- package/dist/{labelled-slider-input-BCH9968c.js.map → labelled-slider-input-aEYDvW2S.js.map} +1 -1
- package/dist/labelled-slider-input.js +1 -1
- package/dist/list-native-drag-controller-CFyrkKUj.d.ts +61 -0
- package/dist/list-native-drag-controller-CFyrkKUj.d.ts.map +1 -0
- package/dist/{list-native-drag-controller-DrY3qeJM.js → list-native-drag-controller-DxD6Yjci.js} +14 -2
- package/dist/list-native-drag-controller-DxD6Yjci.js.map +1 -0
- package/dist/miller.d.ts +2 -2
- package/dist/plots.js +1 -1
- package/dist/slider-input-BxURAAmD.d.ts.map +1 -1
- package/dist/{slider-input-WR8_RwHg.js → slider-input-Cb5uSV42.js} +78 -11
- package/dist/slider-input-Cb5uSV42.js.map +1 -0
- package/dist/slider-input.js +1 -1
- package/dist/{tree-DSMn566I.js → tree-a14n9y7i.js} +1006 -19
- package/dist/tree-a14n9y7i.js.map +1 -0
- package/dist/{tree-component-nPP5Y-WS.d.ts → tree-component-BW2iCFq9.d.ts} +107 -3
- package/dist/tree-component-BW2iCFq9.d.ts.map +1 -0
- package/dist/tree.d.ts +102 -4
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +2 -2
- package/dist/{vertical-list-A6oWfivZ.d.ts → vertical-list-CHrXmmQ3.d.ts} +3 -3
- package/dist/{vertical-list-A6oWfivZ.d.ts.map → vertical-list-CHrXmmQ3.d.ts.map} +1 -1
- package/dist/vertical-list.d.ts +2 -2
- package/dist/vertical-list.js +1 -1
- package/dist/{xy-axis-CrrVdDFe.js → xy-axis-COKw338Q.js} +2 -2
- package/dist/xy-axis-COKw338Q.js.map +1 -0
- package/dist/xy-axis-DQqd2yXJ.d.ts.map +1 -1
- package/docs-user/index.json +2 -2
- package/docs-user/tree.md +75 -0
- package/package.json +1 -1
- package/dist/grid-list-CsZcXxMC.d.ts.map +0 -1
- package/dist/list-drag-types-kpaXz2pZ.d.ts +0 -42
- package/dist/list-drag-types-kpaXz2pZ.d.ts.map +0 -1
- package/dist/list-native-drag-controller-DrY3qeJM.js.map +0 -1
- package/dist/slider-input-WR8_RwHg.js.map +0 -1
- package/dist/tree-DSMn566I.js.map +0 -1
- package/dist/tree-component-nPP5Y-WS.d.ts.map +0 -1
- package/dist/xy-axis-CrrVdDFe.js.map +0 -1
|
@@ -3,6 +3,7 @@ import { n as tickledStyles, t as tickledItemStyles } from "./tickled-styles-BrA
|
|
|
3
3
|
import { t as themeFallbacks } from "./fallbacks-BcKGq-2F.js";
|
|
4
4
|
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
5
5
|
import { i as ListSearchController, n as listSearchStyles, o as registerListSearchCommands, r as LIST_SEARCH_MODES, t as createTreeListSearchAdapter } from "./incr-search-C05WjbZh.js";
|
|
6
|
+
import { t as ListNativeDragController } from "./list-native-drag-controller-DxD6Yjci.js";
|
|
6
7
|
import { n as animateListItemIn, r as animateListItemOut } from "./list-item-animation-BUoEKi5s.js";
|
|
7
8
|
import "./interaction-BskmlA9t.js";
|
|
8
9
|
import { t as collectDataResult } from "./data-provider-35TyWclX.js";
|
|
@@ -10,15 +11,138 @@ import { LitElement, css, html, nothing } from "lit";
|
|
|
10
11
|
import { property, state } from "lit/decorators.js";
|
|
11
12
|
import { createCommandRegistry } from "@clinth/ui-commands";
|
|
12
13
|
import { repeat } from "lit/directives/repeat.js";
|
|
13
|
-
//#region src/common/tree-
|
|
14
|
+
//#region src/common/tree-drop-apply.ts
|
|
14
15
|
function findNode(root, key) {
|
|
15
16
|
if (root.item.key === key) return root;
|
|
16
|
-
|
|
17
|
-
for (const child of root.children) {
|
|
17
|
+
for (const child of root.children ?? []) {
|
|
18
18
|
const found = findNode(child, key);
|
|
19
19
|
if (found) return found;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
+
function findParent(root, key, parent = void 0) {
|
|
23
|
+
for (const child of root.children ?? []) {
|
|
24
|
+
if (child.item.key === key) return parent === void 0 ? root : parent;
|
|
25
|
+
const found = findParent(child, key, child);
|
|
26
|
+
if (found) return found;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** True when `key` is `ancestorKey`, or a descendant of it. */
|
|
30
|
+
function isSelfOrDescendant(root, ancestorKey, key) {
|
|
31
|
+
const ancestor = findNode(root, ancestorKey);
|
|
32
|
+
return ancestor !== void 0 && findNode(ancestor, key) !== void 0;
|
|
33
|
+
}
|
|
34
|
+
/** Remove every node whose key is in `keys` (with its whole subtree), in one pass. */
|
|
35
|
+
function removeKeys(node, keys) {
|
|
36
|
+
if (!node.children) return node;
|
|
37
|
+
return {
|
|
38
|
+
...node,
|
|
39
|
+
children: node.children.filter((c) => !keys.has(c.item.key)).map((c) => removeKeys(c, keys))
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function childrenOf(root, parentKey) {
|
|
43
|
+
if (parentKey === void 0) return root.children ?? [];
|
|
44
|
+
return findNode(root, parentKey)?.children ?? [];
|
|
45
|
+
}
|
|
46
|
+
/** Return a new root with `parentKey`'s children replaced (root itself when `parentKey` is undefined). */
|
|
47
|
+
function withChildren(node, parentKey, children) {
|
|
48
|
+
if (parentKey === void 0) return {
|
|
49
|
+
...node,
|
|
50
|
+
children
|
|
51
|
+
};
|
|
52
|
+
if (node.item.key === parentKey) return {
|
|
53
|
+
...node,
|
|
54
|
+
children
|
|
55
|
+
};
|
|
56
|
+
if (!node.children) return node;
|
|
57
|
+
return {
|
|
58
|
+
...node,
|
|
59
|
+
children: node.children.map((c) => withChildren(c, parentKey, children))
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function clamp$1(n, min, max) {
|
|
63
|
+
return Math.max(min, Math.min(max, n));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Drop keys whose ancestor is also being dragged — only the top-most selected
|
|
67
|
+
* nodes move; their subtrees travel with them. Preserves input order.
|
|
68
|
+
*/
|
|
69
|
+
function pruneDraggedDescendants(root, keys) {
|
|
70
|
+
const set = new Set(keys);
|
|
71
|
+
return keys.filter((key) => {
|
|
72
|
+
let parent = findParent(root, key);
|
|
73
|
+
while (parent) {
|
|
74
|
+
if (set.has(parent.item.key)) return false;
|
|
75
|
+
parent = findParent(root, parent.item.key);
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Framework-agnostic drop application. Given the current immutable `root` and a
|
|
82
|
+
* resolved drop context, returns a **new** root with the drop applied, or the
|
|
83
|
+
* unchanged `root` when the drop is invalid (dragged node into its own subtree,
|
|
84
|
+
* missing reference, empty payload). Never throws, never mutates.
|
|
85
|
+
*
|
|
86
|
+
* The insertion point is re-derived from `target.referenceKey` + `target.position`
|
|
87
|
+
* against the post-removal tree, so same-parent reorders are off-by-one-safe and
|
|
88
|
+
* multi-node drops land as siblings in drag order. `target.index` is honoured only
|
|
89
|
+
* for `position: 'inside'` (0 = first child, large = append).
|
|
90
|
+
*/
|
|
91
|
+
function applyTreeDrop(root, ctx) {
|
|
92
|
+
const { target, source } = ctx;
|
|
93
|
+
let nodes;
|
|
94
|
+
let removeSet = /* @__PURE__ */ new Set();
|
|
95
|
+
if (source === `internal`) {
|
|
96
|
+
const keys = pruneDraggedDescendants(root, [...ctx.draggedKeys]);
|
|
97
|
+
if (keys.length === 0) return root;
|
|
98
|
+
if (target.parentKey !== void 0) {
|
|
99
|
+
for (const key of keys) if (isSelfOrDescendant(root, key, target.parentKey)) return root;
|
|
100
|
+
}
|
|
101
|
+
if (target.position !== `inside`) {
|
|
102
|
+
for (const key of keys) if (isSelfOrDescendant(root, key, target.referenceKey)) return root;
|
|
103
|
+
}
|
|
104
|
+
const resolved = keys.map((k) => findNode(root, k));
|
|
105
|
+
if (resolved.includes(void 0)) return root;
|
|
106
|
+
nodes = resolved;
|
|
107
|
+
removeSet = new Set(keys);
|
|
108
|
+
} else {
|
|
109
|
+
nodes = (ctx.dragged ?? []).map((n) => ({ ...n }));
|
|
110
|
+
if (nodes.length === 0) return root;
|
|
111
|
+
}
|
|
112
|
+
const afterRemoval = removeSet.size > 0 ? removeKeys(root, removeSet) : root;
|
|
113
|
+
let parentKey;
|
|
114
|
+
let index;
|
|
115
|
+
if (target.position === `inside`) {
|
|
116
|
+
if (findNode(afterRemoval, target.referenceKey) === void 0) return root;
|
|
117
|
+
parentKey = target.referenceKey;
|
|
118
|
+
const kids = childrenOf(afterRemoval, parentKey);
|
|
119
|
+
index = clamp$1(target.index, 0, kids.length);
|
|
120
|
+
} else {
|
|
121
|
+
parentKey = findParent(afterRemoval, target.referenceKey)?.item.key;
|
|
122
|
+
const refIdx = childrenOf(afterRemoval, parentKey).findIndex((c) => c.item.key === target.referenceKey);
|
|
123
|
+
if (refIdx < 0) return root;
|
|
124
|
+
index = target.position === `before` ? refIdx : refIdx + 1;
|
|
125
|
+
}
|
|
126
|
+
const kids = [...childrenOf(afterRemoval, parentKey)];
|
|
127
|
+
const next = [
|
|
128
|
+
...kids.slice(0, index),
|
|
129
|
+
...nodes,
|
|
130
|
+
...kids.slice(index)
|
|
131
|
+
];
|
|
132
|
+
return withChildren(afterRemoval, parentKey, next);
|
|
133
|
+
}
|
|
134
|
+
/** Build a synthetic `TreeDropTarget` for programmatic moves (see `TreeDataModel`). */
|
|
135
|
+
function dropTargetFor(referenceKey, position, index = position === `inside` ? Number.MAX_SAFE_INTEGER : 0) {
|
|
136
|
+
return {
|
|
137
|
+
referenceKey,
|
|
138
|
+
position,
|
|
139
|
+
index,
|
|
140
|
+
parentKey: position === `inside` ? referenceKey : void 0,
|
|
141
|
+
depth: 0
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/common/tree-data-model.ts
|
|
22
146
|
/** Return a new root with the node at `key` replaced by `replacer(node)`. */
|
|
23
147
|
function mapNode(root, key, replacer) {
|
|
24
148
|
if (root.item.key === key) return replacer(root);
|
|
@@ -43,11 +167,23 @@ function removeNodeFrom(root, key) {
|
|
|
43
167
|
children: root.children.filter((c) => c.item.key !== key).map((c) => removeNodeFrom(c, key))
|
|
44
168
|
};
|
|
45
169
|
}
|
|
46
|
-
/** Return a new root with
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
170
|
+
/** Return a new root with `newChild` inserted at `index` among the children of `parentKey`. */
|
|
171
|
+
function insertChildAt(root, parentKey, newChild, index) {
|
|
172
|
+
return mapNode(root, parentKey, (parent) => {
|
|
173
|
+
const children = parent.children ?? [];
|
|
174
|
+
const clampedIndex = Math.max(0, Math.min(index, children.length));
|
|
175
|
+
return {
|
|
176
|
+
item: parent.item,
|
|
177
|
+
children: [
|
|
178
|
+
...children.slice(0, clampedIndex),
|
|
179
|
+
newChild,
|
|
180
|
+
...children.slice(clampedIndex)
|
|
181
|
+
]
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function getRootChildren(root) {
|
|
186
|
+
return root.children ?? [];
|
|
51
187
|
}
|
|
52
188
|
/**
|
|
53
189
|
* Manages tree data for tree-like components.
|
|
@@ -175,10 +311,80 @@ var TreeDataModel = class {
|
|
|
175
311
|
}
|
|
176
312
|
/**
|
|
177
313
|
* Moves the node with the given key to become a child of `newParentKey`.
|
|
314
|
+
* When `index` is provided, inserts at that position; otherwise appends.
|
|
178
315
|
* Returns the new root (connected components are notified automatically).
|
|
179
316
|
*/
|
|
180
|
-
moveNode(key, newParentKey) {
|
|
181
|
-
|
|
317
|
+
moveNode(key, newParentKey, index) {
|
|
318
|
+
const next = applyTreeDrop(this.#root, {
|
|
319
|
+
source: `internal`,
|
|
320
|
+
draggedKeys: [key],
|
|
321
|
+
target: dropTargetFor(newParentKey, `inside`, index ?? Number.MAX_SAFE_INTEGER)
|
|
322
|
+
});
|
|
323
|
+
if (next !== this.#root) {
|
|
324
|
+
this.#root = next;
|
|
325
|
+
this.#notify({
|
|
326
|
+
type: `root`,
|
|
327
|
+
root: this.#root
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return this.#root;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Moves the node with the given key to become a sibling of `referenceKey`,
|
|
334
|
+
* positioned `before` or `after` it. A no-op (returns the unchanged root) when
|
|
335
|
+
* `key` is `referenceKey`, an ancestor of it, or either is missing.
|
|
336
|
+
* Returns the new root (connected components are notified automatically).
|
|
337
|
+
*/
|
|
338
|
+
moveNodeRelative(key, referenceKey, position) {
|
|
339
|
+
const next = applyTreeDrop(this.#root, {
|
|
340
|
+
source: `internal`,
|
|
341
|
+
draggedKeys: [key],
|
|
342
|
+
target: dropTargetFor(referenceKey, position)
|
|
343
|
+
});
|
|
344
|
+
if (next !== this.#root) {
|
|
345
|
+
this.#root = next;
|
|
346
|
+
this.#notify({
|
|
347
|
+
type: `root`,
|
|
348
|
+
root: this.#root
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return this.#root;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Applies a resolved drop (from `ixfx-tree-list`'s `tree-drop` event or a
|
|
355
|
+
* hand-built context) to the current root. No-op when the drop is invalid.
|
|
356
|
+
* Returns the new root (connected components are notified automatically).
|
|
357
|
+
*/
|
|
358
|
+
applyDrop(ctx) {
|
|
359
|
+
const next = applyTreeDrop(this.#root, ctx);
|
|
360
|
+
if (next !== this.#root) {
|
|
361
|
+
this.#root = next;
|
|
362
|
+
this.#notify({
|
|
363
|
+
type: `root`,
|
|
364
|
+
root: this.#root
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return this.#root;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Inserts `node` as a child of `parentKey` (or at the root level when `parentKey` is undefined).
|
|
371
|
+
* When `index` is provided, inserts at that position; otherwise appends.
|
|
372
|
+
* Returns the new root (connected components are notified automatically).
|
|
373
|
+
*/
|
|
374
|
+
insertNode(parentKey, node, index) {
|
|
375
|
+
if (parentKey === void 0) {
|
|
376
|
+
const children = getRootChildren(this.#root);
|
|
377
|
+
const clampedIndex = Math.max(0, Math.min(index ?? children.length, children.length));
|
|
378
|
+
this.#root = {
|
|
379
|
+
...this.#root,
|
|
380
|
+
children: [
|
|
381
|
+
...children.slice(0, clampedIndex),
|
|
382
|
+
node,
|
|
383
|
+
...children.slice(clampedIndex)
|
|
384
|
+
]
|
|
385
|
+
};
|
|
386
|
+
} else if (index !== void 0) this.#root = insertChildAt(this.#root, parentKey, node, index);
|
|
387
|
+
else this.#root = addChildTo(this.#root, parentKey, node);
|
|
182
388
|
this.#notify({
|
|
183
389
|
type: `root`,
|
|
184
390
|
root: this.#root
|
|
@@ -200,6 +406,360 @@ var TreeDataModel = class {
|
|
|
200
406
|
}
|
|
201
407
|
};
|
|
202
408
|
//#endregion
|
|
409
|
+
//#region src/tree/tree-drag-registry.ts
|
|
410
|
+
const TREE_DRAG_MIME = `application/x-ixfx-tree`;
|
|
411
|
+
const registry = /* @__PURE__ */ new Map();
|
|
412
|
+
const weakRefs = /* @__PURE__ */ new Map();
|
|
413
|
+
/**
|
|
414
|
+
* The source id of the drag currently in flight, if any. There is only ever one
|
|
415
|
+
* native drag at a time, so a drop target can resolve the dragged nodes during
|
|
416
|
+
* `dragover` — when `DataTransfer.getData()` is unreadable (protected mode) — by
|
|
417
|
+
* looking this up in the registry.
|
|
418
|
+
*/
|
|
419
|
+
let currentSourceId;
|
|
420
|
+
let sourceIdCounter = 0;
|
|
421
|
+
function treeDragGenerateSourceId() {
|
|
422
|
+
return `tree-drag-${++sourceIdCounter}-${Date.now()}`;
|
|
423
|
+
}
|
|
424
|
+
function treeDragRegister(sourceId, element, nodes, keys) {
|
|
425
|
+
registry.set(sourceId, {
|
|
426
|
+
sourceId,
|
|
427
|
+
nodes,
|
|
428
|
+
keys
|
|
429
|
+
});
|
|
430
|
+
weakRefs.set(sourceId, new WeakRef(element));
|
|
431
|
+
currentSourceId = sourceId;
|
|
432
|
+
}
|
|
433
|
+
function treeDragUnregister(sourceId) {
|
|
434
|
+
registry.delete(sourceId);
|
|
435
|
+
weakRefs.delete(sourceId);
|
|
436
|
+
if (currentSourceId === sourceId) currentSourceId = void 0;
|
|
437
|
+
}
|
|
438
|
+
/** The in-flight drag's `{ keys, nodes, element }`, or `undefined` when nothing is dragging. */
|
|
439
|
+
function treeDragCurrent() {
|
|
440
|
+
if (currentSourceId === void 0) return void 0;
|
|
441
|
+
const entry = registry.get(currentSourceId);
|
|
442
|
+
if (!entry) return void 0;
|
|
443
|
+
return {
|
|
444
|
+
sourceId: currentSourceId,
|
|
445
|
+
keys: entry.keys,
|
|
446
|
+
nodes: entry.nodes,
|
|
447
|
+
element: weakRefs.get(currentSourceId)?.deref()
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
//#endregion
|
|
451
|
+
//#region src/tree/tree-drop-controller.ts
|
|
452
|
+
const EDGE_ZONE_PX = 24;
|
|
453
|
+
const MAX_SCROLL_SPEED = 16;
|
|
454
|
+
function clamp(value, min, max) {
|
|
455
|
+
return Math.max(min, Math.min(max, value));
|
|
456
|
+
}
|
|
457
|
+
var TreeDropController = class {
|
|
458
|
+
#host;
|
|
459
|
+
#config;
|
|
460
|
+
#active = false;
|
|
461
|
+
#current;
|
|
462
|
+
#source = `internal`;
|
|
463
|
+
#dragKeys = [];
|
|
464
|
+
#dragNodes = [];
|
|
465
|
+
#expandTimer;
|
|
466
|
+
#expandPendingKey;
|
|
467
|
+
#scrollRaf = 0;
|
|
468
|
+
#pointerX = 0;
|
|
469
|
+
#pointerY = 0;
|
|
470
|
+
#boundContainer;
|
|
471
|
+
constructor(host, config) {
|
|
472
|
+
this.#host = host;
|
|
473
|
+
this.#config = config;
|
|
474
|
+
host.addController(this);
|
|
475
|
+
}
|
|
476
|
+
/** A drag is currently over this tree. */
|
|
477
|
+
get isDragging() {
|
|
478
|
+
return this.#active;
|
|
479
|
+
}
|
|
480
|
+
/** A drag is over this tree but the current position is not a valid drop. */
|
|
481
|
+
get isRejected() {
|
|
482
|
+
return this.#active && this.#current === void 0;
|
|
483
|
+
}
|
|
484
|
+
get dropState() {
|
|
485
|
+
return this.#current;
|
|
486
|
+
}
|
|
487
|
+
hostConnected() {
|
|
488
|
+
this.#bind();
|
|
489
|
+
}
|
|
490
|
+
/** Bind once the shadow `#container` exists (it does not yet at `hostConnected`). */
|
|
491
|
+
hostUpdated() {
|
|
492
|
+
this.#bind();
|
|
493
|
+
}
|
|
494
|
+
#bind() {
|
|
495
|
+
const container = this.#config.getScrollContainer();
|
|
496
|
+
if (!container || container === this.#boundContainer) return;
|
|
497
|
+
this.#unbind();
|
|
498
|
+
this.#boundContainer = container;
|
|
499
|
+
container.addEventListener(`dragenter`, this.#onDragEnter);
|
|
500
|
+
container.addEventListener(`dragover`, this.#onDragOver);
|
|
501
|
+
container.addEventListener(`dragleave`, this.#onDragLeave);
|
|
502
|
+
container.addEventListener(`drop`, this.#onDrop);
|
|
503
|
+
}
|
|
504
|
+
#unbind() {
|
|
505
|
+
const c = this.#boundContainer;
|
|
506
|
+
if (!c) return;
|
|
507
|
+
c.removeEventListener(`dragenter`, this.#onDragEnter);
|
|
508
|
+
c.removeEventListener(`dragover`, this.#onDragOver);
|
|
509
|
+
c.removeEventListener(`dragleave`, this.#onDragLeave);
|
|
510
|
+
c.removeEventListener(`drop`, this.#onDrop);
|
|
511
|
+
this.#boundContainer = void 0;
|
|
512
|
+
}
|
|
513
|
+
hostDisconnected() {
|
|
514
|
+
this.#unbind();
|
|
515
|
+
this.#clearExpand();
|
|
516
|
+
this.#stopScroll();
|
|
517
|
+
this.#active = false;
|
|
518
|
+
this.#current = void 0;
|
|
519
|
+
}
|
|
520
|
+
#onDragEnter = (event) => {
|
|
521
|
+
if (this.#config.getDndMode() === `none` || !event.dataTransfer) return;
|
|
522
|
+
if (this.#config.resolveDrag(event.dataTransfer, `hover`) === void 0) return;
|
|
523
|
+
event.preventDefault();
|
|
524
|
+
if (!this.#active) {
|
|
525
|
+
this.#active = true;
|
|
526
|
+
this.#config.onActiveChange(true);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
#onDragOver = (event) => {
|
|
530
|
+
if (this.#config.getDndMode() === `none` || !event.dataTransfer) return;
|
|
531
|
+
this.#pointerX = event.clientX;
|
|
532
|
+
this.#pointerY = event.clientY;
|
|
533
|
+
const drag = this.#config.resolveDrag(event.dataTransfer, `hover`);
|
|
534
|
+
if (!drag) {
|
|
535
|
+
this.#reject(event);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
if (!this.#active) {
|
|
539
|
+
this.#active = true;
|
|
540
|
+
this.#config.onActiveChange(true);
|
|
541
|
+
}
|
|
542
|
+
this.#source = drag.source;
|
|
543
|
+
this.#dragKeys = drag.keys;
|
|
544
|
+
this.#dragNodes = drag.nodes;
|
|
545
|
+
const rows = this.#config.getVisibleRows();
|
|
546
|
+
this.#handleExpandHover(this.#rowAtPointer(rows, event.clientY));
|
|
547
|
+
this.#kickScroll();
|
|
548
|
+
const target = this.#resolveIntent(event, rows, drag.source);
|
|
549
|
+
if (!target) {
|
|
550
|
+
this.#reject(event, false);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
const ctx = {
|
|
554
|
+
source: drag.source,
|
|
555
|
+
dragged: drag.nodes.length > 0 ? drag.nodes : void 0,
|
|
556
|
+
draggedKeys: drag.keys,
|
|
557
|
+
target,
|
|
558
|
+
dataTransfer: event.dataTransfer
|
|
559
|
+
};
|
|
560
|
+
if (!this.#config.vet(ctx)) {
|
|
561
|
+
this.#reject(event, false);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
event.preventDefault();
|
|
565
|
+
event.dataTransfer.dropEffect = drag.source === `internal` ? `move` : `copy`;
|
|
566
|
+
this.#setDropState(target);
|
|
567
|
+
};
|
|
568
|
+
/** Not a valid drop here: keep the drag active for feedback but accept nothing. */
|
|
569
|
+
#reject(event, clearHover = true) {
|
|
570
|
+
if (event.dataTransfer) event.dataTransfer.dropEffect = `none`;
|
|
571
|
+
this.#setDropState(void 0);
|
|
572
|
+
if (clearHover) this.#clearExpand();
|
|
573
|
+
}
|
|
574
|
+
#onDragLeave = (event) => {
|
|
575
|
+
const container = this.#config.getScrollContainer();
|
|
576
|
+
const related = event.relatedTarget;
|
|
577
|
+
if (container && related && container.contains(related)) return;
|
|
578
|
+
this.#endHover();
|
|
579
|
+
};
|
|
580
|
+
#onDrop = (event) => {
|
|
581
|
+
if (!event.dataTransfer) {
|
|
582
|
+
this.#endHover();
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
event.preventDefault();
|
|
586
|
+
this.#stopScroll();
|
|
587
|
+
this.#clearExpand();
|
|
588
|
+
const finish = (dropped) => {
|
|
589
|
+
this.#current = void 0;
|
|
590
|
+
this.#active = false;
|
|
591
|
+
this.#config.onDropStateChange(void 0);
|
|
592
|
+
this.#config.onActiveChange(false);
|
|
593
|
+
this.#config.onDragEnd(dropped);
|
|
594
|
+
};
|
|
595
|
+
if (this.#config.getDndMode() === `none`) {
|
|
596
|
+
finish(false);
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const drag = this.#config.resolveDrag(event.dataTransfer, `drop`);
|
|
600
|
+
if (!drag) {
|
|
601
|
+
finish(false);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
this.#dragKeys = drag.keys;
|
|
605
|
+
this.#dragNodes = drag.nodes;
|
|
606
|
+
const target = this.#resolveIntent(event, this.#config.getVisibleRows(), drag.source);
|
|
607
|
+
if (!target) {
|
|
608
|
+
finish(false);
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const ctx = {
|
|
612
|
+
source: drag.source,
|
|
613
|
+
dragged: drag.nodes.length > 0 ? drag.nodes : void 0,
|
|
614
|
+
draggedKeys: drag.keys,
|
|
615
|
+
target,
|
|
616
|
+
dataTransfer: event.dataTransfer
|
|
617
|
+
};
|
|
618
|
+
if (!this.#config.vet(ctx)) {
|
|
619
|
+
finish(false);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const detail = {
|
|
623
|
+
...ctx,
|
|
624
|
+
external: drag.source === `external` ? drag.nodes : void 0
|
|
625
|
+
};
|
|
626
|
+
finish(this.#config.commitDrop(detail));
|
|
627
|
+
};
|
|
628
|
+
#endHover() {
|
|
629
|
+
this.#clearExpand();
|
|
630
|
+
this.#stopScroll();
|
|
631
|
+
if (this.#current !== void 0) {
|
|
632
|
+
this.#current = void 0;
|
|
633
|
+
this.#config.onDropStateChange(void 0);
|
|
634
|
+
}
|
|
635
|
+
if (this.#active) {
|
|
636
|
+
this.#active = false;
|
|
637
|
+
this.#config.onActiveChange(false);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
#rowAtPointer(rows, clientY) {
|
|
641
|
+
if (rows.length === 0) return void 0;
|
|
642
|
+
if (clientY < rows[0].rect.top) return rows[0];
|
|
643
|
+
if (clientY > rows[rows.length - 1].rect.bottom) return rows[rows.length - 1];
|
|
644
|
+
return rows.find((r) => clientY >= r.rect.top && clientY <= r.rect.bottom) ?? rows[rows.length - 1];
|
|
645
|
+
}
|
|
646
|
+
#parentRow(rows, index) {
|
|
647
|
+
const target = rows[index];
|
|
648
|
+
for (let i = index - 1; i >= 0; i--) if (rows[i].depth === target.depth - 1) return rows[i];
|
|
649
|
+
}
|
|
650
|
+
#resolveIntent(event, rows, source) {
|
|
651
|
+
if (rows.length === 0) return void 0;
|
|
652
|
+
const row = this.#rowAtPointer(rows, event.clientY);
|
|
653
|
+
if (!row) return void 0;
|
|
654
|
+
const rowIndex = rows.indexOf(row);
|
|
655
|
+
const f = clamp((event.clientY - row.rect.top) / row.rect.height, 0, 1);
|
|
656
|
+
let position = f < .25 ? `before` : f > .75 ? `after` : `inside`;
|
|
657
|
+
const isLeaf = row.node.item.isLeaf === true;
|
|
658
|
+
if (position === `inside` && isLeaf) position = `after`;
|
|
659
|
+
let insideFromExpandedAfter = false;
|
|
660
|
+
if (position === `after` && !isLeaf && this.#config.isExpanded(row.key)) {
|
|
661
|
+
position = `inside`;
|
|
662
|
+
insideFromExpandedAfter = true;
|
|
663
|
+
}
|
|
664
|
+
let parentKey;
|
|
665
|
+
let referenceKey;
|
|
666
|
+
let depth;
|
|
667
|
+
let index;
|
|
668
|
+
if (position === `inside`) {
|
|
669
|
+
parentKey = row.key;
|
|
670
|
+
referenceKey = row.key;
|
|
671
|
+
depth = row.depth + 1;
|
|
672
|
+
index = insideFromExpandedAfter ? 0 : row.node.children?.length ?? 0;
|
|
673
|
+
} else {
|
|
674
|
+
const indent = this.#config.getIndentPx() || 1;
|
|
675
|
+
const treeLeft = rows[0].rect.left;
|
|
676
|
+
const effDepth = clamp(Math.round((event.clientX - treeLeft) / indent), 0, row.depth);
|
|
677
|
+
let anchorIndex = rowIndex;
|
|
678
|
+
for (let up = row.depth - effDepth; up > 0; up--) {
|
|
679
|
+
const parent = this.#parentRow(rows, anchorIndex);
|
|
680
|
+
if (!parent) break;
|
|
681
|
+
anchorIndex = rows.indexOf(parent);
|
|
682
|
+
}
|
|
683
|
+
const anchor = rows[anchorIndex];
|
|
684
|
+
referenceKey = anchor.key;
|
|
685
|
+
depth = anchor.depth;
|
|
686
|
+
const parent = this.#parentRow(rows, anchorIndex);
|
|
687
|
+
parentKey = parent?.key;
|
|
688
|
+
const refIdx = (parent ? parent.node.children ?? [] : rows.filter((r) => r.depth === 0).map((r) => r.node)).findIndex((n) => n.item.key === anchor.key);
|
|
689
|
+
index = (refIdx < 0 ? 0 : refIdx) + (position === `after` ? 1 : 0);
|
|
690
|
+
}
|
|
691
|
+
if (source === `internal`) {
|
|
692
|
+
for (const key of this.#dragKeys) {
|
|
693
|
+
if (key === parentKey || key === referenceKey) return void 0;
|
|
694
|
+
if (parentKey !== void 0 && this.#config.isSelfOrDescendant(key, parentKey)) return void 0;
|
|
695
|
+
if (position !== `inside` && this.#config.isSelfOrDescendant(key, referenceKey)) return void 0;
|
|
696
|
+
}
|
|
697
|
+
if (this.#dragKeys.length > 0 && !this.#config.isReorderAllowed()) {
|
|
698
|
+
if (!this.#dragKeys.some((k) => this.#config.getParentKey(k) !== parentKey)) return void 0;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
parentKey,
|
|
703
|
+
index,
|
|
704
|
+
referenceKey,
|
|
705
|
+
position,
|
|
706
|
+
depth
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
#handleExpandHover(row) {
|
|
710
|
+
if (!row || row.node.item.isLeaf === true || this.#config.isExpanded(row.key)) {
|
|
711
|
+
this.#clearExpand();
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (row.key === this.#expandPendingKey) return;
|
|
715
|
+
this.#clearExpand();
|
|
716
|
+
const key = this.#expandPendingKey = row.key;
|
|
717
|
+
this.#expandTimer = setTimeout(() => {
|
|
718
|
+
this.#expandTimer = void 0;
|
|
719
|
+
if (this.#expandPendingKey === key) {
|
|
720
|
+
this.#expandPendingKey = void 0;
|
|
721
|
+
this.#config.expandKey(key);
|
|
722
|
+
}
|
|
723
|
+
}, Math.max(0, this.#config.getExpandHoverMs()));
|
|
724
|
+
}
|
|
725
|
+
#clearExpand() {
|
|
726
|
+
if (this.#expandTimer !== void 0) {
|
|
727
|
+
clearTimeout(this.#expandTimer);
|
|
728
|
+
this.#expandTimer = void 0;
|
|
729
|
+
}
|
|
730
|
+
this.#expandPendingKey = void 0;
|
|
731
|
+
}
|
|
732
|
+
#kickScroll() {
|
|
733
|
+
if (this.#scrollRaf === 0) this.#scrollRaf = requestAnimationFrame(this.#scrollTick);
|
|
734
|
+
}
|
|
735
|
+
#scrollTick = () => {
|
|
736
|
+
this.#scrollRaf = 0;
|
|
737
|
+
if (!this.#active) return;
|
|
738
|
+
const container = this.#config.getScrollContainer();
|
|
739
|
+
if (!container) return;
|
|
740
|
+
const rect = container.getBoundingClientRect();
|
|
741
|
+
const y = this.#pointerY - rect.top;
|
|
742
|
+
let dy = 0;
|
|
743
|
+
if (y < EDGE_ZONE_PX) dy = -Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, y) / EDGE_ZONE_PX));
|
|
744
|
+
else if (y > rect.height - EDGE_ZONE_PX) dy = Math.ceil(MAX_SCROLL_SPEED * (1 - Math.max(0, rect.height - y) / EDGE_ZONE_PX));
|
|
745
|
+
if (dy !== 0 && this.#pointerX >= rect.left && this.#pointerX <= rect.right) {
|
|
746
|
+
container.scrollTop += dy;
|
|
747
|
+
this.#kickScroll();
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
#stopScroll() {
|
|
751
|
+
if (this.#scrollRaf !== 0) {
|
|
752
|
+
cancelAnimationFrame(this.#scrollRaf);
|
|
753
|
+
this.#scrollRaf = 0;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
#setDropState(state) {
|
|
757
|
+
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;
|
|
758
|
+
this.#current = state;
|
|
759
|
+
if (!unchanged || this.#active) this.#config.onDropStateChange(state);
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
//#endregion
|
|
203
763
|
//#region src/tree/tree-base.ts
|
|
204
764
|
/** Above this many rows entering / leaving at once, skip the animation entirely. */
|
|
205
765
|
const MAX_ANIMATED_ROWS = 50;
|
|
@@ -212,6 +772,10 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
212
772
|
this._selectedNodes = /* @__PURE__ */ new Set();
|
|
213
773
|
this.disableKeyboardNavigation = false;
|
|
214
774
|
this.registry = void 0;
|
|
775
|
+
this.itemDnd = `none`;
|
|
776
|
+
this.dndExpandHoverMs = 500;
|
|
777
|
+
this.reorderable = true;
|
|
778
|
+
this.applyInternalDrop = true;
|
|
215
779
|
this._expandedKeys = /* @__PURE__ */ new Set();
|
|
216
780
|
this.tickled = new TickledController(this, {
|
|
217
781
|
getItems: () => {
|
|
@@ -220,6 +784,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
220
784
|
enabled: true
|
|
221
785
|
}));
|
|
222
786
|
},
|
|
787
|
+
hoverDisabled: () => this.#drop?.isDragging === true || this.#nativeDrag?.isDragging === true,
|
|
223
788
|
onStateChange: () => {
|
|
224
789
|
this.setAttribute(`data-input-mode`, this.tickled.inputMode);
|
|
225
790
|
}
|
|
@@ -236,6 +801,12 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
236
801
|
this.#leaving = /* @__PURE__ */ new Map();
|
|
237
802
|
this.#leavingAnimations = /* @__PURE__ */ new Map();
|
|
238
803
|
this.#treeAnimReady = false;
|
|
804
|
+
this.#dragSourceId = ``;
|
|
805
|
+
this.#nativeDragKeys = /* @__PURE__ */ new Set();
|
|
806
|
+
this.#internalDropHandled = false;
|
|
807
|
+
this.#onContainerScroll = () => {
|
|
808
|
+
this.#rowsCache = void 0;
|
|
809
|
+
};
|
|
239
810
|
this.#onKeyDown = (event) => {
|
|
240
811
|
if (this.search.isOpen) return;
|
|
241
812
|
const nodes = this.#getAllNodes();
|
|
@@ -389,6 +960,28 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
389
960
|
#leaving;
|
|
390
961
|
#leavingAnimations;
|
|
391
962
|
#treeAnimReady;
|
|
963
|
+
#dragSourceId;
|
|
964
|
+
#postDragSuppressTimer;
|
|
965
|
+
#dropState;
|
|
966
|
+
#drop;
|
|
967
|
+
#nativeDrag;
|
|
968
|
+
/** Keys of the nodes currently being dragged out (for `.dragging` styling). */
|
|
969
|
+
#nativeDragKeys;
|
|
970
|
+
/** Set by `commitDrop` for a same-tree internal drop, read by the native `onEnd` to avoid a duplicate `tree-drag-end`. */
|
|
971
|
+
#internalDropHandled;
|
|
972
|
+
/** Per-drag cache of measured rows; invalidated on scroll / update. */
|
|
973
|
+
#rowsCache;
|
|
974
|
+
#onContainerScroll;
|
|
975
|
+
get nativeDrag() {
|
|
976
|
+
return this.#nativeDrag;
|
|
977
|
+
}
|
|
978
|
+
get dropState() {
|
|
979
|
+
return this.#dropState;
|
|
980
|
+
}
|
|
981
|
+
/** Keys of the nodes currently being dragged out of this tree. */
|
|
982
|
+
get nativeDragKeys() {
|
|
983
|
+
return this.#nativeDragKeys;
|
|
984
|
+
}
|
|
392
985
|
#cancelLeavingAnimation(key) {
|
|
393
986
|
this.#leavingAnimations.get(key)?.cancel();
|
|
394
987
|
this.#leavingAnimations.delete(key);
|
|
@@ -500,6 +1093,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
500
1093
|
this.#treeAnimReady = true;
|
|
501
1094
|
}
|
|
502
1095
|
updated(changedProps) {
|
|
1096
|
+
this.#rowsCache = void 0;
|
|
503
1097
|
if (changedProps.has(`root`) && this.root) {
|
|
504
1098
|
this.#abortPending();
|
|
505
1099
|
this._expandedKeys.clear();
|
|
@@ -556,6 +1150,291 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
556
1150
|
});
|
|
557
1151
|
this.registry = registry;
|
|
558
1152
|
this.#syncSearchCommands();
|
|
1153
|
+
this.#initDnd();
|
|
1154
|
+
}
|
|
1155
|
+
#initDnd() {
|
|
1156
|
+
this.#dragSourceId = treeDragGenerateSourceId();
|
|
1157
|
+
this.#nativeDrag = new ListNativeDragController(this, {
|
|
1158
|
+
source: `tree-list`,
|
|
1159
|
+
isEnabled: () => this.itemDnd !== `none` && this.#anyRowDraggable(),
|
|
1160
|
+
resolveEventToKey: (target) => {
|
|
1161
|
+
if (!(target instanceof Element)) return void 0;
|
|
1162
|
+
return target.closest(`li[data-key]`)?.getAttribute(`data-key`) ?? void 0;
|
|
1163
|
+
},
|
|
1164
|
+
prepareSelection: (originKey) => {
|
|
1165
|
+
const allNodes = this.#getAllNodes();
|
|
1166
|
+
const originEntry = allNodes.find((n) => n.node.item.key === originKey);
|
|
1167
|
+
if (!originEntry) return void 0;
|
|
1168
|
+
const selectedNodes = new Set(this._selectedNodes);
|
|
1169
|
+
if (!selectedNodes.has(originEntry.node)) selectedNodes.clear();
|
|
1170
|
+
selectedNodes.add(originEntry.node);
|
|
1171
|
+
const orderedKeys = allNodes.filter((n) => selectedNodes.has(n.node)).map((n) => n.node.item.key);
|
|
1172
|
+
const topKeys = new Set(this.root ? pruneDraggedDescendants(this.root, orderedKeys) : orderedKeys);
|
|
1173
|
+
const selected = allNodes.filter((n) => topKeys.has(n.node.item.key)).map((n, i) => ({
|
|
1174
|
+
key: n.node.item.key,
|
|
1175
|
+
index: i,
|
|
1176
|
+
item: n.node,
|
|
1177
|
+
element: this.shadowRoot?.querySelector(`li[data-key="${CSS.escape(n.node.item.key)}"]`) ?? void 0
|
|
1178
|
+
}));
|
|
1179
|
+
const origin = selected.find((e) => e.key === originKey) ?? {
|
|
1180
|
+
key: originKey,
|
|
1181
|
+
index: 0,
|
|
1182
|
+
item: originEntry.node,
|
|
1183
|
+
element: void 0
|
|
1184
|
+
};
|
|
1185
|
+
if (!selected.some((e) => e.key === origin.key)) selected.unshift(origin);
|
|
1186
|
+
return {
|
|
1187
|
+
origin,
|
|
1188
|
+
selected
|
|
1189
|
+
};
|
|
1190
|
+
},
|
|
1191
|
+
getMetrics: () => ({ rowHeight: this.#getItemHeight() }),
|
|
1192
|
+
getRenderer: () => this.dragPreviewRenderer,
|
|
1193
|
+
dispatch: (detail) => {
|
|
1194
|
+
const keys = detail.selected.map((e) => e.key);
|
|
1195
|
+
const nodes = detail.selected.map((e) => e.item);
|
|
1196
|
+
const evt = new CustomEvent(`list-native-drag-start`, {
|
|
1197
|
+
detail,
|
|
1198
|
+
bubbles: true,
|
|
1199
|
+
composed: true,
|
|
1200
|
+
cancelable: true
|
|
1201
|
+
});
|
|
1202
|
+
const notCancelled = this.dispatchEvent(evt);
|
|
1203
|
+
if (notCancelled) {
|
|
1204
|
+
this.#nativeDragKeys = new Set(keys);
|
|
1205
|
+
this.#internalDropHandled = false;
|
|
1206
|
+
if (this.itemDnd === `internal` || this.itemDnd === `both`) treeDragRegister(this.#dragSourceId, this, nodes, keys);
|
|
1207
|
+
this.dispatchEvent(new CustomEvent(`tree-drag-start`, {
|
|
1208
|
+
detail: {
|
|
1209
|
+
nodes,
|
|
1210
|
+
keys
|
|
1211
|
+
},
|
|
1212
|
+
bubbles: true,
|
|
1213
|
+
composed: true
|
|
1214
|
+
}));
|
|
1215
|
+
}
|
|
1216
|
+
return notCancelled;
|
|
1217
|
+
},
|
|
1218
|
+
writeDataTransfer: (dataTransfer, detail) => {
|
|
1219
|
+
if (this.itemDnd !== `internal` && this.itemDnd !== `both`) return;
|
|
1220
|
+
const keys = detail.selected.map((e) => e.key);
|
|
1221
|
+
const nodes = detail.selected.map((e) => e.item);
|
|
1222
|
+
try {
|
|
1223
|
+
dataTransfer.setData(TREE_DRAG_MIME, JSON.stringify({
|
|
1224
|
+
sourceId: this.#dragSourceId,
|
|
1225
|
+
keys,
|
|
1226
|
+
nodes
|
|
1227
|
+
}));
|
|
1228
|
+
dataTransfer.setData(`text/plain`, nodes.map((n) => n.item.label).join(`\n`));
|
|
1229
|
+
} catch {}
|
|
1230
|
+
},
|
|
1231
|
+
onActiveChange: (active) => {
|
|
1232
|
+
this.toggleAttribute(`data-native-dragging`, active);
|
|
1233
|
+
if (!active) this.#nativeDragKeys = /* @__PURE__ */ new Set();
|
|
1234
|
+
this.requestUpdate();
|
|
1235
|
+
},
|
|
1236
|
+
onEnd: () => {
|
|
1237
|
+
treeDragUnregister(this.#dragSourceId);
|
|
1238
|
+
this.#nativeDragKeys = /* @__PURE__ */ new Set();
|
|
1239
|
+
this.#postDragSuppressTimer = setTimeout(() => {
|
|
1240
|
+
this.#postDragSuppressTimer = void 0;
|
|
1241
|
+
}, 150);
|
|
1242
|
+
if (!this.#internalDropHandled) this.dispatchEvent(new CustomEvent(`tree-drag-end`, {
|
|
1243
|
+
detail: { dropped: false },
|
|
1244
|
+
bubbles: true,
|
|
1245
|
+
composed: true
|
|
1246
|
+
}));
|
|
1247
|
+
this.#internalDropHandled = false;
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
this.#drop = new TreeDropController(this, {
|
|
1251
|
+
getDndMode: () => this.itemDnd,
|
|
1252
|
+
getExpandHoverMs: () => this.dndExpandHoverMs,
|
|
1253
|
+
getVisibleRows: () => this.#getVisibleRows(),
|
|
1254
|
+
getIndentPx: () => this.#getIndentPx(),
|
|
1255
|
+
getScrollContainer: () => this.#container(),
|
|
1256
|
+
isSelfOrDescendant: (ancestorKey, key) => this.#isSelfOrDescendant(ancestorKey, key),
|
|
1257
|
+
isExpanded: (key) => this._expandedKeys.has(key),
|
|
1258
|
+
isReorderAllowed: () => this.reorderable,
|
|
1259
|
+
getParentKey: (key) => this.#findParentByKey(key)?.item.key,
|
|
1260
|
+
resolveDrag: (dataTransfer, phase) => this.#resolveDrag(dataTransfer, phase),
|
|
1261
|
+
vet: (ctx) => {
|
|
1262
|
+
if (this.canDrop && !this.canDrop(ctx)) return false;
|
|
1263
|
+
const evt = new CustomEvent(`tree-drag-over`, {
|
|
1264
|
+
detail: ctx,
|
|
1265
|
+
bubbles: true,
|
|
1266
|
+
composed: true,
|
|
1267
|
+
cancelable: true
|
|
1268
|
+
});
|
|
1269
|
+
return this.dispatchEvent(evt);
|
|
1270
|
+
},
|
|
1271
|
+
expandKey: (key) => this.#springLoadExpand(key),
|
|
1272
|
+
onDropStateChange: (state) => {
|
|
1273
|
+
this.#dropState = state;
|
|
1274
|
+
this.toggleAttribute(`data-drop-rejected`, this.#drop.isDragging && state === void 0);
|
|
1275
|
+
this.requestUpdate();
|
|
1276
|
+
},
|
|
1277
|
+
onActiveChange: (active) => {
|
|
1278
|
+
if (active) {
|
|
1279
|
+
this.#rowsCache = void 0;
|
|
1280
|
+
this.#container()?.addEventListener(`scroll`, this.#onContainerScroll, { passive: true });
|
|
1281
|
+
} else {
|
|
1282
|
+
this.#container()?.removeEventListener(`scroll`, this.#onContainerScroll);
|
|
1283
|
+
this.#rowsCache = void 0;
|
|
1284
|
+
this.toggleAttribute(`data-drop-rejected`, false);
|
|
1285
|
+
}
|
|
1286
|
+
this.requestUpdate();
|
|
1287
|
+
},
|
|
1288
|
+
commitDrop: (detail) => {
|
|
1289
|
+
if (!this.dispatchEvent(new CustomEvent(`tree-drop`, {
|
|
1290
|
+
detail,
|
|
1291
|
+
bubbles: true,
|
|
1292
|
+
composed: true,
|
|
1293
|
+
cancelable: true
|
|
1294
|
+
}))) return false;
|
|
1295
|
+
if (this.applyInternalDrop && detail.source === `internal` && this.model) this.model.applyDrop({
|
|
1296
|
+
source: `internal`,
|
|
1297
|
+
draggedKeys: detail.draggedKeys,
|
|
1298
|
+
target: detail.target
|
|
1299
|
+
});
|
|
1300
|
+
this.#internalDropHandled = true;
|
|
1301
|
+
return true;
|
|
1302
|
+
},
|
|
1303
|
+
onDragEnd: (dropped) => {
|
|
1304
|
+
this.#dropState = void 0;
|
|
1305
|
+
this.toggleAttribute(`data-drop-rejected`, false);
|
|
1306
|
+
this.requestUpdate();
|
|
1307
|
+
this.dispatchEvent(new CustomEvent(`tree-drag-end`, {
|
|
1308
|
+
detail: { dropped },
|
|
1309
|
+
bubbles: true,
|
|
1310
|
+
composed: true
|
|
1311
|
+
}));
|
|
1312
|
+
}
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
#container() {
|
|
1316
|
+
return this.shadowRoot?.querySelector(`#container`) ?? void 0;
|
|
1317
|
+
}
|
|
1318
|
+
#getIndentPx() {
|
|
1319
|
+
const parsed = Number.parseInt(getComputedStyle(this).getPropertyValue(`--tree-indent`), 10);
|
|
1320
|
+
return Number.isNaN(parsed) ? 20 : parsed;
|
|
1321
|
+
}
|
|
1322
|
+
#getItemHeight() {
|
|
1323
|
+
const parsed = Number.parseInt(getComputedStyle(this).getPropertyValue(`--tree-item-height`), 10);
|
|
1324
|
+
return Number.isNaN(parsed) ? 30 : parsed;
|
|
1325
|
+
}
|
|
1326
|
+
/** Measured rows, cached for the duration of a drag and invalidated on scroll / update. */
|
|
1327
|
+
#getVisibleRows() {
|
|
1328
|
+
if (this.#rowsCache) return this.#rowsCache;
|
|
1329
|
+
const rows = [];
|
|
1330
|
+
for (const { node, depth } of this.#getAllNodes()) {
|
|
1331
|
+
const li = this.shadowRoot?.querySelector(`li[data-key="${CSS.escape(node.item.key)}"]`);
|
|
1332
|
+
if (li) rows.push({
|
|
1333
|
+
key: node.item.key,
|
|
1334
|
+
node,
|
|
1335
|
+
depth,
|
|
1336
|
+
rect: li.getBoundingClientRect()
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
this.#rowsCache = rows;
|
|
1340
|
+
return rows;
|
|
1341
|
+
}
|
|
1342
|
+
/** Route spring-load through the real expand path so lazy children load and `expand` fires with the right depth. */
|
|
1343
|
+
#springLoadExpand(key) {
|
|
1344
|
+
if (this._expandedKeys.has(key)) return;
|
|
1345
|
+
const entry = this.#getAllNodes().find((n) => n.node.item.key === key);
|
|
1346
|
+
if (!entry || entry.node.item.isLeaf === true) return;
|
|
1347
|
+
this.#toggleExpand(entry.node, entry.depth);
|
|
1348
|
+
this.#rowsCache = void 0;
|
|
1349
|
+
this.requestUpdate();
|
|
1350
|
+
}
|
|
1351
|
+
#isSelfOrDescendant(ancestorKey, key) {
|
|
1352
|
+
if (ancestorKey === key) return true;
|
|
1353
|
+
let node = this.#getAllNodes().find((n) => n.node.item.key === key)?.node;
|
|
1354
|
+
let parent = node ? this.#findParentByKey(node.item.key) : void 0;
|
|
1355
|
+
while (parent) {
|
|
1356
|
+
if (parent.item.key === ancestorKey) return true;
|
|
1357
|
+
node = parent;
|
|
1358
|
+
parent = this.#findParentByKey(node.item.key);
|
|
1359
|
+
}
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
#findParentByKey(key) {
|
|
1363
|
+
for (const { node } of this.#getAllNodes()) if (node.children?.some((c) => c.item.key === key)) return node;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Decide whether a DataTransfer is acceptable and resolve the dragged set.
|
|
1367
|
+
* During `hover` the DataTransfer is read-protected, so an internal drag is
|
|
1368
|
+
* recovered from the module-level drag registry (there is only one at a time).
|
|
1369
|
+
*/
|
|
1370
|
+
#resolveDrag(dataTransfer, phase) {
|
|
1371
|
+
const mode = this.itemDnd;
|
|
1372
|
+
if (mode === `none`) return void 0;
|
|
1373
|
+
const canInternal = mode === `internal` || mode === `both`;
|
|
1374
|
+
const canExternal = mode === `external` || mode === `both`;
|
|
1375
|
+
let types = [];
|
|
1376
|
+
try {
|
|
1377
|
+
types = Array.from(dataTransfer.types);
|
|
1378
|
+
} catch {}
|
|
1379
|
+
const current = treeDragCurrent();
|
|
1380
|
+
const looksInternal = types.includes(TREE_DRAG_MIME) || current !== void 0;
|
|
1381
|
+
if (canInternal && looksInternal) {
|
|
1382
|
+
if (current && current.keys.length > 0) {
|
|
1383
|
+
const keys = this.root ? pruneDraggedDescendants(this.root, current.keys) : current.keys;
|
|
1384
|
+
return {
|
|
1385
|
+
source: `internal`,
|
|
1386
|
+
keys,
|
|
1387
|
+
nodes: keys.map((k) => this.#getAllNodes().find((n) => n.node.item.key === k)?.node).filter((n) => n !== void 0)
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
if (phase === `drop`) try {
|
|
1391
|
+
const raw = dataTransfer.getData(TREE_DRAG_MIME);
|
|
1392
|
+
if (raw) {
|
|
1393
|
+
const payload = JSON.parse(raw);
|
|
1394
|
+
return {
|
|
1395
|
+
source: `internal`,
|
|
1396
|
+
keys: payload.keys ?? [],
|
|
1397
|
+
nodes: payload.nodes ?? []
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
} catch {}
|
|
1401
|
+
return {
|
|
1402
|
+
source: `internal`,
|
|
1403
|
+
keys: [],
|
|
1404
|
+
nodes: []
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
if (canExternal && !looksInternal) {
|
|
1408
|
+
if (this.acceptDropTypes !== void 0) {
|
|
1409
|
+
const accepted = this.acceptDropTypes.trim().split(/\s+/).filter(Boolean);
|
|
1410
|
+
const present = Array.from(dataTransfer.types);
|
|
1411
|
+
if (accepted.length > 0 && !accepted.some((t) => present.includes(t))) return void 0;
|
|
1412
|
+
}
|
|
1413
|
+
if (phase === `drop`) {
|
|
1414
|
+
const nodes = this.parseExternalDrop?.(dataTransfer);
|
|
1415
|
+
if (!nodes || nodes.length === 0) return void 0;
|
|
1416
|
+
return {
|
|
1417
|
+
source: `external`,
|
|
1418
|
+
keys: nodes.map((n) => n.item.key),
|
|
1419
|
+
nodes
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
return this.parseExternalDrop ? {
|
|
1423
|
+
source: `external`,
|
|
1424
|
+
keys: [],
|
|
1425
|
+
nodes: []
|
|
1426
|
+
} : void 0;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
#anyRowDraggable() {
|
|
1430
|
+
if (this.itemDnd === `none`) return false;
|
|
1431
|
+
const allNodes = this.#getAllNodes();
|
|
1432
|
+
if (allNodes.length === 0) return false;
|
|
1433
|
+
if (!this.canDrag) return true;
|
|
1434
|
+
return allNodes.some(({ node }) => this.canDrag({
|
|
1435
|
+
nodes: [node],
|
|
1436
|
+
keys: [node.item.key]
|
|
1437
|
+
}));
|
|
559
1438
|
}
|
|
560
1439
|
disconnectedCallback() {
|
|
561
1440
|
super.disconnectedCallback();
|
|
@@ -566,6 +1445,12 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
566
1445
|
this.#modelUnsubscribe = void 0;
|
|
567
1446
|
this.#unregisterSearchCommands?.();
|
|
568
1447
|
this.#unregisterSearchCommands = void 0;
|
|
1448
|
+
if (this.#postDragSuppressTimer !== void 0) {
|
|
1449
|
+
clearTimeout(this.#postDragSuppressTimer);
|
|
1450
|
+
this.#postDragSuppressTimer = void 0;
|
|
1451
|
+
}
|
|
1452
|
+
this.#container()?.removeEventListener(`scroll`, this.#onContainerScroll);
|
|
1453
|
+
treeDragUnregister(this.#dragSourceId);
|
|
569
1454
|
if (this.#ownedRegistry) {
|
|
570
1455
|
this.#ownedRegistry.unregister(`select-all`);
|
|
571
1456
|
this.#ownedRegistry.unregister(`deselect-all`);
|
|
@@ -740,6 +1625,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
740
1625
|
`;
|
|
741
1626
|
}
|
|
742
1627
|
_handleItemClick(node, depth, event) {
|
|
1628
|
+
if (this.#drop?.isDragging || this.#nativeDrag?.isDragging || this.#postDragSuppressTimer !== void 0) return;
|
|
743
1629
|
if (event && event.detail >= 2) return;
|
|
744
1630
|
if (this.#pendingNode && this._expandedKeys.has(this.#pendingNode.item.key)) this.#abortPending();
|
|
745
1631
|
this.tickled.handlePointerEnter(node.item.key);
|
|
@@ -1174,6 +2060,23 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1174
2060
|
</ul>
|
|
1175
2061
|
`;
|
|
1176
2062
|
}
|
|
2063
|
+
/** Shared drag-and-drop render state for a row, used by every `_renderNode` variant. */
|
|
2064
|
+
_dndRowState(node) {
|
|
2065
|
+
const draggable = this.itemDnd !== `none` && (this.root?.children?.length ?? 0) > 0 && (this.itemDnd === `internal` || this.itemDnd === `both` || this.itemDnd === `external`) && (this.canDrag?.({
|
|
2066
|
+
nodes: [node],
|
|
2067
|
+
keys: [node.item.key]
|
|
2068
|
+
}) ?? true);
|
|
2069
|
+
const dragging = this.#nativeDragKeys.has(node.item.key);
|
|
2070
|
+
const state = this.#dropState;
|
|
2071
|
+
const dropTarget = state !== void 0 && state.referenceKey === node.item.key;
|
|
2072
|
+
return {
|
|
2073
|
+
draggable,
|
|
2074
|
+
dragging,
|
|
2075
|
+
dropTarget,
|
|
2076
|
+
dropPosition: dropTarget ? state.position : void 0,
|
|
2077
|
+
dropDepth: dropTarget ? state.depth : void 0
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
1177
2080
|
_renderNode(node, depth) {
|
|
1178
2081
|
const selected = this._isSelected(node);
|
|
1179
2082
|
const tickled = this._isFocused(node);
|
|
@@ -1182,9 +2085,10 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1182
2085
|
const isPending = this.#pendingNode === node;
|
|
1183
2086
|
const isFiltered = this._isFilteredOut(node, depth);
|
|
1184
2087
|
const isLeaving = this._isLeaving(node);
|
|
2088
|
+
const dnd = this._dndRowState(node);
|
|
1185
2089
|
return html`
|
|
1186
2090
|
<li
|
|
1187
|
-
class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${isFiltered ? `filtered` : ``} ${isLeaving ? `leaving` : ``}"
|
|
2091
|
+
class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${isFiltered ? `filtered` : ``} ${isLeaving ? `leaving` : ``} ${dnd.dragging ? `dragging` : ``} ${dnd.dropTarget && dnd.dropPosition === `inside` ? `drop-into` : ``}"
|
|
1188
2092
|
role="treeitem"
|
|
1189
2093
|
aria-selected=${selected}
|
|
1190
2094
|
aria-expanded=${isBranch ? isExpanded : nothing}
|
|
@@ -1192,6 +2096,8 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1192
2096
|
aria-level=${depth + 1}
|
|
1193
2097
|
data-key=${node.item.key}
|
|
1194
2098
|
style=${`--depth: ${depth}`}
|
|
2099
|
+
draggable=${dnd.draggable ? `true` : nothing}
|
|
2100
|
+
part=${dnd.dropTarget ? `drop-target` : nothing}
|
|
1195
2101
|
@click=${(e) => this._handleItemClick(node, depth, e)}
|
|
1196
2102
|
@pointerenter=${() => {
|
|
1197
2103
|
this.tickled.handlePointerEnter(node.item.key);
|
|
@@ -1205,6 +2111,11 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1205
2111
|
}));
|
|
1206
2112
|
}}
|
|
1207
2113
|
>
|
|
2114
|
+
${dnd.dropTarget && (dnd.dropPosition === `before` || dnd.dropPosition === `after`) ? html`<div
|
|
2115
|
+
class="drop-line drop-line-${dnd.dropPosition}"
|
|
2116
|
+
style="--drop-depth: ${dnd.dropDepth ?? depth}"
|
|
2117
|
+
part="drop-indicator"
|
|
2118
|
+
></div>` : nothing}
|
|
1208
2119
|
${this.renderNodeContent(node, depth)}
|
|
1209
2120
|
${isPending ? this.renderLoadingIndicator() : nothing}
|
|
1210
2121
|
</li>
|
|
@@ -1225,6 +2136,10 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1225
2136
|
--tree-item-height: 30px;
|
|
1226
2137
|
--tree-caret-size: 30px;
|
|
1227
2138
|
--tree-radius: var(--radius-s);
|
|
2139
|
+
--tree-drop-line: var(--accent);
|
|
2140
|
+
--tree-drop-nub-size: 5px;
|
|
2141
|
+
--tree-drop-into-outline: 2px solid var(--accent);
|
|
2142
|
+
--tree-drop-into-bg: color-mix(in srgb, var(--accent) 14%, transparent);
|
|
1228
2143
|
|
|
1229
2144
|
position: relative;
|
|
1230
2145
|
display: block;
|
|
@@ -1252,6 +2167,7 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1252
2167
|
}
|
|
1253
2168
|
|
|
1254
2169
|
.item {
|
|
2170
|
+
position: relative; /* anchor for the .drop-line before/after indicator */
|
|
1255
2171
|
display: flex;
|
|
1256
2172
|
align-items: center;
|
|
1257
2173
|
height: var(--tree-item-height);
|
|
@@ -1327,11 +2243,49 @@ let TreeBaseElement = class TreeBaseElement extends LitElement {
|
|
|
1327
2243
|
overflow: hidden;
|
|
1328
2244
|
}
|
|
1329
2245
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
2246
|
+
/* Drag and drop styles */
|
|
2247
|
+
.item.dragging {
|
|
2248
|
+
opacity: 0.4;
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
.item.drop-into {
|
|
2252
|
+
outline: var(--tree-drop-into-outline);
|
|
2253
|
+
outline-offset: -2px;
|
|
2254
|
+
background: var(--tree-drop-into-bg);
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
.drop-line {
|
|
2258
|
+
position: absolute;
|
|
2259
|
+
left: calc(var(--tree-indent) * var(--drop-depth, 0) + var(--space-xs));
|
|
2260
|
+
right: var(--space-xs);
|
|
2261
|
+
height: 2px;
|
|
2262
|
+
background: var(--tree-drop-line);
|
|
2263
|
+
pointer-events: none;
|
|
2264
|
+
z-index: 10;
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
/* Nub at the left end of the insertion line (VS Code style). */
|
|
2268
|
+
.drop-line::before {
|
|
2269
|
+
content: "";
|
|
2270
|
+
position: absolute;
|
|
2271
|
+
left: calc(-1 * var(--tree-drop-nub-size) / 2);
|
|
2272
|
+
top: calc(50% - var(--tree-drop-nub-size) / 2);
|
|
2273
|
+
width: var(--tree-drop-nub-size);
|
|
2274
|
+
height: var(--tree-drop-nub-size);
|
|
2275
|
+
border-radius: 50%;
|
|
2276
|
+
background: var(--tree-drop-line);
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
.drop-line-before {
|
|
2280
|
+
top: -1px;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
.drop-line-after {
|
|
2284
|
+
bottom: -1px;
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
:host([data-drop-rejected]) {
|
|
2288
|
+
cursor: not-allowed;
|
|
1335
2289
|
}
|
|
1336
2290
|
`
|
|
1337
2291
|
];
|
|
@@ -1365,6 +2319,31 @@ __decorate([property({
|
|
|
1365
2319
|
attribute: `search-modes`,
|
|
1366
2320
|
reflect: true
|
|
1367
2321
|
})], TreeBaseElement.prototype, "searchModes", void 0);
|
|
2322
|
+
__decorate([property({
|
|
2323
|
+
reflect: true,
|
|
2324
|
+
attribute: `item-dnd`
|
|
2325
|
+
})], TreeBaseElement.prototype, "itemDnd", void 0);
|
|
2326
|
+
__decorate([property({
|
|
2327
|
+
type: String,
|
|
2328
|
+
attribute: `accept-drop-types`
|
|
2329
|
+
})], TreeBaseElement.prototype, "acceptDropTypes", void 0);
|
|
2330
|
+
__decorate([property({
|
|
2331
|
+
type: Number,
|
|
2332
|
+
attribute: `dnd-expand-hover-ms`
|
|
2333
|
+
})], TreeBaseElement.prototype, "dndExpandHoverMs", void 0);
|
|
2334
|
+
__decorate([property({
|
|
2335
|
+
reflect: true,
|
|
2336
|
+
attribute: `reorderable`,
|
|
2337
|
+
converter: {
|
|
2338
|
+
fromAttribute: (value) => value !== `false`,
|
|
2339
|
+
toAttribute: (value) => value ? null : `false`
|
|
2340
|
+
}
|
|
2341
|
+
})], TreeBaseElement.prototype, "reorderable", void 0);
|
|
2342
|
+
__decorate([property({ attribute: false })], TreeBaseElement.prototype, "dragPreviewRenderer", void 0);
|
|
2343
|
+
__decorate([property({ attribute: false })], TreeBaseElement.prototype, "canDrag", void 0);
|
|
2344
|
+
__decorate([property({ attribute: false })], TreeBaseElement.prototype, "canDrop", void 0);
|
|
2345
|
+
__decorate([property({ attribute: false })], TreeBaseElement.prototype, "parseExternalDrop", void 0);
|
|
2346
|
+
__decorate([property({ attribute: false })], TreeBaseElement.prototype, "applyInternalDrop", void 0);
|
|
1368
2347
|
__decorate([state()], TreeBaseElement.prototype, "_expandedKeys", void 0);
|
|
1369
2348
|
__decorate([state()], TreeBaseElement.prototype, "_focusedDepth", void 0);
|
|
1370
2349
|
TreeBaseElement = __decorate([safeCustomElement(`ixfx-tree-base`)], TreeBaseElement);
|
|
@@ -1446,9 +2425,10 @@ let TreeListElement = class TreeListElement extends TreeBaseElement {
|
|
|
1446
2425
|
const hasIconAtDepth = this.#depthsWithIcons.has(depth);
|
|
1447
2426
|
const isLeaving = this._isLeaving(node);
|
|
1448
2427
|
const isFiltered = this._isFilteredOut(node, depth);
|
|
2428
|
+
const dnd = this._dndRowState(node);
|
|
1449
2429
|
return html`
|
|
1450
2430
|
<li
|
|
1451
|
-
class="item ${selected ? `selected` : ``} ${tickled ? `tickled` : ``} ${isBranch ? `branch` : `leaf`} ${hasIconAtDepth ? `has-icon-at-depth` : ``} ${isLeaving ? `leaving` : ``} ${isFiltered ? `filtered` : ``}"
|
|
2431
|
+
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` : ``}"
|
|
1452
2432
|
data-key=${node.item.key}
|
|
1453
2433
|
role="treeitem"
|
|
1454
2434
|
aria-selected=${selected}
|
|
@@ -1456,9 +2436,16 @@ let TreeListElement = class TreeListElement extends TreeBaseElement {
|
|
|
1456
2436
|
aria-hidden=${isLeaving ? `true` : nothing}
|
|
1457
2437
|
aria-level=${depth + 1}
|
|
1458
2438
|
style=${`--depth: ${depth}`}
|
|
2439
|
+
draggable=${dnd.draggable ? `true` : nothing}
|
|
2440
|
+
part=${dnd.dropTarget ? `drop-target` : nothing}
|
|
1459
2441
|
@click=${(e) => this._handleItemClick(node, depth, e)}
|
|
1460
2442
|
@pointerenter=${() => this.tickled.handlePointerEnter(node.item.key)}
|
|
1461
2443
|
>
|
|
2444
|
+
${dnd.dropTarget && (dnd.dropPosition === `before` || dnd.dropPosition === `after`) ? html`<div
|
|
2445
|
+
class="drop-line drop-line-${dnd.dropPosition}"
|
|
2446
|
+
style="--drop-depth: ${dnd.dropDepth ?? depth}"
|
|
2447
|
+
part="drop-indicator"
|
|
2448
|
+
></div>` : nothing}
|
|
1462
2449
|
${this.renderNodeContent(node, depth)}
|
|
1463
2450
|
${isPending ? this.renderLoadingIndicator() : nothing}
|
|
1464
2451
|
</li>
|
|
@@ -1641,6 +2628,6 @@ var TreeController = class {
|
|
|
1641
2628
|
}
|
|
1642
2629
|
};
|
|
1643
2630
|
//#endregion
|
|
1644
|
-
export { TreeDataModel as i, TreeListElement as n, TreeBaseElement as r, TreeController as t };
|
|
2631
|
+
export { TreeDataModel as a, pruneDraggedDescendants as c, TreeDropController as i, TreeListElement as n, applyTreeDrop as o, TreeBaseElement as r, dropTargetFor as s, TreeController as t };
|
|
1645
2632
|
|
|
1646
|
-
//# sourceMappingURL=tree-
|
|
2633
|
+
//# sourceMappingURL=tree-a14n9y7i.js.map
|