@headless-tree/core 1.3.0 → 1.4.0
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 +12 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +40 -14
- package/dist/index.mjs +40 -14
- package/package.json +1 -1
- package/src/features/drag-and-drop/feature.ts +56 -8
- package/src/features/drag-and-drop/types.ts +4 -0
- package/src/features/drag-and-drop/utils.ts +8 -6
- package/src/features/keyboard-drag-and-drop/feature.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
+
## 1.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7ef4864: added feature where closed items are auto-expanded briefly after dragging onto them. set config option `openOnDropDelay` to zero to disable.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 8d53b4f: fixed a bug where external changes to focused or selected items don't trigger a rerender (#150)
|
|
12
|
+
- 1cee368: fixed a bug where the drag line is not cleared after drop (#149)
|
|
13
|
+
- 1e833bb: drag-and-drop feature is no longer dependent on selection feature, and fill default to focused item if selection feature is missing (#143)
|
|
14
|
+
|
|
3
15
|
## 1.3.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,7 @@ interface DndDataRef {
|
|
|
2
2
|
lastDragCode?: string;
|
|
3
3
|
lastAllowDrop?: boolean;
|
|
4
4
|
lastDragEnter?: number;
|
|
5
|
+
autoExpandTimeout?: any;
|
|
5
6
|
windowDragEndListener?: () => void;
|
|
6
7
|
}
|
|
7
8
|
interface DndState<T> {
|
|
@@ -65,6 +66,8 @@ type DragAndDropFeatureDef<T> = {
|
|
|
65
66
|
onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
|
|
66
67
|
onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
|
|
67
68
|
onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
|
|
69
|
+
/** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
|
|
70
|
+
openOnDropDelay?: number;
|
|
68
71
|
};
|
|
69
72
|
treeInstance: {
|
|
70
73
|
getDragTarget: () => DragTarget<T> | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ interface DndDataRef {
|
|
|
2
2
|
lastDragCode?: string;
|
|
3
3
|
lastAllowDrop?: boolean;
|
|
4
4
|
lastDragEnter?: number;
|
|
5
|
+
autoExpandTimeout?: any;
|
|
5
6
|
windowDragEndListener?: () => void;
|
|
6
7
|
}
|
|
7
8
|
interface DndState<T> {
|
|
@@ -65,6 +66,8 @@ type DragAndDropFeatureDef<T> = {
|
|
|
65
66
|
onDrop?: (items: ItemInstance<T>[], target: DragTarget<T>) => void | Promise<void>;
|
|
66
67
|
onDropForeignDragObject?: (dataTransfer: DataTransfer, target: DragTarget<T>) => void | Promise<void>;
|
|
67
68
|
onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
|
|
69
|
+
/** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
|
|
70
|
+
openOnDropDelay?: number;
|
|
68
71
|
};
|
|
69
72
|
treeInstance: {
|
|
70
73
|
getDragTarget: () => DragTarget<T> | null;
|
package/dist/index.js
CHANGED
|
@@ -1296,8 +1296,7 @@ var getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
|
1296
1296
|
}
|
|
1297
1297
|
return { type: makeChildType };
|
|
1298
1298
|
};
|
|
1299
|
-
var getDragCode = (
|
|
1300
|
-
const placement = getTargetPlacement(e, item, tree, true);
|
|
1299
|
+
var getDragCode = (item, placement) => {
|
|
1301
1300
|
return [
|
|
1302
1301
|
item.getId(),
|
|
1303
1302
|
placement.type,
|
|
@@ -1338,6 +1337,9 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1338
1337
|
const canMakeChild = canDrop(e.dataTransfer, itemTarget, tree);
|
|
1339
1338
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1340
1339
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1340
|
+
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
1341
|
+
return itemTarget;
|
|
1342
|
+
}
|
|
1341
1343
|
return parentTarget;
|
|
1342
1344
|
}
|
|
1343
1345
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
@@ -1372,16 +1374,29 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1372
1374
|
};
|
|
1373
1375
|
|
|
1374
1376
|
// src/features/drag-and-drop/feature.ts
|
|
1377
|
+
var handleAutoOpenFolder = (dataRef, tree, item, placement) => {
|
|
1378
|
+
const { openOnDropDelay } = tree.getConfig();
|
|
1379
|
+
const dragCode = dataRef.current.lastDragCode;
|
|
1380
|
+
if (!openOnDropDelay || !item.isFolder() || item.isExpanded() || placement.type !== 2 /* MakeChild */) {
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
clearTimeout(dataRef.current.autoExpandTimeout);
|
|
1384
|
+
dataRef.current.autoExpandTimeout = setTimeout(() => {
|
|
1385
|
+
if (dragCode !== dataRef.current.lastDragCode || !dataRef.current.lastAllowDrop)
|
|
1386
|
+
return;
|
|
1387
|
+
item.expand();
|
|
1388
|
+
}, openOnDropDelay);
|
|
1389
|
+
};
|
|
1375
1390
|
var defaultCanDropForeignDragObject = () => false;
|
|
1376
1391
|
var dragAndDropFeature = {
|
|
1377
1392
|
key: "drag-and-drop",
|
|
1378
|
-
deps: ["selection"],
|
|
1379
1393
|
getDefaultConfig: (defaultConfig, tree) => __spreadValues({
|
|
1380
1394
|
canDrop: (_, target) => target.item.isFolder(),
|
|
1381
1395
|
canDropForeignDragObject: defaultCanDropForeignDragObject,
|
|
1382
1396
|
canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
|
|
1383
1397
|
setDndState: makeStateUpdater("dnd", tree),
|
|
1384
|
-
canReorder: true
|
|
1398
|
+
canReorder: true,
|
|
1399
|
+
openOnDropDelay: 800
|
|
1385
1400
|
}, defaultConfig),
|
|
1386
1401
|
stateHandlerNames: {
|
|
1387
1402
|
dnd: "setDndState"
|
|
@@ -1422,7 +1437,7 @@ var dragAndDropFeature = {
|
|
|
1422
1437
|
};
|
|
1423
1438
|
}
|
|
1424
1439
|
}
|
|
1425
|
-
const bb = (_f = targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1440
|
+
const bb = (_f = targetItem == null ? void 0 : targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1426
1441
|
if (bb) {
|
|
1427
1442
|
return {
|
|
1428
1443
|
indent,
|
|
@@ -1478,20 +1493,20 @@ var dragAndDropFeature = {
|
|
|
1478
1493
|
draggable: true,
|
|
1479
1494
|
onDragEnter: (e) => e.preventDefault(),
|
|
1480
1495
|
onDragStart: (e) => {
|
|
1481
|
-
var _a, _b, _c;
|
|
1482
|
-
const selectedItems = tree.getSelectedItems();
|
|
1496
|
+
var _a, _b, _c, _d;
|
|
1497
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1483
1498
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1484
1499
|
const config = tree.getConfig();
|
|
1485
1500
|
if (!selectedItems.includes(item)) {
|
|
1486
|
-
tree.setSelectedItems([item.getItemMeta().itemId]);
|
|
1501
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1487
1502
|
}
|
|
1488
|
-
if (!((
|
|
1503
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1489
1504
|
e.preventDefault();
|
|
1490
1505
|
return;
|
|
1491
1506
|
}
|
|
1492
1507
|
if (config.setDragImage) {
|
|
1493
1508
|
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1494
|
-
(
|
|
1509
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1495
1510
|
}
|
|
1496
1511
|
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1497
1512
|
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
@@ -1508,7 +1523,8 @@ var dragAndDropFeature = {
|
|
|
1508
1523
|
var _a, _b, _c;
|
|
1509
1524
|
e.stopPropagation();
|
|
1510
1525
|
const dataRef = tree.getDataRef();
|
|
1511
|
-
const
|
|
1526
|
+
const placement = getTargetPlacement(e, item, tree, true);
|
|
1527
|
+
const nextDragCode = getDragCode(item, placement);
|
|
1512
1528
|
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
1513
1529
|
if (dataRef.current.lastAllowDrop) {
|
|
1514
1530
|
e.preventDefault();
|
|
@@ -1517,6 +1533,7 @@ var dragAndDropFeature = {
|
|
|
1517
1533
|
}
|
|
1518
1534
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1519
1535
|
dataRef.current.lastDragEnter = Date.now();
|
|
1536
|
+
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1520
1537
|
const target = getDragTarget(e, item, tree);
|
|
1521
1538
|
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)))) {
|
|
1522
1539
|
dataRef.current.lastAllowDrop = false;
|
|
@@ -1563,12 +1580,18 @@ var dragAndDropFeature = {
|
|
|
1563
1580
|
e.stopPropagation();
|
|
1564
1581
|
const dataRef = tree.getDataRef();
|
|
1565
1582
|
const target = getDragTarget(e, item, tree);
|
|
1566
|
-
|
|
1583
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1584
|
+
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1585
|
+
tree.applySubStateUpdate("dnd", {
|
|
1586
|
+
draggedItems: void 0,
|
|
1587
|
+
draggingOverItem: void 0,
|
|
1588
|
+
dragTarget: void 0
|
|
1589
|
+
});
|
|
1590
|
+
if (!isValidDrop) {
|
|
1567
1591
|
return;
|
|
1568
1592
|
}
|
|
1569
1593
|
e.preventDefault();
|
|
1570
1594
|
const config = tree.getConfig();
|
|
1571
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1572
1595
|
dataRef.current.lastDragCode = void 0;
|
|
1573
1596
|
if (draggedItems) {
|
|
1574
1597
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
@@ -1740,7 +1763,10 @@ var keyboardDragAndDropFeature = {
|
|
|
1740
1763
|
preventDefault: true,
|
|
1741
1764
|
isEnabled: (tree) => !tree.getState().dnd,
|
|
1742
1765
|
handler: (_, tree) => {
|
|
1743
|
-
|
|
1766
|
+
var _a, _b;
|
|
1767
|
+
const selectedItems = (_b = (_a = tree.getSelectedItems) == null ? void 0 : _a.call(tree)) != null ? _b : [
|
|
1768
|
+
tree.getFocusedItem()
|
|
1769
|
+
];
|
|
1744
1770
|
const focusedItem = tree.getFocusedItem();
|
|
1745
1771
|
tree.startKeyboardDrag(
|
|
1746
1772
|
selectedItems.includes(focusedItem) ? selectedItems : selectedItems.concat(focusedItem)
|
package/dist/index.mjs
CHANGED
|
@@ -1252,8 +1252,7 @@ var getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
|
1252
1252
|
}
|
|
1253
1253
|
return { type: makeChildType };
|
|
1254
1254
|
};
|
|
1255
|
-
var getDragCode = (
|
|
1256
|
-
const placement = getTargetPlacement(e, item, tree, true);
|
|
1255
|
+
var getDragCode = (item, placement) => {
|
|
1257
1256
|
return [
|
|
1258
1257
|
item.getId(),
|
|
1259
1258
|
placement.type,
|
|
@@ -1294,6 +1293,9 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1294
1293
|
const canMakeChild = canDrop(e.dataTransfer, itemTarget, tree);
|
|
1295
1294
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1296
1295
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1296
|
+
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
1297
|
+
return itemTarget;
|
|
1298
|
+
}
|
|
1297
1299
|
return parentTarget;
|
|
1298
1300
|
}
|
|
1299
1301
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
@@ -1328,16 +1330,29 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1328
1330
|
};
|
|
1329
1331
|
|
|
1330
1332
|
// src/features/drag-and-drop/feature.ts
|
|
1333
|
+
var handleAutoOpenFolder = (dataRef, tree, item, placement) => {
|
|
1334
|
+
const { openOnDropDelay } = tree.getConfig();
|
|
1335
|
+
const dragCode = dataRef.current.lastDragCode;
|
|
1336
|
+
if (!openOnDropDelay || !item.isFolder() || item.isExpanded() || placement.type !== 2 /* MakeChild */) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
clearTimeout(dataRef.current.autoExpandTimeout);
|
|
1340
|
+
dataRef.current.autoExpandTimeout = setTimeout(() => {
|
|
1341
|
+
if (dragCode !== dataRef.current.lastDragCode || !dataRef.current.lastAllowDrop)
|
|
1342
|
+
return;
|
|
1343
|
+
item.expand();
|
|
1344
|
+
}, openOnDropDelay);
|
|
1345
|
+
};
|
|
1331
1346
|
var defaultCanDropForeignDragObject = () => false;
|
|
1332
1347
|
var dragAndDropFeature = {
|
|
1333
1348
|
key: "drag-and-drop",
|
|
1334
|
-
deps: ["selection"],
|
|
1335
1349
|
getDefaultConfig: (defaultConfig, tree) => __spreadValues({
|
|
1336
1350
|
canDrop: (_, target) => target.item.isFolder(),
|
|
1337
1351
|
canDropForeignDragObject: defaultCanDropForeignDragObject,
|
|
1338
1352
|
canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
|
|
1339
1353
|
setDndState: makeStateUpdater("dnd", tree),
|
|
1340
|
-
canReorder: true
|
|
1354
|
+
canReorder: true,
|
|
1355
|
+
openOnDropDelay: 800
|
|
1341
1356
|
}, defaultConfig),
|
|
1342
1357
|
stateHandlerNames: {
|
|
1343
1358
|
dnd: "setDndState"
|
|
@@ -1378,7 +1393,7 @@ var dragAndDropFeature = {
|
|
|
1378
1393
|
};
|
|
1379
1394
|
}
|
|
1380
1395
|
}
|
|
1381
|
-
const bb = (_f = targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1396
|
+
const bb = (_f = targetItem == null ? void 0 : targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1382
1397
|
if (bb) {
|
|
1383
1398
|
return {
|
|
1384
1399
|
indent,
|
|
@@ -1434,20 +1449,20 @@ var dragAndDropFeature = {
|
|
|
1434
1449
|
draggable: true,
|
|
1435
1450
|
onDragEnter: (e) => e.preventDefault(),
|
|
1436
1451
|
onDragStart: (e) => {
|
|
1437
|
-
var _a, _b, _c;
|
|
1438
|
-
const selectedItems = tree.getSelectedItems();
|
|
1452
|
+
var _a, _b, _c, _d;
|
|
1453
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1439
1454
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1440
1455
|
const config = tree.getConfig();
|
|
1441
1456
|
if (!selectedItems.includes(item)) {
|
|
1442
|
-
tree.setSelectedItems([item.getItemMeta().itemId]);
|
|
1457
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1443
1458
|
}
|
|
1444
|
-
if (!((
|
|
1459
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1445
1460
|
e.preventDefault();
|
|
1446
1461
|
return;
|
|
1447
1462
|
}
|
|
1448
1463
|
if (config.setDragImage) {
|
|
1449
1464
|
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1450
|
-
(
|
|
1465
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1451
1466
|
}
|
|
1452
1467
|
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1453
1468
|
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
@@ -1464,7 +1479,8 @@ var dragAndDropFeature = {
|
|
|
1464
1479
|
var _a, _b, _c;
|
|
1465
1480
|
e.stopPropagation();
|
|
1466
1481
|
const dataRef = tree.getDataRef();
|
|
1467
|
-
const
|
|
1482
|
+
const placement = getTargetPlacement(e, item, tree, true);
|
|
1483
|
+
const nextDragCode = getDragCode(item, placement);
|
|
1468
1484
|
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
1469
1485
|
if (dataRef.current.lastAllowDrop) {
|
|
1470
1486
|
e.preventDefault();
|
|
@@ -1473,6 +1489,7 @@ var dragAndDropFeature = {
|
|
|
1473
1489
|
}
|
|
1474
1490
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1475
1491
|
dataRef.current.lastDragEnter = Date.now();
|
|
1492
|
+
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1476
1493
|
const target = getDragTarget(e, item, tree);
|
|
1477
1494
|
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)))) {
|
|
1478
1495
|
dataRef.current.lastAllowDrop = false;
|
|
@@ -1519,12 +1536,18 @@ var dragAndDropFeature = {
|
|
|
1519
1536
|
e.stopPropagation();
|
|
1520
1537
|
const dataRef = tree.getDataRef();
|
|
1521
1538
|
const target = getDragTarget(e, item, tree);
|
|
1522
|
-
|
|
1539
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1540
|
+
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1541
|
+
tree.applySubStateUpdate("dnd", {
|
|
1542
|
+
draggedItems: void 0,
|
|
1543
|
+
draggingOverItem: void 0,
|
|
1544
|
+
dragTarget: void 0
|
|
1545
|
+
});
|
|
1546
|
+
if (!isValidDrop) {
|
|
1523
1547
|
return;
|
|
1524
1548
|
}
|
|
1525
1549
|
e.preventDefault();
|
|
1526
1550
|
const config = tree.getConfig();
|
|
1527
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1528
1551
|
dataRef.current.lastDragCode = void 0;
|
|
1529
1552
|
if (draggedItems) {
|
|
1530
1553
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
@@ -1696,7 +1719,10 @@ var keyboardDragAndDropFeature = {
|
|
|
1696
1719
|
preventDefault: true,
|
|
1697
1720
|
isEnabled: (tree) => !tree.getState().dnd,
|
|
1698
1721
|
handler: (_, tree) => {
|
|
1699
|
-
|
|
1722
|
+
var _a, _b;
|
|
1723
|
+
const selectedItems = (_b = (_a = tree.getSelectedItems) == null ? void 0 : _a.call(tree)) != null ? _b : [
|
|
1724
|
+
tree.getFocusedItem()
|
|
1725
|
+
];
|
|
1700
1726
|
const focusedItem = tree.getFocusedItem();
|
|
1701
1727
|
tree.startKeyboardDrag(
|
|
1702
1728
|
selectedItems.includes(focusedItem) ? selectedItems : selectedItems.concat(focusedItem)
|
package/package.json
CHANGED
|
@@ -1,17 +1,51 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
FeatureImplementation,
|
|
3
|
+
type ItemInstance,
|
|
4
|
+
type TreeInstance,
|
|
5
|
+
} from "../../types/core";
|
|
2
6
|
import { DndDataRef, DragLineData, DragTarget } from "./types";
|
|
3
7
|
import {
|
|
8
|
+
PlacementType,
|
|
9
|
+
type TargetPlacement,
|
|
4
10
|
canDrop,
|
|
5
11
|
getDragCode,
|
|
6
12
|
getDragTarget,
|
|
13
|
+
getTargetPlacement,
|
|
7
14
|
isOrderedDragTarget,
|
|
8
15
|
} from "./utils";
|
|
9
16
|
import { makeStateUpdater } from "../../utils";
|
|
10
17
|
|
|
18
|
+
const handleAutoOpenFolder = (
|
|
19
|
+
dataRef: { current: DndDataRef },
|
|
20
|
+
tree: TreeInstance<any>,
|
|
21
|
+
item: ItemInstance<any>,
|
|
22
|
+
placement: TargetPlacement,
|
|
23
|
+
) => {
|
|
24
|
+
const { openOnDropDelay } = tree.getConfig();
|
|
25
|
+
const dragCode = dataRef.current.lastDragCode;
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
!openOnDropDelay ||
|
|
29
|
+
!item.isFolder() ||
|
|
30
|
+
item.isExpanded() ||
|
|
31
|
+
placement.type !== PlacementType.MakeChild
|
|
32
|
+
) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
clearTimeout(dataRef.current.autoExpandTimeout);
|
|
36
|
+
dataRef.current.autoExpandTimeout = setTimeout(() => {
|
|
37
|
+
if (
|
|
38
|
+
dragCode !== dataRef.current.lastDragCode ||
|
|
39
|
+
!dataRef.current.lastAllowDrop
|
|
40
|
+
)
|
|
41
|
+
return;
|
|
42
|
+
item.expand();
|
|
43
|
+
}, openOnDropDelay);
|
|
44
|
+
};
|
|
45
|
+
|
|
11
46
|
const defaultCanDropForeignDragObject = () => false;
|
|
12
47
|
export const dragAndDropFeature: FeatureImplementation = {
|
|
13
48
|
key: "drag-and-drop",
|
|
14
|
-
deps: ["selection"],
|
|
15
49
|
|
|
16
50
|
getDefaultConfig: (defaultConfig, tree) => ({
|
|
17
51
|
canDrop: (_, target) => target.item.isFolder(),
|
|
@@ -22,6 +56,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
22
56
|
: () => false,
|
|
23
57
|
setDndState: makeStateUpdater("dnd", tree),
|
|
24
58
|
canReorder: true,
|
|
59
|
+
openOnDropDelay: 800,
|
|
25
60
|
...defaultConfig,
|
|
26
61
|
}),
|
|
27
62
|
|
|
@@ -74,7 +109,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
74
109
|
}
|
|
75
110
|
}
|
|
76
111
|
|
|
77
|
-
const bb = targetItem
|
|
112
|
+
const bb = targetItem?.getElement()?.getBoundingClientRect();
|
|
78
113
|
|
|
79
114
|
if (bb) {
|
|
80
115
|
return {
|
|
@@ -149,12 +184,14 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
149
184
|
onDragEnter: (e: DragEvent) => e.preventDefault(),
|
|
150
185
|
|
|
151
186
|
onDragStart: (e: DragEvent) => {
|
|
152
|
-
const selectedItems = tree.getSelectedItems
|
|
187
|
+
const selectedItems = tree.getSelectedItems
|
|
188
|
+
? tree.getSelectedItems()
|
|
189
|
+
: [tree.getFocusedItem()];
|
|
153
190
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
154
191
|
const config = tree.getConfig();
|
|
155
192
|
|
|
156
193
|
if (!selectedItems.includes(item)) {
|
|
157
|
-
tree.setSelectedItems([item.getItemMeta().itemId]);
|
|
194
|
+
tree.setSelectedItems?.([item.getItemMeta().itemId]);
|
|
158
195
|
}
|
|
159
196
|
|
|
160
197
|
if (!(config.canDrag?.(items) ?? true)) {
|
|
@@ -185,7 +222,9 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
185
222
|
onDragOver: (e: DragEvent) => {
|
|
186
223
|
e.stopPropagation(); // don't bubble up to container dragover
|
|
187
224
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
188
|
-
const
|
|
225
|
+
const placement = getTargetPlacement(e, item, tree, true);
|
|
226
|
+
const nextDragCode = getDragCode(item, placement);
|
|
227
|
+
|
|
189
228
|
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
190
229
|
if (dataRef.current.lastAllowDrop) {
|
|
191
230
|
e.preventDefault();
|
|
@@ -195,6 +234,8 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
195
234
|
dataRef.current.lastDragCode = nextDragCode;
|
|
196
235
|
dataRef.current.lastDragEnter = Date.now();
|
|
197
236
|
|
|
237
|
+
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
238
|
+
|
|
198
239
|
const target = getDragTarget(e, item, tree);
|
|
199
240
|
|
|
200
241
|
if (
|
|
@@ -260,14 +301,21 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
260
301
|
e.stopPropagation();
|
|
261
302
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
262
303
|
const target = getDragTarget(e, item, tree);
|
|
304
|
+
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
305
|
+
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
263
306
|
|
|
264
|
-
|
|
307
|
+
tree.applySubStateUpdate("dnd", {
|
|
308
|
+
draggedItems: undefined,
|
|
309
|
+
draggingOverItem: undefined,
|
|
310
|
+
dragTarget: undefined,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
if (!isValidDrop) {
|
|
265
314
|
return;
|
|
266
315
|
}
|
|
267
316
|
|
|
268
317
|
e.preventDefault();
|
|
269
318
|
const config = tree.getConfig();
|
|
270
|
-
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
271
319
|
|
|
272
320
|
dataRef.current.lastDragCode = undefined;
|
|
273
321
|
|
|
@@ -4,6 +4,7 @@ export interface DndDataRef {
|
|
|
4
4
|
lastDragCode?: string;
|
|
5
5
|
lastAllowDrop?: boolean;
|
|
6
6
|
lastDragEnter?: number;
|
|
7
|
+
autoExpandTimeout?: any;
|
|
7
8
|
windowDragEndListener?: () => void;
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -93,6 +94,9 @@ export type DragAndDropFeatureDef<T> = {
|
|
|
93
94
|
target: DragTarget<T>,
|
|
94
95
|
) => void | Promise<void>;
|
|
95
96
|
onCompleteForeignDrop?: (items: ItemInstance<T>[]) => void;
|
|
97
|
+
|
|
98
|
+
/** When dragging for this many ms on a closed folder, the folder will automatically open. Set to zero to disable. */
|
|
99
|
+
openOnDropDelay?: number;
|
|
96
100
|
};
|
|
97
101
|
treeInstance: {
|
|
98
102
|
getDragTarget: () => DragTarget<T> | null;
|
|
@@ -7,14 +7,14 @@ export enum ItemDropCategory {
|
|
|
7
7
|
LastInGroup,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
enum PlacementType {
|
|
10
|
+
export enum PlacementType {
|
|
11
11
|
ReorderAbove,
|
|
12
12
|
ReorderBelow,
|
|
13
13
|
MakeChild,
|
|
14
14
|
Reparent,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
type TargetPlacement =
|
|
17
|
+
export type TargetPlacement =
|
|
18
18
|
| {
|
|
19
19
|
type:
|
|
20
20
|
| PlacementType.ReorderAbove
|
|
@@ -95,7 +95,7 @@ export const getInsertionIndex = <T>(
|
|
|
95
95
|
return childIndex - numberOfDragItemsBeforeTarget;
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
-
const getTargetPlacement = (
|
|
98
|
+
export const getTargetPlacement = (
|
|
99
99
|
e: any,
|
|
100
100
|
item: ItemInstance<any>,
|
|
101
101
|
tree: TreeInstance<any>,
|
|
@@ -153,11 +153,9 @@ const getTargetPlacement = (
|
|
|
153
153
|
};
|
|
154
154
|
|
|
155
155
|
export const getDragCode = (
|
|
156
|
-
e: any,
|
|
157
156
|
item: ItemInstance<any>,
|
|
158
|
-
|
|
157
|
+
placement: TargetPlacement,
|
|
159
158
|
) => {
|
|
160
|
-
const placement = getTargetPlacement(e, item, tree, true);
|
|
161
159
|
return [
|
|
162
160
|
item.getId(),
|
|
163
161
|
placement.type,
|
|
@@ -222,6 +220,10 @@ export const getDragTarget = (
|
|
|
222
220
|
canBecomeSibling &&
|
|
223
221
|
placement.type !== PlacementType.MakeChild
|
|
224
222
|
) {
|
|
223
|
+
if (draggedItems?.some((item) => item.isDescendentOf(parent.getId()))) {
|
|
224
|
+
// dropping on itself should be illegal, return item, canDrop will then return false
|
|
225
|
+
return itemTarget;
|
|
226
|
+
}
|
|
225
227
|
return parentTarget;
|
|
226
228
|
}
|
|
227
229
|
|
|
@@ -191,7 +191,9 @@ export const keyboardDragAndDropFeature: FeatureImplementation = {
|
|
|
191
191
|
preventDefault: true,
|
|
192
192
|
isEnabled: (tree) => !tree.getState().dnd,
|
|
193
193
|
handler: (_, tree) => {
|
|
194
|
-
const selectedItems = tree.getSelectedItems()
|
|
194
|
+
const selectedItems = tree.getSelectedItems?.() ?? [
|
|
195
|
+
tree.getFocusedItem(),
|
|
196
|
+
];
|
|
195
197
|
const focusedItem = tree.getFocusedItem();
|
|
196
198
|
|
|
197
199
|
tree.startKeyboardDrag(
|