react-beautiful-dnd
Version:
Beautiful, accessible drag and drop for lists with React.js
250 lines (216 loc) • 6.27 kB
JavaScript
// @flow
import type { Store as ReduxStore, Dispatch as ReduxDispatch } from 'redux';
import type { Action as ActionCreators } from './state/action-creators';
export type Id = string;
export type DraggableId = Id;
export type DroppableId = Id;
export type TypeId = Id;
export type ZIndex = number | string;
export type Position = {|
x: number,
y: number,
|};
export type Spacing = {
top: number,
right: number,
bottom: number,
left: number,
}
export type ClientRect = {|
top: number,
right: number,
bottom: number,
left: number,
width: number,
height: number,
|}
export type Direction = 'horizontal' | 'vertical';
export type VerticalAxis = {|
direction: 'vertical',
line: 'y',
crossLine: 'x',
start: 'top',
end: 'bottom',
size: 'height',
crossAxisStart: 'left',
crossAxisEnd: 'right',
crossAxisSize: 'width',
|}
export type HorizontalAxis = {|
direction: 'horizontal',
line: 'x',
crossLine: 'y',
start: 'left',
end: 'right',
size: 'width',
crossAxisStart: 'top',
crossAxisEnd: 'bottom',
crossAxisSize: 'height',
|}
export type Axis = VerticalAxis | HorizontalAxis
export type DimensionFragment = {|
...ClientRect,
center: Position,
|}
export type DraggableDimension = {|
id: DraggableId,
droppableId: DroppableId,
// relative to the viewport when the drag started
client: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
|},
// relative to the whole page
page: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
|},
|}
export type DroppableDimension = {|
id: DroppableId,
axis: Axis,
isEnabled: boolean,
// relative to the current viewport
client: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
// the area in which content presses up against
withMarginAndPadding: DimensionFragment,
|},
// relative to the whole page
page: {|
withMargin: DimensionFragment,
withoutMargin: DimensionFragment,
// the area in which content presses up against
withMarginAndPadding: DimensionFragment,
|},
// Some droppables will have a scroll container - either themselves or a parent element.
// We need to take into account the dimensions and scroll of this container when calculating
// the true visible area of the droppable. If the droppable doesn't have scrolling then
// the dimension of the container will be the same as the dimensions of the droppable itself.
container: {|
scroll: {|
initial: Position,
current: Position,
|},
bounds: DimensionFragment,
|},
|}
export type DraggableLocation = {|
droppableId: DroppableId,
index: number
|};
export type DraggableDimensionMap = { [key: DraggableId]: DraggableDimension };
export type DroppableDimensionMap = { [key: DroppableId]: DroppableDimension };
export type DragMovement = {|
// The draggables that need to move in response to a drag.
// Ordered by closest draggable to the *current* location of the dragging item
draggables: DraggableId[],
amount: Position,
// is moving forward relative to the starting position
isBeyondStartPosition: boolean,
|}
export type DragImpact = {|
movement: DragMovement,
// the direction of the Droppable you are over
direction: ?Direction,
destination: ?DraggableLocation,
|}
export type InitialDragLocation = {|
selection: Position,
center: Position,
|}
export type InitialDrag = {|
source: DraggableLocation,
// relative to the viewport when the drag started
client: InitialDragLocation,
// viewport + window scroll (position relative to 0, 0)
page: InitialDragLocation,
// Storing scroll directly to support movement during a window scroll.
// Value required for comparison with current scroll
windowScroll: Position,
|}
export type CurrentDragLocation = {|
// where the user initially selected
selection: Position,
// the current center of the item
center: Position,
// how far the item has moved from its original position
offset: Position,
|}
export type CurrentDrag = {|
id: DraggableId,
type: TypeId,
// whether scrolling is allowed - otherwise a scroll will cancel the drag
isScrollAllowed: boolean,
// viewport
client: CurrentDragLocation,
// viewport + scroll
page: CurrentDragLocation,
// Storing scroll directly to support movement during a window scroll.
// Value required for comparison with current scroll
windowScroll: Position,
// whether or not movements should be animated
shouldAnimate: boolean,
|}
type PreviousDrag = {
droppableOverId: ?DroppableId,
};
// published when a drag starts
export type DragStart = {|
draggableId: DraggableId,
type: TypeId,
source: DraggableLocation,
|}
// published when a drag finishes
export type DropResult = {|
draggableId: DraggableId,
type: TypeId,
source: DraggableLocation,
// may not have any destination (drag to nowhere)
destination: ?DraggableLocation,
|}
export type DragState = {|
initial: InitialDrag,
current: CurrentDrag,
impact: DragImpact,
previous?: PreviousDrag,
|}
export type DropTrigger = 'DROP' | 'CANCEL';
export type PendingDrop = {|
trigger: DropTrigger,
newHomeOffset: Position,
impact: DragImpact,
result: DropResult,
|}
export type Phase = 'IDLE' | 'COLLECTING_DIMENSIONS' | 'DRAGGING' | 'DROP_ANIMATING' | 'DROP_COMPLETE';
export type DimensionState = {|
request: ?TypeId,
draggable: DraggableDimensionMap,
droppable: DroppableDimensionMap,
|};
export type DropState = {|
pending: ?PendingDrop,
result: ?DropResult,
|}
export type State = {
phase: Phase,
dimension: DimensionState,
// null if not dragging
drag: ?DragState,
// available when dropping or cancelling
drop: ?DropState,
};
export type Action = ActionCreators;
export type Dispatch = ReduxDispatch<Action>;
export type Store = ReduxStore<State, Action, Dispatch>;
export type Hooks = {
onDragStart?: (start: DragStart) => void,
onDragEnd: (result: DropResult) => void,
}
// These types are 'fake'. They really just resolve to 'any'.
// But it is useful for readability and intention
export type ReactClass = any;
export type ReactElement = any;
export type HTMLElement = any;
export type HOC = (Component: ReactClass) => ReactClass;