UNPKG

react-beautiful-dnd-next

Version:

Beautiful and accessible drag and drop for lists with React

118 lines (106 loc) 3.6 kB
// @flow import { type Position, type Rect } from 'css-box-model'; import type { DragMovement, DraggableDimension, DroppableDimension, DragImpact, Axis, Displacement, Viewport, UserDirection, DisplacedBy, OnLift, } from '../../types'; import getDisplacement from '../get-displacement'; import getDisplacementMap from '../get-displacement-map'; import isUserMovingForward from '../user-direction/is-user-moving-forward'; import getDisplacedBy from '../get-displaced-by'; import getDidStartDisplaced from '../starting-displaced/did-start-displaced'; type Args = {| pageBorderBoxCenterWithDroppableScrollChange: Position, draggable: DraggableDimension, destination: DroppableDimension, insideDestinationWithoutDraggable: DraggableDimension[], previousImpact: DragImpact, viewport: Viewport, userDirection: UserDirection, onLift: OnLift, |}; export default ({ pageBorderBoxCenterWithDroppableScrollChange: currentCenter, draggable, destination, insideDestinationWithoutDraggable, previousImpact, viewport, userDirection, onLift, }: Args): DragImpact => { const axis: Axis = destination.axis; const isMovingForward: boolean = isUserMovingForward( destination.axis, userDirection, ); const displacedBy: DisplacedBy = getDisplacedBy( destination.axis, draggable.displaceBy, ); const targetCenter: number = currentCenter[axis.line]; const displacement: number = displacedBy.value; const displaced: Displacement[] = insideDestinationWithoutDraggable .filter((child: DraggableDimension): boolean => { const borderBox: Rect = child.page.borderBox; const start: number = borderBox[axis.start]; const end: number = borderBox[axis.end]; const didStartDisplaced: boolean = getDidStartDisplaced( child.descriptor.id, onLift, ); // Moving forward will decrease the amount of things needed to be displaced if (isMovingForward) { if (didStartDisplaced) { // if started displaced then its displaced position is its resting position // continue to keep the item at rest until we go onto the start of the item return targetCenter < start; } // if the item did not start displaced then we displace the item // while we are still before the start edge return targetCenter < start + displacement; } // Moving backwards will increase the amount of things needed to be displaced // The logic for this works by looking at assuming everything has been displaced // backwards and then looking at how you would undo that if (didStartDisplaced) { // we continue to displace the item until we move back over the end of the item without displacement return targetCenter <= end - displacement; } // a non-displaced item is at rest. when we hit the item from the bottom we move it out of the way return targetCenter <= end; }) .map((dimension: DraggableDimension): Displacement => getDisplacement({ draggable: dimension, destination, previousImpact, viewport: viewport.frame, onLift, }), ); const newIndex: number = insideDestinationWithoutDraggable.length - displaced.length; const movement: DragMovement = { displacedBy, displaced, map: getDisplacementMap(displaced), }; const impact: DragImpact = { movement, destination: { droppableId: destination.descriptor.id, index: newIndex, }, merge: null, }; return impact; };