|
1 | 1 | // @flow |
2 | | -import type { Rect, Position } from 'css-box-model'; |
| 2 | +import type { Rect } from 'css-box-model'; |
3 | 3 | import type { |
4 | 4 | DraggableId, |
5 | 5 | Axis, |
6 | | - UserDirection, |
7 | 6 | DraggableDimension, |
8 | 7 | DroppableDimension, |
9 | | - CombineImpact, |
10 | 8 | DragImpact, |
11 | | - DisplacementGroups, |
12 | 9 | LiftEffect, |
13 | 10 | DisplacedBy, |
14 | 11 | } from '../../types'; |
15 | | -import isWithin from '../is-within'; |
16 | 12 | import { find } from '../../native-with-fallback'; |
17 | | -import isUserMovingForward from '../user-direction/is-user-moving-forward'; |
18 | | -import getCombinedItemDisplacement from '../get-combined-item-displacement'; |
19 | | -import removeDraggableFromList from '../remove-draggable-from-list'; |
20 | | -import calculateCombineImpact from '../calculate-drag-impact/calculate-combine-impact'; |
| 13 | +import getDidStartAfterCritical from '../did-start-after-critical'; |
21 | 14 | import getDisplacedBy from '../get-displaced-by'; |
22 | | - |
23 | | -function getWhenEntered( |
24 | | - id: DraggableId, |
25 | | - current: UserDirection, |
26 | | - lastCombineImpact: ?CombineImpact, |
27 | | -): UserDirection { |
28 | | - if (!lastCombineImpact) { |
29 | | - return current; |
30 | | - } |
31 | | - if (id !== lastCombineImpact.combine.draggableId) { |
32 | | - return current; |
33 | | - } |
34 | | - return lastCombineImpact.whenEntered; |
35 | | -} |
36 | | - |
37 | | -type IsCombiningWithArgs = {| |
38 | | - id: DraggableId, |
39 | | - currentCenter: Position, |
40 | | - axis: Axis, |
41 | | - borderBox: Rect, |
42 | | - displaceBy: Position, |
43 | | - currentUserDirection: UserDirection, |
44 | | - lastCombineImpact: ?CombineImpact, |
45 | | -|}; |
46 | | - |
47 | | -const isCombiningWith = ({ |
48 | | - id, |
49 | | - currentCenter, |
50 | | - axis, |
51 | | - borderBox, |
52 | | - displaceBy, |
53 | | - currentUserDirection, |
54 | | - lastCombineImpact, |
55 | | -}: IsCombiningWithArgs): boolean => { |
56 | | - const start: number = borderBox[axis.start] + displaceBy[axis.line]; |
57 | | - const end: number = borderBox[axis.end] + displaceBy[axis.line]; |
58 | | - const size: number = borderBox[axis.size]; |
59 | | - const twoThirdsOfSize: number = size * 0.666; |
60 | | - |
61 | | - const whenEntered: UserDirection = getWhenEntered( |
62 | | - id, |
63 | | - currentUserDirection, |
64 | | - lastCombineImpact, |
65 | | - ); |
66 | | - const isMovingForward: boolean = isUserMovingForward(axis, whenEntered); |
67 | | - const targetCenter: number = currentCenter[axis.line]; |
68 | | - |
69 | | - if (isMovingForward) { |
70 | | - // combine when moving in the front 2/3 of the item |
71 | | - return isWithin(start, start + twoThirdsOfSize)(targetCenter); |
72 | | - } |
73 | | - // combine when moving in the back 2/3 of the item |
74 | | - return isWithin(end - twoThirdsOfSize, end)(targetCenter); |
75 | | -}; |
76 | | - |
77 | | -function tryGetCombineImpact(impact: DragImpact): ?CombineImpact { |
78 | | - if (impact.at && impact.at.type === 'COMBINE') { |
79 | | - return impact.at; |
80 | | - } |
81 | | - return null; |
82 | | -} |
| 15 | +import getIsDisplaced from '../get-is-displaced'; |
| 16 | +import removeDraggableFromList from '../remove-draggable-from-list'; |
83 | 17 |
|
84 | 18 | type Args = {| |
85 | 19 | draggable: DraggableDimension, |
86 | | - pageBorderBoxCenterWithDroppableScrollChange: Position, |
| 20 | + pageBorderBoxWithDroppableScroll: Rect, |
87 | 21 | previousImpact: DragImpact, |
88 | 22 | destination: DroppableDimension, |
89 | 23 | insideDestination: DraggableDimension[], |
90 | | - userDirection: UserDirection, |
91 | 24 | afterCritical: LiftEffect, |
92 | 25 | |}; |
| 26 | + |
| 27 | +// exported for testing |
| 28 | +export const combineThresholdDivisor: number = 4; |
| 29 | + |
93 | 30 | export default ({ |
94 | 31 | draggable, |
95 | | - pageBorderBoxCenterWithDroppableScrollChange: currentCenter, |
| 32 | + pageBorderBoxWithDroppableScroll: targetRect, |
96 | 33 | previousImpact, |
97 | 34 | destination, |
98 | 35 | insideDestination, |
99 | | - userDirection, |
100 | 36 | afterCritical, |
101 | 37 | }: Args): ?DragImpact => { |
102 | 38 | if (!destination.isCombineEnabled) { |
103 | 39 | return null; |
104 | 40 | } |
105 | | - |
106 | 41 | const axis: Axis = destination.axis; |
107 | | - const displaced: DisplacementGroups = previousImpact.displaced; |
108 | | - const canBeDisplacedBy: DisplacedBy = getDisplacedBy( |
| 42 | + const displacedBy: DisplacedBy = getDisplacedBy( |
109 | 43 | destination.axis, |
110 | 44 | draggable.displaceBy, |
111 | 45 | ); |
112 | | - const lastCombineImpact: ?CombineImpact = tryGetCombineImpact(previousImpact); |
| 46 | + const displacement: number = displacedBy.value; |
| 47 | + |
| 48 | + const targetStart: number = targetRect[axis.start]; |
| 49 | + const targetEnd: number = targetRect[axis.end]; |
| 50 | + |
| 51 | + const withoutDragging: DraggableDimension[] = removeDraggableFromList( |
| 52 | + draggable, |
| 53 | + insideDestination, |
| 54 | + ); |
113 | 55 |
|
114 | 56 | const combineWith: ?DraggableDimension = find( |
115 | | - removeDraggableFromList(draggable, insideDestination), |
| 57 | + withoutDragging, |
116 | 58 | (child: DraggableDimension): boolean => { |
117 | 59 | const id: DraggableId = child.descriptor.id; |
| 60 | + const childRect: Rect = child.page.borderBox; |
| 61 | + const childSize: number = childRect[axis.size]; |
| 62 | + const threshold: number = childSize / combineThresholdDivisor; |
118 | 63 |
|
119 | | - const displaceBy: Position = getCombinedItemDisplacement({ |
120 | | - displaced, |
| 64 | + const didStartAfterCritical: boolean = getDidStartAfterCritical( |
| 65 | + id, |
121 | 66 | afterCritical, |
122 | | - combineWith: id, |
123 | | - displacedBy: canBeDisplacedBy, |
124 | | - }); |
| 67 | + ); |
125 | 68 |
|
126 | | - return isCombiningWith({ |
| 69 | + const isDisplaced: boolean = getIsDisplaced({ |
| 70 | + displaced: previousImpact.displaced, |
127 | 71 | id, |
128 | | - currentCenter, |
129 | | - axis, |
130 | | - borderBox: child.page.borderBox, |
131 | | - displaceBy, |
132 | | - currentUserDirection: userDirection, |
133 | | - lastCombineImpact, |
134 | 72 | }); |
| 73 | + |
| 74 | + /* |
| 75 | + Only combining when in the combine region |
| 76 | + As soon as a boundary is hit then no longer combining |
| 77 | + */ |
| 78 | + |
| 79 | + if (didStartAfterCritical) { |
| 80 | + // In original position |
| 81 | + // Will combine with item when inside a band |
| 82 | + if (isDisplaced) { |
| 83 | + return ( |
| 84 | + targetEnd > childRect[axis.start] + threshold && |
| 85 | + targetEnd < childRect[axis.end] - threshold |
| 86 | + ); |
| 87 | + } |
| 88 | + |
| 89 | + // child is now 'displaced' backwards from where it started |
| 90 | + // want to combine when we move backwards onto it |
| 91 | + return ( |
| 92 | + targetStart > childRect[axis.start] - displacement + threshold && |
| 93 | + targetStart < childRect[axis.end] - displacement - threshold |
| 94 | + ); |
| 95 | + } |
| 96 | + |
| 97 | + // item has moved forwards |
| 98 | + if (isDisplaced) { |
| 99 | + return ( |
| 100 | + targetEnd > childRect[axis.start] + displacement + threshold && |
| 101 | + targetEnd < childRect[axis.end] + displacement - threshold |
| 102 | + ); |
| 103 | + } |
| 104 | + |
| 105 | + // is in resting position - being moved backwards on to |
| 106 | + return ( |
| 107 | + targetStart > childRect[axis.start] + threshold && |
| 108 | + targetStart < childRect[axis.end] - threshold |
| 109 | + ); |
135 | 110 | }, |
136 | 111 | ); |
137 | 112 |
|
138 | 113 | if (!combineWith) { |
139 | 114 | return null; |
140 | 115 | } |
141 | 116 |
|
142 | | - return calculateCombineImpact({ |
143 | | - combineWithId: combineWith.descriptor.id, |
144 | | - destinationId: destination.descriptor.id, |
145 | | - previousImpact, |
146 | | - userDirection, |
147 | | - }); |
| 117 | + const impact: DragImpact = { |
| 118 | + // no change to displacement when combining |
| 119 | + displacedBy, |
| 120 | + displaced: previousImpact.displaced, |
| 121 | + at: { |
| 122 | + type: 'COMBINE', |
| 123 | + combine: { |
| 124 | + draggableId: combineWith.descriptor.id, |
| 125 | + droppableId: destination.descriptor.id, |
| 126 | + }, |
| 127 | + }, |
| 128 | + }; |
| 129 | + return impact; |
148 | 130 | }; |
0 commit comments