Skip to content

Commit d3fcad8

Browse files
tflanaganLFDanLuyihuiliao
authored
dnd: when dragging, stop propagation to potential parent draggables (#4601)
* dnd: when dragging, stop propagation to potential parent draggables * dnd: fix spelling typo * dnd: attempt to add test for nested dragging * dnd: fix missing dataTransfer var in test * dnd: add stopPropagation to onDrag and onDragEnd --------- Co-authored-by: Daniel Lu <[email protected]> Co-authored-by: Yihui Liao <[email protected]>
1 parent 2c0321d commit d3fcad8

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

packages/@react-aria/dnd/src/useDrag.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ export function useDrag(options: DragOptions): DragResult {
9292
return;
9393
}
9494

95+
// Prevent the drag event from propagating to any parent draggables
96+
e.stopPropagation();
97+
9598
// If this drag was initiated by a mobile screen reader (e.g. VoiceOver or TalkBack), enter virtual dragging mode.
9699
if (modalityOnPointerDown.current === 'virtual') {
97100
e.preventDefault();
@@ -164,6 +167,9 @@ export function useDrag(options: DragOptions): DragResult {
164167
};
165168

166169
let onDrag = (e: DragEvent) => {
170+
// Prevent the drag event from propagating to any parent draggables
171+
e.stopPropagation();
172+
167173
if (e.clientX === state.x && e.clientY === state.y) {
168174
return;
169175
}
@@ -181,6 +187,9 @@ export function useDrag(options: DragOptions): DragResult {
181187
};
182188

183189
let onDragEnd = (e: DragEvent) => {
190+
// Prevent the drag event from propagating to any parent draggables
191+
e.stopPropagation();
192+
184193
if (typeof options.onDragEnd === 'function') {
185194
let event: DragEndEvent = {
186195
type: 'dragend',

packages/@react-aria/dnd/test/dnd.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,40 @@ describe('useDrag and useDrop', function () {
334334
expect(onDropExit).toHaveBeenCalledTimes(1);
335335
});
336336

337+
describe('nested drag targets', () => {
338+
let onDragStartParent = jest.fn();
339+
let onDragMoveParent = jest.fn();
340+
let onDragEndParent = jest.fn();
341+
let onDragStartChild = jest.fn();
342+
let onDragMoveChild = jest.fn();
343+
let onDragEndChild = jest.fn();
344+
345+
function renderNestedDrag() {
346+
return render(
347+
<Draggable onDragStart={onDragStartParent} onDragMove={onDragMoveParent} onDragEnd={onDragEndParent}>
348+
<Draggable onDragStart={onDragStartChild} onDragMove={onDragMoveChild} onDragEnd={onDragEndChild}>
349+
Drag me child
350+
</Draggable>
351+
</Draggable>
352+
);
353+
}
354+
355+
it('does not trigger parent drag when dragging child', () => {
356+
let tree = renderNestedDrag();
357+
let draggableChild = tree.getByText('Drag me child');
358+
359+
let dataTransfer = new DataTransfer();
360+
fireEvent(draggableChild, new DragEvent('drag', {dataTransfer, clientX: 1, clientY: 1}));
361+
expect(onDragMoveParent).not.toHaveBeenCalled();
362+
expect(onDragMoveChild).toHaveBeenCalledTimes(1);
363+
expect(onDragMoveChild).toHaveBeenCalledWith({
364+
type: 'dragmove',
365+
x: 1,
366+
y: 1
367+
});
368+
});
369+
});
370+
337371
describe('nested drop targets', () => {
338372
let onDropParent = jest.fn();
339373
let onDropEnterParent = jest.fn();

0 commit comments

Comments
 (0)