126 lines
3.3 KiB
TypeScript
126 lines
3.3 KiB
TypeScript
import type { Rect } from 'css-box-model';
|
|
import type {
|
|
DraggableId,
|
|
Axis,
|
|
DraggableDimension,
|
|
DroppableDimension,
|
|
DragImpact,
|
|
LiftEffect,
|
|
DisplacedBy,
|
|
} from '../../types';
|
|
import getDidStartAfterCritical from '../did-start-after-critical';
|
|
import getDisplacedBy from '../get-displaced-by';
|
|
import getIsDisplaced from '../get-is-displaced';
|
|
import removeDraggableFromList from '../remove-draggable-from-list';
|
|
|
|
interface Args {
|
|
draggable: DraggableDimension;
|
|
pageBorderBoxWithDroppableScroll: Rect;
|
|
previousImpact: DragImpact;
|
|
destination: DroppableDimension;
|
|
insideDestination: DraggableDimension[];
|
|
afterCritical: LiftEffect;
|
|
}
|
|
|
|
// exported for testing
|
|
export const combineThresholdDivisor = 4;
|
|
|
|
export default ({
|
|
draggable,
|
|
pageBorderBoxWithDroppableScroll: targetRect,
|
|
previousImpact,
|
|
destination,
|
|
insideDestination,
|
|
afterCritical,
|
|
}: Args): DragImpact | null => {
|
|
if (!destination.isCombineEnabled) {
|
|
return null;
|
|
}
|
|
const axis: Axis = destination.axis;
|
|
const displacedBy: DisplacedBy = getDisplacedBy(
|
|
destination.axis,
|
|
draggable.displaceBy,
|
|
);
|
|
const displacement: number = displacedBy.value;
|
|
|
|
const targetStart: number = targetRect[axis.start];
|
|
const targetEnd: number = targetRect[axis.end];
|
|
|
|
const withoutDragging: DraggableDimension[] = removeDraggableFromList(
|
|
draggable,
|
|
insideDestination,
|
|
);
|
|
|
|
const combineWith = withoutDragging.find((child): boolean => {
|
|
const id: DraggableId = child.descriptor.id;
|
|
const childRect: Rect = child.page.borderBox;
|
|
const childSize: number = childRect[axis.size];
|
|
const threshold: number = childSize / combineThresholdDivisor;
|
|
|
|
const didStartAfterCritical: boolean = getDidStartAfterCritical(
|
|
id,
|
|
afterCritical,
|
|
);
|
|
|
|
const isDisplaced: boolean = getIsDisplaced({
|
|
displaced: previousImpact.displaced,
|
|
id,
|
|
});
|
|
|
|
/*
|
|
Only combining when in the combine region
|
|
As soon as a boundary is hit then no longer combining
|
|
*/
|
|
|
|
if (didStartAfterCritical) {
|
|
// In original position
|
|
// Will combine with item when inside a band
|
|
if (isDisplaced) {
|
|
return (
|
|
targetEnd > childRect[axis.start] + threshold &&
|
|
targetEnd < childRect[axis.end] - threshold
|
|
);
|
|
}
|
|
|
|
// child is now 'displaced' backwards from where it started
|
|
// want to combine when we move backwards onto it
|
|
return (
|
|
targetStart > childRect[axis.start] - displacement + threshold &&
|
|
targetStart < childRect[axis.end] - displacement - threshold
|
|
);
|
|
}
|
|
|
|
// item has moved forwards
|
|
if (isDisplaced) {
|
|
return (
|
|
targetEnd > childRect[axis.start] + displacement + threshold &&
|
|
targetEnd < childRect[axis.end] + displacement - threshold
|
|
);
|
|
}
|
|
|
|
// is in resting position - being moved backwards on to
|
|
return (
|
|
targetStart > childRect[axis.start] + threshold &&
|
|
targetStart < childRect[axis.end] - threshold
|
|
);
|
|
});
|
|
|
|
if (!combineWith) {
|
|
return null;
|
|
}
|
|
|
|
const impact: DragImpact = {
|
|
// no change to displacement when combining
|
|
displacedBy,
|
|
displaced: previousImpact.displaced,
|
|
at: {
|
|
type: 'COMBINE',
|
|
combine: {
|
|
draggableId: combineWith.descriptor.id,
|
|
droppableId: destination.descriptor.id,
|
|
},
|
|
},
|
|
};
|
|
return impact;
|
|
};
|