@planningcenter/react-beautiful-dnd 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +13 -0
  3. package/README.md +178 -0
  4. package/dist/react-beautiful-dnd.cjs.js +8728 -0
  5. package/dist/react-beautiful-dnd.cjs.js.flow +3 -0
  6. package/dist/react-beautiful-dnd.esm.js +8715 -0
  7. package/dist/react-beautiful-dnd.js +11726 -0
  8. package/dist/react-beautiful-dnd.min.js +1 -0
  9. package/package.json +155 -0
  10. package/src/animation.js +75 -0
  11. package/src/debug/middleware/action-timing-average.js +52 -0
  12. package/src/debug/middleware/action-timing.js +16 -0
  13. package/src/debug/middleware/log.js +26 -0
  14. package/src/debug/middleware/user-timing.js +16 -0
  15. package/src/debug/timings.js +86 -0
  16. package/src/dev-warning.js +50 -0
  17. package/src/empty.js +6 -0
  18. package/src/index.js +67 -0
  19. package/src/invariant.js +33 -0
  20. package/src/native-with-fallback.js +69 -0
  21. package/src/screen-reader-message-preset.js +134 -0
  22. package/src/state/action-creators.js +328 -0
  23. package/src/state/auto-scroller/auto-scroller-types.js +8 -0
  24. package/src/state/auto-scroller/can-scroll.js +160 -0
  25. package/src/state/auto-scroller/fluid-scroller/config.js +25 -0
  26. package/src/state/auto-scroller/fluid-scroller/did-start-in-scrollable-area.js +1 -0
  27. package/src/state/auto-scroller/fluid-scroller/get-best-scrollable-droppable.js +77 -0
  28. package/src/state/auto-scroller/fluid-scroller/get-droppable-scroll-change.js +50 -0
  29. package/src/state/auto-scroller/fluid-scroller/get-percentage.js +25 -0
  30. package/src/state/auto-scroller/fluid-scroller/get-scroll/adjust-for-size-limits.js +30 -0
  31. package/src/state/auto-scroller/fluid-scroller/get-scroll/buffer-thresholds/calc-axis-scroll-conditions.js +68 -0
  32. package/src/state/auto-scroller/fluid-scroller/get-scroll/buffer-thresholds/get-scroll-conditions.js +56 -0
  33. package/src/state/auto-scroller/fluid-scroller/get-scroll/buffer-thresholds/index.js +66 -0
  34. package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/dampen-value-by-time.js +48 -0
  35. package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/get-distance-thresholds.js +31 -0
  36. package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/get-value-from-distance.js +67 -0
  37. package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/get-value.js +51 -0
  38. package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/index.js +50 -0
  39. package/src/state/auto-scroller/fluid-scroller/get-scroll/get-scroll-on-axis/min-scroll.js +4 -0
  40. package/src/state/auto-scroller/fluid-scroller/get-scroll/index.js +139 -0
  41. package/src/state/auto-scroller/fluid-scroller/get-window-scroll-change.js +43 -0
  42. package/src/state/auto-scroller/fluid-scroller/index.js +99 -0
  43. package/src/state/auto-scroller/fluid-scroller/scroll.js +80 -0
  44. package/src/state/auto-scroller/index.js +59 -0
  45. package/src/state/auto-scroller/jump-scroller.js +139 -0
  46. package/src/state/axis.js +26 -0
  47. package/src/state/calculate-drag-impact/calculate-reorder-impact.js +136 -0
  48. package/src/state/can-start-drag.js +29 -0
  49. package/src/state/create-store.js +97 -0
  50. package/src/state/did-start-after-critical.js +9 -0
  51. package/src/state/dimension-marshal/dimension-marshal-types.js +46 -0
  52. package/src/state/dimension-marshal/dimension-marshal.js +218 -0
  53. package/src/state/dimension-marshal/get-initial-publish.js +66 -0
  54. package/src/state/dimension-marshal/while-dragging-publisher.js +146 -0
  55. package/src/state/dimension-structures.js +35 -0
  56. package/src/state/droppable/get-droppable.js +101 -0
  57. package/src/state/droppable/is-home-of.js +7 -0
  58. package/src/state/droppable/scroll-droppable.js +53 -0
  59. package/src/state/droppable/should-use-placeholder.js +7 -0
  60. package/src/state/droppable/util/clip.js +17 -0
  61. package/src/state/droppable/util/get-subject.js +63 -0
  62. package/src/state/droppable/what-is-dragged-over-from-result.js +16 -0
  63. package/src/state/droppable/what-is-dragged-over.js +16 -0
  64. package/src/state/droppable/with-placeholder.js +174 -0
  65. package/src/state/get-center-from-impact/get-client-border-box-center/get-client-from-page-border-box-center.js +29 -0
  66. package/src/state/get-center-from-impact/get-client-border-box-center/index.js +44 -0
  67. package/src/state/get-center-from-impact/get-page-border-box-center/index.js +70 -0
  68. package/src/state/get-center-from-impact/get-page-border-box-center/when-combining.js +39 -0
  69. package/src/state/get-center-from-impact/get-page-border-box-center/when-reordering.js +112 -0
  70. package/src/state/get-center-from-impact/move-relative-to.js +66 -0
  71. package/src/state/get-combined-item-displacement.js +34 -0
  72. package/src/state/get-displaced-by.js +17 -0
  73. package/src/state/get-displacement-groups.js +130 -0
  74. package/src/state/get-drag-impact/get-combine-impact.js +130 -0
  75. package/src/state/get-drag-impact/get-reorder-impact.js +143 -0
  76. package/src/state/get-drag-impact/index.js +93 -0
  77. package/src/state/get-draggables-inside-droppable.js +31 -0
  78. package/src/state/get-droppable-over.js +158 -0
  79. package/src/state/get-frame.js +10 -0
  80. package/src/state/get-home-location.js +7 -0
  81. package/src/state/get-impact-location.js +16 -0
  82. package/src/state/get-is-displaced.js +11 -0
  83. package/src/state/get-lift-effect.js +82 -0
  84. package/src/state/get-max-scroll.js +30 -0
  85. package/src/state/is-movement-allowed.js +6 -0
  86. package/src/state/is-within.js +9 -0
  87. package/src/state/middleware/auto-scroll.js +38 -0
  88. package/src/state/middleware/dimension-marshal-stopper.js +20 -0
  89. package/src/state/middleware/drop/drop-animation-finish-middleware.js +21 -0
  90. package/src/state/middleware/drop/drop-animation-flush-on-scroll-middleware.js +63 -0
  91. package/src/state/middleware/drop/drop-middleware.js +146 -0
  92. package/src/state/middleware/drop/get-drop-duration.js +47 -0
  93. package/src/state/middleware/drop/get-drop-impact.js +77 -0
  94. package/src/state/middleware/drop/get-new-home-client-offset.js +54 -0
  95. package/src/state/middleware/drop/index.js +2 -0
  96. package/src/state/middleware/focus.js +42 -0
  97. package/src/state/middleware/lift.js +66 -0
  98. package/src/state/middleware/pending-drop.js +37 -0
  99. package/src/state/middleware/responders/async-marshal.js +55 -0
  100. package/src/state/middleware/responders/expiring-announce.js +44 -0
  101. package/src/state/middleware/responders/index.js +2 -0
  102. package/src/state/middleware/responders/is-equal.js +57 -0
  103. package/src/state/middleware/responders/publisher.js +253 -0
  104. package/src/state/middleware/responders/responders-middleware.js +75 -0
  105. package/src/state/middleware/scroll-listener.js +31 -0
  106. package/src/state/middleware/style.js +22 -0
  107. package/src/state/middleware/util/validate-dimensions.js +71 -0
  108. package/src/state/move-in-direction/index.js +84 -0
  109. package/src/state/move-in-direction/move-cross-axis/get-best-cross-axis-droppable.js +168 -0
  110. package/src/state/move-in-direction/move-cross-axis/get-closest-draggable.js +79 -0
  111. package/src/state/move-in-direction/move-cross-axis/index.js +109 -0
  112. package/src/state/move-in-direction/move-cross-axis/move-to-new-droppable.js +121 -0
  113. package/src/state/move-in-direction/move-cross-axis/without-starting-displacement.js +31 -0
  114. package/src/state/move-in-direction/move-in-direction-types.js +9 -0
  115. package/src/state/move-in-direction/move-to-next-place/index.js +132 -0
  116. package/src/state/move-in-direction/move-to-next-place/is-totally-visible-in-new-location.js +52 -0
  117. package/src/state/move-in-direction/move-to-next-place/move-to-next-combine/index.js +97 -0
  118. package/src/state/move-in-direction/move-to-next-place/move-to-next-index/from-combine.js +52 -0
  119. package/src/state/move-in-direction/move-to-next-place/move-to-next-index/from-reorder.js +43 -0
  120. package/src/state/move-in-direction/move-to-next-place/move-to-next-index/index.js +86 -0
  121. package/src/state/no-impact.js +33 -0
  122. package/src/state/patch-dimension-map.js +11 -0
  123. package/src/state/patch-droppable-map.js +10 -0
  124. package/src/state/position.js +58 -0
  125. package/src/state/post-reducer/when-moving/refresh-snap.js +67 -0
  126. package/src/state/post-reducer/when-moving/update.js +120 -0
  127. package/src/state/publish-while-dragging-in-virtual/adjust-additions-for-scroll-changes.js +58 -0
  128. package/src/state/publish-while-dragging-in-virtual/index.js +158 -0
  129. package/src/state/publish-while-dragging-in-virtual/offset-draggable.js +35 -0
  130. package/src/state/recompute-placeholders.js +99 -0
  131. package/src/state/rect.js +7 -0
  132. package/src/state/reducer.js +457 -0
  133. package/src/state/registry/create-registry.js +162 -0
  134. package/src/state/registry/registry-types.js +98 -0
  135. package/src/state/registry/use-registry.js +20 -0
  136. package/src/state/remove-draggable-from-list.js +13 -0
  137. package/src/state/scroll-viewport.js +34 -0
  138. package/src/state/spacing.js +45 -0
  139. package/src/state/store-types.js +16 -0
  140. package/src/state/update-displacement-visibility/recompute.js +54 -0
  141. package/src/state/update-displacement-visibility/speculatively-increase.js +111 -0
  142. package/src/state/visibility/is-partially-visible-through-frame.js +60 -0
  143. package/src/state/visibility/is-position-in-frame.js +12 -0
  144. package/src/state/visibility/is-totally-visible-through-frame-on-axis.js +19 -0
  145. package/src/state/visibility/is-totally-visible-through-frame.js +18 -0
  146. package/src/state/visibility/is-visible.js +102 -0
  147. package/src/state/with-scroll-change/with-all-displacement.js +15 -0
  148. package/src/state/with-scroll-change/with-droppable-displacement.js +13 -0
  149. package/src/state/with-scroll-change/with-droppable-scroll.js +13 -0
  150. package/src/state/with-scroll-change/with-viewport-displacement.js +7 -0
  151. package/src/types.js +542 -0
  152. package/src/view/animate-in-out/animate-in-out.jsx +95 -0
  153. package/src/view/animate-in-out/index.js +2 -0
  154. package/src/view/check-is-valid-inner-ref.js +15 -0
  155. package/src/view/context/app-context.js +19 -0
  156. package/src/view/context/droppable-context.js +11 -0
  157. package/src/view/context/store-context.js +5 -0
  158. package/src/view/data-attributes.js +37 -0
  159. package/src/view/drag-drop-context/app.jsx +273 -0
  160. package/src/view/drag-drop-context/check-doctype.js +39 -0
  161. package/src/view/drag-drop-context/check-react-version.js +71 -0
  162. package/src/view/drag-drop-context/drag-drop-context-types.js +7 -0
  163. package/src/view/drag-drop-context/drag-drop-context.jsx +68 -0
  164. package/src/view/drag-drop-context/error-boundary.jsx +88 -0
  165. package/src/view/drag-drop-context/index.js +2 -0
  166. package/src/view/drag-drop-context/use-startup-validation.js +13 -0
  167. package/src/view/drag-drop-context/use-unique-context-id.js +13 -0
  168. package/src/view/draggable/connected-draggable.js +372 -0
  169. package/src/view/draggable/draggable-api.jsx +48 -0
  170. package/src/view/draggable/draggable-types.js +191 -0
  171. package/src/view/draggable/draggable.jsx +171 -0
  172. package/src/view/draggable/get-style.js +109 -0
  173. package/src/view/draggable/index.js +2 -0
  174. package/src/view/draggable/use-validation.js +70 -0
  175. package/src/view/droppable/connected-droppable.js +280 -0
  176. package/src/view/droppable/droppable-types.js +91 -0
  177. package/src/view/droppable/droppable.jsx +167 -0
  178. package/src/view/droppable/index.js +2 -0
  179. package/src/view/droppable/use-validation.js +101 -0
  180. package/src/view/event-bindings/bind-events.js +39 -0
  181. package/src/view/event-bindings/event-types.js +14 -0
  182. package/src/view/get-body-element.js +8 -0
  183. package/src/view/get-border-box-center-position.js +5 -0
  184. package/src/view/get-document-element.js +8 -0
  185. package/src/view/get-elements/find-drag-handle.js +38 -0
  186. package/src/view/get-elements/find-draggable.js +30 -0
  187. package/src/view/is-strict-equal.js +2 -0
  188. package/src/view/is-type-of-element/is-element.js +6 -0
  189. package/src/view/is-type-of-element/is-html-element.js +6 -0
  190. package/src/view/is-type-of-element/is-svg-element.js +12 -0
  191. package/src/view/key-codes.js +13 -0
  192. package/src/view/placeholder/index.js +2 -0
  193. package/src/view/placeholder/placeholder-types.js +16 -0
  194. package/src/view/placeholder/placeholder.jsx +198 -0
  195. package/src/view/scroll-listener.js +72 -0
  196. package/src/view/throw-if-invalid-inner-ref.js +15 -0
  197. package/src/view/use-announcer/index.js +2 -0
  198. package/src/view/use-announcer/use-announcer.js +80 -0
  199. package/src/view/use-dev-setup-warning.js +22 -0
  200. package/src/view/use-dev.js +9 -0
  201. package/src/view/use-draggable-publisher/get-dimension.js +44 -0
  202. package/src/view/use-draggable-publisher/index.js +2 -0
  203. package/src/view/use-draggable-publisher/use-draggable-publisher.js +87 -0
  204. package/src/view/use-droppable-publisher/check-for-nested-scroll-container.js +27 -0
  205. package/src/view/use-droppable-publisher/get-closest-scrollable.js +95 -0
  206. package/src/view/use-droppable-publisher/get-dimension.js +139 -0
  207. package/src/view/use-droppable-publisher/get-env.js +31 -0
  208. package/src/view/use-droppable-publisher/get-listener-options.js +12 -0
  209. package/src/view/use-droppable-publisher/get-scroll.js +7 -0
  210. package/src/view/use-droppable-publisher/index.js +2 -0
  211. package/src/view/use-droppable-publisher/is-in-fixed-container.js +21 -0
  212. package/src/view/use-droppable-publisher/use-droppable-publisher.js +283 -0
  213. package/src/view/use-focus-marshal/focus-marshal-types.js +13 -0
  214. package/src/view/use-focus-marshal/index.js +2 -0
  215. package/src/view/use-focus-marshal/use-focus-marshal.js +129 -0
  216. package/src/view/use-hidden-text-element/index.js +2 -0
  217. package/src/view/use-hidden-text-element/use-hidden-text-element.js +60 -0
  218. package/src/view/use-isomorphic-layout-effect.js +18 -0
  219. package/src/view/use-previous-ref.js +14 -0
  220. package/src/view/use-required-context.js +9 -0
  221. package/src/view/use-sensor-marshal/closest.js +50 -0
  222. package/src/view/use-sensor-marshal/find-closest-draggable-id-from-event.js +50 -0
  223. package/src/view/use-sensor-marshal/index.js +5 -0
  224. package/src/view/use-sensor-marshal/is-event-in-interactive-element.js +66 -0
  225. package/src/view/use-sensor-marshal/lock.js +48 -0
  226. package/src/view/use-sensor-marshal/sensors/use-keyboard-sensor.js +243 -0
  227. package/src/view/use-sensor-marshal/sensors/use-mouse-sensor.js +386 -0
  228. package/src/view/use-sensor-marshal/sensors/use-touch-sensor.js +461 -0
  229. package/src/view/use-sensor-marshal/sensors/util/prevent-standard-key-events.js +19 -0
  230. package/src/view/use-sensor-marshal/sensors/util/supported-page-visibility-event-name.js +29 -0
  231. package/src/view/use-sensor-marshal/use-sensor-marshal.js +495 -0
  232. package/src/view/use-sensor-marshal/use-validate-sensor-hooks.js +20 -0
  233. package/src/view/use-style-marshal/get-styles.js +170 -0
  234. package/src/view/use-style-marshal/index.js +2 -0
  235. package/src/view/use-style-marshal/style-marshal-types.js +8 -0
  236. package/src/view/use-style-marshal/use-style-marshal.js +126 -0
  237. package/src/view/use-unique-id.js +25 -0
  238. package/src/view/visually-hidden-style.js +16 -0
  239. package/src/view/window/get-max-window-scroll.js +19 -0
  240. package/src/view/window/get-viewport.js +49 -0
  241. package/src/view/window/get-window-from-el.js +3 -0
  242. package/src/view/window/get-window-scroll.js +30 -0
  243. package/src/view/window/scroll-window.js +7 -0
@@ -0,0 +1,63 @@
1
+ // @flow
2
+ import { getRect, type Rect, type Spacing, type BoxModel } from 'css-box-model';
3
+ import type {
4
+ Axis,
5
+ Scrollable,
6
+ DroppableSubject,
7
+ PlaceholderInSubject,
8
+ } from '../../../types';
9
+ import executeClip from './clip';
10
+ import { offsetByPosition } from '../../spacing';
11
+
12
+ const scroll = (target: Spacing, frame: ?Scrollable): Spacing => {
13
+ if (!frame) {
14
+ return target;
15
+ }
16
+
17
+ return offsetByPosition(target, frame.scroll.diff.displacement);
18
+ };
19
+
20
+ const increase = (
21
+ target: Spacing,
22
+ axis: Axis,
23
+ withPlaceholder: ?PlaceholderInSubject,
24
+ ): Spacing => {
25
+ if (withPlaceholder && withPlaceholder.increasedBy) {
26
+ return {
27
+ ...target,
28
+ [axis.end]: target[axis.end] + withPlaceholder.increasedBy[axis.line],
29
+ };
30
+ }
31
+ return target;
32
+ };
33
+
34
+ const clip = (target: Spacing, frame: ?Scrollable): ?Rect => {
35
+ if (frame && frame.shouldClipSubject) {
36
+ return executeClip(frame.pageMarginBox, target);
37
+ }
38
+ return getRect(target);
39
+ };
40
+
41
+ type Args = {|
42
+ page: BoxModel,
43
+ withPlaceholder: ?PlaceholderInSubject,
44
+ axis: Axis,
45
+ frame: ?Scrollable,
46
+ |};
47
+
48
+ export default ({
49
+ page,
50
+ withPlaceholder,
51
+ axis,
52
+ frame,
53
+ }: Args): DroppableSubject => {
54
+ const scrolled: Spacing = scroll(page.marginBox, frame);
55
+ const increased: Spacing = increase(scrolled, axis, withPlaceholder);
56
+ const clipped: ?Rect = clip(increased, frame);
57
+
58
+ return {
59
+ page,
60
+ withPlaceholder,
61
+ active: clipped,
62
+ };
63
+ };
@@ -0,0 +1,16 @@
1
+ // @flow
2
+ import type { DroppableId, DropResult } from '../../types';
3
+
4
+ export default (result: DropResult): ?DroppableId => {
5
+ const { combine, destination } = result;
6
+
7
+ if (destination) {
8
+ return destination.droppableId;
9
+ }
10
+
11
+ if (combine) {
12
+ return combine.droppableId;
13
+ }
14
+
15
+ return null;
16
+ };
@@ -0,0 +1,16 @@
1
+ // @flow
2
+ import type { ImpactLocation, DroppableId, DragImpact } from '../../types';
3
+
4
+ export default (impact: DragImpact): ?DroppableId => {
5
+ const at: ?ImpactLocation = impact.at;
6
+
7
+ if (!at) {
8
+ return null;
9
+ }
10
+
11
+ if (at.type === 'REORDER') {
12
+ return at.destination.droppableId;
13
+ }
14
+
15
+ return at.combine.droppableId;
16
+ };
@@ -0,0 +1,174 @@
1
+ // @flow
2
+ import { type Position } from 'css-box-model';
3
+ import { invariant } from '../../invariant';
4
+ import type {
5
+ Axis,
6
+ DroppableDimension,
7
+ DraggableDimension,
8
+ DraggableDimensionMap,
9
+ Scrollable,
10
+ DroppableSubject,
11
+ PlaceholderInSubject,
12
+ } from '../../types';
13
+ import getDraggablesInsideDroppable from '../get-draggables-inside-droppable';
14
+ import { add, patch } from '../position';
15
+ import getSubject from './util/get-subject';
16
+ import isHomeOf from './is-home-of';
17
+ import getDisplacedBy from '../get-displaced-by';
18
+
19
+ const getRequiredGrowthForPlaceholder = (
20
+ droppable: DroppableDimension,
21
+ placeholderSize: Position,
22
+ draggables: DraggableDimensionMap,
23
+ ): ?Position => {
24
+ const axis: Axis = droppable.axis;
25
+
26
+ // A virtual list will most likely not contain all of the Draggables
27
+ // so counting them does not help.
28
+ if (droppable.descriptor.mode === 'virtual') {
29
+ return patch(axis.line, placeholderSize[axis.line]);
30
+ }
31
+
32
+ // TODO: consider margin collapsing?
33
+ // Using contentBox as that is where the Draggables will sit
34
+ const availableSpace: number = droppable.subject.page.contentBox[axis.size];
35
+ const insideDroppable: DraggableDimension[] = getDraggablesInsideDroppable(
36
+ droppable.descriptor.id,
37
+ draggables,
38
+ );
39
+ const spaceUsed: number = insideDroppable.reduce(
40
+ (sum: number, dimension: DraggableDimension): number =>
41
+ sum + dimension.client.marginBox[axis.size],
42
+ 0,
43
+ );
44
+ const requiredSpace: number = spaceUsed + placeholderSize[axis.line];
45
+ const needsToGrowBy: number = requiredSpace - availableSpace;
46
+
47
+ // nothing to do here
48
+ if (needsToGrowBy <= 0) {
49
+ return null;
50
+ }
51
+
52
+ return patch(axis.line, needsToGrowBy);
53
+ };
54
+
55
+ const withMaxScroll = (frame: Scrollable, max: Position): Scrollable => ({
56
+ ...frame,
57
+ scroll: {
58
+ ...frame.scroll,
59
+ max,
60
+ },
61
+ });
62
+
63
+ export const addPlaceholder = (
64
+ droppable: DroppableDimension,
65
+ draggable: DraggableDimension,
66
+ draggables: DraggableDimensionMap,
67
+ ): DroppableDimension => {
68
+ const frame: ?Scrollable = droppable.frame;
69
+
70
+ invariant(
71
+ !isHomeOf(draggable, droppable),
72
+ 'Should not add placeholder space to home list',
73
+ );
74
+
75
+ invariant(
76
+ !droppable.subject.withPlaceholder,
77
+ 'Cannot add placeholder size to a subject when it already has one',
78
+ );
79
+
80
+ const placeholderSize: Position = getDisplacedBy(
81
+ droppable.axis,
82
+ draggable.displaceBy,
83
+ ).point;
84
+
85
+ const requiredGrowth: ?Position = getRequiredGrowthForPlaceholder(
86
+ droppable,
87
+ placeholderSize,
88
+ draggables,
89
+ );
90
+
91
+ const added: PlaceholderInSubject = {
92
+ placeholderSize,
93
+ increasedBy: requiredGrowth,
94
+ oldFrameMaxScroll: droppable.frame ? droppable.frame.scroll.max : null,
95
+ };
96
+
97
+ if (!frame) {
98
+ const subject: DroppableSubject = getSubject({
99
+ page: droppable.subject.page,
100
+ withPlaceholder: added,
101
+ axis: droppable.axis,
102
+ frame: droppable.frame,
103
+ });
104
+ return {
105
+ ...droppable,
106
+ subject,
107
+ };
108
+ }
109
+
110
+ const maxScroll: Position = requiredGrowth
111
+ ? add(frame.scroll.max, requiredGrowth)
112
+ : frame.scroll.max;
113
+
114
+ const newFrame: Scrollable = withMaxScroll(frame, maxScroll);
115
+
116
+ const subject: DroppableSubject = getSubject({
117
+ page: droppable.subject.page,
118
+ withPlaceholder: added,
119
+ axis: droppable.axis,
120
+ frame: newFrame,
121
+ });
122
+ return {
123
+ ...droppable,
124
+ subject,
125
+ frame: newFrame,
126
+ };
127
+ };
128
+
129
+ export const removePlaceholder = (
130
+ droppable: DroppableDimension,
131
+ ): DroppableDimension => {
132
+ const added: ?PlaceholderInSubject = droppable.subject.withPlaceholder;
133
+ invariant(
134
+ added,
135
+ 'Cannot remove placeholder form subject when there was none',
136
+ );
137
+
138
+ const frame: ?Scrollable = droppable.frame;
139
+
140
+ if (!frame) {
141
+ const subject: DroppableSubject = getSubject({
142
+ page: droppable.subject.page,
143
+ axis: droppable.axis,
144
+ frame: null,
145
+ // cleared
146
+ withPlaceholder: null,
147
+ });
148
+ return {
149
+ ...droppable,
150
+ subject,
151
+ };
152
+ }
153
+
154
+ const oldMaxScroll: ?Position = added.oldFrameMaxScroll;
155
+ invariant(
156
+ oldMaxScroll,
157
+ 'Expected droppable with frame to have old max frame scroll when removing placeholder',
158
+ );
159
+
160
+ const newFrame: Scrollable = withMaxScroll(frame, oldMaxScroll);
161
+
162
+ const subject: DroppableSubject = getSubject({
163
+ page: droppable.subject.page,
164
+ axis: droppable.axis,
165
+ frame: newFrame,
166
+ // cleared
167
+ withPlaceholder: null,
168
+ });
169
+ return {
170
+ ...droppable,
171
+ subject,
172
+ frame: newFrame,
173
+ };
174
+ };
@@ -0,0 +1,29 @@
1
+ // @flow
2
+ import type { Position } from 'css-box-model';
3
+ import type { Viewport, DraggableDimension } from '../../../types';
4
+ import { add, subtract } from '../../position';
5
+ import withViewportDisplacement from '../../with-scroll-change/with-viewport-displacement';
6
+
7
+ type Args = {|
8
+ pageBorderBoxCenter: Position,
9
+ draggable: DraggableDimension,
10
+ viewport: Viewport,
11
+ |};
12
+
13
+ export default ({
14
+ pageBorderBoxCenter,
15
+ draggable,
16
+ viewport,
17
+ }: Args): Position => {
18
+ const withoutPageScrollChange: Position = withViewportDisplacement(
19
+ viewport,
20
+ pageBorderBoxCenter,
21
+ );
22
+
23
+ const offset: Position = subtract(
24
+ withoutPageScrollChange,
25
+ draggable.page.borderBox.center,
26
+ );
27
+
28
+ return add(draggable.client.borderBox.center, offset);
29
+ };
@@ -0,0 +1,44 @@
1
+ // @flow
2
+ import type { Position } from 'css-box-model';
3
+ import type {
4
+ DroppableDimension,
5
+ Viewport,
6
+ DragImpact,
7
+ DraggableDimension,
8
+ DraggableDimensionMap,
9
+ LiftEffect,
10
+ } from '../../../types';
11
+ import getPageBorderBoxCenterFromImpact from '../get-page-border-box-center';
12
+ import getClientFromPageBorderBoxCenter from './get-client-from-page-border-box-center';
13
+
14
+ type Args = {|
15
+ impact: DragImpact,
16
+ draggable: DraggableDimension,
17
+ droppable: DroppableDimension,
18
+ draggables: DraggableDimensionMap,
19
+ viewport: Viewport,
20
+ afterCritical: LiftEffect,
21
+ |};
22
+
23
+ export default ({
24
+ impact,
25
+ draggable,
26
+ droppable,
27
+ draggables,
28
+ viewport,
29
+ afterCritical,
30
+ }: Args): Position => {
31
+ const pageBorderBoxCenter: Position = getPageBorderBoxCenterFromImpact({
32
+ impact,
33
+ draggable,
34
+ draggables,
35
+ droppable,
36
+ afterCritical,
37
+ });
38
+
39
+ return getClientFromPageBorderBoxCenter({
40
+ pageBorderBoxCenter,
41
+ draggable,
42
+ viewport,
43
+ });
44
+ };
@@ -0,0 +1,70 @@
1
+ // @flow
2
+ import type { Position } from 'css-box-model';
3
+ import type {
4
+ DragImpact,
5
+ DraggableDimension,
6
+ DroppableDimension,
7
+ DraggableDimensionMap,
8
+ ImpactLocation,
9
+ LiftEffect,
10
+ } from '../../../types';
11
+ import whenCombining from './when-combining';
12
+ import whenReordering from './when-reordering';
13
+ import withDroppableDisplacement from '../../with-scroll-change/with-droppable-displacement';
14
+
15
+ type Args = {|
16
+ impact: DragImpact,
17
+ afterCritical: LiftEffect,
18
+ draggable: DraggableDimension,
19
+ droppable: ?DroppableDimension,
20
+ draggables: DraggableDimensionMap,
21
+ |};
22
+
23
+ const getResultWithoutDroppableDisplacement = ({
24
+ impact,
25
+ draggable,
26
+ droppable,
27
+ draggables,
28
+ afterCritical,
29
+ }: Args): Position => {
30
+ const original: Position = draggable.page.borderBox.center;
31
+ const at: ?ImpactLocation = impact.at;
32
+
33
+ if (!droppable) {
34
+ return original;
35
+ }
36
+
37
+ if (!at) {
38
+ return original;
39
+ }
40
+
41
+ if (at.type === 'REORDER') {
42
+ return whenReordering({
43
+ impact,
44
+ draggable,
45
+ draggables,
46
+ droppable,
47
+ afterCritical,
48
+ });
49
+ }
50
+
51
+ return whenCombining({
52
+ impact,
53
+ draggables,
54
+ afterCritical,
55
+ });
56
+ };
57
+
58
+ export default (args: Args): Position => {
59
+ const withoutDisplacement: Position = getResultWithoutDroppableDisplacement(
60
+ args,
61
+ );
62
+
63
+ const droppable: ?DroppableDimension = args.droppable;
64
+
65
+ const withDisplacement: Position = droppable
66
+ ? withDroppableDisplacement(droppable, withoutDisplacement)
67
+ : withoutDisplacement;
68
+
69
+ return withDisplacement;
70
+ };
@@ -0,0 +1,39 @@
1
+ // @flow
2
+ import { type Position } from 'css-box-model';
3
+ import { invariant } from '../../../invariant';
4
+ import type {
5
+ DraggableDimensionMap,
6
+ DraggableId,
7
+ Combine,
8
+ LiftEffect,
9
+ DragImpact,
10
+ } from '../../../types';
11
+ import { add } from '../../position';
12
+ import getCombinedItemDisplacement from '../../get-combined-item-displacement';
13
+ import { tryGetCombine } from '../../get-impact-location';
14
+
15
+ type Args = {|
16
+ impact: DragImpact,
17
+ // all draggables in the system
18
+ draggables: DraggableDimensionMap,
19
+ afterCritical: LiftEffect,
20
+ |};
21
+
22
+ // Returns the client offset required to move an item from its
23
+ // original client position to its final resting position
24
+ export default ({ afterCritical, impact, draggables }: Args): Position => {
25
+ const combine: ?Combine = tryGetCombine(impact);
26
+ invariant(combine);
27
+
28
+ const combineWith: DraggableId = combine.draggableId;
29
+ const center: Position = draggables[combineWith].page.borderBox.center;
30
+
31
+ const displaceBy: Position = getCombinedItemDisplacement({
32
+ displaced: impact.displaced,
33
+ afterCritical,
34
+ combineWith,
35
+ displacedBy: impact.displacedBy,
36
+ });
37
+
38
+ return add(center, displaceBy);
39
+ };
@@ -0,0 +1,112 @@
1
+ // @flow
2
+ import { offset, type Position, type BoxModel } from 'css-box-model';
3
+ import type {
4
+ Axis,
5
+ DragImpact,
6
+ DraggableId,
7
+ DraggableDimension,
8
+ DraggableDimensionMap,
9
+ DroppableDimension,
10
+ LiftEffect,
11
+ } from '../../../types';
12
+ import { goBefore, goAfter, goIntoStart } from '../move-relative-to';
13
+ import getDraggablesInsideDroppable from '../../get-draggables-inside-droppable';
14
+ import { negate } from '../../position';
15
+ import didStartAfterCritical from '../../did-start-after-critical';
16
+
17
+ type NewHomeArgs = {|
18
+ impact: DragImpact,
19
+ draggable: DraggableDimension,
20
+ draggables: DraggableDimensionMap,
21
+ droppable: DroppableDimension,
22
+ afterCritical: LiftEffect,
23
+ |};
24
+
25
+ // Returns the client offset required to move an item from its
26
+ // original client position to its final resting position
27
+ export default ({
28
+ impact,
29
+ draggable,
30
+ draggables,
31
+ droppable,
32
+ afterCritical,
33
+ }: NewHomeArgs): Position => {
34
+ const insideDestination: DraggableDimension[] = getDraggablesInsideDroppable(
35
+ droppable.descriptor.id,
36
+ draggables,
37
+ );
38
+
39
+ const draggablePage: BoxModel = draggable.page;
40
+ const axis: Axis = droppable.axis;
41
+
42
+ // this will only happen in a foreign list
43
+ if (!insideDestination.length) {
44
+ return goIntoStart({
45
+ axis,
46
+ moveInto: droppable.page,
47
+ isMoving: draggablePage,
48
+ });
49
+ }
50
+
51
+ const { displaced, displacedBy } = impact;
52
+ const closestAfter: ?DraggableId = displaced.all[0];
53
+
54
+ // go before the first displaced item
55
+ // items can only be displaced forwards
56
+ if (closestAfter) {
57
+ const closest: DraggableDimension = draggables[closestAfter];
58
+ // want to go before where it would be with the displacement
59
+
60
+ // target is displaced and is already in it's starting position
61
+ if (didStartAfterCritical(closestAfter, afterCritical)) {
62
+ return goBefore({
63
+ axis,
64
+ moveRelativeTo: closest.page,
65
+ isMoving: draggablePage,
66
+ });
67
+ }
68
+
69
+ // target has been displaced during the drag and it is not in its starting position
70
+ // we need to account for the displacement
71
+ const withDisplacement: BoxModel = offset(closest.page, displacedBy.point);
72
+
73
+ return goBefore({
74
+ axis,
75
+ moveRelativeTo: withDisplacement,
76
+ isMoving: draggablePage,
77
+ });
78
+ }
79
+
80
+ // Nothing in list is displaced, we should go after the last item
81
+
82
+ const last: DraggableDimension =
83
+ insideDestination[insideDestination.length - 1];
84
+
85
+ // we can just go into our original position if the last item
86
+ // is the dragging item
87
+ if (last.descriptor.id === draggable.descriptor.id) {
88
+ return draggablePage.borderBox.center;
89
+ }
90
+
91
+ if (didStartAfterCritical(last.descriptor.id, afterCritical)) {
92
+ // if the item started displaced and it is no longer displaced then
93
+ // we need to go after it it's non-displaced position
94
+
95
+ const page: BoxModel = offset(
96
+ last.page,
97
+ negate(afterCritical.displacedBy.point),
98
+ );
99
+ return goAfter({
100
+ axis,
101
+ moveRelativeTo: page,
102
+ isMoving: draggablePage,
103
+ });
104
+ }
105
+
106
+ // item is in its resting spot. we can go straight after it
107
+ return goAfter({
108
+ axis,
109
+ moveRelativeTo: last.page,
110
+ isMoving: draggablePage,
111
+ });
112
+ };
@@ -0,0 +1,66 @@
1
+ // @flow
2
+ import type { Position, BoxModel, Rect } from 'css-box-model';
3
+ import { patch } from '../position';
4
+ import type { Axis } from '../../types';
5
+
6
+ type Args = {|
7
+ axis: Axis,
8
+ moveRelativeTo: BoxModel,
9
+ isMoving: BoxModel,
10
+ |};
11
+
12
+ const distanceFromStartToBorderBoxCenter = (
13
+ axis: Axis,
14
+ box: BoxModel,
15
+ ): number => box.margin[axis.start] + box.borderBox[axis.size] / 2;
16
+
17
+ const distanceFromEndToBorderBoxCenter = (axis: Axis, box: BoxModel): number =>
18
+ box.margin[axis.end] + box.borderBox[axis.size] / 2;
19
+
20
+ // We align the moving item against the cross axis start of the target
21
+ // We used to align the moving item cross axis center with the cross axis center of the target.
22
+ // However, this leads to a bad experience when reordering columns
23
+ const getCrossAxisBorderBoxCenter = (
24
+ axis: Axis,
25
+ target: Rect,
26
+ isMoving: BoxModel,
27
+ ): number =>
28
+ target[axis.crossAxisStart] +
29
+ isMoving.margin[axis.crossAxisStart] +
30
+ isMoving.borderBox[axis.crossAxisSize] / 2;
31
+
32
+ export const goAfter = ({ axis, moveRelativeTo, isMoving }: Args): Position =>
33
+ patch(
34
+ axis.line,
35
+ // start measuring from the end of the target
36
+ moveRelativeTo.marginBox[axis.end] +
37
+ distanceFromStartToBorderBoxCenter(axis, isMoving),
38
+ getCrossAxisBorderBoxCenter(axis, moveRelativeTo.marginBox, isMoving),
39
+ );
40
+
41
+ export const goBefore = ({ axis, moveRelativeTo, isMoving }: Args): Position =>
42
+ patch(
43
+ axis.line,
44
+ // start measuring from the start of the target
45
+ moveRelativeTo.marginBox[axis.start] -
46
+ distanceFromEndToBorderBoxCenter(axis, isMoving),
47
+ getCrossAxisBorderBoxCenter(axis, moveRelativeTo.marginBox, isMoving),
48
+ );
49
+ type GoIntoArgs = {|
50
+ axis: Axis,
51
+ moveInto: BoxModel,
52
+ isMoving: BoxModel,
53
+ |};
54
+
55
+ // moves into the content box
56
+ export const goIntoStart = ({
57
+ axis,
58
+ moveInto,
59
+ isMoving,
60
+ }: GoIntoArgs): Position =>
61
+ patch(
62
+ axis.line,
63
+ moveInto.contentBox[axis.start] +
64
+ distanceFromStartToBorderBoxCenter(axis, isMoving),
65
+ getCrossAxisBorderBoxCenter(axis, moveInto.contentBox, isMoving),
66
+ );
@@ -0,0 +1,34 @@
1
+ // @flow
2
+ import type { Position } from 'css-box-model';
3
+ import type {
4
+ DisplacementGroups,
5
+ LiftEffect,
6
+ DraggableId,
7
+ DisplacedBy,
8
+ } from '../types';
9
+ import { origin, negate } from './position';
10
+ import didStartAfterCritical from './did-start-after-critical';
11
+
12
+ type Args = {|
13
+ displaced: DisplacementGroups,
14
+ afterCritical: LiftEffect,
15
+ combineWith: DraggableId,
16
+ displacedBy: DisplacedBy,
17
+ |};
18
+
19
+ export default ({
20
+ displaced,
21
+ afterCritical,
22
+ combineWith,
23
+ displacedBy,
24
+ }: Args): Position => {
25
+ const isDisplaced: boolean = Boolean(
26
+ displaced.visible[combineWith] || displaced.invisible[combineWith],
27
+ );
28
+
29
+ if (didStartAfterCritical(combineWith, afterCritical)) {
30
+ return isDisplaced ? origin : negate(displacedBy.point);
31
+ }
32
+
33
+ return isDisplaced ? displacedBy.point : origin;
34
+ };
@@ -0,0 +1,17 @@
1
+ // @flow
2
+ import memoizeOne from 'memoize-one';
3
+ import { type Position } from 'css-box-model';
4
+ import type { Axis, DisplacedBy } from '../types';
5
+ import { patch } from './position';
6
+
7
+ // TODO: memoization needed?
8
+ export default memoizeOne(function getDisplacedBy(
9
+ axis: Axis,
10
+ displaceBy: Position,
11
+ ): DisplacedBy {
12
+ const displacement: number = displaceBy[axis.line];
13
+ return {
14
+ value: displacement,
15
+ point: patch(axis.line, displacement),
16
+ };
17
+ });