fix(ui): skip firing collision detection on dnd when droppable scrolled out

Requires some additional logic in the collision detection algorithm.

Closes #4621
This commit is contained in:
psychedelicious 2023-09-21 16:41:35 +10:00 committed by Kent Keirsey
parent b4790002c7
commit 6d1057c560
3 changed files with 41 additions and 3 deletions

View File

@ -31,7 +31,7 @@ const IAIDroppable = (props: IAIDroppableProps) => {
insetInlineStart={0} insetInlineStart={0}
w="full" w="full"
h="full" h="full"
pointerEvents="none" pointerEvents={active ? 'auto' : 'none'}
> >
<AnimatePresence> <AnimatePresence>
{isValidDrop(data, active) && ( {isValidDrop(data, active) && (

View File

@ -2,7 +2,6 @@ import {
DragOverlay, DragOverlay,
MouseSensor, MouseSensor,
TouchSensor, TouchSensor,
pointerWithin,
useSensor, useSensor,
useSensors, useSensors,
} from '@dnd-kit/core'; } from '@dnd-kit/core';
@ -14,6 +13,7 @@ import { AnimatePresence, motion } from 'framer-motion';
import { PropsWithChildren, memo, useCallback, useState } from 'react'; import { PropsWithChildren, memo, useCallback, useState } from 'react';
import { useScaledModifer } from '../hooks/useScaledCenteredModifer'; import { useScaledModifer } from '../hooks/useScaledCenteredModifer';
import { DragEndEvent, DragStartEvent, TypesafeDraggableData } from '../types'; import { DragEndEvent, DragStartEvent, TypesafeDraggableData } from '../types';
import { customPointerWithin } from '../util/customPointerWithin';
import { DndContextTypesafe } from './DndContextTypesafe'; import { DndContextTypesafe } from './DndContextTypesafe';
import DragPreview from './DragPreview'; import DragPreview from './DragPreview';
@ -77,7 +77,7 @@ const AppDndContext = (props: PropsWithChildren) => {
onDragStart={handleDragStart} onDragStart={handleDragStart}
onDragEnd={handleDragEnd} onDragEnd={handleDragEnd}
sensors={sensors} sensors={sensors}
collisionDetection={pointerWithin} collisionDetection={customPointerWithin}
autoScroll={false} autoScroll={false}
> >
{props.children} {props.children}

View File

@ -0,0 +1,38 @@
import { CollisionDetection, pointerWithin } from '@dnd-kit/core';
/**
* Filters out droppable elements that are overflowed, then applies the pointerWithin collision detection.
*
* Fixes collision detection firing on droppables that are not visible, having been scrolled out of view.
*
* See https://github.com/clauderic/dnd-kit/issues/1198
*/
export const customPointerWithin: CollisionDetection = (arg) => {
if (!arg.pointerCoordinates) {
// sanity check
return [];
}
// Get all elements at the pointer coordinates. This excludes elements which are overflowed,
// so it won't include the droppable elements that are scrolled out of view.
const targetElements = document.elementsFromPoint(
arg.pointerCoordinates.x,
arg.pointerCoordinates.y
);
const filteredDroppableContainers = arg.droppableContainers.filter(
(container) => {
if (!container.node.current) {
return false;
}
// Only include droppable elements that are in the list of elements at the pointer coordinates.
return targetElements.includes(container.node.current);
}
);
// Run the provided collision detection with the filtered droppable elements.
return pointerWithin({
...arg,
droppableContainers: filteredDroppableContainers,
});
};