import type { Position } from 'css-box-model'; import type { DraggableId, DroppableDimension, DraggableDimension, DraggableDimensionMap, DragImpact, Displacement, DisplacementGroups, DraggableIdMap, DisplacementMap, Viewport, } from '../../types'; import scrollViewport from '../scroll-viewport'; import scrollDroppable from '../droppable/scroll-droppable'; import { add } from '../position'; import getDisplacementGroups from '../get-displacement-groups'; interface SpeculativeArgs { impact: DragImpact; destination: DroppableDimension; viewport: Viewport; draggables: DraggableDimensionMap; maxScrollChange: Position; } function getDraggables( ids: DraggableId[], draggables: DraggableDimensionMap, ): DraggableDimension[] { return ids.map((id: DraggableId): DraggableDimension => draggables[id]); } function tryGetVisible( id: DraggableId, groups: DisplacementGroups[], ): Displacement | null { for (let i = 0; i < groups.length; i++) { const displacement: Displacement | null = groups[i].visible[id]; if (displacement) { return displacement; } } return null; } export default ({ impact, viewport, destination, draggables, maxScrollChange, }: SpeculativeArgs): DragImpact => { const scrolledViewport: Viewport = scrollViewport( viewport, add(viewport.scroll.current, maxScrollChange), ); const scrolledDroppable: DroppableDimension = destination.frame ? scrollDroppable( destination, add(destination.frame.scroll.current, maxScrollChange), ) : destination; const last: DisplacementGroups = impact.displaced; const withViewportScroll: DisplacementGroups = getDisplacementGroups({ afterDragging: getDraggables(last.all, draggables), destination, displacedBy: impact.displacedBy, viewport: scrolledViewport.frame, last, // we want the addition to be animated forceShouldAnimate: false, }); const withDroppableScroll: DisplacementGroups = getDisplacementGroups({ afterDragging: getDraggables(last.all, draggables), destination: scrolledDroppable, displacedBy: impact.displacedBy, viewport: viewport.frame, last, // we want the addition to be animated forceShouldAnimate: false, }); const invisible: DraggableIdMap = {}; const visible: DisplacementMap = {}; const groups: DisplacementGroups[] = [ // this will populate the previous entries with the correct animation values last, withViewportScroll, withDroppableScroll, ]; last.all.forEach((id: DraggableId) => { const displacement: Displacement | null = tryGetVisible(id, groups); if (displacement) { visible[id] = displacement; return; } invisible[id] = true; }); const newImpact: DragImpact = { ...impact, displaced: { all: last.all, invisible, visible }, }; return newImpact; };