Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/react-aria/src/dnd/DragManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,13 @@ class DragSession {

let minDistance = Infinity;
let nearest = -1;
let ancestor = -1;
for (let i = 0; i < this.validDropTargets.length; i++) {
let dropTarget = this.validDropTargets[i];
if (ancestor < 0 && nodeContains(dropTarget.element, this.dragTarget.element)) {
ancestor = i;
}

let rect = dropTarget.element.getBoundingClientRect();
let dx = rect.left - dragTargetRect.left;
let dy = rect.top - dragTargetRect.top;
Expand All @@ -541,7 +546,7 @@ class DragSession {
}
}

return nearest;
return ancestor >= 0 ? ancestor : nearest;
}

setCurrentDropTarget(dropTarget: DropTarget | null, item?: DroppableItem): void {
Expand Down
49 changes: 49 additions & 0 deletions packages/react-aria/test/dnd/dnd.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,55 @@ describe('useDrag and useDrop', function () {
expect(document.activeElement).toBe(droppable);
});

it('should prefer an ancestor drop target over the nearest drop target', async () => {
let onDropEnter = jest.fn();
let onDropEnter2 = jest.fn();
let tree = render(
<>
<Droppable onDropEnter={onDropEnter}>
<Draggable />
</Droppable>
<Droppable onDropEnter={onDropEnter2}>Drop here 2</Droppable>
</>
);

let draggable = tree.getByText('Drag me');
let droppable = draggable.parentElement;
let droppable2 = tree.getByText('Drop here 2');
let rect = (left, top) => ({
left,
top,
x: left,
y: top,
width: 100,
height: 50
});

jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockImplementation(function () {
if (this === droppable) {
return rect(1000, 0);
}

if (this === droppable2) {
return rect(10, 0);
}

return rect(0, 0);
});

await user.tab();
await user.tab();
expect(document.activeElement).toBe(draggable);

await user.keyboard('{Enter}');
act(() => jest.runAllTimers());
expect(document.activeElement).toBe(droppable);
expect(droppable).toHaveAttribute('data-droptarget', 'true');
expect(droppable2).toHaveAttribute('data-droptarget', 'false');
expect(onDropEnter).toHaveBeenCalledTimes(1);
expect(onDropEnter2).not.toHaveBeenCalled();
});

it('should cancel the drag when pressing the escape key', async () => {
let tree = render(
<>
Expand Down