@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,132 @@
1
+ // @flow
2
+ import type { Position } from 'css-box-model';
3
+ import type {
4
+ DroppableDimension,
5
+ DraggableDimension,
6
+ DraggableDimensionMap,
7
+ DragImpact,
8
+ Viewport,
9
+ LiftEffect,
10
+ } from '../../../types';
11
+ import type { PublicResult } from '../move-in-direction-types';
12
+ import getDraggablesInsideDroppable from '../../get-draggables-inside-droppable';
13
+ import moveToNextCombine from './move-to-next-combine';
14
+ import moveToNextIndex from './move-to-next-index';
15
+ import isHomeOf from '../../droppable/is-home-of';
16
+ import getPageBorderBoxCenter from '../../get-center-from-impact/get-page-border-box-center';
17
+ import speculativelyIncrease from '../../update-displacement-visibility/speculatively-increase';
18
+ import getClientFromPageBorderBoxCenter from '../../get-center-from-impact/get-client-border-box-center/get-client-from-page-border-box-center';
19
+ import { subtract } from '../../position';
20
+ import isTotallyVisibleInNewLocation from './is-totally-visible-in-new-location';
21
+
22
+ type Args = {|
23
+ isMovingForward: boolean,
24
+ draggable: DraggableDimension,
25
+ destination: DroppableDimension,
26
+ draggables: DraggableDimensionMap,
27
+ previousImpact: DragImpact,
28
+ viewport: Viewport,
29
+ previousClientSelection: Position,
30
+ previousPageBorderBoxCenter: Position,
31
+ afterCritical: LiftEffect,
32
+ |};
33
+
34
+ export default ({
35
+ isMovingForward,
36
+ draggable,
37
+ destination,
38
+ draggables,
39
+ previousImpact,
40
+ viewport,
41
+ previousPageBorderBoxCenter,
42
+ previousClientSelection,
43
+ afterCritical,
44
+ }: Args): ?PublicResult => {
45
+ if (!destination.isEnabled) {
46
+ return null;
47
+ }
48
+
49
+ const insideDestination: DraggableDimension[] = getDraggablesInsideDroppable(
50
+ destination.descriptor.id,
51
+ draggables,
52
+ );
53
+ const isInHomeList: boolean = isHomeOf(draggable, destination);
54
+
55
+ const impact: ?DragImpact =
56
+ moveToNextCombine({
57
+ isMovingForward,
58
+ draggable,
59
+ destination,
60
+ insideDestination,
61
+ previousImpact,
62
+ }) ||
63
+ moveToNextIndex({
64
+ isMovingForward,
65
+ isInHomeList,
66
+ draggable,
67
+ draggables,
68
+ destination,
69
+ insideDestination,
70
+ previousImpact,
71
+ viewport,
72
+ afterCritical,
73
+ });
74
+
75
+ if (!impact) {
76
+ return null;
77
+ }
78
+
79
+ const pageBorderBoxCenter: Position = getPageBorderBoxCenter({
80
+ impact,
81
+ draggable,
82
+ droppable: destination,
83
+ draggables,
84
+ afterCritical,
85
+ });
86
+
87
+ const isVisibleInNewLocation: boolean = isTotallyVisibleInNewLocation({
88
+ draggable,
89
+ destination,
90
+ newPageBorderBoxCenter: pageBorderBoxCenter,
91
+ viewport: viewport.frame,
92
+ // already taken into account by getPageBorderBoxCenter
93
+ withDroppableDisplacement: false,
94
+ // we only care about it being visible relative to the main axis
95
+ // this is important with dynamic changes as scroll bar and toggle
96
+ // on the cross axis during a drag
97
+ onlyOnMainAxis: true,
98
+ });
99
+
100
+ if (isVisibleInNewLocation) {
101
+ // using the client center as the selection point
102
+ const clientSelection: Position = getClientFromPageBorderBoxCenter({
103
+ pageBorderBoxCenter,
104
+ draggable,
105
+ viewport,
106
+ });
107
+ return {
108
+ clientSelection,
109
+ impact,
110
+ scrollJumpRequest: null,
111
+ };
112
+ }
113
+
114
+ const distance: Position = subtract(
115
+ pageBorderBoxCenter,
116
+ previousPageBorderBoxCenter,
117
+ );
118
+
119
+ const cautious: DragImpact = speculativelyIncrease({
120
+ impact,
121
+ viewport,
122
+ destination,
123
+ draggables,
124
+ maxScrollChange: distance,
125
+ });
126
+
127
+ return {
128
+ clientSelection: previousClientSelection,
129
+ impact: cautious,
130
+ scrollJumpRequest: distance,
131
+ };
132
+ };
@@ -0,0 +1,52 @@
1
+ // @flow
2
+ import { type Position, type Rect, type Spacing } from 'css-box-model';
3
+ import { subtract } from '../../position';
4
+ import { offsetByPosition } from '../../spacing';
5
+ import {
6
+ isTotallyVisible,
7
+ isTotallyVisibleOnAxis,
8
+ type Args as IsVisibleArgs,
9
+ } from '../../visibility/is-visible';
10
+ import type { DraggableDimension, DroppableDimension } from '../../../types';
11
+
12
+ type Args = {|
13
+ draggable: DraggableDimension,
14
+ destination: DroppableDimension,
15
+ newPageBorderBoxCenter: Position,
16
+ viewport: Rect,
17
+ // only allowing a 'false' value. Being super clear
18
+ withDroppableDisplacement: false,
19
+ onlyOnMainAxis?: boolean,
20
+ |};
21
+
22
+ export default ({
23
+ draggable,
24
+ destination,
25
+ newPageBorderBoxCenter,
26
+ viewport,
27
+ withDroppableDisplacement,
28
+ onlyOnMainAxis = false,
29
+ }: Args): boolean => {
30
+ // What would the location of the Draggable be once the move is completed?
31
+ // We are not considering margins for this calculation.
32
+ // This is because a move might move a Draggable slightly outside of the bounds
33
+ // of a Droppable (which is okay)
34
+ const changeNeeded: Position = subtract(
35
+ newPageBorderBoxCenter,
36
+ draggable.page.borderBox.center,
37
+ );
38
+ const shifted: Spacing = offsetByPosition(
39
+ draggable.page.borderBox,
40
+ changeNeeded,
41
+ );
42
+
43
+ // Must be totally visible, not just partially visible.
44
+ const args: IsVisibleArgs = {
45
+ target: shifted,
46
+ destination,
47
+ withDroppableDisplacement,
48
+ viewport,
49
+ };
50
+
51
+ return onlyOnMainAxis ? isTotallyVisibleOnAxis(args) : isTotallyVisible(args);
52
+ };
@@ -0,0 +1,97 @@
1
+ // @flow
2
+ import { invariant } from '../../../../invariant';
3
+ import type {
4
+ DraggableDimension,
5
+ DroppableDimension,
6
+ DragImpact,
7
+ CombineImpact,
8
+ DraggableLocation,
9
+ DraggableId,
10
+ } from '../../../../types';
11
+ import { tryGetDestination } from '../../../get-impact-location';
12
+ import { findIndex } from '../../../../native-with-fallback';
13
+ import removeDraggableFromList from '../../../remove-draggable-from-list';
14
+
15
+ export type Args = {|
16
+ isMovingForward: boolean,
17
+ draggable: DraggableDimension,
18
+ destination: DroppableDimension,
19
+ insideDestination: DraggableDimension[],
20
+ previousImpact: DragImpact,
21
+ |};
22
+
23
+ export default ({
24
+ isMovingForward,
25
+ draggable,
26
+ destination,
27
+ insideDestination,
28
+ previousImpact,
29
+ }: Args): ?DragImpact => {
30
+ if (!destination.isCombineEnabled) {
31
+ return null;
32
+ }
33
+
34
+ const location: ?DraggableLocation = tryGetDestination(previousImpact);
35
+
36
+ if (!location) {
37
+ return null;
38
+ }
39
+
40
+ function getImpact(target: DraggableId) {
41
+ const at: CombineImpact = {
42
+ type: 'COMBINE',
43
+ combine: {
44
+ draggableId: target,
45
+ droppableId: destination.descriptor.id,
46
+ },
47
+ };
48
+ return {
49
+ ...previousImpact,
50
+ at,
51
+ };
52
+ }
53
+
54
+ const all: DraggableId[] = previousImpact.displaced.all;
55
+ const closestId: ?DraggableId = all.length ? all[0] : null;
56
+
57
+ if (isMovingForward) {
58
+ return closestId ? getImpact(closestId) : null;
59
+ }
60
+
61
+ const withoutDraggable = removeDraggableFromList(
62
+ draggable,
63
+ insideDestination,
64
+ );
65
+
66
+ // Moving backwards
67
+
68
+ // if nothing is displaced - move backwards onto the last item
69
+ if (!closestId) {
70
+ if (!withoutDraggable.length) {
71
+ return null;
72
+ }
73
+ const last: DraggableDimension =
74
+ withoutDraggable[withoutDraggable.length - 1];
75
+ return getImpact(last.descriptor.id);
76
+ }
77
+
78
+ // We are moving from being between two displaced items
79
+ // backwards onto the first one
80
+
81
+ // need to find the first item before the closest
82
+ const indexOfClosest: number = findIndex(
83
+ withoutDraggable,
84
+ (d) => d.descriptor.id === closestId,
85
+ );
86
+ invariant(indexOfClosest !== -1, 'Could not find displaced item in set');
87
+
88
+ const proposedIndex: number = indexOfClosest - 1;
89
+
90
+ // There is no displaced item before
91
+ if (proposedIndex < 0) {
92
+ return null;
93
+ }
94
+
95
+ const before: DraggableDimension = withoutDraggable[proposedIndex];
96
+ return getImpact(before.descriptor.id);
97
+ };
@@ -0,0 +1,52 @@
1
+ // @flow
2
+ import type {
3
+ DroppableDimension,
4
+ Combine,
5
+ DraggableDimension,
6
+ DraggableDimensionMap,
7
+ DisplacementGroups,
8
+ DraggableId,
9
+ LiftEffect,
10
+ } from '../../../../types';
11
+ import didStartAfterCritical from '../../../did-start-after-critical';
12
+
13
+ type Args = {|
14
+ isMovingForward: boolean,
15
+ destination: DroppableDimension,
16
+ displaced: DisplacementGroups,
17
+ draggables: DraggableDimensionMap,
18
+ combine: Combine,
19
+ afterCritical: LiftEffect,
20
+ |};
21
+
22
+ export default ({
23
+ isMovingForward,
24
+ destination,
25
+ draggables,
26
+ combine,
27
+ afterCritical,
28
+ }: Args): ?number => {
29
+ if (!destination.isCombineEnabled) {
30
+ return null;
31
+ }
32
+ const combineId: DraggableId = combine.draggableId;
33
+ const combineWith: DraggableDimension = draggables[combineId];
34
+ const combineWithIndex: number = combineWith.descriptor.index;
35
+ const didCombineWithStartAfterCritical: boolean = didStartAfterCritical(
36
+ combineId,
37
+ afterCritical,
38
+ );
39
+
40
+ if (didCombineWithStartAfterCritical) {
41
+ if (isMovingForward) {
42
+ return combineWithIndex;
43
+ }
44
+ return combineWithIndex - 1;
45
+ }
46
+
47
+ if (isMovingForward) {
48
+ return combineWithIndex + 1;
49
+ }
50
+
51
+ return combineWithIndex;
52
+ };
@@ -0,0 +1,43 @@
1
+ // @flow
2
+ import type { DraggableDimension, DraggableLocation } from '../../../../types';
3
+
4
+ type Args = {|
5
+ isMovingForward: boolean,
6
+ isInHomeList: boolean,
7
+ location: DraggableLocation,
8
+ insideDestination: DraggableDimension[],
9
+ |};
10
+
11
+ export default ({
12
+ isMovingForward,
13
+ isInHomeList,
14
+ insideDestination,
15
+ location,
16
+ }: Args): ?number => {
17
+ // cannot move in the list
18
+ if (!insideDestination.length) {
19
+ return null;
20
+ }
21
+
22
+ const currentIndex: number = location.index;
23
+ const proposedIndex: number = isMovingForward
24
+ ? currentIndex + 1
25
+ : currentIndex - 1;
26
+
27
+ // Accounting for lists that might not start with an index of 0
28
+ const firstIndex: number = insideDestination[0].descriptor.index;
29
+ const lastIndex: number =
30
+ insideDestination[insideDestination.length - 1].descriptor.index;
31
+
32
+ // When in foreign list we allow movement after the last item
33
+ const upperBound: number = isInHomeList ? lastIndex : lastIndex + 1;
34
+
35
+ if (proposedIndex < firstIndex) {
36
+ return null;
37
+ }
38
+ if (proposedIndex > upperBound) {
39
+ return null;
40
+ }
41
+
42
+ return proposedIndex;
43
+ };
@@ -0,0 +1,86 @@
1
+ // @flow
2
+ import { invariant } from '../../../../invariant';
3
+ import type {
4
+ DraggableDimension,
5
+ DroppableDimension,
6
+ DraggableDimensionMap,
7
+ DragImpact,
8
+ LiftEffect,
9
+ Viewport,
10
+ ImpactLocation,
11
+ } from '../../../../types';
12
+ import calculateReorderImpact from '../../../calculate-drag-impact/calculate-reorder-impact';
13
+ import fromCombine from './from-combine';
14
+ import fromReorder from './from-reorder';
15
+
16
+ export type Args = {|
17
+ isMovingForward: boolean,
18
+ isInHomeList: boolean,
19
+ draggable: DraggableDimension,
20
+ draggables: DraggableDimensionMap,
21
+ destination: DroppableDimension,
22
+ insideDestination: DraggableDimension[],
23
+ previousImpact: DragImpact,
24
+ viewport: Viewport,
25
+ afterCritical: LiftEffect,
26
+ |};
27
+
28
+ export default ({
29
+ isMovingForward,
30
+ isInHomeList,
31
+ draggable,
32
+ draggables,
33
+ destination,
34
+ insideDestination,
35
+ previousImpact,
36
+ viewport,
37
+ afterCritical,
38
+ }: Args): ?DragImpact => {
39
+ const wasAt: ?ImpactLocation = previousImpact.at;
40
+ invariant(wasAt, 'Cannot move in direction without previous impact location');
41
+
42
+ if (wasAt.type === 'REORDER') {
43
+ const newIndex: ?number = fromReorder({
44
+ isMovingForward,
45
+ isInHomeList,
46
+ location: wasAt.destination,
47
+ insideDestination,
48
+ });
49
+ // TODO: can we just pass new index on?
50
+ if (newIndex == null) {
51
+ return null;
52
+ }
53
+ return calculateReorderImpact({
54
+ draggable,
55
+ insideDestination,
56
+ destination,
57
+ viewport,
58
+ last: previousImpact.displaced,
59
+ displacedBy: previousImpact.displacedBy,
60
+ index: newIndex,
61
+ });
62
+ }
63
+
64
+ // COMBINE
65
+ const newIndex: ?number = fromCombine({
66
+ isMovingForward,
67
+ destination,
68
+ displaced: previousImpact.displaced,
69
+ draggables,
70
+ combine: wasAt.combine,
71
+ afterCritical,
72
+ });
73
+ if (newIndex == null) {
74
+ return null;
75
+ }
76
+
77
+ return calculateReorderImpact({
78
+ draggable,
79
+ insideDestination,
80
+ destination,
81
+ viewport,
82
+ last: previousImpact.displaced,
83
+ displacedBy: previousImpact.displacedBy,
84
+ index: newIndex,
85
+ });
86
+ };
@@ -0,0 +1,33 @@
1
+ // @flow
2
+ import type {
3
+ DisplacementGroups,
4
+ DragImpact,
5
+ DisplacedBy,
6
+ LiftEffect,
7
+ } from '../types';
8
+ import { origin } from './position';
9
+
10
+ export const noDisplacedBy: DisplacedBy = {
11
+ point: origin,
12
+ value: 0,
13
+ };
14
+
15
+ export const emptyGroups: DisplacementGroups = {
16
+ invisible: {},
17
+ visible: {},
18
+ all: [],
19
+ };
20
+
21
+ const noImpact: DragImpact = {
22
+ displaced: emptyGroups,
23
+ displacedBy: noDisplacedBy,
24
+ at: null,
25
+ };
26
+
27
+ export default noImpact;
28
+
29
+ export const noAfterCritical: LiftEffect = {
30
+ inVirtualList: false,
31
+ effected: {},
32
+ displacedBy: noDisplacedBy,
33
+ };
@@ -0,0 +1,11 @@
1
+ // @flow
2
+ import type { DimensionMap, DroppableDimension } from '../types';
3
+ import patchDroppableMap from './patch-droppable-map';
4
+
5
+ export default (
6
+ dimensions: DimensionMap,
7
+ updated: DroppableDimension,
8
+ ): DimensionMap => ({
9
+ draggables: dimensions.draggables,
10
+ droppables: patchDroppableMap(dimensions.droppables, updated),
11
+ });
@@ -0,0 +1,10 @@
1
+ // @flow
2
+ import type { DroppableDimension, DroppableDimensionMap } from '../types';
3
+
4
+ export default (
5
+ droppables: DroppableDimensionMap,
6
+ updated: DroppableDimension,
7
+ ): DroppableDimensionMap => ({
8
+ ...droppables,
9
+ [updated.descriptor.id]: updated,
10
+ });
@@ -0,0 +1,58 @@
1
+ // @flow
2
+ import { type Position } from 'css-box-model';
3
+
4
+ export const origin: Position = { x: 0, y: 0 };
5
+
6
+ export const add = (point1: Position, point2: Position): Position => ({
7
+ x: point1.x + point2.x,
8
+ y: point1.y + point2.y,
9
+ });
10
+
11
+ export const subtract = (point1: Position, point2: Position): Position => ({
12
+ x: point1.x - point2.x,
13
+ y: point1.y - point2.y,
14
+ });
15
+
16
+ export const isEqual = (point1: Position, point2: Position): boolean =>
17
+ point1.x === point2.x && point1.y === point2.y;
18
+
19
+ export const negate = (point: Position): Position => ({
20
+ // if the value is already 0, do not return -0
21
+ x: point.x !== 0 ? -point.x : 0,
22
+ y: point.y !== 0 ? -point.y : 0,
23
+ });
24
+
25
+ // Allows you to build a position from values.
26
+ // Really useful when working with the Axis type
27
+ // patch('x', 5) = { x: 5, y: 0 }
28
+ // patch('y', 5, 1) = { x: 1, y: 5 }
29
+ export const patch = (
30
+ line: 'x' | 'y',
31
+ value: number,
32
+ otherValue?: number = 0,
33
+ ): Position => ({
34
+ // set the value of 'x', or 'y'
35
+ [line]: value,
36
+ // set the value of the other line
37
+ [line === 'x' ? 'y' : 'x']: otherValue,
38
+ });
39
+
40
+ // Returns the distance between two points
41
+ // https://www.mathsisfun.com/algebra/distance-2-points.html
42
+ export const distance = (point1: Position, point2: Position): number =>
43
+ Math.sqrt(
44
+ Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2),
45
+ );
46
+
47
+ // When given a list of points, it finds the smallest distance to any point
48
+ export const closest = (target: Position, points: Position[]): number =>
49
+ Math.min(...points.map((point: Position) => distance(target, point)));
50
+
51
+ // used to apply any function to both values of a point
52
+ // eg: const floor = apply(Math.floor)(point);
53
+ export const apply = (fn: (value: number) => number) => (
54
+ point: Position,
55
+ ): Position => ({
56
+ x: fn(point.x),
57
+ y: fn(point.y),
58
+ });
@@ -0,0 +1,67 @@
1
+ // @flow
2
+ import type { Position } from 'css-box-model';
3
+ import { invariant } from '../../../invariant';
4
+ import type {
5
+ DroppableDimension,
6
+ DraggableDimension,
7
+ StateWhenUpdatesAllowed,
8
+ DroppableId,
9
+ DimensionMap,
10
+ DragImpact,
11
+ Viewport,
12
+ } from '../../../types';
13
+ import whatIsDraggedOver from '../../droppable/what-is-dragged-over';
14
+ import recomputeDisplacementVisibility from '../../update-displacement-visibility/recompute';
15
+ import getClientBorderBoxCenter from '../../get-center-from-impact/get-client-border-box-center';
16
+ import update from './update';
17
+
18
+ type Args = {|
19
+ state: StateWhenUpdatesAllowed,
20
+ dimensions?: DimensionMap,
21
+ viewport?: Viewport,
22
+ |};
23
+
24
+ export default ({
25
+ state,
26
+ dimensions: forcedDimensions,
27
+ viewport: forcedViewport,
28
+ }: // when a draggable is changing enabled state, sometimes it needs to force refresh an impact
29
+ Args): StateWhenUpdatesAllowed => {
30
+ invariant(state.movementMode === 'SNAP');
31
+
32
+ const needsVisibilityCheck: DragImpact = state.impact;
33
+ const viewport: Viewport = forcedViewport || state.viewport;
34
+ const dimensions: DimensionMap = forcedDimensions || state.dimensions;
35
+ const { draggables, droppables } = dimensions;
36
+
37
+ const draggable: DraggableDimension = draggables[state.critical.draggable.id];
38
+ const isOver: ?DroppableId = whatIsDraggedOver(needsVisibilityCheck);
39
+ invariant(isOver, 'Must be over a destination in SNAP movement mode');
40
+ const destination: DroppableDimension = droppables[isOver];
41
+
42
+ const impact: DragImpact = recomputeDisplacementVisibility({
43
+ impact: needsVisibilityCheck,
44
+ viewport,
45
+ destination,
46
+ draggables,
47
+ });
48
+
49
+ const clientSelection: Position = getClientBorderBoxCenter({
50
+ impact,
51
+ draggable,
52
+ droppable: destination,
53
+ draggables,
54
+ viewport,
55
+ afterCritical: state.afterCritical,
56
+ });
57
+
58
+ return update({
59
+ // new
60
+ impact,
61
+ clientSelection,
62
+ // pass through
63
+ state,
64
+ dimensions,
65
+ viewport,
66
+ });
67
+ };