@headless-tree/core 0.0.0-20251215184014 → 0.0.0-20260107220200
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/CHANGELOG.md +8 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +20 -17
- package/dist/index.mjs +20 -17
- package/package.json +1 -1
- package/src/features/async-data-loader/feature.ts +14 -8
- package/src/features/async-data-loader/types.ts +11 -3
- package/src/features/drag-and-drop/drag-and-drop.spec.ts +33 -2
- package/src/features/drag-and-drop/feature.ts +5 -4
- package/src/features/drag-and-drop/utils.ts +10 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20260107220200
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 39a8b44: Add skipUpdateTree parameter to `updateCachedChildrenIds` and `updateCachedData` in async tree loader
|
|
8
|
+
- ffd2619: Fixed an issue where `canDropForeignDragObject` was being called in `onDragOver` events without payload. `canDropForeignDragObject` should never be called in `onDragOver` events since there, browsers do not allow access to the data transfer payload. Now, `canDropForeignDragObject` is only called in onDrop events, and `canDragForeignDragObjectOver` is always called in `onDragOver` events.
|
|
9
|
+
|
|
10
|
+
## 1.6.1
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
|
6
13
|
|
package/dist/index.d.mts
CHANGED
|
@@ -329,9 +329,11 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
329
329
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
330
330
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
331
331
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
332
|
-
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
334
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
335
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
336
|
+
updateCachedChildrenIds: (childrenIds: string[], skipUpdateTree?: boolean) => void;
|
|
335
337
|
hasLoadedData: () => boolean;
|
|
336
338
|
isLoading: () => boolean;
|
|
337
339
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -329,9 +329,11 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
329
329
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
330
330
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
331
331
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
332
|
-
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
334
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
335
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
336
|
+
updateCachedChildrenIds: (childrenIds: string[], skipUpdateTree?: boolean) => void;
|
|
335
337
|
hasLoadedData: () => boolean;
|
|
336
338
|
isLoading: () => boolean;
|
|
337
339
|
};
|
package/dist/index.js
CHANGED
|
@@ -1274,15 +1274,17 @@ var asyncDataLoaderFeature = {
|
|
|
1274
1274
|
}
|
|
1275
1275
|
yield loadChildrenIds(tree, itemId);
|
|
1276
1276
|
}),
|
|
1277
|
-
updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1277
|
+
updateCachedChildrenIds: ({ tree, itemId }, childrenIds, skipUpdateTree) => {
|
|
1278
|
+
getDataRef(tree).current.childrenIds[itemId] = childrenIds;
|
|
1279
|
+
if (!skipUpdateTree) {
|
|
1280
|
+
tree.rebuildTree();
|
|
1281
|
+
}
|
|
1281
1282
|
},
|
|
1282
|
-
updateCachedData: ({ tree, itemId }, data) => {
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1283
|
+
updateCachedData: ({ tree, itemId }, data, skipUpdateTree) => {
|
|
1284
|
+
getDataRef(tree).current.itemData[itemId] = data;
|
|
1285
|
+
if (!skipUpdateTree) {
|
|
1286
|
+
tree.rebuildTree();
|
|
1287
|
+
}
|
|
1286
1288
|
},
|
|
1287
1289
|
hasLoadedData: ({ tree, itemId }) => {
|
|
1288
1290
|
const dataRef = tree.getDataRef();
|
|
@@ -1449,15 +1451,16 @@ var getReparentTarget = (item, reparentLevel, draggedItems) => {
|
|
|
1449
1451
|
dragLineLevel: reparentLevel
|
|
1450
1452
|
};
|
|
1451
1453
|
};
|
|
1452
|
-
var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) => {
|
|
1454
|
+
var getDragTarget = (e, item, tree, hasDataTransferPayload, canReorder = tree.getConfig().canReorder) => {
|
|
1453
1455
|
var _a;
|
|
1456
|
+
const dataTransfer = hasDataTransferPayload ? e.dataTransfer : null;
|
|
1454
1457
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1455
1458
|
const itemMeta = item.getItemMeta();
|
|
1456
1459
|
const parent = item.getParent();
|
|
1457
1460
|
const itemTarget = { item };
|
|
1458
1461
|
const parentTarget = parent ? { item: parent } : null;
|
|
1459
|
-
const canBecomeSibling = parentTarget && canDrop(
|
|
1460
|
-
const canMakeChild = canDrop(
|
|
1462
|
+
const canBecomeSibling = parentTarget && canDrop(dataTransfer, parentTarget, tree);
|
|
1463
|
+
const canMakeChild = canDrop(dataTransfer, itemTarget, tree);
|
|
1461
1464
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1462
1465
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1463
1466
|
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
@@ -1466,7 +1469,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1466
1469
|
return parentTarget;
|
|
1467
1470
|
}
|
|
1468
1471
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
1469
|
-
return getDragTarget(e, parent, tree, false);
|
|
1472
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1470
1473
|
}
|
|
1471
1474
|
if (!parent) {
|
|
1472
1475
|
return itemTarget;
|
|
@@ -1475,7 +1478,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1475
1478
|
return itemTarget;
|
|
1476
1479
|
}
|
|
1477
1480
|
if (!canBecomeSibling) {
|
|
1478
|
-
return getDragTarget(e, parent, tree, false);
|
|
1481
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1479
1482
|
}
|
|
1480
1483
|
if (placement.type === 3 /* Reparent */) {
|
|
1481
1484
|
return getReparentTarget(item, placement.reparentLevel, draggedItems);
|
|
@@ -1657,12 +1660,12 @@ var dragAndDropFeature = {
|
|
|
1657
1660
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1658
1661
|
dataRef.current.lastDragEnter = Date.now();
|
|
1659
1662
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1660
|
-
const target = getDragTarget(e, item, tree);
|
|
1663
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1661
1664
|
if (!((_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems) && (!e.dataTransfer || !((_c = (_b = tree.getConfig()).canDragForeignDragObjectOver) == null ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
|
|
1662
1665
|
dataRef.current.lastAllowDrop = false;
|
|
1663
1666
|
return;
|
|
1664
1667
|
}
|
|
1665
|
-
if (!canDrop(
|
|
1668
|
+
if (!canDrop(null, target, tree)) {
|
|
1666
1669
|
dataRef.current.lastAllowDrop = false;
|
|
1667
1670
|
return;
|
|
1668
1671
|
}
|
|
@@ -1692,7 +1695,7 @@ var dragAndDropFeature = {
|
|
|
1692
1695
|
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1693
1696
|
return;
|
|
1694
1697
|
}
|
|
1695
|
-
const target = getDragTarget(e, item, tree);
|
|
1698
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1696
1699
|
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1697
1700
|
return;
|
|
1698
1701
|
}
|
|
@@ -1702,7 +1705,7 @@ var dragAndDropFeature = {
|
|
|
1702
1705
|
var _a, _b, _c;
|
|
1703
1706
|
e.stopPropagation();
|
|
1704
1707
|
const dataRef = tree.getDataRef();
|
|
1705
|
-
const target = getDragTarget(e, item, tree);
|
|
1708
|
+
const target = getDragTarget(e, item, tree, true);
|
|
1706
1709
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1707
1710
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1708
1711
|
tree.applySubStateUpdate("dnd", {
|
package/dist/index.mjs
CHANGED
|
@@ -1230,15 +1230,17 @@ var asyncDataLoaderFeature = {
|
|
|
1230
1230
|
}
|
|
1231
1231
|
yield loadChildrenIds(tree, itemId);
|
|
1232
1232
|
}),
|
|
1233
|
-
updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1233
|
+
updateCachedChildrenIds: ({ tree, itemId }, childrenIds, skipUpdateTree) => {
|
|
1234
|
+
getDataRef(tree).current.childrenIds[itemId] = childrenIds;
|
|
1235
|
+
if (!skipUpdateTree) {
|
|
1236
|
+
tree.rebuildTree();
|
|
1237
|
+
}
|
|
1237
1238
|
},
|
|
1238
|
-
updateCachedData: ({ tree, itemId }, data) => {
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1239
|
+
updateCachedData: ({ tree, itemId }, data, skipUpdateTree) => {
|
|
1240
|
+
getDataRef(tree).current.itemData[itemId] = data;
|
|
1241
|
+
if (!skipUpdateTree) {
|
|
1242
|
+
tree.rebuildTree();
|
|
1243
|
+
}
|
|
1242
1244
|
},
|
|
1243
1245
|
hasLoadedData: ({ tree, itemId }) => {
|
|
1244
1246
|
const dataRef = tree.getDataRef();
|
|
@@ -1405,15 +1407,16 @@ var getReparentTarget = (item, reparentLevel, draggedItems) => {
|
|
|
1405
1407
|
dragLineLevel: reparentLevel
|
|
1406
1408
|
};
|
|
1407
1409
|
};
|
|
1408
|
-
var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) => {
|
|
1410
|
+
var getDragTarget = (e, item, tree, hasDataTransferPayload, canReorder = tree.getConfig().canReorder) => {
|
|
1409
1411
|
var _a;
|
|
1412
|
+
const dataTransfer = hasDataTransferPayload ? e.dataTransfer : null;
|
|
1410
1413
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1411
1414
|
const itemMeta = item.getItemMeta();
|
|
1412
1415
|
const parent = item.getParent();
|
|
1413
1416
|
const itemTarget = { item };
|
|
1414
1417
|
const parentTarget = parent ? { item: parent } : null;
|
|
1415
|
-
const canBecomeSibling = parentTarget && canDrop(
|
|
1416
|
-
const canMakeChild = canDrop(
|
|
1418
|
+
const canBecomeSibling = parentTarget && canDrop(dataTransfer, parentTarget, tree);
|
|
1419
|
+
const canMakeChild = canDrop(dataTransfer, itemTarget, tree);
|
|
1417
1420
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1418
1421
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1419
1422
|
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
@@ -1422,7 +1425,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1422
1425
|
return parentTarget;
|
|
1423
1426
|
}
|
|
1424
1427
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
1425
|
-
return getDragTarget(e, parent, tree, false);
|
|
1428
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1426
1429
|
}
|
|
1427
1430
|
if (!parent) {
|
|
1428
1431
|
return itemTarget;
|
|
@@ -1431,7 +1434,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1431
1434
|
return itemTarget;
|
|
1432
1435
|
}
|
|
1433
1436
|
if (!canBecomeSibling) {
|
|
1434
|
-
return getDragTarget(e, parent, tree, false);
|
|
1437
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1435
1438
|
}
|
|
1436
1439
|
if (placement.type === 3 /* Reparent */) {
|
|
1437
1440
|
return getReparentTarget(item, placement.reparentLevel, draggedItems);
|
|
@@ -1613,12 +1616,12 @@ var dragAndDropFeature = {
|
|
|
1613
1616
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1614
1617
|
dataRef.current.lastDragEnter = Date.now();
|
|
1615
1618
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1616
|
-
const target = getDragTarget(e, item, tree);
|
|
1619
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1617
1620
|
if (!((_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems) && (!e.dataTransfer || !((_c = (_b = tree.getConfig()).canDragForeignDragObjectOver) == null ? void 0 : _c.call(_b, e.dataTransfer, target)))) {
|
|
1618
1621
|
dataRef.current.lastAllowDrop = false;
|
|
1619
1622
|
return;
|
|
1620
1623
|
}
|
|
1621
|
-
if (!canDrop(
|
|
1624
|
+
if (!canDrop(null, target, tree)) {
|
|
1622
1625
|
dataRef.current.lastAllowDrop = false;
|
|
1623
1626
|
return;
|
|
1624
1627
|
}
|
|
@@ -1648,7 +1651,7 @@ var dragAndDropFeature = {
|
|
|
1648
1651
|
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1649
1652
|
return;
|
|
1650
1653
|
}
|
|
1651
|
-
const target = getDragTarget(e, item, tree);
|
|
1654
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1652
1655
|
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1653
1656
|
return;
|
|
1654
1657
|
}
|
|
@@ -1658,7 +1661,7 @@ var dragAndDropFeature = {
|
|
|
1658
1661
|
var _a, _b, _c;
|
|
1659
1662
|
e.stopPropagation();
|
|
1660
1663
|
const dataRef = tree.getDataRef();
|
|
1661
|
-
const target = getDragTarget(e, item, tree);
|
|
1664
|
+
const target = getDragTarget(e, item, tree, true);
|
|
1662
1665
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1663
1666
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1664
1667
|
tree.applySubStateUpdate("dnd", {
|
package/package.json
CHANGED
|
@@ -180,15 +180,21 @@ export const asyncDataLoaderFeature: FeatureImplementation = {
|
|
|
180
180
|
}
|
|
181
181
|
await loadChildrenIds(tree, itemId);
|
|
182
182
|
},
|
|
183
|
-
updateCachedChildrenIds: (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
183
|
+
updateCachedChildrenIds: (
|
|
184
|
+
{ tree, itemId },
|
|
185
|
+
childrenIds,
|
|
186
|
+
skipUpdateTree,
|
|
187
|
+
) => {
|
|
188
|
+
getDataRef(tree).current.childrenIds[itemId] = childrenIds;
|
|
189
|
+
if (!skipUpdateTree) {
|
|
190
|
+
tree.rebuildTree();
|
|
191
|
+
}
|
|
187
192
|
},
|
|
188
|
-
updateCachedData: ({ tree, itemId }, data) => {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
updateCachedData: ({ tree, itemId }, data, skipUpdateTree) => {
|
|
194
|
+
getDataRef(tree).current.itemData[itemId] = data;
|
|
195
|
+
if (!skipUpdateTree) {
|
|
196
|
+
tree.rebuildTree();
|
|
197
|
+
}
|
|
192
198
|
},
|
|
193
199
|
hasLoadedData: ({ tree, itemId }) => {
|
|
194
200
|
const dataRef = tree.getDataRef<AsyncDataLoaderDataRef>();
|
|
@@ -39,6 +39,7 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
39
39
|
waitForItemChildrenLoaded: (itemId: string) => Promise<void>;
|
|
40
40
|
loadItemData: (itemId: string) => Promise<T>;
|
|
41
41
|
loadChildrenIds: (itemId: string) => Promise<string[]>;
|
|
42
|
+
|
|
42
43
|
/* idea: recursiveLoadItems: (itemId: string, cancelToken?: { current: boolean }, onLoad: (itemIds: string[]) => void) => Promise<T[]> */
|
|
43
44
|
};
|
|
44
45
|
itemInstance: SyncDataLoaderFeatureDef<T>["itemInstance"] & {
|
|
@@ -52,9 +53,16 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
52
53
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
53
54
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
54
55
|
|
|
55
|
-
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
57
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
58
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
59
|
+
|
|
60
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
61
|
+
updateCachedChildrenIds: (
|
|
62
|
+
childrenIds: string[],
|
|
63
|
+
skipUpdateTree?: boolean,
|
|
64
|
+
) => void;
|
|
65
|
+
|
|
58
66
|
hasLoadedData: () => boolean;
|
|
59
67
|
isLoading: () => boolean;
|
|
60
68
|
};
|
|
@@ -328,8 +328,7 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
328
328
|
"onDropForeignDragObject",
|
|
329
329
|
);
|
|
330
330
|
const event = tree.createBottomDragEvent(2);
|
|
331
|
-
tree.setElementBoundingBox("
|
|
332
|
-
tree.setElementBoundingBox("x213");
|
|
331
|
+
tree.setElementBoundingBox("x112");
|
|
333
332
|
tree.do.dragOver("x112", event);
|
|
334
333
|
tree.do.drop("x112", event);
|
|
335
334
|
expect(onDropForeignDragObject).toHaveBeenCalledWith(
|
|
@@ -357,6 +356,38 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
357
356
|
tree.do.drop("x11", event);
|
|
358
357
|
expect(onDropForeignDragObject).not.toHaveBeenCalled();
|
|
359
358
|
});
|
|
359
|
+
|
|
360
|
+
it("calls canDragForeignDragObjectOver in drag over events, not canDropForeignDragObject", () => {
|
|
361
|
+
const canDropForeignDragObject = tree
|
|
362
|
+
.mockedHandler("canDropForeignDragObject")
|
|
363
|
+
.mockReturnValue(true);
|
|
364
|
+
const canDragForeignDragObjectOver = tree
|
|
365
|
+
.mockedHandler("canDragForeignDragObjectOver")
|
|
366
|
+
.mockReturnValue(true);
|
|
367
|
+
const event = TestTree.dragEvent();
|
|
368
|
+
tree.do.dragOver("x11", event);
|
|
369
|
+
expect(canDragForeignDragObjectOver).toHaveBeenCalledWith(
|
|
370
|
+
event.dataTransfer,
|
|
371
|
+
{ item: tree.item("x11") },
|
|
372
|
+
);
|
|
373
|
+
expect(canDropForeignDragObject).not.toHaveBeenCalled();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("calls canDropForeignDragObject in drop events, not canDragForeignDragObjectOver", () => {
|
|
377
|
+
const canDropForeignDragObject = tree
|
|
378
|
+
.mockedHandler("canDropForeignDragObject")
|
|
379
|
+
.mockReturnValue(true);
|
|
380
|
+
const canDragForeignDragObjectOver = tree
|
|
381
|
+
.mockedHandler("canDragForeignDragObjectOver")
|
|
382
|
+
.mockReturnValue(true);
|
|
383
|
+
const event = TestTree.dragEvent();
|
|
384
|
+
tree.do.drop("x11", event);
|
|
385
|
+
expect(canDropForeignDragObject).toHaveBeenCalledWith(
|
|
386
|
+
event.dataTransfer,
|
|
387
|
+
{ item: tree.item("x11") },
|
|
388
|
+
);
|
|
389
|
+
expect(canDragForeignDragObjectOver).not.toHaveBeenCalled();
|
|
390
|
+
});
|
|
360
391
|
});
|
|
361
392
|
|
|
362
393
|
describe("with insertion handlers", () => {
|
|
@@ -236,7 +236,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
236
236
|
|
|
237
237
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
238
238
|
|
|
239
|
-
const target = getDragTarget(e, item, tree);
|
|
239
|
+
const target = getDragTarget(e, item, tree, false);
|
|
240
240
|
|
|
241
241
|
if (
|
|
242
242
|
!tree.getState().dnd?.draggedItems &&
|
|
@@ -249,7 +249,8 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
// dataTransfer.payload is not accessible in onDragOver, so just skip entirely here. It'll be checked again in onDrop
|
|
253
|
+
if (!canDrop(null, target, tree)) {
|
|
253
254
|
dataRef.current.lastAllowDrop = false;
|
|
254
255
|
return;
|
|
255
256
|
}
|
|
@@ -285,7 +286,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
285
286
|
return;
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
const target = getDragTarget(e, item, tree);
|
|
289
|
+
const target = getDragTarget(e, item, tree, false);
|
|
289
290
|
if (
|
|
290
291
|
canDragForeignDragObjectOver &&
|
|
291
292
|
e.dataTransfer &&
|
|
@@ -300,7 +301,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
300
301
|
onDrop: async (e: DragEvent) => {
|
|
301
302
|
e.stopPropagation();
|
|
302
303
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
303
|
-
const target = getDragTarget(e, item, tree);
|
|
304
|
+
const target = getDragTarget(e, item, tree, true);
|
|
304
305
|
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
305
306
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
306
307
|
|
|
@@ -29,6 +29,8 @@ export type TargetPlacement =
|
|
|
29
29
|
export const isOrderedDragTarget = <T>(dragTarget: DragTarget<T>) =>
|
|
30
30
|
"childIndex" in dragTarget;
|
|
31
31
|
|
|
32
|
+
/** @param dataTransfer - If the data transfer object should not be considered, e.g. because the event is
|
|
33
|
+
* onDragOver where the browser does not allow reading the payload, pass null */
|
|
32
34
|
export const canDrop = (
|
|
33
35
|
dataTransfer: DataTransfer | null,
|
|
34
36
|
target: DragTarget<any>,
|
|
@@ -197,21 +199,25 @@ export const getReparentTarget = <T>(
|
|
|
197
199
|
};
|
|
198
200
|
};
|
|
199
201
|
|
|
202
|
+
/** @param hasDataTransferPayload - If the data transfer object should not be considered, e.g. because the event is
|
|
203
|
+
* onDragOver where the browser does not allow reading the payload, pass false */
|
|
200
204
|
export const getDragTarget = (
|
|
201
205
|
e: any,
|
|
202
206
|
item: ItemInstance<any>,
|
|
203
207
|
tree: TreeInstance<any>,
|
|
208
|
+
hasDataTransferPayload: boolean,
|
|
204
209
|
canReorder = tree.getConfig().canReorder,
|
|
205
210
|
): DragTarget<any> => {
|
|
211
|
+
const dataTransfer = hasDataTransferPayload ? e.dataTransfer : null;
|
|
206
212
|
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
207
213
|
const itemMeta = item.getItemMeta();
|
|
208
214
|
const parent = item.getParent();
|
|
209
215
|
const itemTarget: DragTarget<any> = { item };
|
|
210
216
|
const parentTarget: DragTarget<any> | null = parent ? { item: parent } : null;
|
|
211
217
|
const canBecomeSibling =
|
|
212
|
-
parentTarget && canDrop(
|
|
218
|
+
parentTarget && canDrop(dataTransfer, parentTarget, tree);
|
|
213
219
|
|
|
214
|
-
const canMakeChild = canDrop(
|
|
220
|
+
const canMakeChild = canDrop(dataTransfer, itemTarget, tree);
|
|
215
221
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
216
222
|
|
|
217
223
|
if (
|
|
@@ -229,7 +235,7 @@ export const getDragTarget = (
|
|
|
229
235
|
|
|
230
236
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
231
237
|
// TODO! this breaks in story DND/Can Drop. Maybe move this logic into a composable DragTargetStrategy[] ?
|
|
232
|
-
return getDragTarget(e, parent, tree, false);
|
|
238
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
233
239
|
}
|
|
234
240
|
|
|
235
241
|
if (!parent) {
|
|
@@ -242,7 +248,7 @@ export const getDragTarget = (
|
|
|
242
248
|
}
|
|
243
249
|
|
|
244
250
|
if (!canBecomeSibling) {
|
|
245
|
-
return getDragTarget(e, parent, tree, false);
|
|
251
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
246
252
|
}
|
|
247
253
|
|
|
248
254
|
if (placement.type === PlacementType.Reparent) {
|