Skip to content

Commit

Permalink
A new collision engine (#1638)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexreardon authored Dec 4, 2019
2 parents cf5c727 + 5f43206 commit c54e509
Show file tree
Hide file tree
Showing 73 changed files with 2,428 additions and 2,000 deletions.
22 changes: 11 additions & 11 deletions .size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
{
"dist/react-beautiful-dnd.js": {
"bundled": 381298,
"minified": 140093,
"gzipped": 42104
"bundled": 379875,
"minified": 139571,
"gzipped": 41966
},
"dist/react-beautiful-dnd.min.js": {
"bundled": 322912,
"minified": 115528,
"gzipped": 34201
"bundled": 321489,
"minified": 115006,
"gzipped": 34084
},
"dist/react-beautiful-dnd.esm.js": {
"bundled": 242417,
"minified": 126431,
"gzipped": 32987,
"bundled": 241086,
"minified": 125714,
"gzipped": 32875,
"treeshaked": {
"rollup": {
"code": 21303,
"code": 21306,
"import_statements": 788
},
"webpack": {
"code": 24960
"code": 24963
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-beautiful-dnd",
"version": "12.1.1",
"version": "12.2.0-alpha.1",
"description": "Beautiful and accessible drag and drop for lists with React",
"author": "Alex Reardon <areardon@atlassian.com>",
"keywords": [
Expand Down
64 changes: 0 additions & 64 deletions src/state/calculate-drag-impact/calculate-combine-impact.js

This file was deleted.

176 changes: 79 additions & 97 deletions src/state/get-drag-impact/get-combine-impact.js
Original file line number Diff line number Diff line change
@@ -1,148 +1,130 @@
// @flow
import type { Rect, Position } from 'css-box-model';
import type { Rect } from 'css-box-model';
import type {
DraggableId,
Axis,
UserDirection,
DraggableDimension,
DroppableDimension,
CombineImpact,
DragImpact,
DisplacementGroups,
LiftEffect,
DisplacedBy,
} from '../../types';
import isWithin from '../is-within';
import { find } from '../../native-with-fallback';
import isUserMovingForward from '../user-direction/is-user-moving-forward';
import getCombinedItemDisplacement from '../get-combined-item-displacement';
import removeDraggableFromList from '../remove-draggable-from-list';
import calculateCombineImpact from '../calculate-drag-impact/calculate-combine-impact';
import getDidStartAfterCritical from '../did-start-after-critical';
import getDisplacedBy from '../get-displaced-by';

function getWhenEntered(
id: DraggableId,
current: UserDirection,
lastCombineImpact: ?CombineImpact,
): UserDirection {
if (!lastCombineImpact) {
return current;
}
if (id !== lastCombineImpact.combine.draggableId) {
return current;
}
return lastCombineImpact.whenEntered;
}

type IsCombiningWithArgs = {|
id: DraggableId,
currentCenter: Position,
axis: Axis,
borderBox: Rect,
displaceBy: Position,
currentUserDirection: UserDirection,
lastCombineImpact: ?CombineImpact,
|};

const isCombiningWith = ({
id,
currentCenter,
axis,
borderBox,
displaceBy,
currentUserDirection,
lastCombineImpact,
}: IsCombiningWithArgs): boolean => {
const start: number = borderBox[axis.start] + displaceBy[axis.line];
const end: number = borderBox[axis.end] + displaceBy[axis.line];
const size: number = borderBox[axis.size];
const twoThirdsOfSize: number = size * 0.666;

const whenEntered: UserDirection = getWhenEntered(
id,
currentUserDirection,
lastCombineImpact,
);
const isMovingForward: boolean = isUserMovingForward(axis, whenEntered);
const targetCenter: number = currentCenter[axis.line];

if (isMovingForward) {
// combine when moving in the front 2/3 of the item
return isWithin(start, start + twoThirdsOfSize)(targetCenter);
}
// combine when moving in the back 2/3 of the item
return isWithin(end - twoThirdsOfSize, end)(targetCenter);
};

function tryGetCombineImpact(impact: DragImpact): ?CombineImpact {
if (impact.at && impact.at.type === 'COMBINE') {
return impact.at;
}
return null;
}
import getIsDisplaced from '../get-is-displaced';
import removeDraggableFromList from '../remove-draggable-from-list';

type Args = {|
draggable: DraggableDimension,
pageBorderBoxCenterWithDroppableScrollChange: Position,
pageBorderBoxWithDroppableScroll: Rect,
previousImpact: DragImpact,
destination: DroppableDimension,
insideDestination: DraggableDimension[],
userDirection: UserDirection,
afterCritical: LiftEffect,
|};

// exported for testing
export const combineThresholdDivisor: number = 4;

export default ({
draggable,
pageBorderBoxCenterWithDroppableScrollChange: currentCenter,
pageBorderBoxWithDroppableScroll: targetRect,
previousImpact,
destination,
insideDestination,
userDirection,
afterCritical,
}: Args): ?DragImpact => {
if (!destination.isCombineEnabled) {
return null;
}

const axis: Axis = destination.axis;
const displaced: DisplacementGroups = previousImpact.displaced;
const canBeDisplacedBy: DisplacedBy = getDisplacedBy(
const displacedBy: DisplacedBy = getDisplacedBy(
destination.axis,
draggable.displaceBy,
);
const lastCombineImpact: ?CombineImpact = tryGetCombineImpact(previousImpact);
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: ?DraggableDimension = find(
removeDraggableFromList(draggable, insideDestination),
withoutDragging,
(child: DraggableDimension): 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 displaceBy: Position = getCombinedItemDisplacement({
displaced,
const didStartAfterCritical: boolean = getDidStartAfterCritical(
id,
afterCritical,
combineWith: id,
displacedBy: canBeDisplacedBy,
});
);

return isCombiningWith({
const isDisplaced: boolean = getIsDisplaced({
displaced: previousImpact.displaced,
id,
currentCenter,
axis,
borderBox: child.page.borderBox,
displaceBy,
currentUserDirection: userDirection,
lastCombineImpact,
});

/*
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;
}

return calculateCombineImpact({
combineWithId: combineWith.descriptor.id,
destinationId: destination.descriptor.id,
previousImpact,
userDirection,
});
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;
};
Loading

0 comments on commit c54e509

Please sign in to comment.