react-beautiful-dnd-next
Version:
Beautiful and accessible drag and drop for lists with React
78 lines (67 loc) • 1.98 kB
JavaScript
// @flow
import memoizeOne from 'memoize-one';
import invariant from 'tiny-invariant';
import { type Position } from 'css-box-model';
import type {
DroppableDimension,
DroppableDimensionMap,
DroppableId,
} from '../../../types';
import isPositionInFrame from '../../visibility/is-position-in-frame';
import { toDroppableList } from '../../dimension-structures';
import { find } from '../../../native-with-fallback';
const getScrollableDroppables = memoizeOne(
(droppables: DroppableDimensionMap): DroppableDimension[] =>
toDroppableList(droppables).filter(
(droppable: DroppableDimension): boolean => {
// exclude disabled droppables
if (!droppable.isEnabled) {
return false;
}
// only want droppables that are scrollable
if (!droppable.frame) {
return false;
}
return true;
},
),
);
const getScrollableDroppableOver = (
target: Position,
droppables: DroppableDimensionMap,
): ?DroppableDimension => {
const maybe: ?DroppableDimension = find(
getScrollableDroppables(droppables),
(droppable: DroppableDimension): boolean => {
invariant(droppable.frame, 'Invalid result');
return isPositionInFrame(droppable.frame.pageMarginBox)(target);
},
);
return maybe;
};
type Api = {|
center: Position,
destination: ?DroppableId,
droppables: DroppableDimensionMap,
|};
export default ({
center,
destination,
droppables,
}: Api): ?DroppableDimension => {
// We need to scroll the best droppable frame we can so that the
// placeholder buffer logic works correctly
if (destination) {
const dimension: DroppableDimension = droppables[destination];
if (!dimension.frame) {
return null;
}
return dimension;
}
// 2. If we are not over a droppable - are we over a droppable frame?
const dimension: ?DroppableDimension = getScrollableDroppableOver(
center,
droppables,
);
return dimension;
};