@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,99 @@
1
+ // @flow
2
+ import rafSchd from 'raf-schd';
3
+ import { type Position } from 'css-box-model';
4
+ import type {
5
+ DraggingState,
6
+ DroppableId,
7
+ FluidScrollerOptions,
8
+ } from '../../../types';
9
+ import scroll from './scroll';
10
+ import { invariant } from '../../../invariant';
11
+ import * as timings from '../../../debug/timings';
12
+
13
+ export type PublicArgs = {|
14
+ scrollWindow: (change: Position) => void,
15
+ scrollDroppable: (id: DroppableId, change: Position) => void,
16
+ fluidScrollerOptions?: FluidScrollerOptions,
17
+ |};
18
+
19
+ export type FluidScroller = {|
20
+ scroll: (state: DraggingState) => void,
21
+ start: (state: DraggingState) => void,
22
+ stop: () => void,
23
+ fluidScrollerOptions?: FluidScrollerOptions,
24
+ |};
25
+
26
+ type WhileDragging = {|
27
+ dragStartTime: number,
28
+ shouldUseTimeDampening: boolean,
29
+ |};
30
+
31
+ export default ({
32
+ scrollWindow,
33
+ scrollDroppable,
34
+ fluidScrollerOptions,
35
+ }: PublicArgs): FluidScroller => {
36
+ const scheduleWindowScroll = rafSchd(scrollWindow);
37
+ const scheduleDroppableScroll = rafSchd(scrollDroppable);
38
+ let dragging: ?WhileDragging = null;
39
+
40
+ const tryScroll = (state: DraggingState): void => {
41
+ invariant(dragging, 'Cannot fluid scroll if not dragging');
42
+ const { shouldUseTimeDampening, dragStartTime } = dragging;
43
+
44
+ scroll({
45
+ state,
46
+ scrollWindow: scheduleWindowScroll,
47
+ scrollDroppable: scheduleDroppableScroll,
48
+ dragStartTime,
49
+ shouldUseTimeDampening,
50
+ fluidScrollerOptions,
51
+ });
52
+ };
53
+
54
+ const start = (state: DraggingState) => {
55
+ timings.start('starting fluid scroller');
56
+ invariant(!dragging, 'Cannot start auto scrolling when already started');
57
+ const dragStartTime: number = Date.now();
58
+
59
+ let wasScrollNeeded: boolean = false;
60
+ const fakeScrollCallback = () => {
61
+ wasScrollNeeded = true;
62
+ };
63
+ scroll({
64
+ state,
65
+ dragStartTime: 0,
66
+ shouldUseTimeDampening: false,
67
+ scrollWindow: fakeScrollCallback,
68
+ scrollDroppable: fakeScrollCallback,
69
+ fluidScrollerOptions,
70
+ });
71
+
72
+ dragging = {
73
+ dragStartTime,
74
+ shouldUseTimeDampening: wasScrollNeeded,
75
+ };
76
+ timings.finish('starting fluid scroller');
77
+
78
+ // we know an auto scroll is needed - let's do it!
79
+ if (wasScrollNeeded) {
80
+ tryScroll(state);
81
+ }
82
+ };
83
+
84
+ const stop = () => {
85
+ // can be called defensively
86
+ if (!dragging) {
87
+ return;
88
+ }
89
+ scheduleWindowScroll.cancel();
90
+ scheduleDroppableScroll.cancel();
91
+ dragging = null;
92
+ };
93
+
94
+ return {
95
+ start,
96
+ stop,
97
+ scroll: tryScroll,
98
+ };
99
+ };
@@ -0,0 +1,80 @@
1
+ // @flow
2
+ import { type Position, type Rect } from 'css-box-model';
3
+ import type {
4
+ DraggingState,
5
+ DroppableId,
6
+ DraggableDimension,
7
+ DroppableDimension,
8
+ FluidScrollerOptions,
9
+ Viewport,
10
+ } from '../../../types';
11
+ import getBestScrollableDroppable from './get-best-scrollable-droppable';
12
+ import whatIsDraggedOver from '../../droppable/what-is-dragged-over';
13
+ import getWindowScrollChange from './get-window-scroll-change';
14
+ import getDroppableScrollChange from './get-droppable-scroll-change';
15
+
16
+ type Args = {|
17
+ state: DraggingState,
18
+ dragStartTime: number,
19
+ shouldUseTimeDampening: boolean,
20
+ scrollWindow: (scroll: Position) => void,
21
+ scrollDroppable: (id: DroppableId, scroll: Position) => void,
22
+ fluidScrollerOptions?: FluidScrollerOptions,
23
+ |};
24
+
25
+ export default ({
26
+ state,
27
+ dragStartTime,
28
+ shouldUseTimeDampening,
29
+ scrollWindow,
30
+ scrollDroppable,
31
+ fluidScrollerOptions,
32
+ }: Args): void => {
33
+ const center: Position = state.current.page.borderBoxCenter;
34
+ const centerInitial = state.initial.page.borderBoxCenter;
35
+ const draggable: DraggableDimension =
36
+ state.dimensions.draggables[state.critical.draggable.id];
37
+ const subject: Rect = draggable.page.marginBox;
38
+ // 1. Can we scroll the viewport?
39
+ if (state.isWindowScrollAllowed) {
40
+ const viewport: Viewport = state.viewport;
41
+ const change: ?Position = getWindowScrollChange({
42
+ dragStartTime,
43
+ viewport,
44
+ subject,
45
+ center,
46
+ centerInitial,
47
+ shouldUseTimeDampening,
48
+ fluidScrollerOptions,
49
+ });
50
+
51
+ if (change) {
52
+ scrollWindow(change);
53
+ return;
54
+ }
55
+ }
56
+
57
+ const droppable: ?DroppableDimension = getBestScrollableDroppable({
58
+ center,
59
+ destination: whatIsDraggedOver(state.impact),
60
+ droppables: state.dimensions.droppables,
61
+ });
62
+
63
+ if (!droppable) {
64
+ return;
65
+ }
66
+
67
+ const change: ?Position = getDroppableScrollChange({
68
+ dragStartTime,
69
+ droppable,
70
+ subject,
71
+ center,
72
+ centerInitial,
73
+ shouldUseTimeDampening,
74
+ fluidScrollerOptions,
75
+ });
76
+
77
+ if (change) {
78
+ scrollDroppable(droppable.descriptor.id, change);
79
+ }
80
+ };
@@ -0,0 +1,59 @@
1
+ // @flow
2
+ import { type Position } from 'css-box-model';
3
+ import createFluidScroller, { type FluidScroller } from './fluid-scroller';
4
+ import createJumpScroller, { type JumpScroller } from './jump-scroller';
5
+ import type { AutoScroller } from './auto-scroller-types';
6
+ import type { DroppableId, FluidScrollerOptions, State } from '../../types';
7
+ import type { MoveArgs } from '../action-creators';
8
+
9
+ export type Args = {|
10
+ scrollWindow: (offset: Position) => void,
11
+ scrollDroppable: (id: DroppableId, change: Position) => void,
12
+ move: (args: MoveArgs) => mixed,
13
+ fluidScrollerOptions: FluidScrollerOptions,
14
+ |};
15
+
16
+ export default ({
17
+ scrollDroppable,
18
+ scrollWindow,
19
+ move,
20
+ fluidScrollerOptions,
21
+ }: Args): AutoScroller => {
22
+ const fluidScroller: FluidScroller = createFluidScroller({
23
+ scrollWindow,
24
+ scrollDroppable,
25
+ fluidScrollerOptions,
26
+ });
27
+
28
+ const jumpScroll: JumpScroller = createJumpScroller({
29
+ move,
30
+ scrollWindow,
31
+ scrollDroppable,
32
+ });
33
+
34
+ const scroll = (state: State) => {
35
+ // Only allowing auto scrolling in the DRAGGING phase
36
+ if (state.phase !== 'DRAGGING') {
37
+ return;
38
+ }
39
+
40
+ if (state.movementMode === 'FLUID') {
41
+ fluidScroller.scroll(state);
42
+ return;
43
+ }
44
+
45
+ if (!state.scrollJumpRequest) {
46
+ return;
47
+ }
48
+
49
+ jumpScroll(state);
50
+ };
51
+
52
+ const scroller: AutoScroller = {
53
+ scroll,
54
+ start: fluidScroller.start,
55
+ stop: fluidScroller.stop,
56
+ };
57
+
58
+ return scroller;
59
+ };
@@ -0,0 +1,139 @@
1
+ // @flow
2
+ import { type Position } from 'css-box-model';
3
+ import { invariant } from '../../invariant';
4
+ import { add, subtract } from '../position';
5
+ import {
6
+ canScrollWindow,
7
+ canScrollDroppable,
8
+ getWindowOverlap,
9
+ getDroppableOverlap,
10
+ } from './can-scroll';
11
+ import whatIsDraggedOver from '../droppable/what-is-dragged-over';
12
+ import { type MoveArgs } from '../action-creators';
13
+ import type {
14
+ DroppableDimension,
15
+ Viewport,
16
+ DraggingState,
17
+ DroppableId,
18
+ } from '../../types';
19
+
20
+ type Args = {|
21
+ scrollDroppable: (id: DroppableId, change: Position) => void,
22
+ scrollWindow: (offset: Position) => void,
23
+ move: (args: MoveArgs) => mixed,
24
+ |};
25
+
26
+ export type JumpScroller = (state: DraggingState) => void;
27
+
28
+ type Remainder = Position;
29
+
30
+ export default ({
31
+ move,
32
+ scrollDroppable,
33
+ scrollWindow,
34
+ }: Args): JumpScroller => {
35
+ const moveByOffset = (state: DraggingState, offset: Position) => {
36
+ const client: Position = add(state.current.client.selection, offset);
37
+ move({ client });
38
+ };
39
+
40
+ const scrollDroppableAsMuchAsItCan = (
41
+ droppable: DroppableDimension,
42
+ change: Position,
43
+ ): ?Remainder => {
44
+ // Droppable cannot absorb any of the scroll
45
+ if (!canScrollDroppable(droppable, change)) {
46
+ return change;
47
+ }
48
+
49
+ const overlap: ?Position = getDroppableOverlap(droppable, change);
50
+
51
+ // Droppable can absorb the entire change
52
+ if (!overlap) {
53
+ scrollDroppable(droppable.descriptor.id, change);
54
+ return null;
55
+ }
56
+
57
+ // Droppable can only absorb a part of the change
58
+ const whatTheDroppableCanScroll: Position = subtract(change, overlap);
59
+ scrollDroppable(droppable.descriptor.id, whatTheDroppableCanScroll);
60
+
61
+ const remainder: Position = subtract(change, whatTheDroppableCanScroll);
62
+ return remainder;
63
+ };
64
+
65
+ const scrollWindowAsMuchAsItCan = (
66
+ isWindowScrollAllowed: boolean,
67
+ viewport: Viewport,
68
+ change: Position,
69
+ ): ?Position => {
70
+ if (!isWindowScrollAllowed) {
71
+ return change;
72
+ }
73
+
74
+ if (!canScrollWindow(viewport, change)) {
75
+ // window cannot absorb any of the scroll
76
+ return change;
77
+ }
78
+
79
+ const overlap: ?Position = getWindowOverlap(viewport, change);
80
+
81
+ // window can absorb entire scroll
82
+ if (!overlap) {
83
+ scrollWindow(change);
84
+ return null;
85
+ }
86
+
87
+ // window can only absorb a part of the scroll
88
+ const whatTheWindowCanScroll: Position = subtract(change, overlap);
89
+ scrollWindow(whatTheWindowCanScroll);
90
+
91
+ const remainder: Position = subtract(change, whatTheWindowCanScroll);
92
+ return remainder;
93
+ };
94
+
95
+ const jumpScroller: JumpScroller = (state: DraggingState) => {
96
+ const request: ?Position = state.scrollJumpRequest;
97
+
98
+ if (!request) {
99
+ return;
100
+ }
101
+
102
+ const destination: ?DroppableId = whatIsDraggedOver(state.impact);
103
+ invariant(
104
+ destination,
105
+ 'Cannot perform a jump scroll when there is no destination',
106
+ );
107
+
108
+ // 1. We scroll the droppable first if we can to avoid the draggable
109
+ // leaving the list
110
+
111
+ const droppableRemainder: ?Position = scrollDroppableAsMuchAsItCan(
112
+ state.dimensions.droppables[destination],
113
+ request,
114
+ );
115
+
116
+ // droppable absorbed the entire scroll
117
+ if (!droppableRemainder) {
118
+ return;
119
+ }
120
+
121
+ const viewport: Viewport = state.viewport;
122
+ const windowRemainder: ?Position = scrollWindowAsMuchAsItCan(
123
+ state.isWindowScrollAllowed,
124
+ viewport,
125
+ droppableRemainder,
126
+ );
127
+
128
+ // window could absorb all the droppable remainder
129
+ if (!windowRemainder) {
130
+ return;
131
+ }
132
+
133
+ // The entire scroll could not be absorbed by the droppable and window
134
+ // so we manually move whatever is left
135
+ moveByOffset(state, windowRemainder);
136
+ };
137
+
138
+ return jumpScroller;
139
+ };
@@ -0,0 +1,26 @@
1
+ // @flow
2
+ import type { HorizontalAxis, VerticalAxis } from '../types';
3
+
4
+ export const vertical: VerticalAxis = {
5
+ direction: 'vertical',
6
+ line: 'y',
7
+ crossAxisLine: 'x',
8
+ start: 'top',
9
+ end: 'bottom',
10
+ size: 'height',
11
+ crossAxisStart: 'left',
12
+ crossAxisEnd: 'right',
13
+ crossAxisSize: 'width',
14
+ };
15
+
16
+ export const horizontal: HorizontalAxis = {
17
+ direction: 'horizontal',
18
+ line: 'x',
19
+ crossAxisLine: 'y',
20
+ start: 'left',
21
+ end: 'right',
22
+ size: 'width',
23
+ crossAxisStart: 'top',
24
+ crossAxisEnd: 'bottom',
25
+ crossAxisSize: 'height',
26
+ };
@@ -0,0 +1,136 @@
1
+ // @flow
2
+ import type {
3
+ DraggableDimension,
4
+ DroppableDimension,
5
+ DragImpact,
6
+ DisplacementGroups,
7
+ Viewport,
8
+ DisplacedBy,
9
+ } from '../../types';
10
+ import removeDraggableFromList from '../remove-draggable-from-list';
11
+ import isHomeOf from '../droppable/is-home-of';
12
+ import { emptyGroups } from '../no-impact';
13
+ import { find } from '../../native-with-fallback';
14
+ import getDisplacementGroups from '../get-displacement-groups';
15
+
16
+ type Args = {|
17
+ draggable: DraggableDimension,
18
+ insideDestination: DraggableDimension[],
19
+ destination: DroppableDimension,
20
+ viewport: Viewport,
21
+ displacedBy: DisplacedBy,
22
+ last: DisplacementGroups,
23
+ index: ?number,
24
+ forceShouldAnimate?: boolean,
25
+ |};
26
+
27
+ function getIndexOfLastItem(
28
+ draggables: DraggableDimension[],
29
+ options: {| inHomeList: boolean |},
30
+ ): number {
31
+ if (!draggables.length) {
32
+ return 0;
33
+ }
34
+
35
+ const indexOfLastItem: number =
36
+ draggables[draggables.length - 1].descriptor.index;
37
+
38
+ // When in a foreign list there will be an additional one item in the list
39
+ return options.inHomeList ? indexOfLastItem : indexOfLastItem + 1;
40
+ }
41
+
42
+ type GoAtEndArgs = {|
43
+ insideDestination: DraggableDimension[],
44
+ inHomeList: boolean,
45
+ displacedBy: DisplacedBy,
46
+ destination: DroppableDimension,
47
+ |};
48
+
49
+ function goAtEnd({
50
+ insideDestination,
51
+ inHomeList,
52
+ displacedBy,
53
+ destination,
54
+ }: GoAtEndArgs): DragImpact {
55
+ const newIndex: number = getIndexOfLastItem(insideDestination, {
56
+ inHomeList,
57
+ });
58
+
59
+ return {
60
+ displaced: emptyGroups,
61
+ displacedBy,
62
+ at: {
63
+ type: 'REORDER',
64
+ destination: {
65
+ droppableId: destination.descriptor.id,
66
+ index: newIndex,
67
+ },
68
+ },
69
+ };
70
+ }
71
+
72
+ export default function calculateReorderImpact({
73
+ draggable,
74
+ insideDestination,
75
+ destination,
76
+ viewport,
77
+ displacedBy,
78
+ last,
79
+ index,
80
+ forceShouldAnimate,
81
+ }: Args): DragImpact {
82
+ const inHomeList: boolean = isHomeOf(draggable, destination);
83
+
84
+ // Go into last spot of list
85
+ if (index == null) {
86
+ return goAtEnd({
87
+ insideDestination,
88
+ inHomeList,
89
+ displacedBy,
90
+ destination,
91
+ });
92
+ }
93
+
94
+ // this might be the dragging item
95
+ const match: ?DraggableDimension = find(
96
+ insideDestination,
97
+ (item: DraggableDimension) => item.descriptor.index === index,
98
+ );
99
+
100
+ if (!match) {
101
+ return goAtEnd({
102
+ insideDestination,
103
+ inHomeList,
104
+ displacedBy,
105
+ destination,
106
+ });
107
+ }
108
+ const withoutDragging: DraggableDimension[] = removeDraggableFromList(
109
+ draggable,
110
+ insideDestination,
111
+ );
112
+
113
+ const sliceFrom: number = insideDestination.indexOf(match);
114
+ const impacted: DraggableDimension[] = withoutDragging.slice(sliceFrom);
115
+
116
+ const displaced: DisplacementGroups = getDisplacementGroups({
117
+ afterDragging: impacted,
118
+ destination,
119
+ displacedBy,
120
+ last,
121
+ viewport: viewport.frame,
122
+ forceShouldAnimate,
123
+ });
124
+
125
+ return {
126
+ displaced,
127
+ displacedBy,
128
+ at: {
129
+ type: 'REORDER',
130
+ destination: {
131
+ droppableId: destination.descriptor.id,
132
+ index,
133
+ },
134
+ },
135
+ };
136
+ }
@@ -0,0 +1,29 @@
1
+ // @flow
2
+ import type { State, DraggableId } from '../types';
3
+
4
+ export default (state: State, id: DraggableId): boolean => {
5
+ // Ready to go!
6
+ if (state.phase === 'IDLE') {
7
+ return true;
8
+ }
9
+
10
+ // Can lift depending on the type of drop animation
11
+ if (state.phase !== 'DROP_ANIMATING') {
12
+ return false;
13
+ }
14
+
15
+ // - For a user drop we allow the user to drag other Draggables
16
+ // immediately as items are most likely already in their home
17
+ // - For a cancel items will be moving back to their original position
18
+ // as such it is a cleaner experience to block them from dragging until
19
+ // the drop animation is complete. Otherwise they will be grabbing
20
+ // items not in their original position which can lead to bad visuals
21
+ // Not allowing dragging of the dropping draggable
22
+ if (state.completed.result.draggableId === id) {
23
+ return false;
24
+ }
25
+
26
+ // if dropping - allow lifting
27
+ // if cancelling - disallow lifting
28
+ return state.completed.result.reason === 'DROP';
29
+ };
@@ -0,0 +1,97 @@
1
+ // @flow
2
+ /* eslint-disable no-underscore-dangle */
3
+ import { applyMiddleware, createStore, compose } from 'redux';
4
+ import reducer from './reducer';
5
+ import lift from './middleware/lift';
6
+ import style from './middleware/style';
7
+ import drop from './middleware/drop/drop-middleware';
8
+ import scrollListener from './middleware/scroll-listener';
9
+ import responders from './middleware/responders/responders-middleware';
10
+ import dropAnimationFinish from './middleware/drop/drop-animation-finish-middleware';
11
+ import dropAnimationFlushOnScroll from './middleware/drop/drop-animation-flush-on-scroll-middleware';
12
+ import dimensionMarshalStopper from './middleware/dimension-marshal-stopper';
13
+ import focus from './middleware/focus';
14
+ import autoScroll from './middleware/auto-scroll';
15
+ import pendingDrop from './middleware/pending-drop';
16
+ import type { DimensionMarshal } from './dimension-marshal/dimension-marshal-types';
17
+ import type { FocusMarshal } from '../view/use-focus-marshal/focus-marshal-types';
18
+ import type { StyleMarshal } from '../view/use-style-marshal/style-marshal-types';
19
+ import type { AutoScroller } from './auto-scroller/auto-scroller-types';
20
+ import type { Responders, Announce } from '../types';
21
+ import type { Store } from './store-types';
22
+
23
+ // We are checking if window is available before using it.
24
+ // This is needed for universal apps that render the component server side.
25
+ // Details: https://github.com/zalmoxisus/redux-devtools-extension#12-advanced-store-setup
26
+ const composeEnhancers =
27
+ process.env.NODE_ENV !== 'production' &&
28
+ typeof window !== 'undefined' &&
29
+ window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
30
+ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
31
+ name: 'react-beautiful-dnd',
32
+ })
33
+ : compose;
34
+
35
+ type Args = {|
36
+ dimensionMarshal: DimensionMarshal,
37
+ focusMarshal: FocusMarshal,
38
+ styleMarshal: StyleMarshal,
39
+ getResponders: () => Responders,
40
+ announce: Announce,
41
+ autoScroller: AutoScroller,
42
+ |};
43
+
44
+ export default ({
45
+ dimensionMarshal,
46
+ focusMarshal,
47
+ styleMarshal,
48
+ getResponders,
49
+ announce,
50
+ autoScroller,
51
+ }: Args): Store =>
52
+ createStore(
53
+ reducer,
54
+ composeEnhancers(
55
+ applyMiddleware(
56
+ // ## Debug middleware
57
+
58
+ // > uncomment to use
59
+ // debugging logger
60
+ // require('../debug/middleware/log').default('light'),
61
+ // // user timing api
62
+ // require('../debug/middleware/user-timing').default,
63
+ // debugging timer
64
+ // require('../debug/middleware/action-timing').default,
65
+ // average action timer
66
+ // require('../debug/middleware/action-timing-average').default(200),
67
+
68
+ // ## Application middleware
69
+
70
+ // Style updates do not cause more actions. It is important to update styles
71
+ // before responders are called: specifically the onDragEnd responder. We need to clear
72
+ // the transition styles off the elements before a reorder to prevent strange
73
+ // post drag animations in firefox. Even though we clear the transition off
74
+ // a Draggable - if it is done after a reorder firefox will still apply the
75
+ // transition.
76
+ // Must be called before dimension marshal for lifting to apply collecting styles
77
+ style(styleMarshal),
78
+ // Stop the dimension marshal collecting anything
79
+ // when moving into a phase where collection is no longer needed.
80
+ // We need to stop the marshal before responders fire as responders can cause
81
+ // dimension registration changes in response to reordering
82
+ dimensionMarshalStopper(dimensionMarshal),
83
+ // Fire application responders in response to drag changes
84
+ lift(dimensionMarshal),
85
+ drop,
86
+ // When a drop animation finishes - fire a drop complete
87
+ dropAnimationFinish,
88
+ dropAnimationFlushOnScroll,
89
+ pendingDrop,
90
+ autoScroll(autoScroller),
91
+ scrollListener,
92
+ focus(focusMarshal),
93
+ // Fire responders for consumers (after update to store)
94
+ responders(getResponders, announce),
95
+ ),
96
+ ),
97
+ );
@@ -0,0 +1,9 @@
1
+ // @flow
2
+ import type { DraggableId, LiftEffect } from '../types';
3
+
4
+ export default function didStartAfterCritical(
5
+ draggableId: DraggableId,
6
+ afterCritical: LiftEffect,
7
+ ): boolean {
8
+ return Boolean(afterCritical.effected[draggableId]);
9
+ }