@headless-tree/core 0.0.0-20250807215101 → 0.0.0-20250818221556
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 +19 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +42 -15
- package/dist/index.mjs +42 -15
- 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/hotkeys-core/feature.ts +1 -0
- package/src/features/keyboard-drag-and-drop/feature.ts +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20250818221556
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 215ab4b: add a new symbol that can be used in hotkey configurations "metaorcontrol" that will trigger if either any windows control key or mac meta key is pressed (#141)
|
|
8
|
+
|
|
9
|
+
## 1.4.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 7ef4864: added feature where closed items are auto-expanded briefly after dragging onto them. set config option `openOnDropDelay` to zero to disable.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 8d53b4f: fixed a bug where external changes to focused or selected items don't trigger a rerender (#150)
|
|
18
|
+
- 1cee368: fixed a bug where the drag line is not cleared after drop (#149)
|
|
19
|
+
- 1e833bb: drag-and-drop feature is no longer dependent on selection feature, and fill default to focused item if selection feature is missing (#143)
|
|
20
|
+
|
|
21
|
+
## 1.3.0
|
|
4
22
|
|
|
5
23
|
### Minor Changes
|
|
6
24
|
|
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
|
@@ -929,7 +929,8 @@ var specialKeys = {
|
|
|
929
929
|
plus: /^(NumpadAdd|Plus)$/,
|
|
930
930
|
minus: /^(NumpadSubtract|Minus)$/,
|
|
931
931
|
control: /^(ControlLeft|ControlRight)$/,
|
|
932
|
-
shift: /^(ShiftLeft|ShiftRight)
|
|
932
|
+
shift: /^(ShiftLeft|ShiftRight)$/,
|
|
933
|
+
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/
|
|
933
934
|
};
|
|
934
935
|
var testHotkeyMatch = (pressedKeys, tree, hotkey) => {
|
|
935
936
|
const supposedKeys = hotkey.hotkey.toLowerCase().split("+");
|
|
@@ -1296,8 +1297,7 @@ var getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
|
1296
1297
|
}
|
|
1297
1298
|
return { type: makeChildType };
|
|
1298
1299
|
};
|
|
1299
|
-
var getDragCode = (
|
|
1300
|
-
const placement = getTargetPlacement(e, item, tree, true);
|
|
1300
|
+
var getDragCode = (item, placement) => {
|
|
1301
1301
|
return [
|
|
1302
1302
|
item.getId(),
|
|
1303
1303
|
placement.type,
|
|
@@ -1338,6 +1338,9 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1338
1338
|
const canMakeChild = canDrop(e.dataTransfer, itemTarget, tree);
|
|
1339
1339
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1340
1340
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1341
|
+
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
1342
|
+
return itemTarget;
|
|
1343
|
+
}
|
|
1341
1344
|
return parentTarget;
|
|
1342
1345
|
}
|
|
1343
1346
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
@@ -1372,16 +1375,29 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1372
1375
|
};
|
|
1373
1376
|
|
|
1374
1377
|
// src/features/drag-and-drop/feature.ts
|
|
1378
|
+
var handleAutoOpenFolder = (dataRef, tree, item, placement) => {
|
|
1379
|
+
const { openOnDropDelay } = tree.getConfig();
|
|
1380
|
+
const dragCode = dataRef.current.lastDragCode;
|
|
1381
|
+
if (!openOnDropDelay || !item.isFolder() || item.isExpanded() || placement.type !== 2 /* MakeChild */) {
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
clearTimeout(dataRef.current.autoExpandTimeout);
|
|
1385
|
+
dataRef.current.autoExpandTimeout = setTimeout(() => {
|
|
1386
|
+
if (dragCode !== dataRef.current.lastDragCode || !dataRef.current.lastAllowDrop)
|
|
1387
|
+
return;
|
|
1388
|
+
item.expand();
|
|
1389
|
+
}, openOnDropDelay);
|
|
1390
|
+
};
|
|
1375
1391
|
var defaultCanDropForeignDragObject = () => false;
|
|
1376
1392
|
var dragAndDropFeature = {
|
|
1377
1393
|
key: "drag-and-drop",
|
|
1378
|
-
deps: ["selection"],
|
|
1379
1394
|
getDefaultConfig: (defaultConfig, tree) => __spreadValues({
|
|
1380
1395
|
canDrop: (_, target) => target.item.isFolder(),
|
|
1381
1396
|
canDropForeignDragObject: defaultCanDropForeignDragObject,
|
|
1382
1397
|
canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
|
|
1383
1398
|
setDndState: makeStateUpdater("dnd", tree),
|
|
1384
|
-
canReorder: true
|
|
1399
|
+
canReorder: true,
|
|
1400
|
+
openOnDropDelay: 800
|
|
1385
1401
|
}, defaultConfig),
|
|
1386
1402
|
stateHandlerNames: {
|
|
1387
1403
|
dnd: "setDndState"
|
|
@@ -1422,7 +1438,7 @@ var dragAndDropFeature = {
|
|
|
1422
1438
|
};
|
|
1423
1439
|
}
|
|
1424
1440
|
}
|
|
1425
|
-
const bb = (_f = targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1441
|
+
const bb = (_f = targetItem == null ? void 0 : targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1426
1442
|
if (bb) {
|
|
1427
1443
|
return {
|
|
1428
1444
|
indent,
|
|
@@ -1478,20 +1494,20 @@ var dragAndDropFeature = {
|
|
|
1478
1494
|
draggable: true,
|
|
1479
1495
|
onDragEnter: (e) => e.preventDefault(),
|
|
1480
1496
|
onDragStart: (e) => {
|
|
1481
|
-
var _a, _b, _c;
|
|
1482
|
-
const selectedItems = tree.getSelectedItems();
|
|
1497
|
+
var _a, _b, _c, _d;
|
|
1498
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1483
1499
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1484
1500
|
const config = tree.getConfig();
|
|
1485
1501
|
if (!selectedItems.includes(item)) {
|
|
1486
|
-
tree.setSelectedItems([item.getItemMeta().itemId]);
|
|
1502
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1487
1503
|
}
|
|
1488
|
-
if (!((
|
|
1504
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1489
1505
|
e.preventDefault();
|
|
1490
1506
|
return;
|
|
1491
1507
|
}
|
|
1492
1508
|
if (config.setDragImage) {
|
|
1493
1509
|
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1494
|
-
(
|
|
1510
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1495
1511
|
}
|
|
1496
1512
|
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1497
1513
|
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
@@ -1508,7 +1524,8 @@ var dragAndDropFeature = {
|
|
|
1508
1524
|
var _a, _b, _c;
|
|
1509
1525
|
e.stopPropagation();
|
|
1510
1526
|
const dataRef = tree.getDataRef();
|
|
1511
|
-
const
|
|
1527
|
+
const placement = getTargetPlacement(e, item, tree, true);
|
|
1528
|
+
const nextDragCode = getDragCode(item, placement);
|
|
1512
1529
|
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
1513
1530
|
if (dataRef.current.lastAllowDrop) {
|
|
1514
1531
|
e.preventDefault();
|
|
@@ -1517,6 +1534,7 @@ var dragAndDropFeature = {
|
|
|
1517
1534
|
}
|
|
1518
1535
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1519
1536
|
dataRef.current.lastDragEnter = Date.now();
|
|
1537
|
+
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1520
1538
|
const target = getDragTarget(e, item, tree);
|
|
1521
1539
|
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
1540
|
dataRef.current.lastAllowDrop = false;
|
|
@@ -1563,12 +1581,18 @@ var dragAndDropFeature = {
|
|
|
1563
1581
|
e.stopPropagation();
|
|
1564
1582
|
const dataRef = tree.getDataRef();
|
|
1565
1583
|
const target = getDragTarget(e, item, tree);
|
|
1566
|
-
|
|
1584
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1585
|
+
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1586
|
+
tree.applySubStateUpdate("dnd", {
|
|
1587
|
+
draggedItems: void 0,
|
|
1588
|
+
draggingOverItem: void 0,
|
|
1589
|
+
dragTarget: void 0
|
|
1590
|
+
});
|
|
1591
|
+
if (!isValidDrop) {
|
|
1567
1592
|
return;
|
|
1568
1593
|
}
|
|
1569
1594
|
e.preventDefault();
|
|
1570
1595
|
const config = tree.getConfig();
|
|
1571
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1572
1596
|
dataRef.current.lastDragCode = void 0;
|
|
1573
1597
|
if (draggedItems) {
|
|
1574
1598
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
@@ -1740,7 +1764,10 @@ var keyboardDragAndDropFeature = {
|
|
|
1740
1764
|
preventDefault: true,
|
|
1741
1765
|
isEnabled: (tree) => !tree.getState().dnd,
|
|
1742
1766
|
handler: (_, tree) => {
|
|
1743
|
-
|
|
1767
|
+
var _a, _b;
|
|
1768
|
+
const selectedItems = (_b = (_a = tree.getSelectedItems) == null ? void 0 : _a.call(tree)) != null ? _b : [
|
|
1769
|
+
tree.getFocusedItem()
|
|
1770
|
+
];
|
|
1744
1771
|
const focusedItem = tree.getFocusedItem();
|
|
1745
1772
|
tree.startKeyboardDrag(
|
|
1746
1773
|
selectedItems.includes(focusedItem) ? selectedItems : selectedItems.concat(focusedItem)
|
package/dist/index.mjs
CHANGED
|
@@ -885,7 +885,8 @@ var specialKeys = {
|
|
|
885
885
|
plus: /^(NumpadAdd|Plus)$/,
|
|
886
886
|
minus: /^(NumpadSubtract|Minus)$/,
|
|
887
887
|
control: /^(ControlLeft|ControlRight)$/,
|
|
888
|
-
shift: /^(ShiftLeft|ShiftRight)
|
|
888
|
+
shift: /^(ShiftLeft|ShiftRight)$/,
|
|
889
|
+
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/
|
|
889
890
|
};
|
|
890
891
|
var testHotkeyMatch = (pressedKeys, tree, hotkey) => {
|
|
891
892
|
const supposedKeys = hotkey.hotkey.toLowerCase().split("+");
|
|
@@ -1252,8 +1253,7 @@ var getTargetPlacement = (e, item, tree, canMakeChild) => {
|
|
|
1252
1253
|
}
|
|
1253
1254
|
return { type: makeChildType };
|
|
1254
1255
|
};
|
|
1255
|
-
var getDragCode = (
|
|
1256
|
-
const placement = getTargetPlacement(e, item, tree, true);
|
|
1256
|
+
var getDragCode = (item, placement) => {
|
|
1257
1257
|
return [
|
|
1258
1258
|
item.getId(),
|
|
1259
1259
|
placement.type,
|
|
@@ -1294,6 +1294,9 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1294
1294
|
const canMakeChild = canDrop(e.dataTransfer, itemTarget, tree);
|
|
1295
1295
|
const placement = getTargetPlacement(e, item, tree, canMakeChild);
|
|
1296
1296
|
if (!canReorder && parent && canBecomeSibling && placement.type !== 2 /* MakeChild */) {
|
|
1297
|
+
if (draggedItems == null ? void 0 : draggedItems.some((item2) => item2.isDescendentOf(parent.getId()))) {
|
|
1298
|
+
return itemTarget;
|
|
1299
|
+
}
|
|
1297
1300
|
return parentTarget;
|
|
1298
1301
|
}
|
|
1299
1302
|
if (!canReorder && parent && !canBecomeSibling) {
|
|
@@ -1328,16 +1331,29 @@ var getDragTarget = (e, item, tree, canReorder = tree.getConfig().canReorder) =>
|
|
|
1328
1331
|
};
|
|
1329
1332
|
|
|
1330
1333
|
// src/features/drag-and-drop/feature.ts
|
|
1334
|
+
var handleAutoOpenFolder = (dataRef, tree, item, placement) => {
|
|
1335
|
+
const { openOnDropDelay } = tree.getConfig();
|
|
1336
|
+
const dragCode = dataRef.current.lastDragCode;
|
|
1337
|
+
if (!openOnDropDelay || !item.isFolder() || item.isExpanded() || placement.type !== 2 /* MakeChild */) {
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
clearTimeout(dataRef.current.autoExpandTimeout);
|
|
1341
|
+
dataRef.current.autoExpandTimeout = setTimeout(() => {
|
|
1342
|
+
if (dragCode !== dataRef.current.lastDragCode || !dataRef.current.lastAllowDrop)
|
|
1343
|
+
return;
|
|
1344
|
+
item.expand();
|
|
1345
|
+
}, openOnDropDelay);
|
|
1346
|
+
};
|
|
1331
1347
|
var defaultCanDropForeignDragObject = () => false;
|
|
1332
1348
|
var dragAndDropFeature = {
|
|
1333
1349
|
key: "drag-and-drop",
|
|
1334
|
-
deps: ["selection"],
|
|
1335
1350
|
getDefaultConfig: (defaultConfig, tree) => __spreadValues({
|
|
1336
1351
|
canDrop: (_, target) => target.item.isFolder(),
|
|
1337
1352
|
canDropForeignDragObject: defaultCanDropForeignDragObject,
|
|
1338
1353
|
canDragForeignDragObjectOver: defaultConfig.canDropForeignDragObject !== defaultCanDropForeignDragObject ? (dataTransfer) => dataTransfer.effectAllowed !== "none" : () => false,
|
|
1339
1354
|
setDndState: makeStateUpdater("dnd", tree),
|
|
1340
|
-
canReorder: true
|
|
1355
|
+
canReorder: true,
|
|
1356
|
+
openOnDropDelay: 800
|
|
1341
1357
|
}, defaultConfig),
|
|
1342
1358
|
stateHandlerNames: {
|
|
1343
1359
|
dnd: "setDndState"
|
|
@@ -1378,7 +1394,7 @@ var dragAndDropFeature = {
|
|
|
1378
1394
|
};
|
|
1379
1395
|
}
|
|
1380
1396
|
}
|
|
1381
|
-
const bb = (_f = targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1397
|
+
const bb = (_f = targetItem == null ? void 0 : targetItem.getElement()) == null ? void 0 : _f.getBoundingClientRect();
|
|
1382
1398
|
if (bb) {
|
|
1383
1399
|
return {
|
|
1384
1400
|
indent,
|
|
@@ -1434,20 +1450,20 @@ var dragAndDropFeature = {
|
|
|
1434
1450
|
draggable: true,
|
|
1435
1451
|
onDragEnter: (e) => e.preventDefault(),
|
|
1436
1452
|
onDragStart: (e) => {
|
|
1437
|
-
var _a, _b, _c;
|
|
1438
|
-
const selectedItems = tree.getSelectedItems();
|
|
1453
|
+
var _a, _b, _c, _d;
|
|
1454
|
+
const selectedItems = tree.getSelectedItems ? tree.getSelectedItems() : [tree.getFocusedItem()];
|
|
1439
1455
|
const items = selectedItems.includes(item) ? selectedItems : [item];
|
|
1440
1456
|
const config = tree.getConfig();
|
|
1441
1457
|
if (!selectedItems.includes(item)) {
|
|
1442
|
-
tree.setSelectedItems([item.getItemMeta().itemId]);
|
|
1458
|
+
(_a = tree.setSelectedItems) == null ? void 0 : _a.call(tree, [item.getItemMeta().itemId]);
|
|
1443
1459
|
}
|
|
1444
|
-
if (!((
|
|
1460
|
+
if (!((_c = (_b = config.canDrag) == null ? void 0 : _b.call(config, items)) != null ? _c : true)) {
|
|
1445
1461
|
e.preventDefault();
|
|
1446
1462
|
return;
|
|
1447
1463
|
}
|
|
1448
1464
|
if (config.setDragImage) {
|
|
1449
1465
|
const { imgElement, xOffset, yOffset } = config.setDragImage(items);
|
|
1450
|
-
(
|
|
1466
|
+
(_d = e.dataTransfer) == null ? void 0 : _d.setDragImage(imgElement, xOffset != null ? xOffset : 0, yOffset != null ? yOffset : 0);
|
|
1451
1467
|
}
|
|
1452
1468
|
if (config.createForeignDragObject && e.dataTransfer) {
|
|
1453
1469
|
const { format, data, dropEffect, effectAllowed } = config.createForeignDragObject(items);
|
|
@@ -1464,7 +1480,8 @@ var dragAndDropFeature = {
|
|
|
1464
1480
|
var _a, _b, _c;
|
|
1465
1481
|
e.stopPropagation();
|
|
1466
1482
|
const dataRef = tree.getDataRef();
|
|
1467
|
-
const
|
|
1483
|
+
const placement = getTargetPlacement(e, item, tree, true);
|
|
1484
|
+
const nextDragCode = getDragCode(item, placement);
|
|
1468
1485
|
if (nextDragCode === dataRef.current.lastDragCode) {
|
|
1469
1486
|
if (dataRef.current.lastAllowDrop) {
|
|
1470
1487
|
e.preventDefault();
|
|
@@ -1473,6 +1490,7 @@ var dragAndDropFeature = {
|
|
|
1473
1490
|
}
|
|
1474
1491
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1475
1492
|
dataRef.current.lastDragEnter = Date.now();
|
|
1493
|
+
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1476
1494
|
const target = getDragTarget(e, item, tree);
|
|
1477
1495
|
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
1496
|
dataRef.current.lastAllowDrop = false;
|
|
@@ -1519,12 +1537,18 @@ var dragAndDropFeature = {
|
|
|
1519
1537
|
e.stopPropagation();
|
|
1520
1538
|
const dataRef = tree.getDataRef();
|
|
1521
1539
|
const target = getDragTarget(e, item, tree);
|
|
1522
|
-
|
|
1540
|
+
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1541
|
+
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1542
|
+
tree.applySubStateUpdate("dnd", {
|
|
1543
|
+
draggedItems: void 0,
|
|
1544
|
+
draggingOverItem: void 0,
|
|
1545
|
+
dragTarget: void 0
|
|
1546
|
+
});
|
|
1547
|
+
if (!isValidDrop) {
|
|
1523
1548
|
return;
|
|
1524
1549
|
}
|
|
1525
1550
|
e.preventDefault();
|
|
1526
1551
|
const config = tree.getConfig();
|
|
1527
|
-
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1528
1552
|
dataRef.current.lastDragCode = void 0;
|
|
1529
1553
|
if (draggedItems) {
|
|
1530
1554
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
@@ -1696,7 +1720,10 @@ var keyboardDragAndDropFeature = {
|
|
|
1696
1720
|
preventDefault: true,
|
|
1697
1721
|
isEnabled: (tree) => !tree.getState().dnd,
|
|
1698
1722
|
handler: (_, tree) => {
|
|
1699
|
-
|
|
1723
|
+
var _a, _b;
|
|
1724
|
+
const selectedItems = (_b = (_a = tree.getSelectedItems) == null ? void 0 : _a.call(tree)) != null ? _b : [
|
|
1725
|
+
tree.getFocusedItem()
|
|
1726
|
+
];
|
|
1700
1727
|
const focusedItem = tree.getFocusedItem();
|
|
1701
1728
|
tree.startKeyboardDrag(
|
|
1702
1729
|
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
|
|
|
@@ -13,6 +13,7 @@ const specialKeys: Record<string, RegExp> = {
|
|
|
13
13
|
minus: /^(NumpadSubtract|Minus)$/,
|
|
14
14
|
control: /^(ControlLeft|ControlRight)$/,
|
|
15
15
|
shift: /^(ShiftLeft|ShiftRight)$/,
|
|
16
|
+
metaorcontrol: /^(MetaLeft|MetaRight|ControlLeft|ControlRight)$/,
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
const testHotkeyMatch = (
|
|
@@ -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(
|