UNPKG

react-beautiful-dnd

Version:

Beautiful, accessible drag and drop for lists with React.js

136 lines (119 loc) 3.83 kB
// @flow import invariant from 'tiny-invariant'; import { type Position } from 'css-box-model'; import moveToEdge from '../../../move-to-edge'; import getDisplacement from '../../../get-displacement'; import withDroppableDisplacement from '../../../with-droppable-displacement'; import type { Edge } from '../../../move-to-edge'; import type { Result } from '../move-cross-axis-types'; import type { Axis, Viewport, Displacement, DragImpact, DraggableDimension, DroppableDimension, } from '../../../../types'; type Args = {| amount: Position, homeIndex: number, movingRelativeTo: DraggableDimension, insideDestination: DraggableDimension[], draggable: DraggableDimension, destination: DroppableDimension, previousImpact: DragImpact, viewport: Viewport, |}; export default ({ amount, homeIndex, movingRelativeTo, insideDestination, draggable, destination, previousImpact, viewport, }: Args): Result => { const axis: Axis = destination.axis; const targetIndex: number = insideDestination.indexOf(movingRelativeTo); invariant( targetIndex !== -1, 'Unable to find target in destination droppable', ); // Moving back to original index // Super simple - just move it back to the original center with no impact if (targetIndex === homeIndex) { const newCenter: Position = draggable.page.borderBox.center; const newImpact: DragImpact = { movement: { displaced: [], amount, isBeyondStartPosition: false, }, direction: destination.axis.direction, destination: { droppableId: destination.descriptor.id, index: homeIndex, }, }; return { pageBorderBoxCenter: withDroppableDisplacement(destination, newCenter), impact: newImpact, }; } // When moving *before* where the item started: // We align the dragging item top of the target // and move everything from the target to the original position forwards // When moving *after* where the item started: // We align the dragging item to the end of the target // and move everything from the target to the original position backwards const isMovingPastOriginalIndex = targetIndex > homeIndex; const edge: Edge = isMovingPastOriginalIndex ? 'end' : 'start'; const newCenter: Position = moveToEdge({ source: draggable.page.borderBox, sourceEdge: edge, destination: isMovingPastOriginalIndex ? movingRelativeTo.page.borderBox : movingRelativeTo.page.marginBox, destinationEdge: edge, destinationAxis: axis, }); const modified: DraggableDimension[] = (() => { if (!isMovingPastOriginalIndex) { return insideDestination.slice(targetIndex, homeIndex); } // We are aligning to the bottom of the target and moving everything // back to the original index backwards // We want everything after the original index to move const from: number = homeIndex + 1; // We need the target to move backwards const to: number = targetIndex + 1; // Need to ensure that the list is sorted with the closest item being first return insideDestination.slice(from, to).reverse(); })(); const displaced: Displacement[] = modified.map( (dimension: DraggableDimension): Displacement => getDisplacement({ draggable: dimension, destination, previousImpact, viewport: viewport.frame, }), ); const newImpact: DragImpact = { movement: { displaced, amount, isBeyondStartPosition: isMovingPastOriginalIndex, }, direction: axis.direction, destination: { droppableId: destination.descriptor.id, index: targetIndex, }, }; return { pageBorderBoxCenter: withDroppableDisplacement(destination, newCenter), impact: newImpact, }; };