Skip to content

Commit a6a2006

Browse files
committed
fix: maintain item order when dropping (#315)
1 parent 0eb1fa9 commit a6a2006

File tree

5 files changed

+37
-14
lines changed

5 files changed

+37
-14
lines changed

next-release-notes.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,2 @@
1-
<!--
2-
### Breaking Changes
3-
4-
### Features
5-
61
### Bug Fixes and Improvements
7-
8-
### Other Changes
9-
-->
2+
- Maintain original item order when dropping items (#315)

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"private": true,
1212
"scripts": {
1313
"start": "lerna run start --parallel",
14+
"start:core": "lerna run start --parallel --scope react-complex-tree",
1415
"build": "lerna run build",
1516
"build:core": "lerna run build --scope react-complex-tree",
1617
"test": "lerna run test --stream",

packages/core/src/controlledEnvironment/DragAndDropProvider.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { buildMapForTrees } from '../utils';
1515
import { useCallSoon } from '../useCallSoon';
1616
import { computeItemHeight } from './layoutUtils';
1717
import { useStableHandler } from '../use-stable-handler';
18+
import { useGetOriginalItemOrder } from '../use-get-original-item-order';
1819

1920
const DragAndDropContext = React.createContext<DragAndDropContextProps>(
2021
null as any
@@ -38,6 +39,7 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
3839
const [dragCode, setDragCode] = useState('_nodrag');
3940
const getViableDragPositions = useGetViableDragPositions();
4041
const callSoon = useCallSoon();
42+
const getOriginalItemOrder = useGetOriginalItemOrder();
4143

4244
const resetProgrammaticDragIndexForCurrentTree = useCallback(
4345
(
@@ -222,8 +224,9 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
222224
return;
223225
}
224226

225-
const resolvedDraggingItems = draggingItems.map(
226-
id => environment.items[id]
227+
const resolvedDraggingItems = getOriginalItemOrder(
228+
environment.activeTreeId,
229+
draggingItems.map(id => environment.items[id])
227230
);
228231

229232
if (environment.canDrag && !environment.canDrag(resolvedDraggingItems)) {
@@ -236,7 +239,7 @@ export const DragAndDropProvider: React.FC<React.PropsWithChildren> = ({
236239
// Needs to be done after onStartDraggingItems was called, so that viableDragPositions is populated
237240
});
238241
}
239-
}, [onStartDraggingItems, environment]);
242+
}, [environment, getOriginalItemOrder, onStartDraggingItems]);
240243

241244
const abortProgrammaticDrag = useCallback(() => {
242245
resetState();

packages/core/src/treeItem/useTreeItemRenderContext.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useTreeEnvironment } from '../controlledEnvironment/ControlledTreeEnvir
66
import { useInteractionManager } from '../controlledEnvironment/InteractionManagerProvider';
77
import { useDragAndDrop } from '../controlledEnvironment/DragAndDropProvider';
88
import { useSelectUpTo } from '../tree/useSelectUpTo';
9+
import { useGetOriginalItemOrder } from '../use-get-original-item-order';
910

1011
// TODO restructure file. Everything into one hook file without helper methods, let all props be generated outside (InteractionManager and AccessibilityPropsManager), ...
1112

@@ -16,6 +17,7 @@ export const useTreeItemRenderContext = (item?: TreeItem) => {
1617
const dnd = useDragAndDrop();
1718
const selectUpTo = useSelectUpTo('last-focus');
1819
const itemTitle = item && environment.getItemTitle(item);
20+
const getOriginalItemOrder = useGetOriginalItemOrder();
1921

2022
const isSearchMatching = useMemo(
2123
() =>
@@ -129,10 +131,11 @@ export const useTreeItemRenderContext = (item?: TreeItem) => {
129131
}
130132

131133
if (canDrag) {
132-
dnd.onStartDraggingItems(
133-
selectedItems.map(id => environment.items[id]),
134-
treeId
134+
const orderedItems = getOriginalItemOrder(
135+
treeId,
136+
selectedItems.map(id => environment.items[id])
135137
);
138+
dnd.onStartDraggingItems(orderedItems, treeId);
136139
}
137140
},
138141
};
@@ -232,5 +235,6 @@ export const useTreeItemRenderContext = (item?: TreeItem) => {
232235
interactionManager,
233236
selectUpTo,
234237
setRenamingItem,
238+
getOriginalItemOrder,
235239
]);
236240
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { useTreeEnvironment } from './controlledEnvironment/ControlledTreeEnvironment';
2+
import { TreeItem } from './types';
3+
import { useStableHandler } from './use-stable-handler';
4+
5+
export const useGetOriginalItemOrder = () => {
6+
const env = useTreeEnvironment();
7+
return useStableHandler((treeId: string, items: TreeItem[]) =>
8+
items
9+
.map(
10+
item =>
11+
[
12+
item,
13+
env.linearItems[treeId].findIndex(
14+
linearItem => linearItem.item === item.index
15+
),
16+
] as const
17+
)
18+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
19+
.sort(([_, aPos], [_2, bPos]) => bPos - aPos)
20+
.map(([item]) => item)
21+
);
22+
};

0 commit comments

Comments
 (0)