@headless-tree/core 0.0.0-20251215184014 → 0.0.0-20260107224057
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 +10 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +32 -20
- package/dist/index.mjs +32 -20
- package/package.json +1 -1
- package/src/features/async-data-loader/feature.ts +14 -8
- package/src/features/async-data-loader/types.ts +11 -3
- package/src/features/drag-and-drop/drag-and-drop.spec.ts +33 -2
- package/src/features/drag-and-drop/feature.ts +9 -4
- package/src/features/drag-and-drop/utils.ts +10 -4
- package/src/features/keyboard-drag-and-drop/feature.ts +1 -0
- package/src/features/tree/feature.ts +6 -2
- package/src/utils.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# @headless-tree/core
|
|
2
2
|
|
|
3
|
-
## 0.0.0-
|
|
3
|
+
## 0.0.0-20260107224057
|
|
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
|
+
|
|
12
|
+
## 1.6.1
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
|
6
15
|
|
package/dist/index.d.mts
CHANGED
|
@@ -329,9 +329,11 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
329
329
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
330
330
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
331
331
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
332
|
-
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
334
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
335
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
336
|
+
updateCachedChildrenIds: (childrenIds: string[], skipUpdateTree?: boolean) => void;
|
|
335
337
|
hasLoadedData: () => boolean;
|
|
336
338
|
isLoading: () => boolean;
|
|
337
339
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -329,9 +329,11 @@ type AsyncDataLoaderFeatureDef<T> = {
|
|
|
329
329
|
* @param optimistic If true, the item will not trigger a state update on `loadingItemChildrens`, and
|
|
330
330
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
331
331
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
332
|
-
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
333
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
334
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
335
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
336
|
+
updateCachedChildrenIds: (childrenIds: string[], skipUpdateTree?: boolean) => void;
|
|
335
337
|
hasLoadedData: () => boolean;
|
|
336
338
|
isLoading: () => boolean;
|
|
337
339
|
};
|
package/dist/index.js
CHANGED
|
@@ -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);
|
|
@@ -1657,12 +1665,12 @@ var dragAndDropFeature = {
|
|
|
1657
1665
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1658
1666
|
dataRef.current.lastDragEnter = Date.now();
|
|
1659
1667
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1660
|
-
const target = getDragTarget(e, item, tree);
|
|
1668
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1661
1669
|
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
1670
|
dataRef.current.lastAllowDrop = false;
|
|
1663
1671
|
return;
|
|
1664
1672
|
}
|
|
1665
|
-
if (!canDrop(
|
|
1673
|
+
if (!canDrop(null, target, tree)) {
|
|
1666
1674
|
dataRef.current.lastAllowDrop = false;
|
|
1667
1675
|
return;
|
|
1668
1676
|
}
|
|
@@ -1692,7 +1700,7 @@ var dragAndDropFeature = {
|
|
|
1692
1700
|
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1693
1701
|
return;
|
|
1694
1702
|
}
|
|
1695
|
-
const target = getDragTarget(e, item, tree);
|
|
1703
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1696
1704
|
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1697
1705
|
return;
|
|
1698
1706
|
}
|
|
@@ -1702,7 +1710,7 @@ var dragAndDropFeature = {
|
|
|
1702
1710
|
var _a, _b, _c;
|
|
1703
1711
|
e.stopPropagation();
|
|
1704
1712
|
const dataRef = tree.getDataRef();
|
|
1705
|
-
const target = getDragTarget(e, item, tree);
|
|
1713
|
+
const target = getDragTarget(e, item, tree, true);
|
|
1706
1714
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1707
1715
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1708
1716
|
tree.applySubStateUpdate("dnd", {
|
|
@@ -1718,9 +1726,12 @@ var dragAndDropFeature = {
|
|
|
1718
1726
|
dataRef.current.lastDragCode = void 0;
|
|
1719
1727
|
if (draggedItems) {
|
|
1720
1728
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
1729
|
+
draggedItems[0].setFocused();
|
|
1721
1730
|
} else if (e.dataTransfer) {
|
|
1722
1731
|
yield (_c = config.onDropForeignDragObject) == null ? void 0 : _c.call(config, e.dataTransfer, target);
|
|
1723
1732
|
}
|
|
1733
|
+
tree.applySubStateUpdate("dnd", null);
|
|
1734
|
+
tree.updateDomFocus();
|
|
1724
1735
|
})
|
|
1725
1736
|
}),
|
|
1726
1737
|
isDragTarget: ({ tree, item }) => {
|
|
@@ -1946,6 +1957,7 @@ var keyboardDragAndDropFeature = {
|
|
|
1946
1957
|
} else if (dataTransfer) {
|
|
1947
1958
|
yield (_d = config.onDropForeignDragObject) == null ? void 0 : _d.call(config, dataTransfer, target);
|
|
1948
1959
|
}
|
|
1960
|
+
tree.updateDomFocus();
|
|
1949
1961
|
tree.applySubStateUpdate(
|
|
1950
1962
|
"assistiveDndState",
|
|
1951
1963
|
3 /* Completed */
|
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);
|
|
@@ -1613,12 +1621,12 @@ var dragAndDropFeature = {
|
|
|
1613
1621
|
dataRef.current.lastDragCode = nextDragCode;
|
|
1614
1622
|
dataRef.current.lastDragEnter = Date.now();
|
|
1615
1623
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
1616
|
-
const target = getDragTarget(e, item, tree);
|
|
1624
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1617
1625
|
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
1626
|
dataRef.current.lastAllowDrop = false;
|
|
1619
1627
|
return;
|
|
1620
1628
|
}
|
|
1621
|
-
if (!canDrop(
|
|
1629
|
+
if (!canDrop(null, target, tree)) {
|
|
1622
1630
|
dataRef.current.lastAllowDrop = false;
|
|
1623
1631
|
return;
|
|
1624
1632
|
}
|
|
@@ -1648,7 +1656,7 @@ var dragAndDropFeature = {
|
|
|
1648
1656
|
if (((_b = e.dataTransfer) == null ? void 0 : _b.dropEffect) === "none" || !draggedItems) {
|
|
1649
1657
|
return;
|
|
1650
1658
|
}
|
|
1651
|
-
const target = getDragTarget(e, item, tree);
|
|
1659
|
+
const target = getDragTarget(e, item, tree, false);
|
|
1652
1660
|
if (canDragForeignDragObjectOver && e.dataTransfer && !canDragForeignDragObjectOver(e.dataTransfer, target)) {
|
|
1653
1661
|
return;
|
|
1654
1662
|
}
|
|
@@ -1658,7 +1666,7 @@ var dragAndDropFeature = {
|
|
|
1658
1666
|
var _a, _b, _c;
|
|
1659
1667
|
e.stopPropagation();
|
|
1660
1668
|
const dataRef = tree.getDataRef();
|
|
1661
|
-
const target = getDragTarget(e, item, tree);
|
|
1669
|
+
const target = getDragTarget(e, item, tree, true);
|
|
1662
1670
|
const draggedItems = (_a = tree.getState().dnd) == null ? void 0 : _a.draggedItems;
|
|
1663
1671
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
1664
1672
|
tree.applySubStateUpdate("dnd", {
|
|
@@ -1674,9 +1682,12 @@ var dragAndDropFeature = {
|
|
|
1674
1682
|
dataRef.current.lastDragCode = void 0;
|
|
1675
1683
|
if (draggedItems) {
|
|
1676
1684
|
yield (_b = config.onDrop) == null ? void 0 : _b.call(config, draggedItems, target);
|
|
1685
|
+
draggedItems[0].setFocused();
|
|
1677
1686
|
} else if (e.dataTransfer) {
|
|
1678
1687
|
yield (_c = config.onDropForeignDragObject) == null ? void 0 : _c.call(config, e.dataTransfer, target);
|
|
1679
1688
|
}
|
|
1689
|
+
tree.applySubStateUpdate("dnd", null);
|
|
1690
|
+
tree.updateDomFocus();
|
|
1680
1691
|
})
|
|
1681
1692
|
}),
|
|
1682
1693
|
isDragTarget: ({ tree, item }) => {
|
|
@@ -1902,6 +1913,7 @@ var keyboardDragAndDropFeature = {
|
|
|
1902
1913
|
} else if (dataTransfer) {
|
|
1903
1914
|
yield (_d = config.onDropForeignDragObject) == null ? void 0 : _d.call(config, dataTransfer, target);
|
|
1904
1915
|
}
|
|
1916
|
+
tree.updateDomFocus();
|
|
1905
1917
|
tree.applySubStateUpdate(
|
|
1906
1918
|
"assistiveDndState",
|
|
1907
1919
|
3 /* Completed */
|
package/package.json
CHANGED
|
@@ -180,15 +180,21 @@ export const asyncDataLoaderFeature: FeatureImplementation = {
|
|
|
180
180
|
}
|
|
181
181
|
await loadChildrenIds(tree, itemId);
|
|
182
182
|
},
|
|
183
|
-
updateCachedChildrenIds: (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
183
|
+
updateCachedChildrenIds: (
|
|
184
|
+
{ tree, itemId },
|
|
185
|
+
childrenIds,
|
|
186
|
+
skipUpdateTree,
|
|
187
|
+
) => {
|
|
188
|
+
getDataRef(tree).current.childrenIds[itemId] = childrenIds;
|
|
189
|
+
if (!skipUpdateTree) {
|
|
190
|
+
tree.rebuildTree();
|
|
191
|
+
}
|
|
187
192
|
},
|
|
188
|
-
updateCachedData: ({ tree, itemId }, data) => {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
updateCachedData: ({ tree, itemId }, data, skipUpdateTree) => {
|
|
194
|
+
getDataRef(tree).current.itemData[itemId] = data;
|
|
195
|
+
if (!skipUpdateTree) {
|
|
196
|
+
tree.rebuildTree();
|
|
197
|
+
}
|
|
192
198
|
},
|
|
193
199
|
hasLoadedData: ({ tree, itemId }) => {
|
|
194
200
|
const dataRef = tree.getDataRef<AsyncDataLoaderDataRef>();
|
|
@@ -39,6 +39,7 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
39
39
|
waitForItemChildrenLoaded: (itemId: string) => Promise<void>;
|
|
40
40
|
loadItemData: (itemId: string) => Promise<T>;
|
|
41
41
|
loadChildrenIds: (itemId: string) => Promise<string[]>;
|
|
42
|
+
|
|
42
43
|
/* idea: recursiveLoadItems: (itemId: string, cancelToken?: { current: boolean }, onLoad: (itemIds: string[]) => void) => Promise<T[]> */
|
|
43
44
|
};
|
|
44
45
|
itemInstance: SyncDataLoaderFeatureDef<T>["itemInstance"] & {
|
|
@@ -52,9 +53,16 @@ export type AsyncDataLoaderFeatureDef<T> = {
|
|
|
52
53
|
* the tree will continue to display the old data until the new data has loaded. */
|
|
53
54
|
invalidateChildrenIds: (optimistic?: boolean) => Promise<void>;
|
|
54
55
|
|
|
55
|
-
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
/** Set to undefined to clear cache without triggering automatic refetch. Use @invalidateItemData to clear and triggering refetch.
|
|
57
|
+
* @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
58
|
+
updateCachedData: (data: T | undefined, skipUpdateTree?: boolean) => void;
|
|
59
|
+
|
|
60
|
+
/** @param skipUpdateTree If true, the tree will not rebuild the tree structure cache afterwards by calling `tree.rebuildTree()`. */
|
|
61
|
+
updateCachedChildrenIds: (
|
|
62
|
+
childrenIds: string[],
|
|
63
|
+
skipUpdateTree?: boolean,
|
|
64
|
+
) => void;
|
|
65
|
+
|
|
58
66
|
hasLoadedData: () => boolean;
|
|
59
67
|
isLoading: () => boolean;
|
|
60
68
|
};
|
|
@@ -328,8 +328,7 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
328
328
|
"onDropForeignDragObject",
|
|
329
329
|
);
|
|
330
330
|
const event = tree.createBottomDragEvent(2);
|
|
331
|
-
tree.setElementBoundingBox("
|
|
332
|
-
tree.setElementBoundingBox("x213");
|
|
331
|
+
tree.setElementBoundingBox("x112");
|
|
333
332
|
tree.do.dragOver("x112", event);
|
|
334
333
|
tree.do.drop("x112", event);
|
|
335
334
|
expect(onDropForeignDragObject).toHaveBeenCalledWith(
|
|
@@ -357,6 +356,38 @@ describe("core-feature/drag-and-drop", () => {
|
|
|
357
356
|
tree.do.drop("x11", event);
|
|
358
357
|
expect(onDropForeignDragObject).not.toHaveBeenCalled();
|
|
359
358
|
});
|
|
359
|
+
|
|
360
|
+
it("calls canDragForeignDragObjectOver in drag over events, not canDropForeignDragObject", () => {
|
|
361
|
+
const canDropForeignDragObject = tree
|
|
362
|
+
.mockedHandler("canDropForeignDragObject")
|
|
363
|
+
.mockReturnValue(true);
|
|
364
|
+
const canDragForeignDragObjectOver = tree
|
|
365
|
+
.mockedHandler("canDragForeignDragObjectOver")
|
|
366
|
+
.mockReturnValue(true);
|
|
367
|
+
const event = TestTree.dragEvent();
|
|
368
|
+
tree.do.dragOver("x11", event);
|
|
369
|
+
expect(canDragForeignDragObjectOver).toHaveBeenCalledWith(
|
|
370
|
+
event.dataTransfer,
|
|
371
|
+
{ item: tree.item("x11") },
|
|
372
|
+
);
|
|
373
|
+
expect(canDropForeignDragObject).not.toHaveBeenCalled();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("calls canDropForeignDragObject in drop events, not canDragForeignDragObjectOver", () => {
|
|
377
|
+
const canDropForeignDragObject = tree
|
|
378
|
+
.mockedHandler("canDropForeignDragObject")
|
|
379
|
+
.mockReturnValue(true);
|
|
380
|
+
const canDragForeignDragObjectOver = tree
|
|
381
|
+
.mockedHandler("canDragForeignDragObjectOver")
|
|
382
|
+
.mockReturnValue(true);
|
|
383
|
+
const event = TestTree.dragEvent();
|
|
384
|
+
tree.do.drop("x11", event);
|
|
385
|
+
expect(canDropForeignDragObject).toHaveBeenCalledWith(
|
|
386
|
+
event.dataTransfer,
|
|
387
|
+
{ item: tree.item("x11") },
|
|
388
|
+
);
|
|
389
|
+
expect(canDragForeignDragObjectOver).not.toHaveBeenCalled();
|
|
390
|
+
});
|
|
360
391
|
});
|
|
361
392
|
|
|
362
393
|
describe("with insertion handlers", () => {
|
|
@@ -236,7 +236,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
236
236
|
|
|
237
237
|
handleAutoOpenFolder(dataRef, tree, item, placement);
|
|
238
238
|
|
|
239
|
-
const target = getDragTarget(e, item, tree);
|
|
239
|
+
const target = getDragTarget(e, item, tree, false);
|
|
240
240
|
|
|
241
241
|
if (
|
|
242
242
|
!tree.getState().dnd?.draggedItems &&
|
|
@@ -249,7 +249,8 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
249
249
|
return;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
// dataTransfer.payload is not accessible in onDragOver, so just skip entirely here. It'll be checked again in onDrop
|
|
253
|
+
if (!canDrop(null, target, tree)) {
|
|
253
254
|
dataRef.current.lastAllowDrop = false;
|
|
254
255
|
return;
|
|
255
256
|
}
|
|
@@ -285,7 +286,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
285
286
|
return;
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
const target = getDragTarget(e, item, tree);
|
|
289
|
+
const target = getDragTarget(e, item, tree, false);
|
|
289
290
|
if (
|
|
290
291
|
canDragForeignDragObjectOver &&
|
|
291
292
|
e.dataTransfer &&
|
|
@@ -300,7 +301,7 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
300
301
|
onDrop: async (e: DragEvent) => {
|
|
301
302
|
e.stopPropagation();
|
|
302
303
|
const dataRef = tree.getDataRef<DndDataRef>();
|
|
303
|
-
const target = getDragTarget(e, item, tree);
|
|
304
|
+
const target = getDragTarget(e, item, tree, true);
|
|
304
305
|
const draggedItems = tree.getState().dnd?.draggedItems;
|
|
305
306
|
const isValidDrop = canDrop(e.dataTransfer, target, tree);
|
|
306
307
|
|
|
@@ -321,9 +322,13 @@ export const dragAndDropFeature: FeatureImplementation = {
|
|
|
321
322
|
|
|
322
323
|
if (draggedItems) {
|
|
323
324
|
await config.onDrop?.(draggedItems, target);
|
|
325
|
+
draggedItems[0].setFocused();
|
|
324
326
|
} else if (e.dataTransfer) {
|
|
325
327
|
await config.onDropForeignDragObject?.(e.dataTransfer, target);
|
|
326
328
|
}
|
|
329
|
+
|
|
330
|
+
tree.applySubStateUpdate("dnd", null);
|
|
331
|
+
tree.updateDomFocus();
|
|
327
332
|
},
|
|
328
333
|
}),
|
|
329
334
|
|
|
@@ -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,
|
|
@@ -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
|
},
|