@hello-pangea/dnd
Version:
Beautiful and accessible drag and drop for lists with React
93 lines (84 loc) • 2.4 kB
text/typescript
import type { Position, Rect } from 'css-box-model';
import type {
DroppableId,
DraggableDimension,
DroppableDimension,
DraggableDimensionMap,
DroppableDimensionMap,
DragImpact,
Viewport,
LiftEffect,
} from '../../types';
import getDroppableOver from '../get-droppable-over';
import getDraggablesInsideDroppable from '../get-draggables-inside-droppable';
import withDroppableScroll from '../with-scroll-change/with-droppable-scroll';
import getReorderImpact from './get-reorder-impact';
import getCombineImpact from './get-combine-impact';
import noImpact from '../no-impact';
import { offsetRectByPosition } from '../rect';
interface Args {
pageOffset: Position;
draggable: DraggableDimension;
// all dimensions in system
draggables: DraggableDimensionMap;
droppables: DroppableDimensionMap;
previousImpact: DragImpact;
viewport: Viewport;
afterCritical: LiftEffect;
}
export default ({
pageOffset,
draggable,
draggables,
droppables,
previousImpact,
viewport,
afterCritical,
}: Args): DragImpact => {
const pageBorderBox: Rect = offsetRectByPosition(
draggable.page.borderBox,
pageOffset,
);
const destinationId: DroppableId | null = getDroppableOver({
pageBorderBox,
draggable,
droppables,
});
// not dragging over anything
if (!destinationId) {
// A big design decision was made here to collapse the home list
// when not over any list. This yielded the most consistently beautiful experience.
return noImpact;
}
const destination: DroppableDimension = droppables[destinationId];
const insideDestination: DraggableDimension[] = getDraggablesInsideDroppable(
destination.descriptor.id,
draggables,
);
// Where the element actually is now.
// Need to take into account the change of scroll in the droppable
const pageBorderBoxWithDroppableScroll: Rect = withDroppableScroll(
destination,
pageBorderBox,
);
// checking combine first so we combine before any reordering
return (
getCombineImpact({
pageBorderBoxWithDroppableScroll,
draggable,
previousImpact,
destination,
insideDestination,
afterCritical,
}) ||
getReorderImpact({
pageBorderBoxWithDroppableScroll,
draggable,
destination,
insideDestination,
last: previousImpact.displaced,
viewport,
afterCritical,
})
);
};