react-beautiful-dnd
Version:
A beautiful, accessible drag and drop library for lists with React.js
145 lines (129 loc) • 3.29 kB
JavaScript
// @flow
import type {
DroppableId,
DraggableId,
Position,
DraggableDimension,
DroppableDimension,
DimensionFragment,
} from '../types';
export type ClientRect = {|
top: number,
right: number,
bottom: number,
left: number,
width: number,
height: number,
|}
export type Margin = {|
top: number,
right: number,
bottom: number,
left: number,
|}
const origin: Position = { x: 0, y: 0 };
export const noMargin: Margin = {
top: 0,
right: 0,
bottom: 0,
left: 0,
};
const getWithPosition = (clientRect: ClientRect, point: Position): ClientRect => {
const { top, right, bottom, left, width, height } = clientRect;
return {
top: top + point.y,
left: left + point.x,
bottom: bottom + point.y,
right: right + point.x,
height,
width,
};
};
const getWithMargin = (clientRect: ClientRect, margin: Margin): ClientRect => {
const { top, right, bottom, left, height, width } = clientRect;
return {
top: top + margin.top,
left: left + margin.left,
bottom: bottom + margin.bottom,
right: right + margin.right,
height: height + margin.top + margin.bottom,
width: width + margin.left + margin.right,
};
};
const getFragment = (
initial: ClientRect | DimensionFragment,
point?: Position = origin,
): DimensionFragment => ({
top: initial.top + point.y,
left: initial.left + point.x,
bottom: initial.bottom + point.y,
right: initial.right + point.x,
width: initial.width,
height: initial.height,
center: {
x: ((initial.right + point.x) + (initial.left + point.x)) / 2,
y: ((initial.bottom + point.y) + (initial.top + point.y)) / 2,
},
});
type GetDraggableArgs = {|
id: DraggableId,
droppableId: DroppableId,
clientRect: ClientRect,
margin?: Margin,
windowScroll?: Position,
|};
export const getDraggableDimension = ({
id,
droppableId,
clientRect,
margin = noMargin,
windowScroll = origin,
}: GetDraggableArgs): DraggableDimension => {
const withScroll = getWithPosition(clientRect, windowScroll);
const withScrollAndMargin = getWithMargin(withScroll, margin);
const dimension: DraggableDimension = {
id,
droppableId,
// on the viewport
client: {
withoutMargin: getFragment(clientRect),
withMargin: getFragment(getWithMargin(clientRect, margin)),
},
// with scroll
page: {
withoutMargin: getFragment(withScroll),
withMargin: getFragment(withScrollAndMargin),
},
};
return dimension;
};
type GetDroppableArgs = {|
id: DroppableId,
clientRect: ClientRect,
margin?: Margin,
windowScroll?: Position,
scroll?: Position,
|}
export const getDroppableDimension = ({
id,
clientRect,
margin = noMargin,
windowScroll = origin,
scroll = origin,
}: GetDroppableArgs): DroppableDimension => {
const withWindowScroll = getWithPosition(clientRect, windowScroll);
const withWindowScrollAndMargin = getWithMargin(withWindowScroll, margin);
const dimension: DroppableDimension = {
id,
scroll: {
initial: scroll,
// when we start the current scroll is the initial scroll
current: scroll,
},
page: {
withoutMargin: getFragment(withWindowScroll),
withMargin: getFragment(withWindowScrollAndMargin),
},
};
return dimension;
};