@hello-pangea/dnd
Version:
Beautiful and accessible drag and drop for lists with React
136 lines (121 loc) • 2.94 kB
text/typescript
import type {
DraggableDimension,
DroppableDimension,
DragImpact,
DisplacementGroups,
Viewport,
DisplacedBy,
} from '../../types';
import removeDraggableFromList from '../remove-draggable-from-list';
import isHomeOf from '../droppable/is-home-of';
import { emptyGroups } from '../no-impact';
import getDisplacementGroups from '../get-displacement-groups';
interface Args {
draggable: DraggableDimension;
insideDestination: DraggableDimension[];
destination: DroppableDimension;
viewport: Viewport;
displacedBy: DisplacedBy;
last: DisplacementGroups;
index: number | null;
forceShouldAnimate?: boolean;
}
function getIndexOfLastItem(
draggables: DraggableDimension[],
options: {
inHomeList: boolean;
},
): number {
if (!draggables.length) {
return 0;
}
const indexOfLastItem: number =
draggables[draggables.length - 1].descriptor.index;
// When in a foreign list there will be an additional one item in the list
return options.inHomeList ? indexOfLastItem : indexOfLastItem + 1;
}
interface GoAtEndArgs {
insideDestination: DraggableDimension[];
inHomeList: boolean;
displacedBy: DisplacedBy;
destination: DroppableDimension;
}
function goAtEnd({
insideDestination,
inHomeList,
displacedBy,
destination,
}: GoAtEndArgs): DragImpact {
const newIndex: number = getIndexOfLastItem(insideDestination, {
inHomeList,
});
return {
displaced: emptyGroups,
displacedBy,
at: {
type: 'REORDER',
destination: {
droppableId: destination.descriptor.id,
index: newIndex,
},
},
};
}
export default function calculateReorderImpact({
draggable,
insideDestination,
destination,
viewport,
displacedBy,
last,
index,
forceShouldAnimate,
}: Args): DragImpact {
const inHomeList: boolean = isHomeOf(draggable, destination);
// Go into last spot of list
if (index == null) {
return goAtEnd({
insideDestination,
inHomeList,
displacedBy,
destination,
});
}
// this might be the dragging item
const match = insideDestination.find(
(item: DraggableDimension) => item.descriptor.index === index,
);
if (!match) {
return goAtEnd({
insideDestination,
inHomeList,
displacedBy,
destination,
});
}
const withoutDragging: DraggableDimension[] = removeDraggableFromList(
draggable,
insideDestination,
);
const sliceFrom: number = insideDestination.indexOf(match);
const impacted: DraggableDimension[] = withoutDragging.slice(sliceFrom);
const displaced: DisplacementGroups = getDisplacementGroups({
afterDragging: impacted,
destination,
displacedBy,
last,
viewport: viewport.frame,
forceShouldAnimate,
});
return {
displaced,
displacedBy,
at: {
type: 'REORDER',
destination: {
droppableId: destination.descriptor.id,
index,
},
},
};
}