import type { Position } from 'css-box-model'; import type { DragImpact, DraggableDimension, DraggableDimensionMap, DroppableDimension, Viewport, DisplacedBy, LiftEffect, } from '../../../types'; import getDisplacedBy from '../../get-displaced-by'; import { emptyGroups, noDisplacedBy } from '../../no-impact'; import getPageBorderBoxCenter from '../../get-center-from-impact/get-page-border-box-center'; import isTotallyVisibleInNewLocation from '../move-to-next-place/is-totally-visible-in-new-location'; import { addPlaceholder } from '../../droppable/with-placeholder'; import isHomeOf from '../../droppable/is-home-of'; import calculateReorderImpact from '../../calculate-drag-impact/calculate-reorder-impact'; interface Args { previousPageBorderBoxCenter: Position; moveRelativeTo: DraggableDimension | null; insideDestination: DraggableDimension[]; draggable: DraggableDimension; draggables: DraggableDimensionMap; destination: DroppableDimension; viewport: Viewport; afterCritical: LiftEffect; } export default ({ previousPageBorderBoxCenter, moveRelativeTo, insideDestination, draggable, draggables, destination, viewport, afterCritical, }: Args): DragImpact | null => { if (!moveRelativeTo) { // Draggables available, but none are candidates for movement if (insideDestination.length) { return null; } // Try move to top of empty list if it is visible const proposed: DragImpact = { displaced: emptyGroups, displacedBy: noDisplacedBy, at: { type: 'REORDER', destination: { droppableId: destination.descriptor.id, index: 0, }, }, }; const proposedPageBorderBoxCenter: Position = getPageBorderBoxCenter({ impact: proposed, draggable, droppable: destination, draggables, afterCritical, }); // need to add room for a placeholder in a foreign list const withPlaceholder: DroppableDimension = isHomeOf(draggable, destination) ? destination : addPlaceholder(destination, draggable, draggables); const isVisibleInNewLocation: boolean = isTotallyVisibleInNewLocation({ draggable, destination: withPlaceholder, newPageBorderBoxCenter: proposedPageBorderBoxCenter, viewport: viewport.frame, // already taken into account by getPageBorderBoxCenter withDroppableDisplacement: false, onlyOnMainAxis: true, }); return isVisibleInNewLocation ? proposed : null; } const isGoingBeforeTarget = Boolean( // Using <= as we optimise slightly for moving before items in a new list // This is nicer in lists with fixed height items previousPageBorderBoxCenter[destination.axis.line] <= moveRelativeTo.page.borderBox.center[destination.axis.line], ); const proposedIndex: number = (() => { const relativeTo: number = moveRelativeTo.descriptor.index; if (moveRelativeTo.descriptor.id === draggable.descriptor.id) { return relativeTo; } if (isGoingBeforeTarget) { return relativeTo; } return relativeTo + 1; })(); const displacedBy: DisplacedBy = getDisplacedBy( destination.axis, draggable.displaceBy, ); return calculateReorderImpact({ draggable, insideDestination, destination, viewport, displacedBy, // last groups won't be relevant last: emptyGroups, index: proposedIndex, }); };