react-beautiful-dnd
Version:
Beautiful, accessible drag and drop for lists with React.js
66 lines (53 loc) • 2.37 kB
JavaScript
// @flow
import isWithin from './is-within';
import { subtract } from './position';
import { offset } from './spacing';
import type {
Position,
DraggableDimension,
DroppableDimension,
DimensionFragment,
Spacing,
} from '../types';
export const getVisibleBounds = (droppable: DroppableDimension): Spacing => {
const { scroll, bounds: containerBounds } = droppable.container;
// Calculate the mid-drag scroll ∆ of the scroll container
const containerScrollDiff: Position = subtract(scroll.initial, scroll.current);
// Calculate the droppable's bounds, accounting for the container's scroll
const droppableBounds: Spacing = offset(droppable.page.withMargin, containerScrollDiff);
// Clip the droppable's bounds by the scroll container's bounds
// This gives us the droppable's true visible area
// Note: if the droppable doesn't have a scroll parent droppableBounds === container.page
const clippedBounds: Spacing = {
top: Math.max(droppableBounds.top, containerBounds.top),
right: Math.min(droppableBounds.right, containerBounds.right),
bottom: Math.min(droppableBounds.bottom, containerBounds.bottom),
left: Math.max(droppableBounds.left, containerBounds.left),
};
return clippedBounds;
};
const isPointWithin = (bounds: Spacing) => {
const isWithinHorizontal = isWithin(bounds.left, bounds.right);
const isWithinVertical = isWithin(bounds.top, bounds.bottom);
return (point: Position): boolean => (
isWithinHorizontal(point.x) &&
isWithinVertical(point.y)
);
};
export const isPointWithinDroppable = (droppable: DroppableDimension) => (
isPointWithin(getVisibleBounds(droppable))
);
export const isDraggableWithin = (bounds: Spacing) => {
const { top, right, bottom, left } = bounds;
// There are some extremely minor inaccuracy in the calculations of margins (~0.001)
// To allow for this inaccuracy we make the dimension slightly bigger for this calculation
const isWithinHorizontal = isWithin(left - 1, right + 1);
const isWithinVertical = isWithin(top - 1, bottom + 1);
return (draggable: DraggableDimension): boolean => {
const fragment: DimensionFragment = draggable.page.withMargin;
return isWithinHorizontal(fragment.left) &&
isWithinHorizontal(fragment.right) &&
isWithinVertical(fragment.top) &&
isWithinVertical(fragment.bottom);
};
};