@atlaskit/pragmatic-drag-and-drop 1.1.12 → 1.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 (55) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cjs/adapter/element-adapter.js +14 -4
  3. package/dist/cjs/adapter/text-selection-adapter.js +7 -3
  4. package/dist/cjs/entry-point/private/get-element-from-point-without-honey-pot.js +12 -0
  5. package/dist/cjs/honey-pot-fix/get-element-from-point-without-honey-pot.js +23 -0
  6. package/dist/cjs/honey-pot-fix/honey-pot-data-attribute.js +9 -0
  7. package/dist/cjs/honey-pot-fix/is-honey-pot-element.js +10 -0
  8. package/dist/cjs/honey-pot-fix/make-honey-pot-fix.js +315 -0
  9. package/dist/cjs/ledger/lifecycle-manager.js +31 -23
  10. package/dist/cjs/make-adapter/make-adapter.js +4 -0
  11. package/dist/cjs/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +2 -1
  12. package/dist/cjs/util/max-z-index.js +9 -0
  13. package/dist/es2019/adapter/element-adapter.js +14 -4
  14. package/dist/es2019/adapter/text-selection-adapter.js +8 -4
  15. package/dist/es2019/entry-point/private/get-element-from-point-without-honey-pot.js +1 -0
  16. package/dist/es2019/honey-pot-fix/get-element-from-point-without-honey-pot.js +12 -0
  17. package/dist/es2019/honey-pot-fix/honey-pot-data-attribute.js +3 -0
  18. package/dist/es2019/honey-pot-fix/is-honey-pot-element.js +4 -0
  19. package/dist/es2019/honey-pot-fix/make-honey-pot-fix.js +315 -0
  20. package/dist/es2019/ledger/lifecycle-manager.js +31 -23
  21. package/dist/es2019/make-adapter/make-adapter.js +4 -0
  22. package/dist/es2019/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +2 -1
  23. package/dist/es2019/util/max-z-index.js +3 -0
  24. package/dist/esm/adapter/element-adapter.js +14 -4
  25. package/dist/esm/adapter/text-selection-adapter.js +8 -4
  26. package/dist/esm/entry-point/private/get-element-from-point-without-honey-pot.js +1 -0
  27. package/dist/esm/honey-pot-fix/get-element-from-point-without-honey-pot.js +16 -0
  28. package/dist/esm/honey-pot-fix/honey-pot-data-attribute.js +3 -0
  29. package/dist/esm/honey-pot-fix/is-honey-pot-element.js +4 -0
  30. package/dist/esm/honey-pot-fix/make-honey-pot-fix.js +308 -0
  31. package/dist/esm/ledger/lifecycle-manager.js +31 -23
  32. package/dist/esm/make-adapter/make-adapter.js +4 -0
  33. package/dist/esm/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +2 -1
  34. package/dist/esm/util/max-z-index.js +3 -0
  35. package/dist/types/entry-point/private/get-element-from-point-without-honey-pot.d.ts +1 -0
  36. package/dist/types/honey-pot-fix/get-element-from-point-without-honey-pot.d.ts +2 -0
  37. package/dist/types/honey-pot-fix/honey-pot-data-attribute.d.ts +1 -0
  38. package/dist/types/honey-pot-fix/is-honey-pot-element.d.ts +1 -0
  39. package/dist/types/honey-pot-fix/make-honey-pot-fix.d.ts +8 -0
  40. package/dist/types/make-adapter/make-adapter.d.ts +5 -1
  41. package/dist/types/util/max-z-index.d.ts +1 -0
  42. package/dist/types-ts4.5/entry-point/private/get-element-from-point-without-honey-pot.d.ts +1 -0
  43. package/dist/types-ts4.5/honey-pot-fix/get-element-from-point-without-honey-pot.d.ts +2 -0
  44. package/dist/types-ts4.5/honey-pot-fix/honey-pot-data-attribute.d.ts +1 -0
  45. package/dist/types-ts4.5/honey-pot-fix/is-honey-pot-element.d.ts +1 -0
  46. package/dist/types-ts4.5/honey-pot-fix/make-honey-pot-fix.d.ts +8 -0
  47. package/dist/types-ts4.5/make-adapter/make-adapter.d.ts +5 -1
  48. package/dist/types-ts4.5/util/max-z-index.d.ts +1 -0
  49. package/package.json +105 -104
  50. package/private/get-element-from-point-without-honey-pot/package.json +15 -0
  51. package/dist/cjs/util/fix-post-drag-pointer-bug.js +0 -125
  52. package/dist/es2019/util/fix-post-drag-pointer-bug.js +0 -121
  53. package/dist/esm/util/fix-post-drag-pointer-bug.js +0 -119
  54. package/dist/types/util/fix-post-drag-pointer-bug.d.ts +0 -14
  55. package/dist/types-ts4.5/util/fix-post-drag-pointer-bug.d.ts +0 -14
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @atlaskit/pragmatic-drag-and-drop
2
2
 
3
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#116572](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/116572)
8
+ [`98c65e7ff719c`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/98c65e7ff719c) -
9
+ 🍯 Introducing "the honey pot fix" which is an improved workaround for a
10
+ [painful browser bug](https://issues.chromium.org/issues/41129937).
11
+
12
+ **Background**
13
+
14
+ The browser bug causes the browser to think the users pointer is continually depressed at the
15
+ point that the user started a drag. This could lead to incorrect events being triggered, and
16
+ incorrect styles being applied to elements that the user is not currently over during a drag.
17
+
18
+ **Outcomes**
19
+
20
+ - Elements will no longer receive `MouseEvent`s (eg `"mouseenter"` and `"mouseleave"`) during a
21
+ drag (which is a violation of the
22
+ [drag and drop specification](https://html.spec.whatwg.org/multipage/dnd.html#drag-and-drop-processing-model))
23
+ - Elements will no longer apply `:hover` or `:active` styles during a drag. Previously consumers
24
+ would need to disable these style rules during a drag to prevent these styles being applied.
25
+ - Dramatically improved post drop performance. Our prior solution could require a noticeable delay
26
+ due to a large style recalculation after a drop.
27
+
3
28
  ## 1.1.12
4
29
 
5
30
  ### Patch Changes
@@ -8,6 +8,8 @@ exports.draggable = draggable;
8
8
  exports.monitorForElements = exports.dropTargetForElements = void 0;
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var _bindEventListener = require("bind-event-listener");
11
+ var _getElementFromPointWithoutHoneyPot = require("../honey-pot-fix/get-element-from-point-without-honey-pot");
12
+ var _makeHoneyPotFix = require("../honey-pot-fix/make-honey-pot-fix");
11
13
  var _makeAdapter = require("../make-adapter/make-adapter");
12
14
  var _combine = require("../public-utils/combine");
13
15
  var _addAttribute = require("../util/add-attribute");
@@ -23,6 +25,7 @@ function addToRegistry(args) {
23
25
  draggableRegistry.delete(args.element);
24
26
  };
25
27
  }
28
+ var honeyPotFix = (0, _makeHoneyPotFix.makeHoneyPotFix)();
26
29
  var adapter = (0, _makeAdapter.makeAdapter)({
27
30
  typeKey: 'element',
28
31
  defaultDropEffect: 'move',
@@ -32,7 +35,7 @@ var adapter = (0, _makeAdapter.makeAdapter)({
32
35
  * `document` is the first `EventTarget` under `window`
33
36
  * https://twitter.com/alexandereardon/status/1604658588311465985
34
37
  */
35
- return (0, _bindEventListener.bind)(document, {
38
+ return (0, _combine.combine)(honeyPotFix.bindEvents(), (0, _bindEventListener.bind)(document, {
36
39
  type: 'dragstart',
37
40
  listener: function listener(event) {
38
41
  var _entry$dragHandle, _entry$getInitialData, _entry$getInitialData2, _entry$dragHandle2, _entry$getInitialData3, _entry$getInitialData4;
@@ -95,7 +98,13 @@ var adapter = (0, _makeAdapter.makeAdapter)({
95
98
 
96
99
  // Check: is there a drag handle and is the user using it?
97
100
  if (entry.dragHandle) {
98
- var over = document.elementFromPoint(input.clientX, input.clientY);
101
+ // technically don't need this util, but just being
102
+ // consistent with how we look up what is under the users
103
+ // cursor.
104
+ var over = (0, _getElementFromPointWithoutHoneyPot.getElementFromPointWithoutHoneypot)({
105
+ x: input.clientX,
106
+ y: input.clientY
107
+ });
99
108
 
100
109
  // if we are not dragging from the drag handle (or something inside the drag handle)
101
110
  // then we will cancel the active drag
@@ -185,7 +194,7 @@ var adapter = (0, _makeAdapter.makeAdapter)({
185
194
  dragType: dragType
186
195
  });
187
196
  }
188
- });
197
+ }));
189
198
  },
190
199
  dispatchEventToSource: function dispatchEventToSource(_ref) {
191
200
  var _draggableRegistry$ge, _draggableRegistry$ge2;
@@ -202,7 +211,8 @@ var adapter = (0, _makeAdapter.makeAdapter)({
202
211
  // TS doesn't seem to like that one event can need `nativeSetDragImage`
203
212
  // @ts-expect-error
204
213
  payload);
205
- }
214
+ },
215
+ onPostDispatch: honeyPotFix.getOnPostDispatch()
206
216
  });
207
217
  var dropTargetForElements = exports.dropTargetForElements = adapter.dropTarget;
208
218
  var monitorForElements = exports.monitorForElements = adapter.monitor;
@@ -6,7 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.dropTargetForTextSelection = dropTargetForTextSelection;
7
7
  exports.monitorForTextSelection = monitorForTextSelection;
8
8
  var _bindEventListener = require("bind-event-listener");
9
+ var _makeHoneyPotFix = require("../honey-pot-fix/make-honey-pot-fix");
9
10
  var _makeAdapter = require("../make-adapter/make-adapter");
11
+ var _combine = require("../public-utils/combine");
10
12
  var _isSafari = require("../util/is-safari");
11
13
  var _htmlMediaType = require("../util/media-types/html-media-type");
12
14
  var _textMediaType = require("../util/media-types/text-media-type");
@@ -56,6 +58,7 @@ function findTextNode(event) {
56
58
  });
57
59
  return text !== null && text !== void 0 ? text : null;
58
60
  }
61
+ var honeyPotFix = (0, _makeHoneyPotFix.makeHoneyPotFix)();
59
62
  var adapter = (0, _makeAdapter.makeAdapter)({
60
63
  typeKey: 'text-selection',
61
64
  // for text selection, we will usually be making a copy of the text
@@ -64,7 +67,7 @@ var adapter = (0, _makeAdapter.makeAdapter)({
64
67
  // Binding to the `window` so that the element adapter has a
65
68
  // chance to get in first on the `document`.
66
69
  // We are giving preference to the element adapter.
67
- return (0, _bindEventListener.bindAll)(window, [{
70
+ return (0, _combine.combine)(honeyPotFix.bindEvents(), (0, _bindEventListener.bind)(window, {
68
71
  type: 'dragstart',
69
72
  listener: function listener(event) {
70
73
  // If the "dragstart" event is cancelled, then a drag won't start
@@ -116,8 +119,9 @@ var adapter = (0, _makeAdapter.makeAdapter)({
116
119
  }
117
120
  });
118
121
  }
119
- }]);
120
- }
122
+ }));
123
+ },
124
+ onPostDispatch: honeyPotFix.getOnPostDispatch()
121
125
  });
122
126
 
123
127
  // The `onGenerateDragPreview` does not make sense to publish for text selection
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "getElementFromPointWithoutHoneypot", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _getElementFromPointWithoutHoneyPot.getElementFromPointWithoutHoneypot;
10
+ }
11
+ });
12
+ var _getElementFromPointWithoutHoneyPot = require("../../honey-pot-fix/get-element-from-point-without-honey-pot");
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getElementFromPointWithoutHoneypot = getElementFromPointWithoutHoneypot;
8
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
+ var _isHoneyPotElement = require("./is-honey-pot-element");
10
+ function getElementFromPointWithoutHoneypot(client) {
11
+ // eslint-disable-next-line no-restricted-syntax
12
+ var _document$elementsFro = document.elementsFromPoint(client.x, client.y),
13
+ _document$elementsFro2 = (0, _slicedToArray2.default)(_document$elementsFro, 2),
14
+ top = _document$elementsFro2[0],
15
+ second = _document$elementsFro2[1];
16
+ if (!top) {
17
+ return null;
18
+ }
19
+ if ((0, _isHoneyPotElement.isHoneyPotElement)(top)) {
20
+ return second !== null && second !== void 0 ? second : null;
21
+ }
22
+ return top;
23
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.honeyPotDataAttribute = void 0;
7
+ // pulling this into a separate file so adapter(s) that don't
8
+ // need the honey pot can pay as little as possible for it.
9
+ var honeyPotDataAttribute = exports.honeyPotDataAttribute = 'data-pdnd-honey-pot';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isHoneyPotElement = isHoneyPotElement;
7
+ var _honeyPotDataAttribute = require("./honey-pot-data-attribute");
8
+ function isHoneyPotElement(target) {
9
+ return target instanceof Element && target.hasAttribute(_honeyPotDataAttribute.honeyPotDataAttribute);
10
+ }
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.makeHoneyPotFix = makeHoneyPotFix;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _bindEventListener = require("bind-event-listener");
10
+ var _maxZIndex = require("../util/max-z-index");
11
+ var _honeyPotDataAttribute = require("./honey-pot-data-attribute");
12
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
14
+ var honeyPotSize = 2;
15
+ var halfHoneyPotSize = honeyPotSize / 2;
16
+
17
+ /**
18
+ * `clientX` and `clientY` can be in sub pixels (eg `2.332`)
19
+ * However, browser hitbox testing is commonly do to the closest pixel.
20
+ *
21
+ * → https://issues.chromium.org/issues/40940531
22
+ *
23
+ * To be sure that the honey pot will be over the `client` position,
24
+ * we `.floor()` `clientX` and`clientY` and then make it `2px` in size.
25
+ **/
26
+ function floorToClosestPixel(point) {
27
+ return {
28
+ x: Math.floor(point.x),
29
+ y: Math.floor(point.y)
30
+ };
31
+ }
32
+
33
+ /**
34
+ * We want to make sure the honey pot sits around the users position.
35
+ * This seemed to be the most resilient while testing.
36
+ */
37
+ function pullBackByHalfHoneyPotSize(point) {
38
+ return {
39
+ x: point.x - halfHoneyPotSize,
40
+ y: point.y - halfHoneyPotSize
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Prevent the honey pot from changing the window size.
46
+ * This is super unlikely to occur, but just being safe.
47
+ */
48
+ function preventGoingBackwardsOffScreen(point) {
49
+ return {
50
+ x: Math.max(point.x, 0),
51
+ y: Math.max(point.y, 0)
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Prevent the honey pot from changing the window size.
57
+ * This is super unlikely to occur, but just being safe.
58
+ */
59
+ function preventGoingForwardsOffScreen(point) {
60
+ return {
61
+ x: Math.min(point.x, window.innerWidth - honeyPotSize),
62
+ y: Math.min(point.y, window.innerHeight - honeyPotSize)
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Create a `2x2` `DOMRect` around the `client` position
68
+ */
69
+ function getHoneyPotRectFor(_ref) {
70
+ var client = _ref.client;
71
+ var point = preventGoingForwardsOffScreen(preventGoingBackwardsOffScreen(pullBackByHalfHoneyPotSize(floorToClosestPixel(client))));
72
+
73
+ // When debugging, it is helpful to
74
+ // make this element a bit bigger
75
+ return DOMRect.fromRect({
76
+ x: point.x,
77
+ y: point.y,
78
+ width: honeyPotSize,
79
+ height: honeyPotSize
80
+ });
81
+ }
82
+ function getRectStyles(_ref2) {
83
+ var clientRect = _ref2.clientRect;
84
+ return {
85
+ left: "".concat(clientRect.left, "px"),
86
+ top: "".concat(clientRect.top, "px"),
87
+ width: "".concat(clientRect.width, "px"),
88
+ height: "".concat(clientRect.height, "px")
89
+ };
90
+ }
91
+ function isWithin(_ref3) {
92
+ var client = _ref3.client,
93
+ clientRect = _ref3.clientRect;
94
+ return (
95
+ // is within horizontal bounds
96
+ client.x >= clientRect.x && client.x <= clientRect.x + clientRect.width &&
97
+ // is within vertical bounds
98
+ client.y >= clientRect.y && client.y <= clientRect.y + clientRect.height
99
+ );
100
+ }
101
+ /**
102
+ * The honey pot fix is designed to get around a painful bug in all browsers.
103
+ *
104
+ * [Overview](https://www.youtube.com/watch?v=udE9qbFTeQg)
105
+ *
106
+ * **Background**
107
+ *
108
+ * When a drag starts, browsers incorrectly think that the users pointer is
109
+ * still depressed where the drag started. Any element that goes under this position
110
+ * will be entered into, causing `"mouseenter"` events and `":hover"` styles to be applied.
111
+ *
112
+ * _This is a violation of the spec_
113
+ *
114
+ * > "From the moment that the user agent is to initiate the drag-and-drop operation,
115
+ * > until the end of the drag-and-drop operation, device input events
116
+ * > (e.g. mouse and keyboard events) must be suppressed."
117
+ * >
118
+ * > - https://html.spec.whatwg.org/multipage/dnd.html#drag-and-drop-processing-model
119
+ *
120
+ * _Some impacts_
121
+ *
122
+ * - `":hover"` styles being applied where they shouldn't (looks messy)
123
+ * - components such as tooltips responding to `"mouseenter"` can show during a drag,
124
+ * and on an element the user isn't even over
125
+ *
126
+ * Bug: https://issues.chromium.org/issues/41129937
127
+ *
128
+ * **Honey pot fix**
129
+ *
130
+ * 1. Create an element where the browser thinks the depressed pointer is
131
+ * to absorb the incorrect pointer events
132
+ * 2. Remove that element when it is no longer needed
133
+ */
134
+ function mountHoneyPot(_ref4) {
135
+ var initial = _ref4.initial;
136
+ var element = document.createElement('div');
137
+ element.setAttribute(_honeyPotDataAttribute.honeyPotDataAttribute, 'true');
138
+
139
+ // can shift during the drag thanks to Firefox
140
+ var clientRect = getHoneyPotRectFor({
141
+ client: initial
142
+ });
143
+ Object.assign(element.style, _objectSpread(_objectSpread({
144
+ // Setting a background color explicitly to avoid any inherited styles.
145
+ // Looks like this could be `opacity: 0`, but worried that _might_
146
+ // cause the element to be ignored on some platforms.
147
+ // When debugging, set backgroundColor to something like "red".
148
+ backgroundColor: 'transparent',
149
+ position: 'fixed',
150
+ // Being explicit to avoid inheriting styles
151
+ padding: 0,
152
+ margin: 0,
153
+ boxSizing: 'border-box'
154
+ }, getRectStyles({
155
+ clientRect: clientRect
156
+ })), {}, {
157
+ // We want this element to absorb pointer events,
158
+ // it's kind of the whole point 😉
159
+ pointerEvents: 'auto',
160
+ // Want to make sure the honey pot is top of everything else.
161
+ // Don't need to worry about native drag previews, as they will
162
+ // have been rendered (and removed) before the honey pot is rendered
163
+ zIndex: _maxZIndex.maxZIndex
164
+ }));
165
+ document.body.appendChild(element);
166
+
167
+ /**
168
+ * 🦊 In firefox we can get `"pointermove"` events after the drag
169
+ * has started, which is a spec violation.
170
+ * The final `"pointermove"` will reveal where the "depressed" position
171
+ * is for our honey pot fix.
172
+ */
173
+ var unbindPointerMove = (0, _bindEventListener.bind)(window, {
174
+ type: 'pointermove',
175
+ listener: function listener(event) {
176
+ var client = {
177
+ x: event.clientX,
178
+ y: event.clientY
179
+ };
180
+ clientRect = getHoneyPotRectFor({
181
+ client: client
182
+ });
183
+ Object.assign(element.style, getRectStyles({
184
+ clientRect: clientRect
185
+ }));
186
+ },
187
+ // using capture so we are less likely to be impacted by event stopping
188
+ options: {
189
+ capture: true
190
+ }
191
+ });
192
+ return function finish(_ref5) {
193
+ var current = _ref5.current;
194
+ // Don't need this any more
195
+ unbindPointerMove();
196
+
197
+ // If the user is hover the honey pot, we remove it
198
+ // so that the user can continue to interact with the page normally.
199
+ if (isWithin({
200
+ client: current,
201
+ clientRect: clientRect
202
+ })) {
203
+ element.remove();
204
+ return;
205
+ }
206
+ function cleanup() {
207
+ unbindPostDragEvents();
208
+ element.remove();
209
+ }
210
+ var unbindPostDragEvents = (0, _bindEventListener.bindAll)(window, [{
211
+ type: 'pointerdown',
212
+ listener: cleanup
213
+ }, {
214
+ type: 'pointermove',
215
+ listener: cleanup
216
+ }, {
217
+ type: 'focusin',
218
+ listener: cleanup
219
+ }, {
220
+ type: 'focusout',
221
+ listener: cleanup
222
+ },
223
+ // a 'pointerdown' should happen before 'dragstart', but just being super safe
224
+ {
225
+ type: 'dragstart',
226
+ listener: cleanup
227
+ },
228
+ // if the user has dragged something out of the window
229
+ // and then is dragging something back into the window
230
+ // the first events we will see are "dragenter" (and then "dragover").
231
+ // So if we see any of these we need to clear the post drag fix.
232
+ {
233
+ type: 'dragenter',
234
+ listener: cleanup
235
+ }, {
236
+ type: 'dragover',
237
+ listener: cleanup
238
+ }
239
+
240
+ // Not adding a "wheel" event listener, as "wheel" by itself does not
241
+ // resolve the bug.
242
+ ], {
243
+ // Using `capture` so less likely to be impacted by other code stopping events
244
+ capture: true
245
+ });
246
+ };
247
+ }
248
+ function makeHoneyPotFix() {
249
+ var latestPointerMove = null;
250
+ function bindEvents() {
251
+ // For sanity, only collecting this value from when events are first bound.
252
+ // This prevents the case where a super old "pointermove" could be used
253
+ // from a prior interaction.
254
+ latestPointerMove = null;
255
+ return (0, _bindEventListener.bind)(window, {
256
+ type: 'pointermove',
257
+ listener: function listener(event) {
258
+ latestPointerMove = {
259
+ x: event.clientX,
260
+ y: event.clientY
261
+ };
262
+ },
263
+ // listening for pointer move in capture phase
264
+ // so we are less likely to be impacted by events being stopped.
265
+ options: {
266
+ capture: true
267
+ }
268
+ });
269
+ }
270
+ function getOnPostDispatch() {
271
+ var finish = null;
272
+ return function onPostEvent(_ref6) {
273
+ var eventName = _ref6.eventName,
274
+ payload = _ref6.payload;
275
+ // We are adding the honey pot `onDragStart` so we don't
276
+ // impact the creation of the native drag preview.
277
+ if (eventName === 'onDragStart') {
278
+ var _latestPointerMove;
279
+ var input = payload.location.initial.input;
280
+
281
+ // Sometimes there will be no latest "pointermove" (eg iOS).
282
+ // In which case, we use the start position of the drag.
283
+ var initial = (_latestPointerMove = latestPointerMove) !== null && _latestPointerMove !== void 0 ? _latestPointerMove : {
284
+ x: input.clientX,
285
+ y: input.clientY
286
+ };
287
+
288
+ // Don't need to defensively call `finish()` as `onDrop` from
289
+ // one interaction is guaranteed to be called before `onDragStart`
290
+ // of the next.
291
+ finish = mountHoneyPot({
292
+ initial: initial
293
+ });
294
+ }
295
+ if (eventName === 'onDrop') {
296
+ var _finish;
297
+ var _input = payload.location.current.input;
298
+ (_finish = finish) === null || _finish === void 0 || _finish({
299
+ current: {
300
+ x: _input.clientX,
301
+ y: _input.clientY
302
+ }
303
+ });
304
+ finish = null;
305
+ // this interaction is finished, we want to use
306
+ // the latest "pointermove" for each interaction
307
+ latestPointerMove = null;
308
+ }
309
+ };
310
+ }
311
+ return {
312
+ bindEvents: bindEvents,
313
+ getOnPostDispatch: getOnPostDispatch
314
+ };
315
+ }
@@ -7,9 +7,10 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.lifecycle = void 0;
8
8
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
9
  var _bindEventListener = require("bind-event-listener");
10
+ var _getElementFromPointWithoutHoneyPot = require("../honey-pot-fix/get-element-from-point-without-honey-pot");
11
+ var _isHoneyPotElement = require("../honey-pot-fix/is-honey-pot-element");
10
12
  var _isLeavingWindow = require("../util/changing-window/is-leaving-window");
11
13
  var _detectBrokenDrag = require("../util/detect-broken-drag");
12
- var _fixPostDragPointerBug = require("../util/fix-post-drag-pointer-bug");
13
14
  var _getInput = require("../util/get-input");
14
15
  var _dispatchConsumerEvent = require("./dispatch-consumer-event");
15
16
  var globalState = {
@@ -69,7 +70,7 @@ function start(_ref2) {
69
70
  dispatchEvent: dispatchEvent,
70
71
  initial: initial
71
72
  });
72
- function updateDropTargets(next) {
73
+ function updateState(next) {
73
74
  // only looking at whether hierarchy has changed to determine whether something as 'changed'
74
75
  var hasChanged = hasHierarchyChanged({
75
76
  current: state.current.dropTargets,
@@ -88,8 +89,15 @@ function start(_ref2) {
88
89
  }
89
90
  function onUpdateEvent(event) {
90
91
  var input = (0, _getInput.getInput)(event);
92
+
93
+ // If we are over the honey pot, we need to get the element
94
+ // that the user would have been over if not for the honey pot
95
+ var target = (0, _isHoneyPotElement.isHoneyPotElement)(event.target) ? (0, _getElementFromPointWithoutHoneyPot.getElementFromPointWithoutHoneypot)({
96
+ x: input.clientX,
97
+ y: input.clientY
98
+ }) : event.target;
91
99
  var nextDropTargets = getDropTargetsOver({
92
- target: event.target,
100
+ target: target,
93
101
  input: input,
94
102
  source: dragType.payload,
95
103
  current: state.current.dropTargets
@@ -102,7 +110,7 @@ function start(_ref2) {
102
110
  current: nextDropTargets
103
111
  });
104
112
  }
105
- updateDropTargets({
113
+ updateState({
106
114
  dropTargets: nextDropTargets,
107
115
  input: input
108
116
  });
@@ -117,7 +125,7 @@ function start(_ref2) {
117
125
  // will have already cleared the dropTargets to `[]` (as that particular "dragleave" has a `relatedTarget` of `null`)
118
126
 
119
127
  if (state.current.dropTargets.length) {
120
- updateDropTargets({
128
+ updateState({
121
129
  dropTargets: [],
122
130
  input: state.current.input
123
131
  });
@@ -210,7 +218,7 @@ function start(_ref2) {
210
218
  * - [Bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1429937)
211
219
  **/
212
220
 
213
- updateDropTargets({
221
+ updateState({
214
222
  input: state.current.input,
215
223
  dropTargets: []
216
224
  });
@@ -222,6 +230,14 @@ function start(_ref2) {
222
230
  // A "drop" can only happen if the browser allowed the drop
223
231
  type: 'drop',
224
232
  listener: function listener(event) {
233
+ // Capture the final input.
234
+ // We are capturing the final `input` for the
235
+ // most accurate honey pot experience
236
+ state.current = {
237
+ dropTargets: state.current.dropTargets,
238
+ input: (0, _getInput.getInput)(event)
239
+ };
240
+
225
241
  /** If there are no drop targets, then we will get
226
242
  * a "drop" event if:
227
243
  * - `preventUnhandled()` is being used
@@ -234,7 +250,6 @@ function start(_ref2) {
234
250
 
235
251
  if (!state.current.dropTargets.length) {
236
252
  cancel();
237
- // not applying our post drop fix as we are not managing the drop
238
253
  return;
239
254
  }
240
255
  event.preventDefault();
@@ -251,14 +266,6 @@ function start(_ref2) {
251
266
  updatedSourcePayload: dragType.type === 'external' ? dragType.getDropPayload(event) : null
252
267
  });
253
268
  finish();
254
-
255
- // Applying this fix after `dispatch.drop` so that frameworks have the opportunity
256
- // to update UI in response to a "onDrop".
257
- if (dragType.startedFrom === 'internal') {
258
- (0, _fixPostDragPointerBug.fixPostDragPointerBug)({
259
- current: state.current
260
- });
261
- }
262
269
  }
263
270
  }, {
264
271
  // "dragend" fires when on the drag source (eg a draggable element)
@@ -269,17 +276,18 @@ function start(_ref2) {
269
276
 
270
277
  // This "dragend" listener will not fire if there was a successful drop
271
278
  // as we will have already removed the event listener
279
+
272
280
  type: 'dragend',
273
281
  listener: function listener(event) {
282
+ // In firefox, the position of the "dragend" event can
283
+ // be a bit different to the last "dragover" event.
284
+ // Updating the input so we can get the best possible
285
+ // information for the honey pot.
286
+ state.current = {
287
+ dropTargets: state.current.dropTargets,
288
+ input: (0, _getInput.getInput)(event)
289
+ };
274
290
  cancel();
275
-
276
- // Applying this fix after `dispatch.drop` so that frameworks have the opportunity
277
- // to update UI in response to a "onDrop".
278
- if (dragType.startedFrom === 'internal') {
279
- (0, _fixPostDragPointerBug.fixPostDragPointerBug)({
280
- current: state.current
281
- });
282
- }
283
291
  }
284
292
  }].concat((0, _toConsumableArray2.default)((0, _detectBrokenDrag.getBindingsForBrokenDrags)({
285
293
  onDragEnd: cancel
@@ -12,6 +12,7 @@ function makeAdapter(_ref) {
12
12
  var typeKey = _ref.typeKey,
13
13
  mount = _ref.mount,
14
14
  dispatchEventToSource = _ref.dispatchEventToSource,
15
+ onPostDispatch = _ref.onPostDispatch,
15
16
  defaultDropEffect = _ref.defaultDropEffect;
16
17
  var monitorAPI = (0, _makeMonitor.makeMonitor)();
17
18
  var dropTargetAPI = (0, _makeDropTarget.makeDropTarget)({
@@ -27,6 +28,9 @@ function makeAdapter(_ref) {
27
28
 
28
29
  // 3. forward event to monitors
29
30
  monitorAPI.dispatchEvent(args);
31
+
32
+ // 4. post consumer dispatch (used for honey pot fix)
33
+ onPostDispatch === null || onPostDispatch === void 0 || onPostDispatch(args);
30
34
  }
31
35
  function start(_ref2) {
32
36
  var event = _ref2.event,
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.setCustomNativeDragPreview = setCustomNativeDragPreview;
7
7
  var _elementAdapter = require("../../../adapter/element-adapter");
8
8
  var _isSafari = require("../../../util/is-safari");
9
+ var _maxZIndex = require("../../../util/max-z-index");
9
10
  /** A function to remove the element that has been added to the `container`.
10
11
  * @example () => ReactDOM.unmountComponentAtNode(container)
11
12
  */
@@ -64,7 +65,7 @@ function setCustomNativeDragPreview(_ref) {
64
65
  // and then it is destroyed
65
66
  // 2. Did not want to add a dependency onto `@atlaskit/theme`
66
67
  // 3. Want to always be on top of product UI which might have higher z-index's
67
- zIndex: 2147483647,
68
+ zIndex: _maxZIndex.maxZIndex,
68
69
  // Avoiding any additional events caused by the new element (being super safe)
69
70
  pointerEvents: 'none'
70
71
  });
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.maxZIndex = void 0;
7
+ // Maximum possible z-index
8
+ // https://stackoverflow.com/questions/491052/minimum-and-maximum-value-of-z-index
9
+ var maxZIndex = exports.maxZIndex = 2147483647;