@atlaskit/pragmatic-drag-and-drop 0.17.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 (155) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/LICENSE.md +13 -0
  3. package/README.md +43 -0
  4. package/__perf__/add-example.todo +1 -0
  5. package/adapter/element/package.json +15 -0
  6. package/adapter/file/package.json +15 -0
  7. package/addon/cancel-unhandled/package.json +15 -0
  8. package/constellation/index/about.mdx +329 -0
  9. package/constellation/index/props.mdx +3 -0
  10. package/dist/cjs/adapter/element-adapter.js +151 -0
  11. package/dist/cjs/adapter/file-adapter.js +98 -0
  12. package/dist/cjs/addon/cancel-unhandled.js +50 -0
  13. package/dist/cjs/entry-point/adapter/element.js +24 -0
  14. package/dist/cjs/entry-point/adapter/file.js +18 -0
  15. package/dist/cjs/entry-point/addon/cancel-unhandled.js +12 -0
  16. package/dist/cjs/entry-point/experimental/cross-with-element-adapter.js +30 -0
  17. package/dist/cjs/entry-point/types.js +5 -0
  18. package/dist/cjs/entry-point/util/combine.js +12 -0
  19. package/dist/cjs/entry-point/util/disable-native-drag-preview.js +12 -0
  20. package/dist/cjs/entry-point/util/once.js +12 -0
  21. package/dist/cjs/entry-point/util/reorder.js +12 -0
  22. package/dist/cjs/entry-point/util/scroll-just-enough-into-view.js +12 -0
  23. package/dist/cjs/entry-point/util/set-custom-native-drag-preview.js +12 -0
  24. package/dist/cjs/experimental/cross-window-element-adapter.js +131 -0
  25. package/dist/cjs/index.js +12 -0
  26. package/dist/cjs/internal-types.js +5 -0
  27. package/dist/cjs/ledger/dispatch-consumer-event.js +132 -0
  28. package/dist/cjs/ledger/lifecycle-manager.js +335 -0
  29. package/dist/cjs/ledger/usage-ledger.js +37 -0
  30. package/dist/cjs/make-adapter/make-adapter.js +59 -0
  31. package/dist/cjs/make-adapter/make-drop-target.js +271 -0
  32. package/dist/cjs/make-adapter/make-monitor.js +100 -0
  33. package/dist/cjs/util/add-attribute.js +14 -0
  34. package/dist/cjs/util/combine.js +17 -0
  35. package/dist/cjs/util/disable-native-drag-preview.js +36 -0
  36. package/dist/cjs/util/entering-and-leaving-the-window.js +162 -0
  37. package/dist/cjs/util/fix-post-drag-pointer-bug.js +114 -0
  38. package/dist/cjs/util/get-input.js +20 -0
  39. package/dist/cjs/util/once.js +22 -0
  40. package/dist/cjs/util/reorder.js +26 -0
  41. package/dist/cjs/util/scroll-just-enough-into-view.js +17 -0
  42. package/dist/cjs/util/set-custom-native-drag-preview.js +109 -0
  43. package/dist/cjs/version.json +5 -0
  44. package/dist/es2019/adapter/element-adapter.js +143 -0
  45. package/dist/es2019/adapter/file-adapter.js +90 -0
  46. package/dist/es2019/addon/cancel-unhandled.js +43 -0
  47. package/dist/es2019/entry-point/adapter/element.js +1 -0
  48. package/dist/es2019/entry-point/adapter/file.js +1 -0
  49. package/dist/es2019/entry-point/addon/cancel-unhandled.js +1 -0
  50. package/dist/es2019/entry-point/experimental/cross-with-element-adapter.js +1 -0
  51. package/dist/es2019/entry-point/types.js +1 -0
  52. package/dist/es2019/entry-point/util/combine.js +1 -0
  53. package/dist/es2019/entry-point/util/disable-native-drag-preview.js +1 -0
  54. package/dist/es2019/entry-point/util/once.js +1 -0
  55. package/dist/es2019/entry-point/util/reorder.js +1 -0
  56. package/dist/es2019/entry-point/util/scroll-just-enough-into-view.js +1 -0
  57. package/dist/es2019/entry-point/util/set-custom-native-drag-preview.js +1 -0
  58. package/dist/es2019/experimental/cross-window-element-adapter.js +121 -0
  59. package/dist/es2019/index.js +7 -0
  60. package/dist/es2019/internal-types.js +1 -0
  61. package/dist/es2019/ledger/dispatch-consumer-event.js +128 -0
  62. package/dist/es2019/ledger/lifecycle-manager.js +333 -0
  63. package/dist/es2019/ledger/usage-ledger.js +32 -0
  64. package/dist/es2019/make-adapter/make-adapter.js +55 -0
  65. package/dist/es2019/make-adapter/make-drop-target.js +233 -0
  66. package/dist/es2019/make-adapter/make-monitor.js +80 -0
  67. package/dist/es2019/util/add-attribute.js +7 -0
  68. package/dist/es2019/util/combine.js +6 -0
  69. package/dist/es2019/util/disable-native-drag-preview.js +31 -0
  70. package/dist/es2019/util/entering-and-leaving-the-window.js +159 -0
  71. package/dist/es2019/util/fix-post-drag-pointer-bug.js +110 -0
  72. package/dist/es2019/util/get-input.js +14 -0
  73. package/dist/es2019/util/once.js +13 -0
  74. package/dist/es2019/util/reorder.js +17 -0
  75. package/dist/es2019/util/scroll-just-enough-into-view.js +12 -0
  76. package/dist/es2019/util/set-custom-native-drag-preview.js +106 -0
  77. package/dist/es2019/version.json +5 -0
  78. package/dist/esm/adapter/element-adapter.js +142 -0
  79. package/dist/esm/adapter/file-adapter.js +90 -0
  80. package/dist/esm/addon/cancel-unhandled.js +43 -0
  81. package/dist/esm/entry-point/adapter/element.js +1 -0
  82. package/dist/esm/entry-point/adapter/file.js +1 -0
  83. package/dist/esm/entry-point/addon/cancel-unhandled.js +1 -0
  84. package/dist/esm/entry-point/experimental/cross-with-element-adapter.js +1 -0
  85. package/dist/esm/entry-point/types.js +1 -0
  86. package/dist/esm/entry-point/util/combine.js +1 -0
  87. package/dist/esm/entry-point/util/disable-native-drag-preview.js +1 -0
  88. package/dist/esm/entry-point/util/once.js +1 -0
  89. package/dist/esm/entry-point/util/reorder.js +1 -0
  90. package/dist/esm/entry-point/util/scroll-just-enough-into-view.js +1 -0
  91. package/dist/esm/entry-point/util/set-custom-native-drag-preview.js +1 -0
  92. package/dist/esm/experimental/cross-window-element-adapter.js +120 -0
  93. package/dist/esm/index.js +7 -0
  94. package/dist/esm/internal-types.js +1 -0
  95. package/dist/esm/ledger/dispatch-consumer-event.js +125 -0
  96. package/dist/esm/ledger/lifecycle-manager.js +328 -0
  97. package/dist/esm/ledger/usage-ledger.js +31 -0
  98. package/dist/esm/make-adapter/make-adapter.js +53 -0
  99. package/dist/esm/make-adapter/make-drop-target.js +264 -0
  100. package/dist/esm/make-adapter/make-monitor.js +93 -0
  101. package/dist/esm/util/add-attribute.js +8 -0
  102. package/dist/esm/util/combine.js +11 -0
  103. package/dist/esm/util/disable-native-drag-preview.js +30 -0
  104. package/dist/esm/util/entering-and-leaving-the-window.js +156 -0
  105. package/dist/esm/util/fix-post-drag-pointer-bug.js +108 -0
  106. package/dist/esm/util/get-input.js +14 -0
  107. package/dist/esm/util/once.js +16 -0
  108. package/dist/esm/util/reorder.js +19 -0
  109. package/dist/esm/util/scroll-just-enough-into-view.js +11 -0
  110. package/dist/esm/util/set-custom-native-drag-preview.js +104 -0
  111. package/dist/esm/version.json +5 -0
  112. package/dist/types/adapter/element-adapter.d.ts +42 -0
  113. package/dist/types/adapter/file-adapter.d.ts +18 -0
  114. package/dist/types/addon/cancel-unhandled.d.ts +7 -0
  115. package/dist/types/entry-point/adapter/element.d.ts +2 -0
  116. package/dist/types/entry-point/adapter/file.d.ts +2 -0
  117. package/dist/types/entry-point/addon/cancel-unhandled.d.ts +1 -0
  118. package/dist/types/entry-point/experimental/cross-with-element-adapter.d.ts +1 -0
  119. package/dist/types/entry-point/types.d.ts +1 -0
  120. package/dist/types/entry-point/util/combine.d.ts +1 -0
  121. package/dist/types/entry-point/util/disable-native-drag-preview.d.ts +1 -0
  122. package/dist/types/entry-point/util/once.d.ts +1 -0
  123. package/dist/types/entry-point/util/reorder.d.ts +1 -0
  124. package/dist/types/entry-point/util/scroll-just-enough-into-view.d.ts +1 -0
  125. package/dist/types/entry-point/util/set-custom-native-drag-preview.d.ts +1 -0
  126. package/dist/types/experimental/cross-window-element-adapter.d.ts +17 -0
  127. package/dist/types/index.d.ts +2 -0
  128. package/dist/types/internal-types.d.ts +275 -0
  129. package/dist/types/ledger/dispatch-consumer-event.d.ts +26 -0
  130. package/dist/types/ledger/lifecycle-manager.d.ts +16 -0
  131. package/dist/types/ledger/usage-ledger.d.ts +5 -0
  132. package/dist/types/make-adapter/make-adapter.d.ts +14 -0
  133. package/dist/types/make-adapter/make-drop-target.d.ts +5 -0
  134. package/dist/types/make-adapter/make-monitor.d.ts +8 -0
  135. package/dist/types/util/add-attribute.d.ts +5 -0
  136. package/dist/types/util/combine.d.ts +3 -0
  137. package/dist/types/util/disable-native-drag-preview.d.ts +3 -0
  138. package/dist/types/util/entering-and-leaving-the-window.d.ts +6 -0
  139. package/dist/types/util/fix-post-drag-pointer-bug.d.ts +14 -0
  140. package/dist/types/util/get-input.d.ts +2 -0
  141. package/dist/types/util/once.d.ts +2 -0
  142. package/dist/types/util/reorder.d.ts +9 -0
  143. package/dist/types/util/scroll-just-enough-into-view.d.ts +7 -0
  144. package/dist/types/util/set-custom-native-drag-preview.d.ts +52 -0
  145. package/experimental/cross-window-element-adapter/package.json +15 -0
  146. package/package.json +87 -0
  147. package/report.api.md +35 -0
  148. package/tmp/api-report-tmp.d.ts +13 -0
  149. package/types/package.json +15 -0
  150. package/util/combine/package.json +15 -0
  151. package/util/disable-native-drag-preview/package.json +15 -0
  152. package/util/once/package.json +15 -0
  153. package/util/reorder/package.json +15 -0
  154. package/util/scroll-just-enough-into-view/package.json +15 -0
  155. package/util/set-custom-native-drag-preview/package.json +15 -0
@@ -0,0 +1,328 @@
1
+ import { bindAll } from 'bind-event-listener';
2
+ import { isLeavingWindow } from '../util/entering-and-leaving-the-window';
3
+ import { fixPostDragPointerBug } from '../util/fix-post-drag-pointer-bug';
4
+ import { getInput } from '../util/get-input';
5
+ import { makeDispatch } from './dispatch-consumer-event';
6
+ var isActive = false;
7
+ function canStart() {
8
+ return !isActive;
9
+ }
10
+ function getNativeSetDragImage(event) {
11
+ if (event.dataTransfer) {
12
+ // need to use `.bind` as `setDragImage` is required
13
+ // to be run with `event.dataTransfer` as the "this" context
14
+ return event.dataTransfer.setDragImage.bind(event.dataTransfer);
15
+ }
16
+ return null;
17
+ }
18
+ function hasHierarchyChanged(_ref) {
19
+ var current = _ref.current,
20
+ next = _ref.next;
21
+ if (current.length !== next.length) {
22
+ return true;
23
+ }
24
+ // not checking stickiness, data or dropEffect,
25
+ // just whether the hierarchy has changed
26
+ for (var i = 0; i < current.length; i++) {
27
+ if (current[i].element !== next[i].element) {
28
+ return true;
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+ function start(_ref2) {
34
+ var event = _ref2.event,
35
+ dragInterface = _ref2.dragInterface,
36
+ getDropTargetsOver = _ref2.getDropTargetsOver,
37
+ dispatchEvent = _ref2.dispatchEvent;
38
+ if (!canStart()) {
39
+ return;
40
+ }
41
+ isActive = true;
42
+ var initial = getStartLocation({
43
+ event: event,
44
+ dragInterface: dragInterface,
45
+ getDropTargetsOver: getDropTargetsOver
46
+ });
47
+ var current = initial;
48
+ // Setting initial drop effect for the drag
49
+ setDropEffect({
50
+ event: event,
51
+ current: initial.dropTargets
52
+ });
53
+ var dispatch = makeDispatch({
54
+ source: dragInterface.payload,
55
+ dispatchEvent: dispatchEvent,
56
+ initial: initial
57
+ });
58
+ function updateDropTargets(next) {
59
+ // only looking at whether hierarchy has changed to determine whether something as 'changed'
60
+ var hasChanged = hasHierarchyChanged({
61
+ current: current.dropTargets,
62
+ next: next.dropTargets
63
+ });
64
+
65
+ // Always updating the state to include latest data, dropEffect and stickiness
66
+ // Only updating consumers if the hierarchy has changed in some way
67
+ // Consumers can get the latest data by using `onDrag`
68
+ current = next;
69
+ if (hasChanged) {
70
+ dispatch.dragUpdate({
71
+ current: current
72
+ });
73
+ }
74
+ }
75
+ function onUpdateEvent(event) {
76
+ var input = getInput(event);
77
+ var nextDropTargets = getDropTargetsOver({
78
+ target: event.target,
79
+ input: input,
80
+ source: dragInterface.payload,
81
+ current: current.dropTargets
82
+ });
83
+ if (nextDropTargets.length) {
84
+ // 🩸 must call `event.preventDefault()` to allow a browser drop to occur
85
+ event.preventDefault();
86
+ setDropEffect({
87
+ event: event,
88
+ current: nextDropTargets
89
+ });
90
+ }
91
+ updateDropTargets({
92
+ dropTargets: nextDropTargets,
93
+ input: input
94
+ });
95
+ }
96
+ function onDrop(_ref3) {
97
+ var updatedExternalPayload = _ref3.updatedExternalPayload;
98
+ dispatch.drop({
99
+ current: current,
100
+ updatedExternalPayload: updatedExternalPayload
101
+ });
102
+ }
103
+ function cancel() {
104
+ // The spec behaviour is that when a drag is cancelled, or when dropping on no drop targets,
105
+ // a "dragleave" event is fired on the active drop target before a "dragend" event.
106
+ // We are replicating that behaviour in `cancel` if there are any active drop targets to
107
+ // ensure consistent behaviour.
108
+ //
109
+ // Note: When cancelling, or dropping on no drop targets, a "dragleave" event
110
+ // will have already cleared the dropTargets to `[]` (as that particular "dragleave" has a `relatedTarget` of `null`)
111
+
112
+ if (current.dropTargets.length) {
113
+ updateDropTargets({
114
+ dropTargets: [],
115
+ input: current.input
116
+ });
117
+ }
118
+ onDrop({
119
+ updatedExternalPayload: null
120
+ });
121
+ finish();
122
+ }
123
+ function finish() {
124
+ isActive = false;
125
+ unbindEvents();
126
+ }
127
+ var unbindEvents = bindAll(window, [{
128
+ // 👋 Note: we are repurposing the `dragover` event as our `drag` event
129
+ // this is because firefox does not publish pointer coordinates during
130
+ // a `drag` event, but does for every other type of drag event
131
+ // `dragover` fires on all elements that are being dragged over
132
+ // Because we are binding to `window` - our `dragover` is effectively the same as a `drag`
133
+ // 🦊😤
134
+ type: 'dragover',
135
+ listener: function listener(event) {
136
+ // We need to regularly calculate the drop targets in order to allow:
137
+ // - dynamic `canDrop()` checks
138
+ // - rapid updating `getData()` calls to attach data in response to user input (eg for edge detection)
139
+ // Sadly we cannot schedule inspecting changes resulting from this event
140
+ // we need to be able to conditionally cancel the event with `event.preventDefault()`
141
+ // to enable the correct native drop experience.
142
+
143
+ // 1. check to see if anything has changed
144
+ onUpdateEvent(event);
145
+
146
+ // 2. let consumers know a move has occurred
147
+ // This will include the latest 'input' values
148
+ dispatch.drag({
149
+ current: current
150
+ });
151
+ }
152
+ }, {
153
+ type: 'dragenter',
154
+ listener: onUpdateEvent
155
+ }, {
156
+ // This was the only reliable cross browser way I found to detect
157
+ // when the user is leaving the `window`.
158
+ // Internal drags: when we leave the `window` we want to clear any active drop targets,
159
+ // but the drag is not yet over. The user could drag back into the window.
160
+ // We only need to do this because of stickiness
161
+ // External drags: when we leave the `window` the drag operation is over,
162
+ // we will start another drag operation
163
+ type: 'dragleave',
164
+ listener: function listener(event) {
165
+ if (!isLeavingWindow({
166
+ dragLeave: event
167
+ })) {
168
+ return;
169
+ }
170
+ // When a drag is ending without a drop target (or when the drag is cancelled),
171
+ // All browsers fire:
172
+ // 1. "drag"
173
+ // 2. "dragleave"
174
+ // These events have `event.relatedTarget == null` so this code path is also hit in those cases.
175
+ // This is all good! We would be clearing the dropTargets in `cancel()` after the "dragend"
176
+
177
+ // 🐛 Bug workaround: intentionally not updating `input` in "dragleave"
178
+ // In Chrome, this final "dragleave" has default input values (eg clientX == 0)
179
+ // rather than the users current input values
180
+ //
181
+ // - [Conversation](https://twitter.com/alexandereardon/status/1642697633864241152)
182
+ // - [Bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1429937)
183
+ updateDropTargets({
184
+ input: current.input,
185
+ dropTargets: []
186
+ });
187
+ if (dragInterface.startedFrom === 'external') {
188
+ cancel();
189
+ }
190
+ }
191
+ }, {
192
+ type: 'drop',
193
+ listener: function listener(event) {
194
+ var _dragInterface$getDro;
195
+ // A "drop" can only happen if the browser allowed the drop
196
+
197
+ // Opting out of standard browser drop behaviour for the drag
198
+ event.preventDefault();
199
+
200
+ // applying the latest drop effect to the event
201
+ setDropEffect({
202
+ event: event,
203
+ current: current.dropTargets
204
+ });
205
+ onDrop({
206
+ updatedExternalPayload: dragInterface.startedFrom === 'external' ? ((_dragInterface$getDro = dragInterface.getDropPayload) === null || _dragInterface$getDro === void 0 ? void 0 : _dragInterface$getDro.call(dragInterface, event)) || null : null
207
+ });
208
+ finish();
209
+
210
+ // Applying this fix after `dispatch.drop` so that frameworks have the opportunity
211
+ // to update UI in response to a "onDrop".
212
+ if (dragInterface.startedFrom === 'internal') {
213
+ fixPostDragPointerBug({
214
+ current: current
215
+ });
216
+ }
217
+ }
218
+ }, {
219
+ // "dragend" fires when on the drag source (eg a draggable element)
220
+ // when the drag is finished.
221
+ // "dragend" will fire after "drop"(if there was a successful drop)
222
+ // "dragend" does not fire if the draggable source has been removed during the drag
223
+ // or for external drag sources (eg files)
224
+ type: 'dragend',
225
+ listener: function listener() {
226
+ cancel();
227
+
228
+ // Applying this fix after `dispatch.drop` so that frameworks have the opportunity
229
+ // to update UI in response to a "onDrop".
230
+ if (dragInterface.startedFrom === 'internal') {
231
+ fixPostDragPointerBug({
232
+ current: current
233
+ });
234
+ }
235
+ }
236
+ },
237
+ // ## Detecting drag ending for removed draggables
238
+ //
239
+ // If a draggable element is removed during a drag and the user drops:
240
+ // 1. if over a valid drop target: we get a "drop" event to know the drag is finished
241
+ // 2. if not over a valid drop target (or cancelled): we get nothing
242
+ // The "dragend" event will not fire on the source draggable if it has been
243
+ // removed from the DOM.
244
+ // So we need to figure out if a drag operation has finished by looking at other events
245
+ // We can do this by looking at other events
246
+
247
+ // ### First detection: "pointermove" events
248
+
249
+ // 1. "pointermove" events cannot fire during a drag and drop operation
250
+ // according to the spec. So if we get a "pointermove" it means that
251
+ // the drag and drop operations has finished. So if we get a "pointermove"
252
+ // we know that the drag is over
253
+ // 2. 🦊😤 Drag and drop operations are _supposed_ to suppress
254
+ // other pointer events. However, firefox will allow a few
255
+ // pointer event to get through after a drag starts.
256
+ // The most I've seen is 3
257
+ {
258
+ type: 'pointermove',
259
+ listener: function () {
260
+ var callCount = 0;
261
+ return function listener() {
262
+ // Using 20 as it is far bigger than the most observed (3)
263
+ if (callCount < 20) {
264
+ callCount++;
265
+ return;
266
+ }
267
+ cancel();
268
+ };
269
+ }()
270
+ },
271
+ // ### Second detection: "pointerdown" events
272
+
273
+ // If we receive this event then we know that a drag operation has finished
274
+ // and potentially another one is about to start.
275
+ // Note: `pointerdown` fires on all browsers / platforms before "dragstart"
276
+ {
277
+ type: 'pointerdown',
278
+ listener: cancel
279
+ }],
280
+ // Once we have started a managed drag operation it is important that we see / own all drag events
281
+ // We got one adoption bug pop up where some code was stopping (`event.stopPropagation()`)
282
+ // all "drop" events in the bubble phase on the `document.body`.
283
+ // This meant that we never saw the "drop" event.
284
+ {
285
+ capture: true
286
+ });
287
+ dispatch.start({
288
+ nativeSetDragImage: getNativeSetDragImage(event)
289
+ });
290
+ }
291
+ function setDropEffect(_ref4) {
292
+ var _current$;
293
+ var event = _ref4.event,
294
+ current = _ref4.current;
295
+ // setting the `dropEffect` to be the innerMost drop targets dropEffect
296
+ var innerMost = (_current$ = current[0]) === null || _current$ === void 0 ? void 0 : _current$.dropEffect;
297
+ if (innerMost != null && event.dataTransfer) {
298
+ event.dataTransfer.dropEffect = innerMost;
299
+ }
300
+ }
301
+ function getStartLocation(_ref5) {
302
+ var event = _ref5.event,
303
+ dragInterface = _ref5.dragInterface,
304
+ getDropTargetsOver = _ref5.getDropTargetsOver;
305
+ var input = getInput(event);
306
+
307
+ // When dragging from outside of the browser, we don't have any starting drop targets
308
+ if (dragInterface.startedFrom === 'external') {
309
+ return {
310
+ input: input,
311
+ dropTargets: []
312
+ };
313
+ }
314
+ var dropTargets = getDropTargetsOver({
315
+ input: input,
316
+ source: dragInterface.payload,
317
+ target: event.target,
318
+ current: []
319
+ });
320
+ return {
321
+ input: input,
322
+ dropTargets: dropTargets
323
+ };
324
+ }
325
+ export var lifecycle = {
326
+ canStart: canStart,
327
+ start: start
328
+ };
@@ -0,0 +1,31 @@
1
+ // Extending `Map` to allow us to link Key and Values together
2
+
3
+ var ledger = new Map();
4
+ function registerUsage(_ref) {
5
+ var typeKey = _ref.typeKey,
6
+ mount = _ref.mount;
7
+ var entry = ledger.get(typeKey);
8
+ if (entry) {
9
+ entry.usageCount++;
10
+ return entry;
11
+ }
12
+ var initial = {
13
+ typeKey: typeKey,
14
+ unmount: mount(),
15
+ usageCount: 1
16
+ };
17
+ ledger.set(typeKey, initial);
18
+ return initial;
19
+ }
20
+ export function register(args) {
21
+ var entry = registerUsage(args);
22
+ return function unregister() {
23
+ entry.usageCount--;
24
+ if (entry.usageCount > 0) {
25
+ return;
26
+ }
27
+ // Only a single usage left, remove it
28
+ entry.unmount();
29
+ ledger.delete(args.typeKey);
30
+ };
31
+ }
@@ -0,0 +1,53 @@
1
+ import { lifecycle } from '../ledger/lifecycle-manager';
2
+ import { register } from '../ledger/usage-ledger';
3
+ import { makeDropTarget } from './make-drop-target';
4
+ import { makeMonitor } from './make-monitor';
5
+ export function makeAdapter(_ref) {
6
+ var typeKey = _ref.typeKey,
7
+ mount = _ref.mount,
8
+ dispatchEventToSource = _ref.dispatchEventToSource,
9
+ defaultDropEffect = _ref.defaultDropEffect;
10
+ var monitorAPI = makeMonitor();
11
+ var dropTargetAPI = makeDropTarget({
12
+ typeKey: typeKey,
13
+ defaultDropEffect: defaultDropEffect
14
+ });
15
+ function dispatchEvent(args) {
16
+ // 1. forward the event to source
17
+ dispatchEventToSource === null || dispatchEventToSource === void 0 ? void 0 : dispatchEventToSource(args);
18
+
19
+ // 2. forward the event to relevant dropTargets
20
+ dropTargetAPI.dispatchEvent(args);
21
+
22
+ // 3. forward event to monitors
23
+ monitorAPI.dispatchEvent(args);
24
+ }
25
+ function start(_ref2) {
26
+ var event = _ref2.event,
27
+ dragInterface = _ref2.dragInterface;
28
+ lifecycle.start({
29
+ event: event,
30
+ dragInterface: dragInterface,
31
+ getDropTargetsOver: dropTargetAPI.getIsOver,
32
+ dispatchEvent: dispatchEvent
33
+ });
34
+ }
35
+ function registerUsage() {
36
+ function mountAdapter() {
37
+ var api = {
38
+ canStart: lifecycle.canStart,
39
+ start: start
40
+ };
41
+ return mount(api);
42
+ }
43
+ return register({
44
+ typeKey: typeKey,
45
+ mount: mountAdapter
46
+ });
47
+ }
48
+ return {
49
+ registerUsage: registerUsage,
50
+ dropTarget: dropTargetAPI.dropTargetForConsumers,
51
+ monitor: monitorAPI.monitorForConsumers
52
+ };
53
+ }
@@ -0,0 +1,264 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
5
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
6
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
7
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
8
+ import { addAttribute } from '../util/add-attribute';
9
+ import { combine } from '../util/combine';
10
+ function copyReverse(array) {
11
+ return array.slice(0).reverse();
12
+ }
13
+ export function makeDropTarget(_ref) {
14
+ var typeKey = _ref.typeKey,
15
+ defaultDropEffect = _ref.defaultDropEffect;
16
+ var registry = new WeakMap();
17
+ var dropTargetDataAtt = "data-drop-target-for-".concat(typeKey);
18
+ var dropTargetSelector = "[".concat(dropTargetDataAtt, "]");
19
+ function addToRegistry(args) {
20
+ registry.set(args.element, args);
21
+ return function () {
22
+ return registry.delete(args.element);
23
+ };
24
+ }
25
+ function dropTargetForConsumers(args) {
26
+ // Guardrail: warn if the draggable element is already registered
27
+ if (process.env.NODE_ENV !== 'production') {
28
+ var existing = registry.get(args.element);
29
+ if (existing) {
30
+ // eslint-disable-next-line no-console
31
+ console.warn('You have already registered a `droppable` on the same element', {
32
+ existing: existing,
33
+ proposed: args
34
+ });
35
+ }
36
+ }
37
+ return combine(addAttribute(args.element, {
38
+ attribute: dropTargetDataAtt,
39
+ value: 'true'
40
+ }), addToRegistry(args));
41
+ }
42
+ function getActualDropTargets(_ref2) {
43
+ var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2, _args$getIsSticky;
44
+ var source = _ref2.source,
45
+ target = _ref2.target,
46
+ input = _ref2.input,
47
+ _ref2$result = _ref2.result,
48
+ result = _ref2$result === void 0 ? [] : _ref2$result;
49
+ if (!(target instanceof Element)) {
50
+ return result;
51
+ }
52
+ var closest = target.closest(dropTargetSelector);
53
+
54
+ // Cannot find anything else
55
+ if (closest == null) {
56
+ return result;
57
+ }
58
+ var args = registry.get(closest);
59
+
60
+ // error: something had a dropTargetSelector but we could not
61
+ // find a match. For now, failing silently
62
+ if (args == null) {
63
+ return result;
64
+ }
65
+ var feedback = {
66
+ input: input,
67
+ source: source,
68
+ element: args.element
69
+ };
70
+
71
+ // if dropping is not allowed, skip this drop target
72
+ // and continue looking up the DOM tree
73
+ if (args.canDrop && !args.canDrop(feedback)) {
74
+ return getActualDropTargets({
75
+ source: source,
76
+ target: args.element.parentElement,
77
+ input: input,
78
+ result: result
79
+ });
80
+ }
81
+ var data = (_args$getData = (_args$getData2 = args.getData) === null || _args$getData2 === void 0 ? void 0 : _args$getData2.call(args, feedback)) !== null && _args$getData !== void 0 ? _args$getData : {};
82
+ var dropEffect = (_args$getDropEffect = (_args$getDropEffect2 = args.getDropEffect) === null || _args$getDropEffect2 === void 0 ? void 0 : _args$getDropEffect2.call(args, feedback)) !== null && _args$getDropEffect !== void 0 ? _args$getDropEffect : defaultDropEffect;
83
+ var sticky = Boolean((_args$getIsSticky = args.getIsSticky) === null || _args$getIsSticky === void 0 ? void 0 : _args$getIsSticky.call(args, feedback));
84
+ var record = {
85
+ data: data,
86
+ element: args.element,
87
+ dropEffect: dropEffect,
88
+ sticky: sticky
89
+ };
90
+ return getActualDropTargets({
91
+ source: source,
92
+ target: args.element.parentElement,
93
+ input: input,
94
+ // Using bubble ordering. Same ordering as `event.getPath()`
95
+ result: [].concat(_toConsumableArray(result), [record])
96
+ });
97
+ }
98
+ function notifyCurrent(_ref3) {
99
+ var eventName = _ref3.eventName,
100
+ payload = _ref3.payload;
101
+ var _iterator = _createForOfIteratorHelper(payload.location.current.dropTargets),
102
+ _step;
103
+ try {
104
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
105
+ var _entry$eventName;
106
+ var record = _step.value;
107
+ var entry = registry.get(record.element);
108
+ var _args = _objectSpread(_objectSpread({}, payload), {}, {
109
+ self: record
110
+ });
111
+ entry === null || entry === void 0 ? void 0 : (_entry$eventName = entry[eventName]) === null || _entry$eventName === void 0 ? void 0 : _entry$eventName.call(entry,
112
+ // I cannot seem to get the types right here.
113
+ // TS doesn't seem to like that one event can need `nativeSetDragImage`
114
+ // @ts-expect-error
115
+ _args);
116
+ }
117
+ } catch (err) {
118
+ _iterator.e(err);
119
+ } finally {
120
+ _iterator.f();
121
+ }
122
+ }
123
+ var actions = {
124
+ onGenerateDragPreview: notifyCurrent,
125
+ onDrag: notifyCurrent,
126
+ onDragStart: notifyCurrent,
127
+ onDrop: notifyCurrent,
128
+ onDropTargetChange: function onDropTargetChange(_ref4) {
129
+ var payload = _ref4.payload;
130
+ var isCurrent = new Set(payload.location.current.dropTargets.map(function (record) {
131
+ return record.element;
132
+ }));
133
+ var visited = new Set();
134
+ var _iterator2 = _createForOfIteratorHelper(payload.location.previous.dropTargets),
135
+ _step2;
136
+ try {
137
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
138
+ var _entry$onDropTargetCh;
139
+ var record = _step2.value;
140
+ visited.add(record.element);
141
+ var entry = registry.get(record.element);
142
+ var isOver = isCurrent.has(record.element);
143
+ var _args2 = _objectSpread(_objectSpread({}, payload), {}, {
144
+ self: record
145
+ });
146
+ entry === null || entry === void 0 ? void 0 : (_entry$onDropTargetCh = entry.onDropTargetChange) === null || _entry$onDropTargetCh === void 0 ? void 0 : _entry$onDropTargetCh.call(entry, _args2);
147
+
148
+ // if we cannot find the drop target in the current array, then it has been left
149
+ if (!isOver) {
150
+ var _entry$onDragLeave;
151
+ entry === null || entry === void 0 ? void 0 : (_entry$onDragLeave = entry.onDragLeave) === null || _entry$onDragLeave === void 0 ? void 0 : _entry$onDragLeave.call(entry, _args2);
152
+ }
153
+ }
154
+ } catch (err) {
155
+ _iterator2.e(err);
156
+ } finally {
157
+ _iterator2.f();
158
+ }
159
+ var _iterator3 = _createForOfIteratorHelper(payload.location.current.dropTargets),
160
+ _step3;
161
+ try {
162
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
163
+ var _entry$onDropTargetCh2, _entry$onDragEnter;
164
+ var _record = _step3.value;
165
+ // already published an update to this drop target
166
+ if (visited.has(_record.element)) {
167
+ continue;
168
+ }
169
+ // at this point we have a new drop target that is being entered into
170
+ var _args3 = _objectSpread(_objectSpread({}, payload), {}, {
171
+ self: _record
172
+ });
173
+ var _entry = registry.get(_record.element);
174
+ _entry === null || _entry === void 0 ? void 0 : (_entry$onDropTargetCh2 = _entry.onDropTargetChange) === null || _entry$onDropTargetCh2 === void 0 ? void 0 : _entry$onDropTargetCh2.call(_entry, _args3);
175
+ _entry === null || _entry === void 0 ? void 0 : (_entry$onDragEnter = _entry.onDragEnter) === null || _entry$onDragEnter === void 0 ? void 0 : _entry$onDragEnter.call(_entry, _args3);
176
+ }
177
+ } catch (err) {
178
+ _iterator3.e(err);
179
+ } finally {
180
+ _iterator3.f();
181
+ }
182
+ }
183
+ };
184
+ function dispatchEvent(args) {
185
+ // This line does not work in TS 4.2
186
+ // It does work in TS 4.7
187
+ // @ts-expect-error
188
+ actions[args.eventName](args);
189
+ }
190
+ function getIsOver(_ref5) {
191
+ var source = _ref5.source,
192
+ target = _ref5.target,
193
+ input = _ref5.input,
194
+ current = _ref5.current;
195
+ var actual = getActualDropTargets({
196
+ source: source,
197
+ target: target,
198
+ input: input
199
+ });
200
+
201
+ // stickiness is only relevant when we have less
202
+ // drop targets than we did before
203
+ if (actual.length >= current.length) {
204
+ return actual;
205
+ }
206
+
207
+ // less 'actual' drop targets than before,
208
+ // we need to see if 'stickiness' applies
209
+
210
+ // An old drop target will continue to be dropped on if:
211
+ // 1. it has the same parent
212
+ // 2. nothing exists in it's previous index
213
+
214
+ var lastCaptureOrdered = copyReverse(current);
215
+ var actualCaptureOrdered = copyReverse(actual);
216
+ var resultCaptureOrdered = [];
217
+ for (var index = 0; index < lastCaptureOrdered.length; index++) {
218
+ var last = lastCaptureOrdered[index];
219
+ var fresh = actualCaptureOrdered[index];
220
+
221
+ // if a record is in the new index -> use that
222
+ // it will have the latest data + dropEffect
223
+ if (fresh != null) {
224
+ resultCaptureOrdered.push(fresh);
225
+ continue;
226
+ }
227
+
228
+ // At this point we have no drop target in the old spot
229
+ // Check to see if we can use a previous sticky drop target
230
+
231
+ // stickiness is based on relationships to a parent
232
+ // so if we hit a drop target that is not sticky we
233
+ // can finish our search
234
+ if (!last.sticky) {
235
+ break;
236
+ }
237
+
238
+ // We only want the previous sticky item to 'stick' if
239
+ // the parent of the sticky item is unchanged
240
+
241
+ // The "parent" is the one inside of `resultCaptureOrdered`
242
+ // (the parent might be a drop target that was sticky)
243
+ var parent = resultCaptureOrdered[index - 1];
244
+ var lastParent = lastCaptureOrdered[index - 1];
245
+
246
+ // parents are the same (might both be undefined for index == 0)
247
+ // we can add the last entry and keep searching
248
+ if ((parent === null || parent === void 0 ? void 0 : parent.element) === (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
249
+ resultCaptureOrdered.push(last);
250
+ continue;
251
+ }
252
+ // parents are not the same, we can exit our search
253
+ break;
254
+ }
255
+
256
+ // return bubble ordered result
257
+ return copyReverse(resultCaptureOrdered);
258
+ }
259
+ return {
260
+ dropTargetForConsumers: dropTargetForConsumers,
261
+ getIsOver: getIsOver,
262
+ dispatchEvent: dispatchEvent
263
+ };
264
+ }