@hello-pangea/dnd
Version:
Beautiful and accessible drag and drop for lists with React
81 lines (74 loc) • 2.4 kB
text/typescript
import type { Position } from 'css-box-model';
import type {
Viewport,
DraggableDimension,
DroppableDimension,
LiftEffect,
} from '../../../types';
import { distance } from '../../position';
import { isTotallyVisible } from '../../visibility/is-visible';
import withDroppableDisplacement from '../../with-scroll-change/with-droppable-displacement';
import {
getCurrentPageBorderBox,
getCurrentPageBorderBoxCenter,
} from './without-starting-displacement';
interface Args {
pageBorderBoxCenter: Position;
viewport: Viewport;
// the droppable that is being moved to
destination: DroppableDimension;
// the droppables inside the destination
insideDestination: DraggableDimension[];
afterCritical: LiftEffect;
}
export default ({
pageBorderBoxCenter,
viewport,
destination,
insideDestination,
afterCritical,
}: Args): DraggableDimension | null => {
const sorted: DraggableDimension[] = insideDestination
.filter(
(
draggable: DraggableDimension,
): boolean => // Allowing movement to draggables that are not visible in the viewport
// but must be visible in the droppable
// We can improve this, but this limitation is easier for now
isTotallyVisible({
target: getCurrentPageBorderBox(draggable, afterCritical),
destination,
viewport: viewport.frame,
withDroppableDisplacement: true,
}),
)
.sort((a: DraggableDimension, b: DraggableDimension): number => {
// Need to consider the change in scroll in the destination
const distanceToA = distance(
pageBorderBoxCenter,
withDroppableDisplacement(
destination,
getCurrentPageBorderBoxCenter(a, afterCritical),
),
);
const distanceToB = distance(
pageBorderBoxCenter,
withDroppableDisplacement(
destination,
getCurrentPageBorderBoxCenter(b, afterCritical),
),
);
// if a is closer - return a
if (distanceToA < distanceToB) {
return -1;
}
// if b is closer - return b
if (distanceToB < distanceToA) {
return 1;
}
// if the distance to a and b are the same:
// return the one with the lower index (it will be higher on the main axis)
return a.descriptor.index - b.descriptor.index;
});
return sorted[0] || null;
};