@headless-tree/core 1.6.1 → 1.6.2
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 +9 -0
- package/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +83 -61
- package/dist/index.mjs +83 -61
- 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 +81 -2
- package/src/features/drag-and-drop/feature.ts +72 -62
- package/src/features/drag-and-drop/types.ts +7 -0
- package/src/features/drag-and-drop/utils.ts +10 -4
- package/src/features/keyboard-drag-and-drop/feature.ts +1 -0
- package/src/features/prop-memoization/feature.ts +8 -0
- package/src/features/prop-memoization/types.ts +1 -0
- package/src/features/tree/feature.ts +6 -2
- package/src/utils.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
+
## 1.6.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 39a8b44: Add skipUpdateTree parameter to `updateCachedChildrenIds` and `updateCachedData` in async tree loader
|
|
8
|
+
- 26ecc1b: Fixed an issue where dropping items inside a collapsed folder will make the tree become un-focusable until a new item is clicked with mouse again. This could break usage with keyboard-only drag operations.
|
|
9
|
+
- 0108b7a: Fixed a bug where some hotkeys (like up/down navigation, search and renaming) doesn't work after items are dragged within the tree (#179)
|
|
10
|
+
- 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.
|
|
11
|
+
|
|
3
12
|
## 1.6.1
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -68,6 +68,8 @@ type DragAndDropFeatureDef<T> = {
|
|
|
68
68
|
onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
|
|
69
69
|
/** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
|
|
70
70
|
openOnDropDelay?: number;
|
|
71
|
+
/** If true, `item.getProps()` will not include drag event handlers. Use `item.getDragHandleProps()` on the handler element. */
|
|
72
|
+
seperateDragHandle?: boolean;
|
|
71
73
|
};
|
|
72
74
|
treeInstance: {
|
|
73
75
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -84,6 +86,9 @@ type DragAndDropFeatureDef<T> = {
|
|
|
84
86
|
isDragTargetAbove: () => boolean;
|
|
85
87
|
isDragTargetBelow: () => boolean;
|
|
86
88
|
isDraggingOver: () => boolean;
|
|
89
|
+
/** Note that `item.getProps()` already passes in all drag event handlers by default. Set `seperateDragHandle` to true to
|
|
90
|
+
* disable the default behavior and use this on the handler element instead. */
|
|
91
|
+
getDragHandleProps: () => Record<string, any>;
|
|
87
92
|
};
|
|
88
93
|
hotkeys: never;
|
|
89
94
|
};
|
|
@@ -329,9 +334,11 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
329
334
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
330
335
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
331
336
|
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
|
-
|
|
337
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
338
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
339
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
340
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
341
|
+
updateCachedChildrenIds: (childrenIds: string[], skipUpdateTree?: boolean) => void;
|
|
335
342
|
hasLoadedData: () => boolean;
|
|
336
343
|
isLoading: () => boolean;
|
|
337
344
|
};
|
|
@@ -420,6 +427,7 @@ interface PropMemoizationDataRef {
|
|
|
420
427
|
memo?: {
|
|
421
428
|
tree?: Record<string, any>;
|
|
422
429
|
item?: Record<string, any>;
|
|
430
|
+
drag?: Record<string, any>;
|
|
423
431
|
search?: Record<string, any>;
|
|
424
432
|
rename?: Record<string, any>;
|
|
425
433
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,8 @@ type DragAndDropFeatureDef<T> = {
|
|
|
68
68
|
onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
|
|
69
69
|
/** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
|
|
70
70
|
openOnDropDelay?: number;
|
|
71
|
+
/** If true, `item.getProps()` will not include drag event handlers. Use `item.getDragHandleProps()` on the handler element. */
|
|
72
|
+
seperateDragHandle?: boolean;
|
|
71
73
|
};
|
|
72
74
|
treeInstance: {
|
|
73
75
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -84,6 +86,9 @@ type DragAndDropFeatureDef<T> = {
|
|
|
84
86
|
isDragTargetAbove: () => boolean;
|
|
85
87
|
isDragTargetBelow: () => boolean;
|
|
86
88
|
isDraggingOver: () => boolean;
|
|
89
|
+
/** Note that `item.getProps()` already passes in all drag event handlers by default. Set `seperateDragHandle` to true to
|
|
90
|
+
* disable the default behavior and use this on the handler element instead. */
|
|
91
|
+
getDragHandleProps: () => Record<string, any>;
|
|
87
92
|
};
|
|
88
93
|
hotkeys: never;
|
|
89
94
|
};
|
|
@@ -329,9 +334,11 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
329
334
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
330
335
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
331
336
|
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
|
-
|
|
337
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
338
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
339
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
340
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
341
|
+
updateCachedChildrenIds: (childrenIds: string[], skipUpdateTree?: boolean) => void;
|
|
335
342
|
hasLoadedData: () => boolean;
|
|
336
343
|
isLoading: () => boolean;
|
|
337
344
|
};
|
|
@@ -420,6 +427,7 @@ interface PropMemoizationDataRef {
|
|
|
420
427
|
memo?: {
|
|
421
428
|
tree?: Record<string, any>;
|
|
422
429
|
item?: Record<string, any>;
|
|
430
|
+
drag?: Record<string, any>;
|
|
423
431
|
search?: Record<string, any>;
|
|
424
432
|
rename?: Record<string, any>;
|
|
425
433
|
};
|
package/dist/index.js
CHANGED
|
@@ -125,6 +125,7 @@ var poll = (fn, interval = 100, timeout = 1e3) => new Promise((resolve) => {
|
|
|
125
125
|
}, interval);
|
|
126
126
|
clear = setTimeout(() => {
|
|
127
127
|
clearInterval(i);
|
|
128
|
+
resolve();
|
|
128
129
|
}, timeout);
|
|
129
130
|
});
|
|
130
131
|
|
|
@@ -214,12 +215,16 @@ var treeFeature = {
|
|
|
214
215
|
},
|
|
215
216
|
updateDomFocus: ({ tree }) => {
|
|
216
217
|
setTimeout(() => __async(null, null, function* () {
|
|
217
|
-
var _a, _b;
|
|
218
|
+
var _a, _b, _c, _d, _e;
|
|
218
219
|
const focusedItem = tree.getFocusedItem();
|
|
219
220
|
(_b = (_a = tree.getConfig()).scrollToItem) == null ? void 0 : _b.call(_a, focusedItem);
|
|
220
|
-
yield poll(() => focusedItem.getElement() !== null, 20);
|
|
221
|
+
yield poll(() => focusedItem.getElement() !== null, 20, 500);
|
|
221
222
|
const focusedElement = focusedItem.getElement();
|
|
222
|
-
if (!focusedElement)
|
|
223
|
+
if (!focusedElement) {
|
|
224
|
+
(_c = tree.getItems()[0]) == null ? void 0 : _c.setFocused();
|
|
225
|
+
(_e = (_d = tree.getItems()[0]) == null ? void 0 : _d.getElement()) == null ? void 0 : _e.focus();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
223
228
|
focusedElement.focus();
|
|
224
229
|
}));
|
|
225
230
|
},
|
|
@@ -1274,15 +1279,17 @@ var asyncDataLoaderFeature = {
|
|
|
1274
1279
|
}
|
|
1275
1280
|
yield loadChildrenIds(tree, itemId);
|
|
1276
1281
|
}),
|
|
1277
|
-
updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1282
|
+
updateCachedChildrenIds: ({ tree, itemId }, childrenIds, skipUpdateTree) => {
|
|
1283
|
+
getDataRef(tree).current.childrenIds[itemId] = childrenIds;
|
|
1284
|
+
if (!skipUpdateTree) {
|
|
1285
|
+
tree.rebuildTree();
|
|
1286
|
+
}
|
|
1281
1287
|
},
|
|
1282
|
-
updateCachedData: ({ tree, itemId }, data) => {
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1288
|
+
updateCachedData: ({ tree, itemId }, data, skipUpdateTree) => {
|
|
1289
|
+
getDataRef(tree).current.itemData[itemId] = data;
|
|
1290
|
+
if (!skipUpdateTree) {
|
|
1291
|
+
tree.rebuildTree();
|
|
1292
|
+
}
|
|
1286
1293
|
},
|
|
1287
1294
|
hasLoadedData: ({ tree, itemId }) => {
|
|
1288
1295
|
const dataRef = tree.getDataRef();
|
|
@@ -1449,15 +1456,16 @@ var getReparentTarget = (item, reparentLevel, draggedItems) => {
|
|
|
1449
1456
|
dragLineLevel: reparentLevel
|
|
1450
1457
|
};
|
|
1451
1458
|
};
|
|
1452
|
-
var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) => {
|
|
1459
|
+
var getDragTarget = (e, item, tree, hasDataTransferPayload, canReorder = tree.getConfig().canReorder) => {
|
|
1453
1460
|
var _a;
|
|
1461
|
+
const dataTransfer = hasDataTransferPayload ? e.dataTransfer : null;
|
|
1454
1462
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1455
1463
|
const itemMeta = item.getItemMeta();
|
|
1456
1464
|
const parent = item.getParent();
|
|
1457
1465
|
const itemTarget = { item };
|
|
1458
1466
|
const parentTarget = parent ? { item: parent } : null;
|
|
1459
|
-
const canBecomeSibling = parentTarget && canDrop(
|
|
1460
|
-
const canMakeChild = canDrop(
|
|
1467
|
+
const canBecomeSibling = parentTarget && canDrop(dataTransfer, parentTarget, tree);
|
|
1468
|
+
const canMakeChild = canDrop(dataTransfer, itemTarget, tree);
|
|
1461
1469
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1462
1470
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1463
1471
|
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
@@ -1466,7 +1474,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1466
1474
|
return parentTarget;
|
|
1467
1475
|
}
|
|
1468
1476
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
1469
|
-
return getDragTarget(e, parent, tree, false);
|
|
1477
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1470
1478
|
}
|
|
1471
1479
|
if (!parent) {
|
|
1472
1480
|
return itemTarget;
|
|
@@ -1475,7 +1483,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1475
1483
|
return itemTarget;
|
|
1476
1484
|
}
|
|
1477
1485
|
if (!canBecomeSibling) {
|
|
1478
|
-
return getDragTarget(e, parent, tree, false);
|
|
1486
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1479
1487
|
}
|
|
1480
1488
|
if (placement.type === 3 /* Reparent */) {
|
|
1481
1489
|
return getReparentTarget(item, placement.reparentLevel, draggedItems);
|
|
@@ -1612,36 +1620,8 @@ var dragAndDropFeature = {
|
|
|
1612
1620
|
}
|
|
1613
1621
|
},
|
|
1614
1622
|
itemInstance: {
|
|
1615
|
-
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1616
|
-
draggable: true,
|
|
1623
|
+
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues(__spreadValues({}, prev == null ? void 0 : prev()), tree.getConfig().seperateDragHandle ? {} : item.getDragHandleProps()), {
|
|
1617
1624
|
onDragEnter: (e) => e.preventDefault(),
|
|
1618
|
-
onDragStart: (e) => {
|
|
1619
|
-
var _a, _b, _c, _d;
|
|
1620
|
-
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1621
|
-
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1622
|
-
const config = tree.getConfig();
|
|
1623
|
-
if (!selectedItems.includes(item)) {
|
|
1624
|
-
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1625
|
-
}
|
|
1626
|
-
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1627
|
-
e.preventDefault();
|
|
1628
|
-
return;
|
|
1629
|
-
}
|
|
1630
|
-
if (config.setDragImage) {
|
|
1631
|
-
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1632
|
-
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1633
|
-
}
|
|
1634
|
-
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1635
|
-
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1636
|
-
e.dataTransfer.setData(format, data);
|
|
1637
|
-
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1638
|
-
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1639
|
-
}
|
|
1640
|
-
tree.applySubStateUpdate("dnd", {
|
|
1641
|
-
draggedItems: items,
|
|
1642
|
-
draggingOverItem: tree.getFocusedItem()
|
|
1643
|
-
});
|
|
1644
|
-
},
|
|
1645
1625
|
onDragOver: (e) => {
|
|
1646
1626
|
var _a, _b, _c;
|
|
1647
1627
|
e.stopPropagation();
|
|
@@ -1657,12 +1637,12 @@ var dragAndDropFeature = {
|
|
|
1657
1637
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1658
1638
|
dataRef.current.lastDragEnter = Date.now();
|
|
1659
1639
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1660
|
-
const target = getDragTarget(e, item, tree);
|
|
1640
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1661
1641
|
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
1642
|
dataRef.current.lastAllowDrop = false;
|
|
1663
1643
|
return;
|
|
1664
1644
|
}
|
|
1665
|
-
if (!canDrop(
|
|
1645
|
+
if (!canDrop(null, target, tree)) {
|
|
1666
1646
|
dataRef.current.lastAllowDrop = false;
|
|
1667
1647
|
return;
|
|
1668
1648
|
}
|
|
@@ -1685,24 +1665,11 @@ var dragAndDropFeature = {
|
|
|
1685
1665
|
}));
|
|
1686
1666
|
}, 100);
|
|
1687
1667
|
},
|
|
1688
|
-
onDragEnd: (e) => {
|
|
1689
|
-
var _a, _b;
|
|
1690
|
-
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1691
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1692
|
-
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1693
|
-
return;
|
|
1694
|
-
}
|
|
1695
|
-
const target = getDragTarget(e, item, tree);
|
|
1696
|
-
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1697
|
-
return;
|
|
1698
|
-
}
|
|
1699
|
-
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1700
|
-
},
|
|
1701
1668
|
onDrop: (e) => __async(null, null, function* () {
|
|
1702
1669
|
var _a, _b, _c;
|
|
1703
1670
|
e.stopPropagation();
|
|
1704
1671
|
const dataRef = tree.getDataRef();
|
|
1705
|
-
const target = getDragTarget(e, item, tree);
|
|
1672
|
+
const target = getDragTarget(e, item, tree, true);
|
|
1706
1673
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1707
1674
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1708
1675
|
tree.applySubStateUpdate("dnd", {
|
|
@@ -1718,11 +1685,57 @@ var dragAndDropFeature = {
|
|
|
1718
1685
|
dataRef.current.lastDragCode = void 0;
|
|
1719
1686
|
if (draggedItems) {
|
|
1720
1687
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
1688
|
+
draggedItems[0].setFocused();
|
|
1721
1689
|
} else if (e.dataTransfer) {
|
|
1722
1690
|
yield (_c = config.onDropForeignDragObject) == null ? void 0 : _c.call(config, e.dataTransfer, target);
|
|
1723
1691
|
}
|
|
1692
|
+
tree.applySubStateUpdate("dnd", null);
|
|
1693
|
+
tree.updateDomFocus();
|
|
1724
1694
|
})
|
|
1725
1695
|
}),
|
|
1696
|
+
getDragHandleProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1697
|
+
draggable: true,
|
|
1698
|
+
onDragStart: (e) => {
|
|
1699
|
+
var _a, _b, _c, _d;
|
|
1700
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1701
|
+
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1702
|
+
const config = tree.getConfig();
|
|
1703
|
+
if (!selectedItems.includes(item)) {
|
|
1704
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1705
|
+
}
|
|
1706
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1707
|
+
e.preventDefault();
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
if (config.setDragImage) {
|
|
1711
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1712
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1713
|
+
}
|
|
1714
|
+
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1715
|
+
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1716
|
+
e.dataTransfer.setData(format, data);
|
|
1717
|
+
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1718
|
+
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1719
|
+
}
|
|
1720
|
+
tree.applySubStateUpdate("dnd", {
|
|
1721
|
+
draggedItems: items,
|
|
1722
|
+
draggingOverItem: tree.getFocusedItem()
|
|
1723
|
+
});
|
|
1724
|
+
},
|
|
1725
|
+
onDragEnd: (e) => {
|
|
1726
|
+
var _a, _b;
|
|
1727
|
+
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1728
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1729
|
+
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1733
|
+
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1737
|
+
}
|
|
1738
|
+
}),
|
|
1726
1739
|
isDragTarget: ({ tree, item }) => {
|
|
1727
1740
|
const target = tree.getDragTarget();
|
|
1728
1741
|
return target ? target.item.getId() === item.getId() : false;
|
|
@@ -1946,6 +1959,7 @@ var keyboardDragAndDropFeature = {
|
|
|
1946
1959
|
} else if (dataTransfer) {
|
|
1947
1960
|
yield (_d = config.onDropForeignDragObject) == null ? void 0 : _d.call(config, dataTransfer, target);
|
|
1948
1961
|
}
|
|
1962
|
+
tree.updateDomFocus();
|
|
1949
1963
|
tree.applySubStateUpdate(
|
|
1950
1964
|
"assistiveDndState",
|
|
1951
1965
|
3 /* Completed */
|
|
@@ -2296,6 +2310,14 @@ var propMemoizationFeature = {
|
|
|
2296
2310
|
(_e = (_d = dataRef.current.memo).item) != null ? _e : _d.item = {};
|
|
2297
2311
|
return memoize(props, dataRef.current.memo.item);
|
|
2298
2312
|
},
|
|
2313
|
+
getDragHandleProps: ({ item, prev }) => {
|
|
2314
|
+
var _a, _b, _c, _d, _e;
|
|
2315
|
+
const dataRef = item.getDataRef();
|
|
2316
|
+
const props = (_a = prev == null ? void 0 : prev()) != null ? _a : {};
|
|
2317
|
+
(_c = (_b = dataRef.current).memo) != null ? _c : _b.memo = {};
|
|
2318
|
+
(_e = (_d = dataRef.current.memo).drag) != null ? _e : _d.drag = {};
|
|
2319
|
+
return memoize(props, dataRef.current.memo.drag);
|
|
2320
|
+
},
|
|
2299
2321
|
getRenameInputProps: ({ item, prev }) => {
|
|
2300
2322
|
var _a, _b, _c, _d, _e;
|
|
2301
2323
|
const dataRef = item.getDataRef();
|
package/dist/index.mjs
CHANGED
|
@@ -81,6 +81,7 @@ var poll = (fn, interval = 100, timeout = 1e3) => new Promise((resolve) => {
|
|
|
81
81
|
}, interval);
|
|
82
82
|
clear = setTimeout(() => {
|
|
83
83
|
clearInterval(i);
|
|
84
|
+
resolve();
|
|
84
85
|
}, timeout);
|
|
85
86
|
});
|
|
86
87
|
|
|
@@ -170,12 +171,16 @@ var treeFeature = {
|
|
|
170
171
|
},
|
|
171
172
|
updateDomFocus: ({ tree }) => {
|
|
172
173
|
setTimeout(() => __async(null, null, function* () {
|
|
173
|
-
var _a, _b;
|
|
174
|
+
var _a, _b, _c, _d, _e;
|
|
174
175
|
const focusedItem = tree.getFocusedItem();
|
|
175
176
|
(_b = (_a = tree.getConfig()).scrollToItem) == null ? void 0 : _b.call(_a, focusedItem);
|
|
176
|
-
yield poll(() => focusedItem.getElement() !== null, 20);
|
|
177
|
+
yield poll(() => focusedItem.getElement() !== null, 20, 500);
|
|
177
178
|
const focusedElement = focusedItem.getElement();
|
|
178
|
-
if (!focusedElement)
|
|
179
|
+
if (!focusedElement) {
|
|
180
|
+
(_c = tree.getItems()[0]) == null ? void 0 : _c.setFocused();
|
|
181
|
+
(_e = (_d = tree.getItems()[0]) == null ? void 0 : _d.getElement()) == null ? void 0 : _e.focus();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
179
184
|
focusedElement.focus();
|
|
180
185
|
}));
|
|
181
186
|
},
|
|
@@ -1230,15 +1235,17 @@ var asyncDataLoaderFeature = {
|
|
|
1230
1235
|
}
|
|
1231
1236
|
yield loadChildrenIds(tree, itemId);
|
|
1232
1237
|
}),
|
|
1233
|
-
updateCachedChildrenIds: ({ tree, itemId }, childrenIds) => {
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1238
|
+
updateCachedChildrenIds: ({ tree, itemId }, childrenIds, skipUpdateTree) => {
|
|
1239
|
+
getDataRef(tree).current.childrenIds[itemId] = childrenIds;
|
|
1240
|
+
if (!skipUpdateTree) {
|
|
1241
|
+
tree.rebuildTree();
|
|
1242
|
+
}
|
|
1237
1243
|
},
|
|
1238
|
-
updateCachedData: ({ tree, itemId }, data) => {
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1244
|
+
updateCachedData: ({ tree, itemId }, data, skipUpdateTree) => {
|
|
1245
|
+
getDataRef(tree).current.itemData[itemId] = data;
|
|
1246
|
+
if (!skipUpdateTree) {
|
|
1247
|
+
tree.rebuildTree();
|
|
1248
|
+
}
|
|
1242
1249
|
},
|
|
1243
1250
|
hasLoadedData: ({ tree, itemId }) => {
|
|
1244
1251
|
const dataRef = tree.getDataRef();
|
|
@@ -1405,15 +1412,16 @@ var getReparentTarget = (item, reparentLevel, draggedItems) => {
|
|
|
1405
1412
|
dragLineLevel: reparentLevel
|
|
1406
1413
|
};
|
|
1407
1414
|
};
|
|
1408
|
-
var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) => {
|
|
1415
|
+
var getDragTarget = (e, item, tree, hasDataTransferPayload, canReorder = tree.getConfig().canReorder) => {
|
|
1409
1416
|
var _a;
|
|
1417
|
+
const dataTransfer = hasDataTransferPayload ? e.dataTransfer : null;
|
|
1410
1418
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1411
1419
|
const itemMeta = item.getItemMeta();
|
|
1412
1420
|
const parent = item.getParent();
|
|
1413
1421
|
const itemTarget = { item };
|
|
1414
1422
|
const parentTarget = parent ? { item: parent } : null;
|
|
1415
|
-
const canBecomeSibling = parentTarget && canDrop(
|
|
1416
|
-
const canMakeChild = canDrop(
|
|
1423
|
+
const canBecomeSibling = parentTarget && canDrop(dataTransfer, parentTarget, tree);
|
|
1424
|
+
const canMakeChild = canDrop(dataTransfer, itemTarget, tree);
|
|
1417
1425
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1418
1426
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1419
1427
|
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
@@ -1422,7 +1430,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1422
1430
|
return parentTarget;
|
|
1423
1431
|
}
|
|
1424
1432
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
1425
|
-
return getDragTarget(e, parent, tree, false);
|
|
1433
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1426
1434
|
}
|
|
1427
1435
|
if (!parent) {
|
|
1428
1436
|
return itemTarget;
|
|
@@ -1431,7 +1439,7 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1431
1439
|
return itemTarget;
|
|
1432
1440
|
}
|
|
1433
1441
|
if (!canBecomeSibling) {
|
|
1434
|
-
return getDragTarget(e, parent, tree, false);
|
|
1442
|
+
return getDragTarget(e, parent, tree, hasDataTransferPayload, false);
|
|
1435
1443
|
}
|
|
1436
1444
|
if (placement.type === 3 /* Reparent */) {
|
|
1437
1445
|
return getReparentTarget(item, placement.reparentLevel, draggedItems);
|
|
@@ -1568,36 +1576,8 @@ var dragAndDropFeature = {
|
|
|
1568
1576
|
}
|
|
1569
1577
|
},
|
|
1570
1578
|
itemInstance: {
|
|
1571
|
-
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1572
|
-
draggable: true,
|
|
1579
|
+
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues(__spreadValues({}, prev == null ? void 0 : prev()), tree.getConfig().seperateDragHandle ? {} : item.getDragHandleProps()), {
|
|
1573
1580
|
onDragEnter: (e) => e.preventDefault(),
|
|
1574
|
-
onDragStart: (e) => {
|
|
1575
|
-
var _a, _b, _c, _d;
|
|
1576
|
-
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1577
|
-
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1578
|
-
const config = tree.getConfig();
|
|
1579
|
-
if (!selectedItems.includes(item)) {
|
|
1580
|
-
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1581
|
-
}
|
|
1582
|
-
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1583
|
-
e.preventDefault();
|
|
1584
|
-
return;
|
|
1585
|
-
}
|
|
1586
|
-
if (config.setDragImage) {
|
|
1587
|
-
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1588
|
-
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1589
|
-
}
|
|
1590
|
-
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1591
|
-
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1592
|
-
e.dataTransfer.setData(format, data);
|
|
1593
|
-
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1594
|
-
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1595
|
-
}
|
|
1596
|
-
tree.applySubStateUpdate("dnd", {
|
|
1597
|
-
draggedItems: items,
|
|
1598
|
-
draggingOverItem: tree.getFocusedItem()
|
|
1599
|
-
});
|
|
1600
|
-
},
|
|
1601
1581
|
onDragOver: (e) => {
|
|
1602
1582
|
var _a, _b, _c;
|
|
1603
1583
|
e.stopPropagation();
|
|
@@ -1613,12 +1593,12 @@ var dragAndDropFeature = {
|
|
|
1613
1593
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1614
1594
|
dataRef.current.lastDragEnter = Date.now();
|
|
1615
1595
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1616
|
-
const target = getDragTarget(e, item, tree);
|
|
1596
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1617
1597
|
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
1598
|
dataRef.current.lastAllowDrop = false;
|
|
1619
1599
|
return;
|
|
1620
1600
|
}
|
|
1621
|
-
if (!canDrop(
|
|
1601
|
+
if (!canDrop(null, target, tree)) {
|
|
1622
1602
|
dataRef.current.lastAllowDrop = false;
|
|
1623
1603
|
return;
|
|
1624
1604
|
}
|
|
@@ -1641,24 +1621,11 @@ var dragAndDropFeature = {
|
|
|
1641
1621
|
}));
|
|
1642
1622
|
}, 100);
|
|
1643
1623
|
},
|
|
1644
|
-
onDragEnd: (e) => {
|
|
1645
|
-
var _a, _b;
|
|
1646
|
-
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1647
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1648
|
-
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1649
|
-
return;
|
|
1650
|
-
}
|
|
1651
|
-
const target = getDragTarget(e, item, tree);
|
|
1652
|
-
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1653
|
-
return;
|
|
1654
|
-
}
|
|
1655
|
-
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1656
|
-
},
|
|
1657
1624
|
onDrop: (e) => __async(null, null, function* () {
|
|
1658
1625
|
var _a, _b, _c;
|
|
1659
1626
|
e.stopPropagation();
|
|
1660
1627
|
const dataRef = tree.getDataRef();
|
|
1661
|
-
const target = getDragTarget(e, item, tree);
|
|
1628
|
+
const target = getDragTarget(e, item, tree, true);
|
|
1662
1629
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1663
1630
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1664
1631
|
tree.applySubStateUpdate("dnd", {
|
|
@@ -1674,11 +1641,57 @@ var dragAndDropFeature = {
|
|
|
1674
1641
|
dataRef.current.lastDragCode = void 0;
|
|
1675
1642
|
if (draggedItems) {
|
|
1676
1643
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
1644
|
+
draggedItems[0].setFocused();
|
|
1677
1645
|
} else if (e.dataTransfer) {
|
|
1678
1646
|
yield (_c = config.onDropForeignDragObject) == null ? void 0 : _c.call(config, e.dataTransfer, target);
|
|
1679
1647
|
}
|
|
1648
|
+
tree.applySubStateUpdate("dnd", null);
|
|
1649
|
+
tree.updateDomFocus();
|
|
1680
1650
|
})
|
|
1681
1651
|
}),
|
|
1652
|
+
getDragHandleProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1653
|
+
draggable: true,
|
|
1654
|
+
onDragStart: (e) => {
|
|
1655
|
+
var _a, _b, _c, _d;
|
|
1656
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1657
|
+
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1658
|
+
const config = tree.getConfig();
|
|
1659
|
+
if (!selectedItems.includes(item)) {
|
|
1660
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1661
|
+
}
|
|
1662
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1663
|
+
e.preventDefault();
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
if (config.setDragImage) {
|
|
1667
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1668
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1669
|
+
}
|
|
1670
|
+
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1671
|
+
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1672
|
+
e.dataTransfer.setData(format, data);
|
|
1673
|
+
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1674
|
+
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1675
|
+
}
|
|
1676
|
+
tree.applySubStateUpdate("dnd", {
|
|
1677
|
+
draggedItems: items,
|
|
1678
|
+
draggingOverItem: tree.getFocusedItem()
|
|
1679
|
+
});
|
|
1680
|
+
},
|
|
1681
|
+
onDragEnd: (e) => {
|
|
1682
|
+
var _a, _b;
|
|
1683
|
+
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1684
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1685
|
+
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1689
|
+
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1693
|
+
}
|
|
1694
|
+
}),
|
|
1682
1695
|
isDragTarget: ({ tree, item }) => {
|
|
1683
1696
|
const target = tree.getDragTarget();
|
|
1684
1697
|
return target ? target.item.getId() === item.getId() : false;
|
|
@@ -1902,6 +1915,7 @@ var keyboardDragAndDropFeature = {
|
|
|
1902
1915
|
} else if (dataTransfer) {
|
|
1903
1916
|
yield (_d = config.onDropForeignDragObject) == null ? void 0 : _d.call(config, dataTransfer, target);
|
|
1904
1917
|
}
|
|
1918
|
+
tree.updateDomFocus();
|
|
1905
1919
|
tree.applySubStateUpdate(
|
|
1906
1920
|
"assistiveDndState",
|
|
1907
1921
|
3 /* Completed */
|
|
@@ -2252,6 +2266,14 @@ var propMemoizationFeature = {
|
|
|
2252
2266
|
(_e = (_d = dataRef.current.memo).item) != null ? _e : _d.item = {};
|
|
2253
2267
|
return memoize(props, dataRef.current.memo.item);
|
|
2254
2268
|
},
|
|
2269
|
+
getDragHandleProps: ({ item, prev }) => {
|
|
2270
|
+
var _a, _b, _c, _d, _e;
|
|
2271
|
+
const dataRef = item.getDataRef();
|
|
2272
|
+
const props = (_a = prev == null ? void 0 : prev()) != null ? _a : {};
|
|
2273
|
+
(_c = (_b = dataRef.current).memo) != null ? _c : _b.memo = {};
|
|
2274
|
+
(_e = (_d = dataRef.current.memo).drag) != null ? _e : _d.drag = {};
|
|
2275
|
+
return memoize(props, dataRef.current.memo.drag);
|
|
2276
|
+
},
|
|
2255
2277
|
getRenameInputProps: ({ item, prev }) => {
|
|
2256
2278
|
var _a, _b, _c, _d, _e;
|
|
2257
2279
|
const dataRef = item.getDataRef();
|
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", () => {
|
|
@@ -698,6 +729,54 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
698
729
|
});
|
|
699
730
|
});
|
|
700
731
|
|
|
732
|
+
describe("seperateDragHandle", () => {
|
|
733
|
+
it("includes all drag handlers in getProps() when seperateDragHandle is false", () => {
|
|
734
|
+
const props = tree.instance.getItemInstance("x111").getProps();
|
|
735
|
+
expect(props.draggable).toBe(true);
|
|
736
|
+
expect(props.onDragStart).toBeDefined();
|
|
737
|
+
expect(props.onDragEnd).toBeDefined();
|
|
738
|
+
expect(props.onDragEnter).toBeDefined();
|
|
739
|
+
expect(props.onDragOver).toBeDefined();
|
|
740
|
+
expect(props.onDragLeave).toBeDefined();
|
|
741
|
+
expect(props.onDrop).toBeDefined();
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
it("includes drag handle handlers in getDragHandleProps() when seperateDragHandle is false", () => {
|
|
745
|
+
const props = tree.instance
|
|
746
|
+
.getItemInstance("x111")
|
|
747
|
+
.getDragHandleProps();
|
|
748
|
+
expect(props.draggable).toBe(true);
|
|
749
|
+
expect(props.onDragStart).toBeDefined();
|
|
750
|
+
expect(props.onDragEnd).toBeDefined();
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
it("excludes drag handle handlers from getProps() but includes drop handlers when seperateDragHandle is true", async () => {
|
|
754
|
+
const testTree = await tree
|
|
755
|
+
.with({ seperateDragHandle: true })
|
|
756
|
+
.createTestCaseTree();
|
|
757
|
+
const props = testTree.instance.getItemInstance("x111").getProps();
|
|
758
|
+
expect(props.draggable).toBeUndefined();
|
|
759
|
+
expect(props.onDragStart).toBeUndefined();
|
|
760
|
+
expect(props.onDragEnd).toBeUndefined();
|
|
761
|
+
expect(props.onDragEnter).toBeDefined();
|
|
762
|
+
expect(props.onDragOver).toBeDefined();
|
|
763
|
+
expect(props.onDragLeave).toBeDefined();
|
|
764
|
+
expect(props.onDrop).toBeDefined();
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it("includes drag handle handlers in getDragHandleProps() when seperateDragHandle is true", async () => {
|
|
768
|
+
const testTree = await tree
|
|
769
|
+
.with({ seperateDragHandle: true })
|
|
770
|
+
.createTestCaseTree();
|
|
771
|
+
const props = testTree.instance
|
|
772
|
+
.getItemInstance("x111")
|
|
773
|
+
.getDragHandleProps();
|
|
774
|
+
expect(props.draggable).toBe(true);
|
|
775
|
+
expect(props.onDragStart).toBeDefined();
|
|
776
|
+
expect(props.onDragEnd).toBeDefined();
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
|
|
701
780
|
describe("retains last drag state with dragcode", () => {
|
|
702
781
|
it("uses constant number of calls to canDrop", () => {
|
|
703
782
|
const canDrop = tree.mockedHandler("canDrop").mockReturnValue(true);
|
|
@@ -178,47 +178,10 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
178
178
|
itemInstance: {
|
|
179
179
|
getProps: ({ tree, item, prev }) => ({
|
|
180
180
|
...prev?.(),
|
|
181
|
-
|
|
182
|
-
draggable: true,
|
|
181
|
+
...(tree.getConfig().seperateDragHandle ? {} : item.getDragHandleProps()),
|
|
183
182
|
|
|
184
183
|
onDragEnter: (e: DragEvent) => e.preventDefault(),
|
|
185
184
|
|
|
186
|
-
onDragStart: (e: DragEvent) => {
|
|
187
|
-
const selectedItems = tree.getSelectedItems
|
|
188
|
-
? tree.getSelectedItems()
|
|
189
|
-
: [tree.getFocusedItem()];
|
|
190
|
-
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
191
|
-
const config = tree.getConfig();
|
|
192
|
-
|
|
193
|
-
if (!selectedItems.includes(item)) {
|
|
194
|
-
tree.setSelectedItems?.([item.getItemMeta().itemId]);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (!(config.canDrag?.(items) ?? true)) {
|
|
198
|
-
e.preventDefault();
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (config.setDragImage) {
|
|
203
|
-
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
204
|
-
e.dataTransfer?.setDragImage(imgElement, xOffset ?? 0, yOffset ?? 0);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (config.createForeignDragObject && e.dataTransfer) {
|
|
208
|
-
const { format, data, dropEffect, effectAllowed } =
|
|
209
|
-
config.createForeignDragObject(items);
|
|
210
|
-
e.dataTransfer.setData(format, data);
|
|
211
|
-
|
|
212
|
-
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
213
|
-
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
tree.applySubStateUpdate("dnd", {
|
|
217
|
-
draggedItems: items,
|
|
218
|
-
draggingOverItem: tree.getFocusedItem(),
|
|
219
|
-
});
|
|
220
|
-
},
|
|
221
|
-
|
|
222
185
|
onDragOver: (e: DragEvent) => {
|
|
223
186
|
e.stopPropagation(); // don't bubble up to container dragover
|
|
224
187
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
@@ -236,7 +199,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
236
199
|
|
|
237
200
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
238
201
|
|
|
239
|
-
const target = getDragTarget(e, item, tree);
|
|
202
|
+
const target = getDragTarget(e, item, tree, false);
|
|
240
203
|
|
|
241
204
|
if (
|
|
242
205
|
!tree.getState().dnd?.draggedItems &&
|
|
@@ -249,7 +212,8 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
249
212
|
return;
|
|
250
213
|
}
|
|
251
214
|
|
|
252
|
-
|
|
215
|
+
// dataTransfer.payload is not accessible in onDragOver, so just skip entirely here. It'll be checked again in onDrop
|
|
216
|
+
if (!canDrop(null, target, tree)) {
|
|
253
217
|
dataRef.current.lastAllowDrop = false;
|
|
254
218
|
return;
|
|
255
219
|
}
|
|
@@ -276,31 +240,10 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
276
240
|
}, 100);
|
|
277
241
|
},
|
|
278
242
|
|
|
279
|
-
onDragEnd: (e: DragEvent) => {
|
|
280
|
-
const { onCompleteForeignDrop, canDragForeignDragObjectOver } =
|
|
281
|
-
tree.getConfig();
|
|
282
|
-
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
283
|
-
|
|
284
|
-
if (e.dataTransfer?.dropEffect === "none" || !draggedItems) {
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const target = getDragTarget(e, item, tree);
|
|
289
|
-
if (
|
|
290
|
-
canDragForeignDragObjectOver &&
|
|
291
|
-
e.dataTransfer &&
|
|
292
|
-
!canDragForeignDragObjectOver(e.dataTransfer, target)
|
|
293
|
-
) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
onCompleteForeignDrop?.(draggedItems);
|
|
298
|
-
},
|
|
299
|
-
|
|
300
243
|
onDrop: async (e: DragEvent) => {
|
|
301
244
|
e.stopPropagation();
|
|
302
245
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
303
|
-
const target = getDragTarget(e, item, tree);
|
|
246
|
+
const target = getDragTarget(e, item, tree, true);
|
|
304
247
|
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
305
248
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
306
249
|
|
|
@@ -321,9 +264,76 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
321
264
|
|
|
322
265
|
if (draggedItems) {
|
|
323
266
|
await config.onDrop?.(draggedItems, target);
|
|
267
|
+
draggedItems[0].setFocused();
|
|
324
268
|
} else if (e.dataTransfer) {
|
|
325
269
|
await config.onDropForeignDragObject?.(e.dataTransfer, target);
|
|
326
270
|
}
|
|
271
|
+
|
|
272
|
+
tree.applySubStateUpdate("dnd", null);
|
|
273
|
+
tree.updateDomFocus();
|
|
274
|
+
},
|
|
275
|
+
}),
|
|
276
|
+
|
|
277
|
+
getDragHandleProps: ({ tree, item, prev }) => ({
|
|
278
|
+
...prev?.(),
|
|
279
|
+
|
|
280
|
+
draggable: true,
|
|
281
|
+
|
|
282
|
+
onDragStart: (e: DragEvent) => {
|
|
283
|
+
const selectedItems = tree.getSelectedItems
|
|
284
|
+
? tree.getSelectedItems()
|
|
285
|
+
: [tree.getFocusedItem()];
|
|
286
|
+
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
287
|
+
const config = tree.getConfig();
|
|
288
|
+
|
|
289
|
+
if (!selectedItems.includes(item)) {
|
|
290
|
+
tree.setSelectedItems?.([item.getItemMeta().itemId]);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (!(config.canDrag?.(items) ?? true)) {
|
|
294
|
+
e.preventDefault();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (config.setDragImage) {
|
|
299
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
300
|
+
e.dataTransfer?.setDragImage(imgElement, xOffset ?? 0, yOffset ?? 0);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (config.createForeignDragObject && e.dataTransfer) {
|
|
304
|
+
const { format, data, dropEffect, effectAllowed } =
|
|
305
|
+
config.createForeignDragObject(items);
|
|
306
|
+
e.dataTransfer.setData(format, data);
|
|
307
|
+
|
|
308
|
+
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
309
|
+
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
tree.applySubStateUpdate("dnd", {
|
|
313
|
+
draggedItems: items,
|
|
314
|
+
draggingOverItem: tree.getFocusedItem(),
|
|
315
|
+
});
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
onDragEnd: (e: DragEvent) => {
|
|
319
|
+
const { onCompleteForeignDrop, canDragForeignDragObjectOver } =
|
|
320
|
+
tree.getConfig();
|
|
321
|
+
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
322
|
+
|
|
323
|
+
if (e.dataTransfer?.dropEffect === "none" || !draggedItems) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const target = getDragTarget(e, item, tree, false);
|
|
328
|
+
if (
|
|
329
|
+
canDragForeignDragObjectOver &&
|
|
330
|
+
e.dataTransfer &&
|
|
331
|
+
!canDragForeignDragObjectOver(e.dataTransfer, target)
|
|
332
|
+
) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
onCompleteForeignDrop?.(draggedItems);
|
|
327
337
|
},
|
|
328
338
|
}),
|
|
329
339
|
|
|
@@ -97,6 +97,9 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
97
97
|
|
|
98
98
|
/** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
|
|
99
99
|
openOnDropDelay?: number;
|
|
100
|
+
|
|
101
|
+
/** If true, `item.getProps()` will not include drag event handlers. Use `item.getDragHandleProps()` on the handler element. */
|
|
102
|
+
seperateDragHandle?: boolean;
|
|
100
103
|
};
|
|
101
104
|
treeInstance: {
|
|
102
105
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -118,6 +121,10 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
118
121
|
isDragTargetAbove: () => boolean;
|
|
119
122
|
isDragTargetBelow: () => boolean;
|
|
120
123
|
isDraggingOver: () => boolean;
|
|
124
|
+
|
|
125
|
+
/** Note that `item.getProps()` already passes in all drag event handlers by default. Set `seperateDragHandle` to true to
|
|
126
|
+
* disable the default behavior and use this on the handler element instead. */
|
|
127
|
+
getDragHandleProps: () => Record<string, any>;
|
|
121
128
|
};
|
|
122
129
|
hotkeys: never;
|
|
123
130
|
};
|
|
@@ -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) {
|
|
@@ -254,6 +254,7 @@ export const keyboardDragAndDropFeature: FeatureImplementation = {
|
|
|
254
254
|
await config.onDropForeignDragObject?.(dataTransfer, target);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
tree.updateDomFocus();
|
|
257
258
|
tree.applySubStateUpdate(
|
|
258
259
|
"assistiveDndState",
|
|
259
260
|
AssistiveDndState.Completed,
|
|
@@ -59,6 +59,14 @@ export const propMemoizationFeature: FeatureImplementation = {
|
|
|
59
59
|
return memoize(props, dataRef.current.memo.item);
|
|
60
60
|
},
|
|
61
61
|
|
|
62
|
+
getDragHandleProps: ({ item, prev }) => {
|
|
63
|
+
const dataRef = item.getDataRef<PropMemoizationDataRef>();
|
|
64
|
+
const props = prev?.() ?? {};
|
|
65
|
+
dataRef.current.memo ??= {};
|
|
66
|
+
dataRef.current.memo.drag ??= {};
|
|
67
|
+
return memoize(props, dataRef.current.memo.drag);
|
|
68
|
+
},
|
|
69
|
+
|
|
62
70
|
getRenameInputProps: ({ item, prev }) => {
|
|
63
71
|
const dataRef = item.getDataRef<PropMemoizationDataRef>();
|
|
64
72
|
const props = prev?.() ?? {};
|
|
@@ -107,9 +107,13 @@ export const treeFeature: FeatureImplementation<any> = {
|
|
|
107
107
|
setTimeout(async () => {
|
|
108
108
|
const focusedItem = tree.getFocusedItem();
|
|
109
109
|
tree.getConfig().scrollToItem?.(focusedItem);
|
|
110
|
-
await poll(() => focusedItem.getElement() !== null, 20);
|
|
110
|
+
await poll(() => focusedItem.getElement() !== null, 20, 500);
|
|
111
111
|
const focusedElement = focusedItem.getElement();
|
|
112
|
-
if (!focusedElement)
|
|
112
|
+
if (!focusedElement) {
|
|
113
|
+
tree.getItems()[0]?.setFocused();
|
|
114
|
+
tree.getItems()[0]?.getElement()?.focus();
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
113
117
|
focusedElement.focus();
|
|
114
118
|
});
|
|
115
119
|
},
|