Skip to content

Commit 1698737

Browse files
committed
feat: rework dnd logic into droppositionevaluator (#148)
1 parent 3f45c8f commit 1698737

File tree

3 files changed

+327
-309
lines changed

3 files changed

+327
-309
lines changed

packages/core/src/controlledEnvironment/DragAndDropProvider.tsx

+70-27
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
TreeItemIndex,
88
} from '../types';
99
import { useTreeEnvironment } from './ControlledTreeEnvironment';
10-
import { useOnDragOverTreeHandler } from './useOnDragOverTreeHandler';
1110
import { useCanDropAt } from './useCanDropAt';
1211
import { useGetViableDragPositions } from './useGetViableDragPositions';
1312
import { useSideEffect } from '../useSideEffect';
@@ -16,6 +15,8 @@ import { useCallSoon } from '../useCallSoon';
1615
import { computeItemHeight } from './layoutUtils';
1716
import { useStableHandler } from '../useStableHandler';
1817
import { useGetOriginalItemOrder } from '../useGetOriginalItemOrder';
18+
import { DropPositionEvaluation } from './DropPositionEvaluation';
19+
import { useGetGetParentOfLinearItem } from './useGetParentOfLinearItem';
1920

2021
const DragAndDropContext = React.createContext<DragAndDropContextProps>(
2122
null as any
@@ -29,17 +30,20 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
2930
const environment = useTreeEnvironment();
3031
const [isProgrammaticallyDragging, setIsProgrammaticallyDragging] =
3132
useState(false);
32-
const [itemHeight, setItemHeight] = useState(4);
3333
const [viableDragPositions, setViableDragPositions] = useState<{
3434
[treeId: string]: DraggingPosition[];
3535
}>({});
3636
const [programmaticDragIndex, setProgrammaticDragIndex] = useState(0);
37-
const [draggingItems, setDraggingItems] = useState<TreeItem[]>();
3837
const [draggingPosition, setDraggingPosition] = useState<DraggingPosition>();
39-
const [dragCode, setDragCode] = useState('_nodrag');
38+
const [dragCode, setDragCode] = useState('_nodrag'); // TODO should be moved into evaluator
4039
const getViableDragPositions = useGetViableDragPositions();
4140
const callSoon = useCallSoon();
4241
const getOriginalItemOrder = useGetOriginalItemOrder();
42+
const getParentOfLinearItem = useGetGetParentOfLinearItem();
43+
44+
const [dropPositionEvaluator, setDropPositionEvaluator] = useState<
45+
DropPositionEvaluation | undefined
46+
>(undefined);
4347

4448
const resetProgrammaticDragIndexForCurrentTree = useCallback(
4549
(
@@ -93,12 +97,11 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
9397

9498
const resetState = useCallback(() => {
9599
setIsProgrammaticallyDragging(false);
96-
setItemHeight(4);
97100
setViableDragPositions({});
98101
setProgrammaticDragIndex(0);
99-
setDraggingItems(undefined);
100102
setDraggingPosition(undefined);
101103
setDragCode('_nodrag');
104+
setDropPositionEvaluator(undefined);
102105
}, []);
103106

104107
useSideEffect(
@@ -110,12 +113,12 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
110113
) {
111114
resetProgrammaticDragIndexForCurrentTree(
112115
viableDragPositions[environment.activeTreeId],
113-
draggingItems
116+
dropPositionEvaluator?.draggingItems
114117
);
115118
}
116119
},
117120
[
118-
draggingItems,
121+
dropPositionEvaluator?.draggingItems,
119122
environment.activeTreeId,
120123
environment.linearItems,
121124
resetProgrammaticDragIndexForCurrentTree,
@@ -144,32 +147,66 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
144147
const canDropAt = useCanDropAt();
145148

146149
const performDrag = (draggingPosition: DraggingPosition) => {
147-
if (draggingItems && !canDropAt(draggingPosition, draggingItems)) {
150+
if (
151+
dropPositionEvaluator?.draggingItems &&
152+
!canDropAt(draggingPosition, dropPositionEvaluator.draggingItems)
153+
) {
148154
return;
149155
}
150156

151157
setDraggingPosition(draggingPosition);
152158
environment.setActiveTree(draggingPosition.treeId);
153159

154-
if (draggingItems && environment.activeTreeId !== draggingPosition.treeId) {
160+
if (
161+
dropPositionEvaluator?.draggingItems &&
162+
environment.activeTreeId !== draggingPosition.treeId
163+
) {
155164
// TODO maybe do only if draggingItems are different to selectedItems
156165
environment.onSelectItems?.(
157-
draggingItems.map(item => item.index),
166+
dropPositionEvaluator.draggingItems.map(item => item.index),
158167
draggingPosition.treeId
159168
);
160169
}
161170
};
162171

163-
const onDragOverTreeHandler = useOnDragOverTreeHandler(
164-
dragCode,
165-
setDragCode,
166-
draggingItems,
167-
itemHeight,
168-
setDraggingPosition,
169-
performDrag
172+
const onDragOverTreeHandler = useStableHandler(
173+
(
174+
e: DragEvent,
175+
treeId: string,
176+
containerRef: React.MutableRefObject<HTMLElement | undefined>
177+
) => {
178+
// TODO move dragcode check into evaluator
179+
if (!dropPositionEvaluator) return;
180+
const hoveringPosition = dropPositionEvaluator.getHoveringPosition(
181+
e,
182+
treeId,
183+
containerRef
184+
);
185+
const newDragCode = dropPositionEvaluator.getDragCode(
186+
e,
187+
treeId,
188+
hoveringPosition
189+
);
190+
if (newDragCode === dragCode) {
191+
return;
192+
}
193+
setDragCode(newDragCode);
194+
const newDraggingPosition = dropPositionEvaluator.getDraggingPosition(
195+
e,
196+
hoveringPosition,
197+
treeId
198+
);
199+
if (!newDraggingPosition) {
200+
setDraggingPosition(undefined);
201+
return;
202+
}
203+
// setItemHeight(dropPositionEvaluator.itemHeight);
204+
performDrag(newDraggingPosition);
205+
}
170206
);
171207

172208
const onDropHandler = useStableHandler(() => {
209+
const draggingItems = dropPositionEvaluator?.draggingItems;
173210
if (draggingItems && draggingPosition && environment.onDrop) {
174211
environment.onDrop(draggingItems, draggingPosition);
175212

@@ -187,10 +224,16 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
187224
treeId => getViableDragPositions(treeId, items)
188225
);
189226

227+
setDropPositionEvaluator(
228+
new DropPositionEvaluation(
229+
environment,
230+
getParentOfLinearItem,
231+
items,
232+
computeItemHeight(treeId)
233+
)
234+
);
235+
190236
// TODO what if trees have different heights and drag target changes?
191-
const height = computeItemHeight(treeId);
192-
setItemHeight(height);
193-
setDraggingItems(items);
194237
setViableDragPositions(treeViableDragPositions);
195238

196239
if (environment.activeTreeId) {
@@ -201,8 +244,8 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
201244
}
202245
},
203246
[
204-
environment.activeTreeId,
205-
environment.treeIds,
247+
environment,
248+
getParentOfLinearItem,
206249
getViableDragPositions,
207250
resetProgrammaticDragIndexForCurrentTree,
208251
]
@@ -273,9 +316,9 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
273316
completeProgrammaticDrag,
274317
programmaticDragUp,
275318
programmaticDragDown,
276-
draggingItems,
319+
draggingItems: dropPositionEvaluator?.draggingItems,
277320
draggingPosition,
278-
itemHeight,
321+
itemHeight: dropPositionEvaluator?.itemHeight ?? 4,
279322
isProgrammaticallyDragging,
280323
onDragOverTreeHandler,
281324
viableDragPositions,
@@ -287,9 +330,9 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
287330
completeProgrammaticDrag,
288331
programmaticDragUp,
289332
programmaticDragDown,
290-
draggingItems,
333+
dropPositionEvaluator?.draggingItems,
334+
dropPositionEvaluator?.itemHeight,
291335
draggingPosition,
292-
itemHeight,
293336
isProgrammaticallyDragging,
294337
onDragOverTreeHandler,
295338
viableDragPositions,

0 commit comments

Comments
 (0)