Skip to content

Commit 8dc435a

Browse files
committed
fix: dropping on self-parent through keyboard interaction (#363)
1 parent ef61c8e commit 8dc435a

File tree

4 files changed

+90
-43
lines changed

4 files changed

+90
-43
lines changed

next-release-notes.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
### Bug Fixes and Improvements
2-
- Fixes an issue where not providing a submit button ref in a custom rename input renderer would prevent dismissing the input on blur (#368)
2+
- Fixes an issue where not providing a submit button ref in a custom rename input renderer would prevent dismissing the input on blur (#368)
3+
- Fixes an issue where dropping an item on its children was possible through keyboard-based dragging (#363)

packages/core/src/drag/DraggingPositionEvaluation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export class DraggingPositionEvaluation {
298298
treeId
299299
);
300300

301-
if (potentialParents.find(p => p.index === parent.item)) {
301+
if (potentialParents.some(p => p.index === parent.item)) {
302302
return true;
303303
}
304304

packages/core/src/drag/useCanDropAt.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ export const useCanDropAt = () => {
2020
if (
2121
!resolvedItem ||
2222
(!environment.canDropOnFolder && resolvedItem.isFolder) ||
23-
(!environment.canDropOnNonFolder && !resolvedItem.isFolder)
23+
(!environment.canDropOnNonFolder && !resolvedItem.isFolder) ||
24+
draggingItems.some(
25+
draggingItem => draggingItem.index === draggingPosition.targetItem
26+
)
2427
) {
2528
return false;
2629
}

packages/core/src/drag/useGetViableDragPositions.ts

Lines changed: 83 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable no-continue */
12
import { useCallback } from 'react';
23
import { DraggingPosition, TreeItem } from '../types';
34
import { useGetGetParentOfLinearItem } from './useGetParentOfLinearItem';
@@ -9,54 +10,96 @@ export const useGetViableDragPositions = () => {
910
const getParentOfLinearItem = useGetGetParentOfLinearItem();
1011
const canDropAt = useCanDropAt();
1112

13+
const isDescendant = useCallback(
14+
(treeId: string, itemLinearIndex: number, potentialParents: TreeItem[]) => {
15+
// based on DraggingPositionEvaluation.isDescendant()
16+
const { parent, parentLinearIndex } = getParentOfLinearItem(
17+
itemLinearIndex,
18+
treeId
19+
);
20+
if (potentialParents.some(p => p.index === parent.item)) return true;
21+
if (parent.depth === 0) return false;
22+
return isDescendant(treeId, parentLinearIndex, potentialParents);
23+
},
24+
[getParentOfLinearItem]
25+
);
26+
1227
return useCallback(
1328
(treeId: string, draggingItems: TreeItem[]) => {
1429
const linearItems = environment.linearItems[treeId];
15-
return linearItems
16-
.map<DraggingPosition[]>(({ item, depth }, linearIndex) => {
17-
const { parent } = getParentOfLinearItem(linearIndex, treeId);
18-
const childIndex =
19-
environment.items[parent.item].children!.indexOf(item);
30+
const targets: DraggingPosition[] = [];
31+
let skipUntilDepthIsLowerThan = -1;
32+
33+
for (
34+
let linearIndex = 0;
35+
linearIndex < linearItems.length;
36+
// eslint-disable-next-line no-plusplus
37+
linearIndex++
38+
) {
39+
const { item, depth } = linearItems[linearIndex];
40+
41+
if (
42+
skipUntilDepthIsLowerThan !== -1 &&
43+
depth > skipUntilDepthIsLowerThan
44+
) {
45+
continue;
46+
} else {
47+
skipUntilDepthIsLowerThan = -1;
48+
}
49+
50+
const { parent } = getParentOfLinearItem(linearIndex, treeId);
51+
const childIndex =
52+
environment.items[parent.item].children!.indexOf(item);
53+
54+
if (isDescendant(treeId, linearIndex, draggingItems)) {
55+
skipUntilDepthIsLowerThan = depth + 1;
56+
continue;
57+
}
58+
59+
const itemPosition: DraggingPosition = {
60+
targetType: 'item',
61+
parentItem: parent.item,
62+
targetItem: item,
63+
linearIndex,
64+
depth,
65+
treeId,
66+
};
2067

21-
const itemPosition: DraggingPosition = {
22-
targetType: 'item',
23-
parentItem: parent.item,
24-
targetItem: item,
25-
linearIndex,
26-
depth,
27-
treeId,
28-
};
68+
const topPosition: DraggingPosition = {
69+
targetType: 'between-items',
70+
parentItem: parent.item,
71+
linePosition: 'top',
72+
childIndex,
73+
depth,
74+
treeId,
75+
linearIndex,
76+
};
2977

30-
const topPosition: DraggingPosition = {
31-
targetType: 'between-items',
32-
parentItem: parent.item,
33-
linePosition: 'top',
34-
childIndex,
35-
depth,
36-
treeId,
37-
linearIndex,
38-
};
78+
const bottomPosition: DraggingPosition = {
79+
targetType: 'between-items',
80+
parentItem: parent.item,
81+
linePosition: 'bottom',
82+
linearIndex: linearIndex + 1,
83+
childIndex: childIndex + 1,
84+
depth,
85+
treeId,
86+
};
3987

40-
const bottomPosition: DraggingPosition = {
41-
targetType: 'between-items',
42-
parentItem: parent.item,
43-
linePosition: 'bottom',
44-
linearIndex: linearIndex + 1,
45-
childIndex: childIndex + 1,
46-
depth,
47-
treeId,
48-
};
88+
const skipTopPosition =
89+
depth === (linearItems[linearIndex - 1]?.depth ?? -1);
4990

50-
const skipTopPosition =
51-
depth === (linearItems[linearIndex - 1]?.depth ?? -1);
91+
if (!skipTopPosition && canDropAt(topPosition, draggingItems)) {
92+
targets.push(topPosition);
93+
}
94+
if (canDropAt(itemPosition, draggingItems)) {
95+
targets.push(itemPosition);
96+
}
97+
if (canDropAt(bottomPosition, draggingItems)) {
98+
targets.push(bottomPosition);
99+
}
100+
}
52101

53-
if (skipTopPosition) {
54-
return [itemPosition, bottomPosition];
55-
}
56-
return [topPosition, itemPosition, bottomPosition];
57-
})
58-
.reduce((a, b) => [...a, ...b], [])
59-
.filter(position => canDropAt(position, draggingItems));
102+
return targets;
60103
},
61104
[
62105
canDropAt,

0 commit comments

Comments
 (0)