Skip to content

Commit 7c23745

Browse files
committed
feat: initial attempts at multi-depth dropping (#148)
1 parent 065fbc2 commit 7c23745

File tree

2 files changed

+100
-65
lines changed

2 files changed

+100
-65
lines changed

packages/core/src/controlledEnvironment/DraggingPositionEvaluation.ts

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
} from './DraggingPositionEvaluator';
55
import {
66
DraggingPosition,
7+
LinearItem,
78
TreeEnvironmentContextProps,
89
TreeItem,
910
} from '../types';
@@ -17,7 +18,13 @@ export class DraggingPositionEvaluation {
1718

1819
private readonly treeId: string;
1920

20-
private readonly hoveringPosition: HoveringPosition;
21+
private linearIndex: number;
22+
23+
private offset: 'bottom' | 'top' | undefined;
24+
25+
private indentation: number;
26+
27+
private targetItem: LinearItem;
2128

2229
constructor(
2330
evaluator: DraggingPositionEvaluator,
@@ -30,7 +37,10 @@ export class DraggingPositionEvaluation {
3037
this.env = env;
3138
this.e = e;
3239
this.treeId = treeId;
33-
this.hoveringPosition = hoveringPosition;
40+
this.linearIndex = hoveringPosition.linearIndex;
41+
this.offset = hoveringPosition.offset;
42+
this.indentation = hoveringPosition.indentation;
43+
this.targetItem = this.env.linearItems[this.treeId][this.linearIndex];
3444
}
3545

3646
getDraggingPosition(): DraggingPosition | undefined {
@@ -49,118 +59,139 @@ export class DraggingPositionEvaluation {
4959
};
5060
}
5161

52-
// eslint-disable-next-line prefer-const
53-
let { linearIndex, offset, veryBottom } = this.hoveringPosition;
54-
5562
if (
56-
linearIndex < 0 ||
57-
linearIndex >= this.env.linearItems[this.treeId].length
63+
this.linearIndex < 0 ||
64+
this.linearIndex >= this.env.linearItems[this.treeId].length
5865
) {
5966
return undefined;
6067
}
6168

62-
let targetItem = this.env.linearItems[this.treeId][linearIndex];
6369
const redirectTargetToParent =
6470
!this.env.canReorderItems &&
6571
!this.env.canDropOnNonFolder &&
66-
!this.env.items[targetItem.item].isFolder;
72+
!this.env.items[this.targetItem.item].isFolder;
6773

6874
if (redirectTargetToParent) {
6975
const { parentLinearIndex, parent } =
70-
this.evaluator.getParentOfLinearItem(linearIndex, this.treeId);
71-
targetItem = parent;
72-
linearIndex = parentLinearIndex;
76+
this.evaluator.getParentOfLinearItem(this.linearIndex, this.treeId);
77+
this.targetItem = parent;
78+
this.linearIndex = parentLinearIndex;
7379
}
7480

7581
if (
76-
this.isDescendant(this.treeId, linearIndex, this.evaluator.draggingItems)
82+
this.isDescendant(
83+
this.treeId,
84+
this.linearIndex,
85+
this.evaluator.draggingItems
86+
)
7787
) {
7888
return undefined;
7989
}
8090

81-
const nextItem = this.env.linearItems[this.treeId][linearIndex + 1];
91+
const treeLinearItems = this.env.linearItems[this.treeId];
92+
const deepestDepth = treeLinearItems[this.linearIndex].depth;
93+
const legalDropDepthCount = // itemDepthDifferenceToNextItem/isLastInGroup
94+
deepestDepth - (treeLinearItems[this.linearIndex + 1]?.depth ?? 0);
95+
const canReparentUpwards =
96+
this.offset === 'bottom' && legalDropDepthCount > 0;
97+
// Default to zero on last position to allow dropping on root when
98+
// dropping at bottom
99+
if (canReparentUpwards) {
100+
const droppingIndent = Math.max(
101+
deepestDepth - legalDropDepthCount,
102+
this.indentation
103+
);
104+
let newParent = {
105+
parentLinearIndex: this.linearIndex,
106+
parent: this.targetItem,
107+
};
108+
for (let i = deepestDepth; i !== droppingIndent; i -= 1) {
109+
newParent = this.evaluator.getParentOfLinearItem(
110+
newParent.parentLinearIndex,
111+
this.treeId
112+
);
113+
}
114+
115+
if (this.indentation !== treeLinearItems[this.linearIndex].depth) {
116+
this.targetItem = newParent.parent;
117+
}
118+
}
119+
120+
const nextItem = this.env.linearItems[this.treeId][this.linearIndex + 1];
82121
const redirectToFirstChild =
83122
!this.env.canDropBelowOpenFolders &&
84123
nextItem &&
85-
targetItem.depth === nextItem.depth - 1 &&
86-
offset === 'bottom';
124+
this.targetItem.depth === nextItem.depth - 1 &&
125+
this.offset === 'bottom';
87126
if (redirectToFirstChild) {
88-
targetItem = nextItem;
89-
linearIndex += 1;
90-
offset = 'top';
127+
this.targetItem = nextItem;
128+
this.linearIndex += 1;
129+
this.offset = 'top';
91130
}
92131

93-
const { depth } = targetItem;
94-
const targetItemData = this.env.items[targetItem.item];
132+
const { depth } = this.targetItem;
133+
const targetItemData = this.env.items[this.targetItem.item];
95134

96-
if (!offset && !this.env.canDropOnNonFolder && !targetItemData.isFolder) {
135+
if (
136+
!this.offset &&
137+
!this.env.canDropOnNonFolder &&
138+
!targetItemData.isFolder
139+
) {
97140
return undefined;
98141
}
99142

100-
if (!offset && !this.env.canDropOnFolder && targetItemData.isFolder) {
143+
if (!this.offset && !this.env.canDropOnFolder && targetItemData.isFolder) {
101144
return undefined;
102145
}
103146

104-
if (offset && !this.env.canReorderItems) {
147+
if (this.offset && !this.env.canReorderItems) {
105148
return undefined;
106149
}
107150

108151
const { parent } = this.evaluator.getParentOfLinearItem(
109-
linearIndex,
152+
this.linearIndex,
110153
this.treeId
111154
);
112155

113156
if (
114157
this.evaluator.draggingItems.some(
115-
draggingItem => draggingItem.index === targetItem.item
158+
draggingItem => draggingItem.index === this.targetItem.item
116159
)
117160
) {
118161
return undefined;
119162
}
120163

121164
const newChildIndex =
122-
this.env.items[parent.item].children!.indexOf(targetItem.item) +
123-
(offset === 'top' ? 0 : 1);
165+
this.env.items[parent.item].children!.indexOf(this.targetItem.item) +
166+
(this.offset === 'top' ? 0 : 1);
124167

125168
if (
126-
offset === 'top' &&
169+
this.offset === 'top' &&
127170
depth ===
128-
(this.env.linearItems[this.treeId][linearIndex - 1]?.depth ?? -1)
171+
(this.env.linearItems[this.treeId][this.linearIndex - 1]?.depth ?? -1)
129172
) {
130-
offset = 'bottom';
131-
linearIndex -= 1;
173+
this.offset = 'bottom';
174+
this.linearIndex -= 1;
132175
}
133176

134-
if (veryBottom) {
135-
const { rootItem } = this.env.trees[this.treeId];
136-
return {
137-
targetType: 'between-items',
138-
treeId: this.treeId,
139-
parentItem: rootItem,
140-
depth: 0,
141-
linearIndex: linearIndex + 1,
142-
childIndex: this.env.items[rootItem].children?.length ?? 0,
143-
linePosition: 'bottom',
144-
};
145-
}
146-
if (offset) {
177+
if (this.offset) {
147178
return {
148179
targetType: 'between-items',
149180
treeId: this.treeId,
150181
parentItem: parent.item,
151-
depth: targetItem.depth,
152-
linearIndex: linearIndex + (offset === 'top' ? 0 : 1),
182+
depth: this.targetItem.depth,
183+
linearIndex: this.linearIndex + (this.offset === 'top' ? 0 : 1),
153184
childIndex: newChildIndex,
154-
linePosition: offset,
185+
linePosition: this.offset,
155186
};
156187
}
157188
return {
158189
targetType: 'item',
159190
treeId: this.treeId,
160191
parentItem: parent.item,
161-
targetItem: targetItem.item,
162-
depth: targetItem.depth,
163-
linearIndex,
192+
targetItem: this.targetItem.item,
193+
depth: this.targetItem.depth,
194+
linearIndex: this.linearIndex,
164195
};
165196
}
166197

packages/core/src/controlledEnvironment/DraggingPositionEvaluator.ts

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { DraggingPositionEvaluation } from './DraggingPositionEvaluation';
1212
export type HoveringPosition = {
1313
linearIndex: number;
1414
offset: 'bottom' | 'top' | undefined;
15-
veryBottom: boolean;
15+
indentation: number;
1616
};
1717

1818
// TODO move back into hook?
@@ -96,18 +96,22 @@ export class DraggingPositionEvaluator {
9696
const hoveringPosition = (e.clientY - treeBb.top) / this.itemHeight;
9797

9898
const treeLinearItems = this.env.linearItems[treeId];
99-
const linearIndex = Math.max(0, Math.floor(hoveringPosition));
100-
101-
if (linearIndex > treeLinearItems.length - 1) {
102-
return {
103-
linearIndex: treeLinearItems.length - 1,
104-
offset: 'bottom',
105-
veryBottom: true,
106-
} as const;
107-
}
99+
const linearIndex = Math.min(
100+
Math.max(0, Math.floor(hoveringPosition)),
101+
treeLinearItems.length - 1
102+
);
108103

109104
const targetLinearItem = treeLinearItems[linearIndex];
110105
const targetItem = this.env.items[targetLinearItem.item];
106+
107+
const indentation = Math.min(
108+
Math.max(
109+
Math.floor((e.clientX - treeBb.left) / this.env.renderDepthOffset),
110+
0
111+
),
112+
targetLinearItem.depth
113+
);
114+
111115
let offset: 'top' | 'bottom' | undefined;
112116

113117
const lineThreshold = !canReorderItems
@@ -122,7 +126,7 @@ export class DraggingPositionEvaluator {
122126
offset = 'bottom';
123127
}
124128

125-
return { linearIndex, offset, veryBottom: false };
129+
return { linearIndex, offset, indentation };
126130
}
127131

128132
private isNewDragPosition(
@@ -133,10 +137,10 @@ export class DraggingPositionEvaluator {
133137
if (!hoveringPosition) {
134138
return false;
135139
}
136-
const { offset, linearIndex, veryBottom } = hoveringPosition;
140+
const { offset, linearIndex } = hoveringPosition;
137141

138-
const newDragCode = `${treeId}${linearIndex}${offset ?? ''}${
139-
veryBottom && 'vb'
142+
const newDragCode = `${treeId}__${linearIndex}__${offset ?? ''}__${
143+
hoveringPosition.indentation
140144
}`;
141145
if (newDragCode !== this.dragCode) {
142146
this.dragCode = newDragCode;

0 commit comments

Comments
 (0)