@hello-pangea/dnd
Version:
Beautiful and accessible drag and drop for lists with React
82 lines (73 loc) • 2.31 kB
text/typescript
import { invariant } from '../invariant';
import getHomeLocation from './get-home-location';
import type {
DraggableDimension,
DroppableDimension,
DraggableDimensionMap,
DragImpact,
DisplacedBy,
Viewport,
DraggableIdMap,
DisplacementGroups,
LiftEffect,
} from '../types';
import getDraggablesInsideDroppable from './get-draggables-inside-droppable';
import getDisplacedBy from './get-displaced-by';
import getDisplacementGroups from './get-displacement-groups';
interface Args {
draggable: DraggableDimension;
home: DroppableDimension;
draggables: DraggableDimensionMap;
viewport: Viewport;
}
interface Result {
afterCritical: LiftEffect;
impact: DragImpact;
}
export default ({ draggable, home, draggables, viewport }: Args): Result => {
const displacedBy: DisplacedBy = getDisplacedBy(
home.axis,
draggable.displaceBy,
);
const insideHome: DraggableDimension[] = getDraggablesInsideDroppable(
home.descriptor.id,
draggables,
);
// in a list that does not start at 0 the descriptor.index might be different from the index in the list
// eg a list could be: [2,3,4]. A descriptor.index of '2' would actually be in index '0' of the list
const rawIndex: number = insideHome.indexOf(draggable);
invariant(rawIndex !== -1, 'Expected draggable to be inside home list');
const afterDragging: DraggableDimension[] = insideHome.slice(rawIndex + 1);
const effected: DraggableIdMap = afterDragging.reduce(
(previous: DraggableIdMap, item: DraggableDimension): DraggableIdMap => {
previous[item.descriptor.id] = true;
return previous;
},
{},
);
const afterCritical: LiftEffect = {
inVirtualList: home.descriptor.mode === 'virtual',
displacedBy,
effected,
};
const displaced: DisplacementGroups = getDisplacementGroups({
afterDragging,
destination: home,
displacedBy,
last: null,
viewport: viewport.frame,
// originally we do not want any animation as we want
// everything to be fixed in the same position that
// it started in
forceShouldAnimate: false,
});
const impact: DragImpact = {
displaced,
displacedBy,
at: {
type: 'REORDER',
destination: getHomeLocation(draggable.descriptor),
},
};
return { impact, afterCritical };
};