react-beautiful-dnd
Version:
Beautiful, accessible drag and drop for lists with React.js
72 lines (64 loc) • 1.95 kB
JavaScript
// @flow
import { distance } from '../position';
import { isTotallyVisible } from '../visibility/is-visible';
import withDroppableDisplacement from '../with-droppable-displacement';
import type {
Viewport,
Axis,
Position,
DraggableDimension,
DroppableDimension,
} from '../../types';
type Args = {|
axis: Axis,
viewport: Viewport,
pageCenter: Position,
// the droppable that is being moved to
destination: DroppableDimension,
// the droppables inside the destination
insideDestination: DraggableDimension[],
|}
export default ({
axis,
viewport,
pageCenter,
destination,
insideDestination,
}: Args): ?DraggableDimension => {
// Empty list - bail out
if (!insideDestination.length) {
return null;
}
const result: DraggableDimension[] = insideDestination
// Remove any options that are hidden by overflow
// Draggable must be totally visible to move to it
.filter((draggable: DraggableDimension): boolean =>
isTotallyVisible({
target: draggable.page.marginBox,
destination,
viewport: viewport.subject,
}))
.sort((a: DraggableDimension, b: DraggableDimension): number => {
// Need to consider the change in scroll in the destination
const distanceToA = distance(
pageCenter,
withDroppableDisplacement(destination, a.page.marginBox.center)
);
const distanceToB = distance(
pageCenter,
withDroppableDisplacement(destination, b.page.marginBox.center)
);
// 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 that appears first on the main axis
return a.page.marginBox[axis.start] - b.page.marginBox[axis.start];
});
return result.length ? result[0] : null;
};