Skip to content

Commit 07976a3

Browse files
LFDanLudevongovett
andauthored
Fix useListData so that reorder operations are correctly inserted at the correct index (#3724)
* Fix useListData move operation logic specifically fix it for cases where the user is reordering a set of sequential items and is moving it to a drop position one below the last item being moved * Update packages/@react-stately/data/src/useListData.ts Co-authored-by: Devon Govett <[email protected]> Co-authored-by: Devon Govett <[email protected]>
1 parent abbdc20 commit 07976a3

File tree

3 files changed

+27
-11
lines changed

3 files changed

+27
-11
lines changed

packages/@react-spectrum/list/test/ListViewDnd.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,17 +421,17 @@ describe('ListView', function () {
421421
fireEvent(cell, new DragEvent('dragstart', {dataTransfer, clientX: 0, clientY: 0}));
422422
expect(onDragStart).toHaveBeenCalledTimes(1);
423423

424-
fireEvent.pointerMove(cell, {pointerType: 'mouse', button: 0, pointerId: 1, clientX: 1, clientY: 110});
425-
fireEvent(cell, new DragEvent('drag', {dataTransfer, clientX: 1, clientY: 110}));
426-
fireEvent(grid, new DragEvent('dragover', {dataTransfer, clientX: 1, clientY: 110}));
427-
fireEvent.pointerUp(cell, {pointerType: 'mouse', button: 0, pointerId: 1, clientX: 1, clientY: 110});
424+
fireEvent.pointerMove(cell, {pointerType: 'mouse', button: 0, pointerId: 1, clientX: 1, clientY: 150});
425+
fireEvent(cell, new DragEvent('drag', {dataTransfer, clientX: 1, clientY: 150}));
426+
fireEvent(grid, new DragEvent('dragover', {dataTransfer, clientX: 1, clientY: 150}));
427+
fireEvent.pointerUp(cell, {pointerType: 'mouse', button: 0, pointerId: 1, clientX: 1, clientY: 150});
428428

429-
fireEvent(grid, new DragEvent('drop', {dataTransfer, clientX: 1, clientY: 110}));
429+
fireEvent(grid, new DragEvent('drop', {dataTransfer, clientX: 1, clientY: 150}));
430430
act(() => jest.runAllTimers());
431431
await act(async () => Promise.resolve());
432432
expect(onDrop).toHaveBeenCalledTimes(1);
433433

434-
fireEvent(cell, new DragEvent('dragend', {dataTransfer, clientX: 1, clientY: 110}));
434+
fireEvent(cell, new DragEvent('dragend', {dataTransfer, clientX: 1, clientY: 150}));
435435
expect(onDragEnd).toHaveBeenCalledTimes(1);
436436

437437
act(() => jest.runAllTimers());

packages/@react-stately/data/src/useListData.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,11 +326,7 @@ function insert<T>(state: ListState<T>, index: number, ...values: T[]): ListStat
326326

327327
function move<T>(state: ListState<T>, indices: number[], toIndex: number): ListState<T> {
328328
// Shift the target down by the number of items being moved from before the target
329-
for (let index of indices) {
330-
if (index < toIndex) {
331-
toIndex--;
332-
}
333-
}
329+
toIndex -= indices.filter(index => index < toIndex).length;
334330

335331
let moves = indices.map(from => ({
336332
from,

packages/@react-stately/data/test/useListData.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,26 @@ describe('useListData', function () {
601601
many[5]
602602
]);
603603
});
604+
605+
it('should move multiple items before another item to after that item', function () {
606+
let {result} = renderHook(() => useListData({initialItems: many, getKey}));
607+
let initialResult = result.current;
608+
609+
act(() => {
610+
result.current.moveAfter('Five', ['Two', 'Three', 'Four']);
611+
});
612+
613+
expect(result.current.items).not.toBe(initialResult.items);
614+
expect(result.current.items).toHaveLength(6);
615+
expect(result.current.items).toEqual([
616+
many[0],
617+
many[4],
618+
many[1],
619+
many[2],
620+
many[3],
621+
many[5]
622+
]);
623+
});
604624
});
605625

606626
it('should support filtering', function () {

0 commit comments

Comments
 (0)