@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.
- package/CHANGELOG.md +25 -0
- package/dist/cjs/adapter/element-adapter.js +14 -4
- package/dist/cjs/adapter/text-selection-adapter.js +7 -3
- package/dist/cjs/entry-point/private/get-element-from-point-without-honey-pot.js +12 -0
- package/dist/cjs/honey-pot-fix/get-element-from-point-without-honey-pot.js +23 -0
- package/dist/cjs/honey-pot-fix/honey-pot-data-attribute.js +9 -0
- package/dist/cjs/honey-pot-fix/is-honey-pot-element.js +10 -0
- package/dist/cjs/honey-pot-fix/make-honey-pot-fix.js +315 -0
- package/dist/cjs/ledger/lifecycle-manager.js +31 -23
- package/dist/cjs/make-adapter/make-adapter.js +4 -0
- package/dist/cjs/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +2 -1
- package/dist/cjs/util/max-z-index.js +9 -0
- package/dist/es2019/adapter/element-adapter.js +14 -4
- package/dist/es2019/adapter/text-selection-adapter.js +8 -4
- package/dist/es2019/entry-point/private/get-element-from-point-without-honey-pot.js +1 -0
- package/dist/es2019/honey-pot-fix/get-element-from-point-without-honey-pot.js +12 -0
- package/dist/es2019/honey-pot-fix/honey-pot-data-attribute.js +3 -0
- package/dist/es2019/honey-pot-fix/is-honey-pot-element.js +4 -0
- package/dist/es2019/honey-pot-fix/make-honey-pot-fix.js +315 -0
- package/dist/es2019/ledger/lifecycle-manager.js +31 -23
- package/dist/es2019/make-adapter/make-adapter.js +4 -0
- package/dist/es2019/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +2 -1
- package/dist/es2019/util/max-z-index.js +3 -0
- package/dist/esm/adapter/element-adapter.js +14 -4
- package/dist/esm/adapter/text-selection-adapter.js +8 -4
- package/dist/esm/entry-point/private/get-element-from-point-without-honey-pot.js +1 -0
- package/dist/esm/honey-pot-fix/get-element-from-point-without-honey-pot.js +16 -0
- package/dist/esm/honey-pot-fix/honey-pot-data-attribute.js +3 -0
- package/dist/esm/honey-pot-fix/is-honey-pot-element.js +4 -0
- package/dist/esm/honey-pot-fix/make-honey-pot-fix.js +308 -0
- package/dist/esm/ledger/lifecycle-manager.js +31 -23
- package/dist/esm/make-adapter/make-adapter.js +4 -0
- package/dist/esm/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js +2 -1
- package/dist/esm/util/max-z-index.js +3 -0
- package/dist/types/entry-point/private/get-element-from-point-without-honey-pot.d.ts +1 -0
- package/dist/types/honey-pot-fix/get-element-from-point-without-honey-pot.d.ts +2 -0
- package/dist/types/honey-pot-fix/honey-pot-data-attribute.d.ts +1 -0
- package/dist/types/honey-pot-fix/is-honey-pot-element.d.ts +1 -0
- package/dist/types/honey-pot-fix/make-honey-pot-fix.d.ts +8 -0
- package/dist/types/make-adapter/make-adapter.d.ts +5 -1
- package/dist/types/util/max-z-index.d.ts +1 -0
- package/dist/types-ts4.5/entry-point/private/get-element-from-point-without-honey-pot.d.ts +1 -0
- package/dist/types-ts4.5/honey-pot-fix/get-element-from-point-without-honey-pot.d.ts +2 -0
- package/dist/types-ts4.5/honey-pot-fix/honey-pot-data-attribute.d.ts +1 -0
- package/dist/types-ts4.5/honey-pot-fix/is-honey-pot-element.d.ts +1 -0
- package/dist/types-ts4.5/honey-pot-fix/make-honey-pot-fix.d.ts +8 -0
- package/dist/types-ts4.5/make-adapter/make-adapter.d.ts +5 -1
- package/dist/types-ts4.5/util/max-z-index.d.ts +1 -0
- package/package.json +105 -104
- package/private/get-element-from-point-without-honey-pot/package.json +15 -0
- package/dist/cjs/util/fix-post-drag-pointer-bug.js +0 -125
- package/dist/es2019/util/fix-post-drag-pointer-bug.js +0 -121
- package/dist/esm/util/fix-post-drag-pointer-bug.js +0 -119
- package/dist/types/util/fix-post-drag-pointer-bug.d.ts +0 -14
- 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
|
-
|
|
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.
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
package/dist/cjs/public-utils/element/custom-native-drag-preview/set-custom-native-drag-preview.js
CHANGED
|
@@ -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:
|
|
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;
|