@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,386 @@
1
+ // @flow
2
+ import { useRef } from 'react';
3
+ import { useCallback, useMemo } from 'use-memo-one';
4
+ import type { Position } from 'css-box-model';
5
+ import { invariant } from '../../../invariant';
6
+ import type {
7
+ PreDragActions,
8
+ FluidDragActions,
9
+ DraggableId,
10
+ SensorAPI,
11
+ DraggableOptions,
12
+ } from '../../../types';
13
+ import type {
14
+ EventBinding,
15
+ EventOptions,
16
+ } from '../../event-bindings/event-types';
17
+ import bindEvents from '../../event-bindings/bind-events';
18
+ import * as keyCodes from '../../key-codes';
19
+ import preventStandardKeyEvents from './util/prevent-standard-key-events';
20
+ import supportedPageVisibilityEventName from './util/supported-page-visibility-event-name';
21
+ import useLayoutEffect from '../../use-isomorphic-layout-effect';
22
+ import { noop } from '../../../empty';
23
+
24
+ // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
25
+ export const primaryButton: number = 0;
26
+ export const sloppyClickThreshold: number = 5;
27
+
28
+ function isSloppyClickThresholdExceeded(
29
+ original: Position,
30
+ current: Position,
31
+ ): boolean {
32
+ return (
33
+ Math.abs(current.x - original.x) >= sloppyClickThreshold ||
34
+ Math.abs(current.y - original.y) >= sloppyClickThreshold
35
+ );
36
+ }
37
+ type Idle = {|
38
+ type: 'IDLE',
39
+ |};
40
+
41
+ type Pending = {|
42
+ type: 'PENDING',
43
+ point: Position,
44
+ actions: PreDragActions,
45
+ |};
46
+
47
+ type Dragging = {|
48
+ type: 'DRAGGING',
49
+ actions: FluidDragActions,
50
+ |};
51
+
52
+ type Phase = Idle | Pending | Dragging;
53
+
54
+ const idle: Idle = { type: 'IDLE' };
55
+
56
+ type GetCaptureArgs = {|
57
+ cancel: () => void,
58
+ completed: () => void,
59
+ getPhase: () => Phase,
60
+ setPhase: (phase: Phase) => void,
61
+ |};
62
+
63
+ function getCaptureBindings({
64
+ cancel,
65
+ completed,
66
+ getPhase,
67
+ setPhase,
68
+ }: GetCaptureArgs): EventBinding[] {
69
+ return [
70
+ {
71
+ eventName: 'mousemove',
72
+ fn: (event: MouseEvent) => {
73
+ const { button, clientX, clientY } = event;
74
+ if (button !== primaryButton) {
75
+ return;
76
+ }
77
+
78
+ const point: Position = {
79
+ x: clientX,
80
+ y: clientY,
81
+ };
82
+
83
+ const phase: Phase = getPhase();
84
+
85
+ // Already dragging
86
+ if (phase.type === 'DRAGGING') {
87
+ // preventing default as we are using this event
88
+ event.preventDefault();
89
+ phase.actions.move(point);
90
+ return;
91
+ }
92
+
93
+ // There should be a pending drag at this point
94
+ invariant(phase.type === 'PENDING', 'Cannot be IDLE');
95
+ const pending: Position = phase.point;
96
+
97
+ // threshold not yet exceeded
98
+ if (!isSloppyClickThresholdExceeded(pending, point)) {
99
+ return;
100
+ }
101
+
102
+ // preventing default as we are using this event
103
+ event.preventDefault();
104
+
105
+ // Lifting at the current point to prevent the draggable item from
106
+ // jumping by the sloppyClickThreshold
107
+ const actions: FluidDragActions = phase.actions.fluidLift(point);
108
+
109
+ setPhase({
110
+ type: 'DRAGGING',
111
+ actions,
112
+ });
113
+ },
114
+ },
115
+ {
116
+ eventName: 'mouseup',
117
+ fn: (event: MouseEvent) => {
118
+ const phase: Phase = getPhase();
119
+
120
+ if (phase.type !== 'DRAGGING') {
121
+ cancel();
122
+ return;
123
+ }
124
+
125
+ // preventing default as we are using this event
126
+ event.preventDefault();
127
+ phase.actions.drop({ shouldBlockNextClick: true });
128
+ completed();
129
+ },
130
+ },
131
+ {
132
+ eventName: 'mousedown',
133
+ fn: (event: MouseEvent) => {
134
+ // this can happen during a drag when the user clicks a button
135
+ // other than the primary mouse button
136
+ if (getPhase().type === 'DRAGGING') {
137
+ event.preventDefault();
138
+ }
139
+
140
+ cancel();
141
+ },
142
+ },
143
+ {
144
+ eventName: 'keydown',
145
+ fn: (event: KeyboardEvent) => {
146
+ const phase: Phase = getPhase();
147
+ // Abort if any keystrokes while a drag is pending
148
+ if (phase.type === 'PENDING') {
149
+ cancel();
150
+ return;
151
+ }
152
+
153
+ // cancelling a drag
154
+ if (event.keyCode === keyCodes.escape) {
155
+ event.preventDefault();
156
+ cancel();
157
+ return;
158
+ }
159
+
160
+ preventStandardKeyEvents(event);
161
+ },
162
+ },
163
+ {
164
+ eventName: 'resize',
165
+ fn: cancel,
166
+ },
167
+ {
168
+ eventName: 'scroll',
169
+ // kill a pending drag if there is a window scroll
170
+ options: { passive: true, capture: false },
171
+ fn: () => {
172
+ if (getPhase().type === 'PENDING') {
173
+ cancel();
174
+ }
175
+ },
176
+ },
177
+
178
+ // Need to opt out of dragging if the user is a force press
179
+ // Only for safari which has decided to introduce its own custom way of doing things
180
+ // https://developer.apple.com/library/content/documentation/AppleApplications/Conceptual/SafariJSProgTopics/RespondingtoForceTouchEventsfromJavaScript.html
181
+ {
182
+ eventName: 'webkitmouseforcedown',
183
+ // it is considered a indirect cancel so we do not
184
+ // prevent default in any situation.
185
+ fn: (event: Event) => {
186
+ const phase: Phase = getPhase();
187
+ invariant(phase.type !== 'IDLE', 'Unexpected phase');
188
+
189
+ if (phase.actions.shouldRespectForcePress()) {
190
+ cancel();
191
+ return;
192
+ }
193
+
194
+ // This technically doesn't do anything.
195
+ // It won't do anything if `webkitmouseforcewillbegin` is prevented.
196
+ // But it is a good signal that we want to opt out of this
197
+
198
+ event.preventDefault();
199
+ },
200
+ },
201
+ // Cancel on page visibility change
202
+ {
203
+ eventName: supportedPageVisibilityEventName,
204
+ fn: cancel,
205
+ },
206
+ ];
207
+ }
208
+
209
+ export default function useMouseSensor(api: SensorAPI) {
210
+ const phaseRef = useRef<Phase>(idle);
211
+ const unbindEventsRef = useRef<() => void>(noop);
212
+
213
+ const startCaptureBinding: EventBinding = useMemo(
214
+ () => ({
215
+ eventName: 'mousedown',
216
+ fn: function onMouseDown(event: MouseEvent) {
217
+ // Event already used
218
+ if (event.defaultPrevented) {
219
+ return;
220
+ }
221
+ // only starting a drag if dragging with the primary mouse button
222
+ if (event.button !== primaryButton) {
223
+ return;
224
+ }
225
+
226
+ // Do not start a drag if any modifier key is pressed
227
+ if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
228
+ return;
229
+ }
230
+
231
+ const draggableId: ?DraggableId = api.findClosestDraggableId(event);
232
+
233
+ if (!draggableId) {
234
+ return;
235
+ }
236
+
237
+ const actions: ?PreDragActions = api.tryGetLock(
238
+ draggableId,
239
+ // stop is defined later
240
+ // eslint-disable-next-line no-use-before-define
241
+ stop,
242
+ { sourceEvent: event },
243
+ );
244
+
245
+ if (!actions) {
246
+ return;
247
+ }
248
+
249
+ // consuming the event
250
+ event.preventDefault();
251
+
252
+ const point: Position = {
253
+ x: event.clientX,
254
+ y: event.clientY,
255
+ };
256
+
257
+ // unbind this listener
258
+ unbindEventsRef.current();
259
+ // using this function before it is defined as their is a circular usage pattern
260
+ // eslint-disable-next-line no-use-before-define
261
+ startPendingDrag(actions, point);
262
+ },
263
+ }),
264
+ // not including startPendingDrag as it is not defined initially
265
+ // eslint-disable-next-line react-hooks/exhaustive-deps
266
+ [api],
267
+ );
268
+
269
+ const preventForcePressBinding: EventBinding = useMemo(
270
+ () => ({
271
+ eventName: 'webkitmouseforcewillbegin',
272
+ fn: (event: Event) => {
273
+ if (event.defaultPrevented) {
274
+ return;
275
+ }
276
+
277
+ const id: ?DraggableId = api.findClosestDraggableId(event);
278
+
279
+ if (!id) {
280
+ return;
281
+ }
282
+
283
+ const options: ?DraggableOptions = api.findOptionsForDraggable(id);
284
+
285
+ if (!options) {
286
+ return;
287
+ }
288
+
289
+ if (options.shouldRespectForcePress) {
290
+ return;
291
+ }
292
+
293
+ if (!api.canGetLock(id)) {
294
+ return;
295
+ }
296
+
297
+ event.preventDefault();
298
+ },
299
+ }),
300
+ [api],
301
+ );
302
+
303
+ const listenForCapture = useCallback(
304
+ function listenForCapture() {
305
+ const options: EventOptions = {
306
+ passive: false,
307
+ capture: true,
308
+ };
309
+
310
+ unbindEventsRef.current = bindEvents(
311
+ window,
312
+ [preventForcePressBinding, startCaptureBinding],
313
+ options,
314
+ );
315
+ },
316
+ [preventForcePressBinding, startCaptureBinding],
317
+ );
318
+
319
+ const stop = useCallback(() => {
320
+ const current: Phase = phaseRef.current;
321
+ if (current.type === 'IDLE') {
322
+ return;
323
+ }
324
+
325
+ phaseRef.current = idle;
326
+ unbindEventsRef.current();
327
+
328
+ listenForCapture();
329
+ }, [listenForCapture]);
330
+
331
+ const cancel = useCallback(() => {
332
+ const phase: Phase = phaseRef.current;
333
+ stop();
334
+ if (phase.type === 'DRAGGING') {
335
+ phase.actions.cancel({ shouldBlockNextClick: true });
336
+ }
337
+ if (phase.type === 'PENDING') {
338
+ phase.actions.abort();
339
+ }
340
+ }, [stop]);
341
+
342
+ const bindCapturingEvents = useCallback(
343
+ function bindCapturingEvents() {
344
+ const options = { capture: true, passive: false };
345
+ const bindings: EventBinding[] = getCaptureBindings({
346
+ cancel,
347
+ completed: stop,
348
+ getPhase: () => phaseRef.current,
349
+ setPhase: (phase: Phase) => {
350
+ phaseRef.current = phase;
351
+ },
352
+ });
353
+
354
+ unbindEventsRef.current = bindEvents(window, bindings, options);
355
+ },
356
+ [cancel, stop],
357
+ );
358
+
359
+ const startPendingDrag = useCallback(
360
+ function startPendingDrag(actions: PreDragActions, point: Position) {
361
+ invariant(
362
+ phaseRef.current.type === 'IDLE',
363
+ 'Expected to move from IDLE to PENDING drag',
364
+ );
365
+ phaseRef.current = {
366
+ type: 'PENDING',
367
+ point,
368
+ actions,
369
+ };
370
+ bindCapturingEvents();
371
+ },
372
+ [bindCapturingEvents],
373
+ );
374
+
375
+ useLayoutEffect(
376
+ function mount() {
377
+ listenForCapture();
378
+
379
+ // kill any pending window events when unmounting
380
+ return function unmount() {
381
+ unbindEventsRef.current();
382
+ };
383
+ },
384
+ [listenForCapture],
385
+ );
386
+ }