@headless-tree/core 0.0.0-20260107224057 → 0.0.0-20260108162121
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 +7 -1
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +56 -43
- package/dist/index.mjs +56 -43
- package/package.json +1 -1
- package/src/features/drag-and-drop/drag-and-drop.spec.ts +142 -0
- package/src/features/drag-and-drop/feature.ts +68 -59
- package/src/features/drag-and-drop/types.ts +11 -0
- package/src/features/prop-memoization/feature.ts +8 -0
- package/src/features/prop-memoization/types.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20260108162121
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4397d8c: Added `draggedItemOverwritesSelection` as config option to the Drag Feature. Setting it to false will disable the current default behavior, where dragging an unselected item will overwrite the selection to just the dragged item.
|
|
8
|
+
|
|
9
|
+
## 1.6.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
6
12
|
|
package/dist/index.d.mts
CHANGED
|
@@ -68,6 +68,11 @@ 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;
|
|
73
|
+
/** If true, the item that is dragged is not selected, the selected items will be overwritten to just the dragged item.
|
|
74
|
+
* Defaults to true */
|
|
75
|
+
draggedItemOverwritesSelection?: boolean;
|
|
71
76
|
};
|
|
72
77
|
treeInstance: {
|
|
73
78
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -84,6 +89,9 @@ type DragAndDropFeatureDef<T> = {
|
|
|
84
89
|
isDragTargetAbove: () => boolean;
|
|
85
90
|
isDragTargetBelow: () => boolean;
|
|
86
91
|
isDraggingOver: () => boolean;
|
|
92
|
+
/** Note that `item.getProps()` already passes in all drag event handlers by default. Set `seperateDragHandle` to true to
|
|
93
|
+
* disable the default behavior and use this on the handler element instead. */
|
|
94
|
+
getDragHandleProps: () => Record<string, any>;
|
|
87
95
|
};
|
|
88
96
|
hotkeys: never;
|
|
89
97
|
};
|
|
@@ -422,6 +430,7 @@ interface PropMemoizationDataRef {
|
|
|
422
430
|
memo?: {
|
|
423
431
|
tree?: Record<string, any>;
|
|
424
432
|
item?: Record<string, any>;
|
|
433
|
+
drag?: Record<string, any>;
|
|
425
434
|
search?: Record<string, any>;
|
|
426
435
|
rename?: Record<string, any>;
|
|
427
436
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,11 @@ 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;
|
|
73
|
+
/** If true, the item that is dragged is not selected, the selected items will be overwritten to just the dragged item.
|
|
74
|
+
* Defaults to true */
|
|
75
|
+
draggedItemOverwritesSelection?: boolean;
|
|
71
76
|
};
|
|
72
77
|
treeInstance: {
|
|
73
78
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -84,6 +89,9 @@ type DragAndDropFeatureDef<T> = {
|
|
|
84
89
|
isDragTargetAbove: () => boolean;
|
|
85
90
|
isDragTargetBelow: () => boolean;
|
|
86
91
|
isDraggingOver: () => boolean;
|
|
92
|
+
/** Note that `item.getProps()` already passes in all drag event handlers by default. Set `seperateDragHandle` to true to
|
|
93
|
+
* disable the default behavior and use this on the handler element instead. */
|
|
94
|
+
getDragHandleProps: () => Record<string, any>;
|
|
87
95
|
};
|
|
88
96
|
hotkeys: never;
|
|
89
97
|
};
|
|
@@ -422,6 +430,7 @@ interface PropMemoizationDataRef {
|
|
|
422
430
|
memo?: {
|
|
423
431
|
tree?: Record<string, any>;
|
|
424
432
|
item?: Record<string, any>;
|
|
433
|
+
drag?: Record<string, any>;
|
|
425
434
|
search?: Record<string, any>;
|
|
426
435
|
rename?: Record<string, any>;
|
|
427
436
|
};
|
package/dist/index.js
CHANGED
|
@@ -1527,7 +1527,8 @@ var dragAndDropFeature = {
|
|
|
1527
1527
|
canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
|
|
1528
1528
|
setDndState: makeStateUpdater("dnd", tree),
|
|
1529
1529
|
canReorder: true,
|
|
1530
|
-
openOnDropDelay: 800
|
|
1530
|
+
openOnDropDelay: 800,
|
|
1531
|
+
draggedItemOverwritesSelection: true
|
|
1531
1532
|
}, defaultConfig),
|
|
1532
1533
|
stateHandlerNames: {
|
|
1533
1534
|
dnd: "setDndState"
|
|
@@ -1620,36 +1621,8 @@ var dragAndDropFeature = {
|
|
|
1620
1621
|
}
|
|
1621
1622
|
},
|
|
1622
1623
|
itemInstance: {
|
|
1623
|
-
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1624
|
-
draggable: true,
|
|
1624
|
+
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues(__spreadValues({}, prev == null ? void 0 : prev()), tree.getConfig().seperateDragHandle ? {} : item.getDragHandleProps()), {
|
|
1625
1625
|
onDragEnter: (e) => e.preventDefault(),
|
|
1626
|
-
onDragStart: (e) => {
|
|
1627
|
-
var _a, _b, _c, _d;
|
|
1628
|
-
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1629
|
-
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1630
|
-
const config = tree.getConfig();
|
|
1631
|
-
if (!selectedItems.includes(item)) {
|
|
1632
|
-
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1633
|
-
}
|
|
1634
|
-
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1635
|
-
e.preventDefault();
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
if (config.setDragImage) {
|
|
1639
|
-
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1640
|
-
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1641
|
-
}
|
|
1642
|
-
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1643
|
-
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1644
|
-
e.dataTransfer.setData(format, data);
|
|
1645
|
-
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1646
|
-
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1647
|
-
}
|
|
1648
|
-
tree.applySubStateUpdate("dnd", {
|
|
1649
|
-
draggedItems: items,
|
|
1650
|
-
draggingOverItem: tree.getFocusedItem()
|
|
1651
|
-
});
|
|
1652
|
-
},
|
|
1653
1626
|
onDragOver: (e) => {
|
|
1654
1627
|
var _a, _b, _c;
|
|
1655
1628
|
e.stopPropagation();
|
|
@@ -1693,19 +1666,6 @@ var dragAndDropFeature = {
|
|
|
1693
1666
|
}));
|
|
1694
1667
|
}, 100);
|
|
1695
1668
|
},
|
|
1696
|
-
onDragEnd: (e) => {
|
|
1697
|
-
var _a, _b;
|
|
1698
|
-
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1699
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1700
|
-
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1701
|
-
return;
|
|
1702
|
-
}
|
|
1703
|
-
const target = getDragTarget(e, item, tree, false);
|
|
1704
|
-
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1705
|
-
return;
|
|
1706
|
-
}
|
|
1707
|
-
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1708
|
-
},
|
|
1709
1669
|
onDrop: (e) => __async(null, null, function* () {
|
|
1710
1670
|
var _a, _b, _c;
|
|
1711
1671
|
e.stopPropagation();
|
|
@@ -1734,6 +1694,51 @@ var dragAndDropFeature = {
|
|
|
1734
1694
|
tree.updateDomFocus();
|
|
1735
1695
|
})
|
|
1736
1696
|
}),
|
|
1697
|
+
getDragHandleProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1698
|
+
draggable: true,
|
|
1699
|
+
onDragStart: (e) => {
|
|
1700
|
+
var _a, _b, _c, _d;
|
|
1701
|
+
const { draggedItemOverwritesSelection } = tree.getConfig();
|
|
1702
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1703
|
+
const overwriteSelection = !selectedItems.includes(item) && draggedItemOverwritesSelection;
|
|
1704
|
+
const items = overwriteSelection ? [item] : selectedItems;
|
|
1705
|
+
const config = tree.getConfig();
|
|
1706
|
+
if (overwriteSelection) {
|
|
1707
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1708
|
+
}
|
|
1709
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1710
|
+
e.preventDefault();
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
if (config.setDragImage) {
|
|
1714
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1715
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1716
|
+
}
|
|
1717
|
+
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1718
|
+
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1719
|
+
e.dataTransfer.setData(format, data);
|
|
1720
|
+
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1721
|
+
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1722
|
+
}
|
|
1723
|
+
tree.applySubStateUpdate("dnd", {
|
|
1724
|
+
draggedItems: items,
|
|
1725
|
+
draggingOverItem: tree.getFocusedItem()
|
|
1726
|
+
});
|
|
1727
|
+
},
|
|
1728
|
+
onDragEnd: (e) => {
|
|
1729
|
+
var _a, _b;
|
|
1730
|
+
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1731
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1732
|
+
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1736
|
+
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1737
|
+
return;
|
|
1738
|
+
}
|
|
1739
|
+
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1740
|
+
}
|
|
1741
|
+
}),
|
|
1737
1742
|
isDragTarget: ({ tree, item }) => {
|
|
1738
1743
|
const target = tree.getDragTarget();
|
|
1739
1744
|
return target ? target.item.getId() === item.getId() : false;
|
|
@@ -2308,6 +2313,14 @@ var propMemoizationFeature = {
|
|
|
2308
2313
|
(_e = (_d = dataRef.current.memo).item) != null ? _e : _d.item = {};
|
|
2309
2314
|
return memoize(props, dataRef.current.memo.item);
|
|
2310
2315
|
},
|
|
2316
|
+
getDragHandleProps: ({ item, prev }) => {
|
|
2317
|
+
var _a, _b, _c, _d, _e;
|
|
2318
|
+
const dataRef = item.getDataRef();
|
|
2319
|
+
const props = (_a = prev == null ? void 0 : prev()) != null ? _a : {};
|
|
2320
|
+
(_c = (_b = dataRef.current).memo) != null ? _c : _b.memo = {};
|
|
2321
|
+
(_e = (_d = dataRef.current.memo).drag) != null ? _e : _d.drag = {};
|
|
2322
|
+
return memoize(props, dataRef.current.memo.drag);
|
|
2323
|
+
},
|
|
2311
2324
|
getRenameInputProps: ({ item, prev }) => {
|
|
2312
2325
|
var _a, _b, _c, _d, _e;
|
|
2313
2326
|
const dataRef = item.getDataRef();
|
package/dist/index.mjs
CHANGED
|
@@ -1483,7 +1483,8 @@ var dragAndDropFeature = {
|
|
|
1483
1483
|
canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
|
|
1484
1484
|
setDndState: makeStateUpdater("dnd", tree),
|
|
1485
1485
|
canReorder: true,
|
|
1486
|
-
openOnDropDelay: 800
|
|
1486
|
+
openOnDropDelay: 800,
|
|
1487
|
+
draggedItemOverwritesSelection: true
|
|
1487
1488
|
}, defaultConfig),
|
|
1488
1489
|
stateHandlerNames: {
|
|
1489
1490
|
dnd: "setDndState"
|
|
@@ -1576,36 +1577,8 @@ var dragAndDropFeature = {
|
|
|
1576
1577
|
}
|
|
1577
1578
|
},
|
|
1578
1579
|
itemInstance: {
|
|
1579
|
-
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1580
|
-
draggable: true,
|
|
1580
|
+
getProps: ({ tree, item, prev }) => __spreadProps(__spreadValues(__spreadValues({}, prev == null ? void 0 : prev()), tree.getConfig().seperateDragHandle ? {} : item.getDragHandleProps()), {
|
|
1581
1581
|
onDragEnter: (e) => e.preventDefault(),
|
|
1582
|
-
onDragStart: (e) => {
|
|
1583
|
-
var _a, _b, _c, _d;
|
|
1584
|
-
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1585
|
-
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1586
|
-
const config = tree.getConfig();
|
|
1587
|
-
if (!selectedItems.includes(item)) {
|
|
1588
|
-
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1589
|
-
}
|
|
1590
|
-
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1591
|
-
e.preventDefault();
|
|
1592
|
-
return;
|
|
1593
|
-
}
|
|
1594
|
-
if (config.setDragImage) {
|
|
1595
|
-
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1596
|
-
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1597
|
-
}
|
|
1598
|
-
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1599
|
-
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1600
|
-
e.dataTransfer.setData(format, data);
|
|
1601
|
-
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1602
|
-
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1603
|
-
}
|
|
1604
|
-
tree.applySubStateUpdate("dnd", {
|
|
1605
|
-
draggedItems: items,
|
|
1606
|
-
draggingOverItem: tree.getFocusedItem()
|
|
1607
|
-
});
|
|
1608
|
-
},
|
|
1609
1582
|
onDragOver: (e) => {
|
|
1610
1583
|
var _a, _b, _c;
|
|
1611
1584
|
e.stopPropagation();
|
|
@@ -1649,19 +1622,6 @@ var dragAndDropFeature = {
|
|
|
1649
1622
|
}));
|
|
1650
1623
|
}, 100);
|
|
1651
1624
|
},
|
|
1652
|
-
onDragEnd: (e) => {
|
|
1653
|
-
var _a, _b;
|
|
1654
|
-
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1655
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1656
|
-
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
const target = getDragTarget(e, item, tree, false);
|
|
1660
|
-
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1661
|
-
return;
|
|
1662
|
-
}
|
|
1663
|
-
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1664
|
-
},
|
|
1665
1625
|
onDrop: (e) => __async(null, null, function* () {
|
|
1666
1626
|
var _a, _b, _c;
|
|
1667
1627
|
e.stopPropagation();
|
|
@@ -1690,6 +1650,51 @@ var dragAndDropFeature = {
|
|
|
1690
1650
|
tree.updateDomFocus();
|
|
1691
1651
|
})
|
|
1692
1652
|
}),
|
|
1653
|
+
getDragHandleProps: ({ tree, item, prev }) => __spreadProps(__spreadValues({}, prev == null ? void 0 : prev()), {
|
|
1654
|
+
draggable: true,
|
|
1655
|
+
onDragStart: (e) => {
|
|
1656
|
+
var _a, _b, _c, _d;
|
|
1657
|
+
const { draggedItemOverwritesSelection } = tree.getConfig();
|
|
1658
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1659
|
+
const overwriteSelection = !selectedItems.includes(item) && draggedItemOverwritesSelection;
|
|
1660
|
+
const items = overwriteSelection ? [item] : selectedItems;
|
|
1661
|
+
const config = tree.getConfig();
|
|
1662
|
+
if (overwriteSelection) {
|
|
1663
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1664
|
+
}
|
|
1665
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1666
|
+
e.preventDefault();
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
if (config.setDragImage) {
|
|
1670
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1671
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1672
|
+
}
|
|
1673
|
+
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1674
|
+
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
1675
|
+
e.dataTransfer.setData(format, data);
|
|
1676
|
+
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
1677
|
+
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
1678
|
+
}
|
|
1679
|
+
tree.applySubStateUpdate("dnd", {
|
|
1680
|
+
draggedItems: items,
|
|
1681
|
+
draggingOverItem: tree.getFocusedItem()
|
|
1682
|
+
});
|
|
1683
|
+
},
|
|
1684
|
+
onDragEnd: (e) => {
|
|
1685
|
+
var _a, _b;
|
|
1686
|
+
const { onCompleteForeignDrop, canDragForeignDragObjectOver } = tree.getConfig();
|
|
1687
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1688
|
+
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1692
|
+
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1693
|
+
return;
|
|
1694
|
+
}
|
|
1695
|
+
onCompleteForeignDrop == null ? void 0 : onCompleteForeignDrop(draggedItems);
|
|
1696
|
+
}
|
|
1697
|
+
}),
|
|
1693
1698
|
isDragTarget: ({ tree, item }) => {
|
|
1694
1699
|
const target = tree.getDragTarget();
|
|
1695
1700
|
return target ? target.item.getId() === item.getId() : false;
|
|
@@ -2264,6 +2269,14 @@ var propMemoizationFeature = {
|
|
|
2264
2269
|
(_e = (_d = dataRef.current.memo).item) != null ? _e : _d.item = {};
|
|
2265
2270
|
return memoize(props, dataRef.current.memo.item);
|
|
2266
2271
|
},
|
|
2272
|
+
getDragHandleProps: ({ item, prev }) => {
|
|
2273
|
+
var _a, _b, _c, _d, _e;
|
|
2274
|
+
const dataRef = item.getDataRef();
|
|
2275
|
+
const props = (_a = prev == null ? void 0 : prev()) != null ? _a : {};
|
|
2276
|
+
(_c = (_b = dataRef.current).memo) != null ? _c : _b.memo = {};
|
|
2277
|
+
(_e = (_d = dataRef.current.memo).drag) != null ? _e : _d.drag = {};
|
|
2278
|
+
return memoize(props, dataRef.current.memo.drag);
|
|
2279
|
+
},
|
|
2267
2280
|
getRenameInputProps: ({ item, prev }) => {
|
|
2268
2281
|
var _a, _b, _c, _d, _e;
|
|
2269
2282
|
const dataRef = item.getDataRef();
|
package/package.json
CHANGED
|
@@ -729,6 +729,54 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
729
729
|
});
|
|
730
730
|
});
|
|
731
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
|
+
|
|
732
780
|
describe("retains last drag state with dragcode", () => {
|
|
733
781
|
it("uses constant number of calls to canDrop", () => {
|
|
734
782
|
const canDrop = tree.mockedHandler("canDrop").mockReturnValue(true);
|
|
@@ -739,5 +787,99 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
739
787
|
expect(canDrop).toBeCalledTimes(3);
|
|
740
788
|
});
|
|
741
789
|
});
|
|
790
|
+
|
|
791
|
+
describe("draggedItemOverwritesSelection", () => {
|
|
792
|
+
it("overwrites selection when dragging unselected item with draggedItemOverwritesSelection=true", () => {
|
|
793
|
+
tree.do.selectItem("x111");
|
|
794
|
+
tree.do.ctrlSelectItem("x112");
|
|
795
|
+
tree.do.ctrlSelectItem("x113");
|
|
796
|
+
|
|
797
|
+
expect(tree.instance.getItemInstance("x111").isSelected()).toBe(true);
|
|
798
|
+
expect(tree.instance.getItemInstance("x112").isSelected()).toBe(true);
|
|
799
|
+
expect(tree.instance.getItemInstance("x113").isSelected()).toBe(true);
|
|
800
|
+
expect(tree.instance.getItemInstance("x114").isSelected()).toBe(false);
|
|
801
|
+
|
|
802
|
+
tree.do.startDrag("x114");
|
|
803
|
+
|
|
804
|
+
expect(tree.instance.getItemInstance("x111").isSelected()).toBe(false);
|
|
805
|
+
expect(tree.instance.getItemInstance("x112").isSelected()).toBe(false);
|
|
806
|
+
expect(tree.instance.getItemInstance("x113").isSelected()).toBe(false);
|
|
807
|
+
expect(tree.instance.getItemInstance("x114").isSelected()).toBe(true);
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
it("preserves selection when dragging unselected item with draggedItemOverwritesSelection=false", async () => {
|
|
811
|
+
const testTree = await tree
|
|
812
|
+
.with({ draggedItemOverwritesSelection: false })
|
|
813
|
+
.createTestCaseTree();
|
|
814
|
+
|
|
815
|
+
testTree.do.selectItem("x111");
|
|
816
|
+
testTree.do.ctrlSelectItem("x112");
|
|
817
|
+
testTree.do.ctrlSelectItem("x113");
|
|
818
|
+
|
|
819
|
+
expect(testTree.item("x111").isSelected()).toBe(true);
|
|
820
|
+
expect(testTree.item("x112").isSelected()).toBe(true);
|
|
821
|
+
expect(testTree.item("x113").isSelected()).toBe(true);
|
|
822
|
+
expect(testTree.item("x114").isSelected()).toBe(false);
|
|
823
|
+
testTree.do.startDrag("x114");
|
|
824
|
+
|
|
825
|
+
expect(testTree.item("x111").isSelected()).toBe(true);
|
|
826
|
+
expect(testTree.item("x112").isSelected()).toBe(true);
|
|
827
|
+
expect(testTree.item("x113").isSelected()).toBe(true);
|
|
828
|
+
expect(testTree.item("x114").isSelected()).toBe(false);
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
it("does not overwrite selection when dragging selected item with draggedItemOverwritesSelection=true", () => {
|
|
832
|
+
tree.do.selectItem("x111");
|
|
833
|
+
tree.do.ctrlSelectItem("x112");
|
|
834
|
+
tree.do.ctrlSelectItem("x113");
|
|
835
|
+
|
|
836
|
+
expect(tree.item("x111").isSelected()).toBe(true);
|
|
837
|
+
expect(tree.item("x112").isSelected()).toBe(true);
|
|
838
|
+
expect(tree.item("x113").isSelected()).toBe(true);
|
|
839
|
+
|
|
840
|
+
tree.do.startDrag("x111");
|
|
841
|
+
|
|
842
|
+
expect(tree.item("x111").isSelected()).toBe(true);
|
|
843
|
+
expect(tree.item("x112").isSelected()).toBe(true);
|
|
844
|
+
expect(tree.item("x113").isSelected()).toBe(true);
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
it("does not overwrite selection when dragging selected item with draggedItemOverwritesSelection=false", async () => {
|
|
848
|
+
const testTree = await tree
|
|
849
|
+
.with({ draggedItemOverwritesSelection: false })
|
|
850
|
+
.createTestCaseTree();
|
|
851
|
+
|
|
852
|
+
testTree.do.selectItem("x111");
|
|
853
|
+
testTree.do.ctrlSelectItem("x112");
|
|
854
|
+
testTree.do.ctrlSelectItem("x113");
|
|
855
|
+
|
|
856
|
+
expect(testTree.item("x111").isSelected()).toBe(true);
|
|
857
|
+
expect(testTree.item("x112").isSelected()).toBe(true);
|
|
858
|
+
expect(testTree.item("x113").isSelected()).toBe(true);
|
|
859
|
+
|
|
860
|
+
testTree.do.startDrag("x111");
|
|
861
|
+
|
|
862
|
+
expect(testTree.item("x111").isSelected()).toBe(true);
|
|
863
|
+
expect(testTree.item("x112").isSelected()).toBe(true);
|
|
864
|
+
expect(testTree.item("x113").isSelected()).toBe(true);
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
it("drags all selected items when draggedItemOverwritesSelection=false", async () => {
|
|
868
|
+
const testTree = await tree
|
|
869
|
+
.with({ draggedItemOverwritesSelection: false })
|
|
870
|
+
.createTestCaseTree();
|
|
871
|
+
|
|
872
|
+
testTree.do.selectItem("x111");
|
|
873
|
+
testTree.do.ctrlSelectItem("x112");
|
|
874
|
+
testTree.do.ctrlSelectItem("x113");
|
|
875
|
+
|
|
876
|
+
testTree.do.startDrag("x111");
|
|
877
|
+
testTree.do.dragOverAndDrop("x21");
|
|
878
|
+
|
|
879
|
+
testTree.expect.dropped(["x111", "x112", "x113"], {
|
|
880
|
+
item: testTree.item("x21"),
|
|
881
|
+
});
|
|
882
|
+
});
|
|
883
|
+
});
|
|
742
884
|
});
|
|
743
885
|
});
|
|
@@ -57,6 +57,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
57
57
|
setDndState: makeStateUpdater("dnd", tree),
|
|
58
58
|
canReorder: true,
|
|
59
59
|
openOnDropDelay: 800,
|
|
60
|
+
draggedItemOverwritesSelection: true,
|
|
60
61
|
...defaultConfig,
|
|
61
62
|
}),
|
|
62
63
|
|
|
@@ -178,47 +179,10 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
178
179
|
itemInstance: {
|
|
179
180
|
getProps: ({ tree, item, prev }) => ({
|
|
180
181
|
...prev?.(),
|
|
181
|
-
|
|
182
|
-
draggable: true,
|
|
182
|
+
...(tree.getConfig().seperateDragHandle ? {} : item.getDragHandleProps()),
|
|
183
183
|
|
|
184
184
|
onDragEnter: (e: DragEvent) => e.preventDefault(),
|
|
185
185
|
|
|
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
186
|
onDragOver: (e: DragEvent) => {
|
|
223
187
|
e.stopPropagation(); // don't bubble up to container dragover
|
|
224
188
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
@@ -277,27 +241,6 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
277
241
|
}, 100);
|
|
278
242
|
},
|
|
279
243
|
|
|
280
|
-
onDragEnd: (e: DragEvent) => {
|
|
281
|
-
const { onCompleteForeignDrop, canDragForeignDragObjectOver } =
|
|
282
|
-
tree.getConfig();
|
|
283
|
-
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
284
|
-
|
|
285
|
-
if (e.dataTransfer?.dropEffect === "none" || !draggedItems) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const target = getDragTarget(e, item, tree, false);
|
|
290
|
-
if (
|
|
291
|
-
canDragForeignDragObjectOver &&
|
|
292
|
-
e.dataTransfer &&
|
|
293
|
-
!canDragForeignDragObjectOver(e.dataTransfer, target)
|
|
294
|
-
) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
onCompleteForeignDrop?.(draggedItems);
|
|
299
|
-
},
|
|
300
|
-
|
|
301
244
|
onDrop: async (e: DragEvent) => {
|
|
302
245
|
e.stopPropagation();
|
|
303
246
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
@@ -332,6 +275,72 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
332
275
|
},
|
|
333
276
|
}),
|
|
334
277
|
|
|
278
|
+
getDragHandleProps: ({ tree, item, prev }) => ({
|
|
279
|
+
...prev?.(),
|
|
280
|
+
|
|
281
|
+
draggable: true,
|
|
282
|
+
|
|
283
|
+
onDragStart: (e: DragEvent) => {
|
|
284
|
+
const { draggedItemOverwritesSelection } = tree.getConfig();
|
|
285
|
+
const selectedItems = tree.getSelectedItems
|
|
286
|
+
? tree.getSelectedItems()
|
|
287
|
+
: [tree.getFocusedItem()];
|
|
288
|
+
const overwriteSelection =
|
|
289
|
+
!selectedItems.includes(item) && draggedItemOverwritesSelection;
|
|
290
|
+
const items = overwriteSelection ? [item] : selectedItems;
|
|
291
|
+
const config = tree.getConfig();
|
|
292
|
+
|
|
293
|
+
if (overwriteSelection) {
|
|
294
|
+
tree.setSelectedItems?.([item.getItemMeta().itemId]);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!(config.canDrag?.(items) ?? true)) {
|
|
298
|
+
e.preventDefault();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (config.setDragImage) {
|
|
303
|
+
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
304
|
+
e.dataTransfer?.setDragImage(imgElement, xOffset ?? 0, yOffset ?? 0);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (config.createForeignDragObject && e.dataTransfer) {
|
|
308
|
+
const { format, data, dropEffect, effectAllowed } =
|
|
309
|
+
config.createForeignDragObject(items);
|
|
310
|
+
e.dataTransfer.setData(format, data);
|
|
311
|
+
|
|
312
|
+
if (dropEffect) e.dataTransfer.dropEffect = dropEffect;
|
|
313
|
+
if (effectAllowed) e.dataTransfer.effectAllowed = effectAllowed;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
tree.applySubStateUpdate("dnd", {
|
|
317
|
+
draggedItems: items,
|
|
318
|
+
draggingOverItem: tree.getFocusedItem(),
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
onDragEnd: (e: DragEvent) => {
|
|
323
|
+
const { onCompleteForeignDrop, canDragForeignDragObjectOver } =
|
|
324
|
+
tree.getConfig();
|
|
325
|
+
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
326
|
+
|
|
327
|
+
if (e.dataTransfer?.dropEffect === "none" || !draggedItems) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const target = getDragTarget(e, item, tree, false);
|
|
332
|
+
if (
|
|
333
|
+
canDragForeignDragObjectOver &&
|
|
334
|
+
e.dataTransfer &&
|
|
335
|
+
!canDragForeignDragObjectOver(e.dataTransfer, target)
|
|
336
|
+
) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
onCompleteForeignDrop?.(draggedItems);
|
|
341
|
+
},
|
|
342
|
+
}),
|
|
343
|
+
|
|
335
344
|
isDragTarget: ({ tree, item }) => {
|
|
336
345
|
const target = tree.getDragTarget();
|
|
337
346
|
return target ? target.item.getId() === item.getId() : false;
|
|
@@ -97,6 +97,13 @@ 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;
|
|
103
|
+
|
|
104
|
+
/** If true, the item that is dragged is not selected, the selected items will be overwritten to just the dragged item.
|
|
105
|
+
* Defaults to true */
|
|
106
|
+
draggedItemOverwritesSelection?: boolean;
|
|
100
107
|
};
|
|
101
108
|
treeInstance: {
|
|
102
109
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -118,6 +125,10 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
118
125
|
isDragTargetAbove: () => boolean;
|
|
119
126
|
isDragTargetBelow: () => boolean;
|
|
120
127
|
isDraggingOver: () => boolean;
|
|
128
|
+
|
|
129
|
+
/** Note that `item.getProps()` already passes in all drag event handlers by default. Set `seperateDragHandle` to true to
|
|
130
|
+
* disable the default behavior and use this on the handler element instead. */
|
|
131
|
+
getDragHandleProps: () => Record<string, any>;
|
|
121
132
|
};
|
|
122
133
|
hotkeys: never;
|
|
123
134
|
};
|
|
@@ -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?.() ?? {};
|