@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.
- package/CHANGELOG.md +209 -0
- package/LICENSE.md +13 -0
- package/README.md +43 -0
- package/__perf__/add-example.todo +1 -0
- package/adapter/element/package.json +15 -0
- package/adapter/file/package.json +15 -0
- package/addon/cancel-unhandled/package.json +15 -0
- package/constellation/index/about.mdx +329 -0
- package/constellation/index/props.mdx +3 -0
- package/dist/cjs/adapter/element-adapter.js +151 -0
- package/dist/cjs/adapter/file-adapter.js +98 -0
- package/dist/cjs/addon/cancel-unhandled.js +50 -0
- package/dist/cjs/entry-point/adapter/element.js +24 -0
- package/dist/cjs/entry-point/adapter/file.js +18 -0
- package/dist/cjs/entry-point/addon/cancel-unhandled.js +12 -0
- package/dist/cjs/entry-point/experimental/cross-with-element-adapter.js +30 -0
- package/dist/cjs/entry-point/types.js +5 -0
- package/dist/cjs/entry-point/util/combine.js +12 -0
- package/dist/cjs/entry-point/util/disable-native-drag-preview.js +12 -0
- package/dist/cjs/entry-point/util/once.js +12 -0
- package/dist/cjs/entry-point/util/reorder.js +12 -0
- package/dist/cjs/entry-point/util/scroll-just-enough-into-view.js +12 -0
- package/dist/cjs/entry-point/util/set-custom-native-drag-preview.js +12 -0
- package/dist/cjs/experimental/cross-window-element-adapter.js +131 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/internal-types.js +5 -0
- package/dist/cjs/ledger/dispatch-consumer-event.js +132 -0
- package/dist/cjs/ledger/lifecycle-manager.js +335 -0
- package/dist/cjs/ledger/usage-ledger.js +37 -0
- package/dist/cjs/make-adapter/make-adapter.js +59 -0
- package/dist/cjs/make-adapter/make-drop-target.js +271 -0
- package/dist/cjs/make-adapter/make-monitor.js +100 -0
- package/dist/cjs/util/add-attribute.js +14 -0
- package/dist/cjs/util/combine.js +17 -0
- package/dist/cjs/util/disable-native-drag-preview.js +36 -0
- package/dist/cjs/util/entering-and-leaving-the-window.js +162 -0
- package/dist/cjs/util/fix-post-drag-pointer-bug.js +114 -0
- package/dist/cjs/util/get-input.js +20 -0
- package/dist/cjs/util/once.js +22 -0
- package/dist/cjs/util/reorder.js +26 -0
- package/dist/cjs/util/scroll-just-enough-into-view.js +17 -0
- package/dist/cjs/util/set-custom-native-drag-preview.js +109 -0
- package/dist/cjs/version.json +5 -0
- package/dist/es2019/adapter/element-adapter.js +143 -0
- package/dist/es2019/adapter/file-adapter.js +90 -0
- package/dist/es2019/addon/cancel-unhandled.js +43 -0
- package/dist/es2019/entry-point/adapter/element.js +1 -0
- package/dist/es2019/entry-point/adapter/file.js +1 -0
- package/dist/es2019/entry-point/addon/cancel-unhandled.js +1 -0
- package/dist/es2019/entry-point/experimental/cross-with-element-adapter.js +1 -0
- package/dist/es2019/entry-point/types.js +1 -0
- package/dist/es2019/entry-point/util/combine.js +1 -0
- package/dist/es2019/entry-point/util/disable-native-drag-preview.js +1 -0
- package/dist/es2019/entry-point/util/once.js +1 -0
- package/dist/es2019/entry-point/util/reorder.js +1 -0
- package/dist/es2019/entry-point/util/scroll-just-enough-into-view.js +1 -0
- package/dist/es2019/entry-point/util/set-custom-native-drag-preview.js +1 -0
- package/dist/es2019/experimental/cross-window-element-adapter.js +121 -0
- package/dist/es2019/index.js +7 -0
- package/dist/es2019/internal-types.js +1 -0
- package/dist/es2019/ledger/dispatch-consumer-event.js +128 -0
- package/dist/es2019/ledger/lifecycle-manager.js +333 -0
- package/dist/es2019/ledger/usage-ledger.js +32 -0
- package/dist/es2019/make-adapter/make-adapter.js +55 -0
- package/dist/es2019/make-adapter/make-drop-target.js +233 -0
- package/dist/es2019/make-adapter/make-monitor.js +80 -0
- package/dist/es2019/util/add-attribute.js +7 -0
- package/dist/es2019/util/combine.js +6 -0
- package/dist/es2019/util/disable-native-drag-preview.js +31 -0
- package/dist/es2019/util/entering-and-leaving-the-window.js +159 -0
- package/dist/es2019/util/fix-post-drag-pointer-bug.js +110 -0
- package/dist/es2019/util/get-input.js +14 -0
- package/dist/es2019/util/once.js +13 -0
- package/dist/es2019/util/reorder.js +17 -0
- package/dist/es2019/util/scroll-just-enough-into-view.js +12 -0
- package/dist/es2019/util/set-custom-native-drag-preview.js +106 -0
- package/dist/es2019/version.json +5 -0
- package/dist/esm/adapter/element-adapter.js +142 -0
- package/dist/esm/adapter/file-adapter.js +90 -0
- package/dist/esm/addon/cancel-unhandled.js +43 -0
- package/dist/esm/entry-point/adapter/element.js +1 -0
- package/dist/esm/entry-point/adapter/file.js +1 -0
- package/dist/esm/entry-point/addon/cancel-unhandled.js +1 -0
- package/dist/esm/entry-point/experimental/cross-with-element-adapter.js +1 -0
- package/dist/esm/entry-point/types.js +1 -0
- package/dist/esm/entry-point/util/combine.js +1 -0
- package/dist/esm/entry-point/util/disable-native-drag-preview.js +1 -0
- package/dist/esm/entry-point/util/once.js +1 -0
- package/dist/esm/entry-point/util/reorder.js +1 -0
- package/dist/esm/entry-point/util/scroll-just-enough-into-view.js +1 -0
- package/dist/esm/entry-point/util/set-custom-native-drag-preview.js +1 -0
- package/dist/esm/experimental/cross-window-element-adapter.js +120 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/internal-types.js +1 -0
- package/dist/esm/ledger/dispatch-consumer-event.js +125 -0
- package/dist/esm/ledger/lifecycle-manager.js +328 -0
- package/dist/esm/ledger/usage-ledger.js +31 -0
- package/dist/esm/make-adapter/make-adapter.js +53 -0
- package/dist/esm/make-adapter/make-drop-target.js +264 -0
- package/dist/esm/make-adapter/make-monitor.js +93 -0
- package/dist/esm/util/add-attribute.js +8 -0
- package/dist/esm/util/combine.js +11 -0
- package/dist/esm/util/disable-native-drag-preview.js +30 -0
- package/dist/esm/util/entering-and-leaving-the-window.js +156 -0
- package/dist/esm/util/fix-post-drag-pointer-bug.js +108 -0
- package/dist/esm/util/get-input.js +14 -0
- package/dist/esm/util/once.js +16 -0
- package/dist/esm/util/reorder.js +19 -0
- package/dist/esm/util/scroll-just-enough-into-view.js +11 -0
- package/dist/esm/util/set-custom-native-drag-preview.js +104 -0
- package/dist/esm/version.json +5 -0
- package/dist/types/adapter/element-adapter.d.ts +42 -0
- package/dist/types/adapter/file-adapter.d.ts +18 -0
- package/dist/types/addon/cancel-unhandled.d.ts +7 -0
- package/dist/types/entry-point/adapter/element.d.ts +2 -0
- package/dist/types/entry-point/adapter/file.d.ts +2 -0
- package/dist/types/entry-point/addon/cancel-unhandled.d.ts +1 -0
- package/dist/types/entry-point/experimental/cross-with-element-adapter.d.ts +1 -0
- package/dist/types/entry-point/types.d.ts +1 -0
- package/dist/types/entry-point/util/combine.d.ts +1 -0
- package/dist/types/entry-point/util/disable-native-drag-preview.d.ts +1 -0
- package/dist/types/entry-point/util/once.d.ts +1 -0
- package/dist/types/entry-point/util/reorder.d.ts +1 -0
- package/dist/types/entry-point/util/scroll-just-enough-into-view.d.ts +1 -0
- package/dist/types/entry-point/util/set-custom-native-drag-preview.d.ts +1 -0
- package/dist/types/experimental/cross-window-element-adapter.d.ts +17 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/internal-types.d.ts +275 -0
- package/dist/types/ledger/dispatch-consumer-event.d.ts +26 -0
- package/dist/types/ledger/lifecycle-manager.d.ts +16 -0
- package/dist/types/ledger/usage-ledger.d.ts +5 -0
- package/dist/types/make-adapter/make-adapter.d.ts +14 -0
- package/dist/types/make-adapter/make-drop-target.d.ts +5 -0
- package/dist/types/make-adapter/make-monitor.d.ts +8 -0
- package/dist/types/util/add-attribute.d.ts +5 -0
- package/dist/types/util/combine.d.ts +3 -0
- package/dist/types/util/disable-native-drag-preview.d.ts +3 -0
- package/dist/types/util/entering-and-leaving-the-window.d.ts +6 -0
- package/dist/types/util/fix-post-drag-pointer-bug.d.ts +14 -0
- package/dist/types/util/get-input.d.ts +2 -0
- package/dist/types/util/once.d.ts +2 -0
- package/dist/types/util/reorder.d.ts +9 -0
- package/dist/types/util/scroll-just-enough-into-view.d.ts +7 -0
- package/dist/types/util/set-custom-native-drag-preview.d.ts +52 -0
- package/experimental/cross-window-element-adapter/package.json +15 -0
- package/package.json +87 -0
- package/report.api.md +35 -0
- package/tmp/api-report-tmp.d.ts +13 -0
- package/types/package.json +15 -0
- package/util/combine/package.json +15 -0
- package/util/disable-native-drag-preview/package.json +15 -0
- package/util/once/package.json +15 -0
- package/util/reorder/package.json +15 -0
- package/util/scroll-just-enough-into-view/package.json +15 -0
- package/util/set-custom-native-drag-preview/package.json +15 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
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; } } }; }
|
|
3
|
+
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); }
|
|
4
|
+
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; }
|
|
5
|
+
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; }
|
|
6
|
+
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; }
|
|
7
|
+
export function makeMonitor() {
|
|
8
|
+
var registry = new Set();
|
|
9
|
+
var dragging = null;
|
|
10
|
+
function tryAddToActive(monitor) {
|
|
11
|
+
if (!dragging) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
// Monitor is allowed to monitor events if:
|
|
15
|
+
// 1. It has no `canMonitor` function (default is that a monitor can listen to everything)
|
|
16
|
+
// 2. `canMonitor` returns true
|
|
17
|
+
if (!monitor.canMonitor || monitor.canMonitor(dragging.canMonitorArgs)) {
|
|
18
|
+
dragging.active.add(monitor);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function monitorForConsumers(args) {
|
|
22
|
+
// We are giving each `args` a new reference so that you
|
|
23
|
+
// can create multiple monitors with the same `args`.
|
|
24
|
+
var entry = _objectSpread({}, args);
|
|
25
|
+
registry.add(entry);
|
|
26
|
+
|
|
27
|
+
// if there is an active drag we need to see if this new monitor is relevant
|
|
28
|
+
tryAddToActive(entry);
|
|
29
|
+
return function cleanup() {
|
|
30
|
+
registry.delete(entry);
|
|
31
|
+
|
|
32
|
+
// We need to stop publishing events during a drag to this monitor!
|
|
33
|
+
if (dragging) {
|
|
34
|
+
dragging.active.delete(entry);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function dispatchEvent(_ref) {
|
|
39
|
+
var eventName = _ref.eventName,
|
|
40
|
+
payload = _ref.payload;
|
|
41
|
+
if (eventName === 'onGenerateDragPreview') {
|
|
42
|
+
dragging = {
|
|
43
|
+
canMonitorArgs: {
|
|
44
|
+
initial: payload.location.initial,
|
|
45
|
+
source: payload.source
|
|
46
|
+
},
|
|
47
|
+
active: new Set()
|
|
48
|
+
};
|
|
49
|
+
var _iterator = _createForOfIteratorHelper(registry),
|
|
50
|
+
_step;
|
|
51
|
+
try {
|
|
52
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
53
|
+
var monitor = _step.value;
|
|
54
|
+
tryAddToActive(monitor);
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
_iterator.e(err);
|
|
58
|
+
} finally {
|
|
59
|
+
_iterator.f();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// This should never happen.
|
|
64
|
+
if (!dragging) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Creating an array from the set _before_ iterating
|
|
69
|
+
// This is so that monitors added during the current event will not be called.
|
|
70
|
+
// This behaviour matches native EventTargets where an event listener
|
|
71
|
+
// cannot add another event listener during an active event to the same
|
|
72
|
+
// event target in the same event (for us we have a single global event target)
|
|
73
|
+
var active = Array.from(dragging.active);
|
|
74
|
+
for (var _i = 0, _active = active; _i < _active.length; _i++) {
|
|
75
|
+
var _monitor = _active[_i];
|
|
76
|
+
// A monitor can be removed by another monitor during an event.
|
|
77
|
+
// We need to check that the monitor is still registered before calling it
|
|
78
|
+
if (dragging.active.has(_monitor)) {
|
|
79
|
+
var _monitor$eventName;
|
|
80
|
+
// @ts-expect-error: I cannot get this type working!
|
|
81
|
+
(_monitor$eventName = _monitor[eventName]) === null || _monitor$eventName === void 0 ? void 0 : _monitor$eventName.call(_monitor, payload);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (eventName === 'onDrop') {
|
|
85
|
+
dragging.active.clear();
|
|
86
|
+
dragging = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
dispatchEvent: dispatchEvent,
|
|
91
|
+
monitorForConsumers: monitorForConsumers
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Create a new combined function that will call all the provided functions */
|
|
2
|
+
export function combine() {
|
|
3
|
+
for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
4
|
+
fns[_key] = arguments[_key];
|
|
5
|
+
}
|
|
6
|
+
return function cleanup() {
|
|
7
|
+
fns.forEach(function (fn) {
|
|
8
|
+
return fn();
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// In order to disable the native drag preview you can
|
|
2
|
+
// use `event.dataTransfer.setDragImage()` to set a small
|
|
3
|
+
// invisible image as the drag preview.
|
|
4
|
+
// There are alternative techniques,
|
|
5
|
+
// (eg setting opacity to in onGenerateDragPreview and then 1 in onDragStart)
|
|
6
|
+
// but the technique in this file worked best across browsers and platforms
|
|
7
|
+
|
|
8
|
+
// Here we are preloading the image so that it is ready for the first drag.
|
|
9
|
+
// Even though the image is base64 encoded, the browser queues an async task
|
|
10
|
+
// to decode the image. The image needs to be decoded before it can be used
|
|
11
|
+
var tinyTransparentImage = function () {
|
|
12
|
+
// SSR safe
|
|
13
|
+
if (typeof window === 'undefined') {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Image generated by: https://png-pixel.com/
|
|
18
|
+
// It is a 1x1 transparent gif
|
|
19
|
+
// It is the smallest possible transparent image we could find that works on all platforms
|
|
20
|
+
// Note: using an encoded SVG would be nicer code, but it doesn't work on iOS
|
|
21
|
+
var img = new Image();
|
|
22
|
+
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
|
|
23
|
+
return img;
|
|
24
|
+
}();
|
|
25
|
+
export function disableNativeDragPreview(_ref) {
|
|
26
|
+
var nativeSetDragImage = _ref.nativeSetDragImage;
|
|
27
|
+
if (nativeSetDragImage && tinyTransparentImage) {
|
|
28
|
+
nativeSetDragImage(tinyTransparentImage, 0, 0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { bindAll } from 'bind-event-listener';
|
|
2
|
+
|
|
3
|
+
// *Usually* to detect if you are entering / leaving a window you can
|
|
4
|
+
// use the `event.relatedTarget` property:
|
|
5
|
+
|
|
6
|
+
// "dragenter":
|
|
7
|
+
// - `event.relatedTarget` should point to the element that you are coming from
|
|
8
|
+
// - Scenario: A -> B
|
|
9
|
+
// - `event.target`: `B` (entering B)
|
|
10
|
+
// - `event.relatedTarget`: `A`: (leaving A - where you are coming from)
|
|
11
|
+
// - if `event.relatedTarget` is `null` then you are entering the window (coming from `null`)
|
|
12
|
+
//
|
|
13
|
+
// "dragleave"
|
|
14
|
+
// - `event.relatedTarget` should point to the element you are going to
|
|
15
|
+
// - Scenario: A -> B (entered B, leaving A)
|
|
16
|
+
// - `event.target`: `A` (leaving A)
|
|
17
|
+
// - `event.relatedTarget`: `B`: (entering into B - where you are going to)
|
|
18
|
+
// - if `event.relatedTarget` is `null` then you are leaving the window (going to `null`)
|
|
19
|
+
//
|
|
20
|
+
// Unfortunately in Safari `event.relatedTarget` is *always* set to `null`
|
|
21
|
+
// Safari bug: https://bugs.webkit.org/show_bug.cgi?id=242627
|
|
22
|
+
// To work around this we count "dragenter" and "dragleave" events
|
|
23
|
+
var safariFix = {
|
|
24
|
+
isSafari: false,
|
|
25
|
+
// Using symbols for event properties so we don't clash with
|
|
26
|
+
// anything on the `event` object
|
|
27
|
+
leavingWindow: Symbol('leaving'),
|
|
28
|
+
enteringWindow: Symbol('entering')
|
|
29
|
+
};
|
|
30
|
+
export function isEnteringWindow(_ref) {
|
|
31
|
+
var dragEnter = _ref.dragEnter;
|
|
32
|
+
if (dragEnter.type !== 'dragenter') {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (safariFix.isSafari) {
|
|
36
|
+
return dragEnter.hasOwnProperty(safariFix.enteringWindow);
|
|
37
|
+
}
|
|
38
|
+
// This is the standard check.
|
|
39
|
+
// if `relatedTarget` is `null` during a "dragenter"
|
|
40
|
+
// then we are entering the`window`
|
|
41
|
+
return dragEnter.relatedTarget == null;
|
|
42
|
+
}
|
|
43
|
+
export function isLeavingWindow(_ref2) {
|
|
44
|
+
var dragLeave = _ref2.dragLeave;
|
|
45
|
+
if (dragLeave.type !== 'dragleave') {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (safariFix.isSafari) {
|
|
49
|
+
return dragLeave.hasOwnProperty(safariFix.leavingWindow);
|
|
50
|
+
}
|
|
51
|
+
// This is the standard check.
|
|
52
|
+
// if `relatedTarget` is `null` during a "dragleave"
|
|
53
|
+
// then we are leave the `window`
|
|
54
|
+
return dragLeave.relatedTarget == null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// NOTE: this fix currently has no test coverage
|
|
58
|
+
// - our drag and drop browser tests currently only run in Chrome due to tooling limitations
|
|
59
|
+
// - it didn't feel helpful to unit test as it is merely replicating a bug
|
|
60
|
+
|
|
61
|
+
(function fixSafari() {
|
|
62
|
+
// Don't do anything when server side rendering
|
|
63
|
+
if (typeof window === 'undefined') {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// rather than checking the userAgent for "jsdom" we can do this check
|
|
68
|
+
// so that the check will be removed completely in production code
|
|
69
|
+
if (process.env.NODE_ENV === 'test') {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
var _navigator = navigator,
|
|
73
|
+
userAgent = _navigator.userAgent;
|
|
74
|
+
var isSafari = userAgent.includes('AppleWebKit') && !userAgent.includes('Chrome');
|
|
75
|
+
if (!isSafari) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
safariFix.isSafari = true;
|
|
79
|
+
function getInitialState() {
|
|
80
|
+
return {
|
|
81
|
+
enterCount: 0,
|
|
82
|
+
isOverWindow: false
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
var state = getInitialState();
|
|
86
|
+
function resetState() {
|
|
87
|
+
state = getInitialState();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// These event listeners are bound _forever_ and _never_ removed
|
|
91
|
+
// We don't bother cleaning up these event listeners (for now)
|
|
92
|
+
// as this workaround is only for Safari
|
|
93
|
+
|
|
94
|
+
// This is how the event count works:
|
|
95
|
+
//
|
|
96
|
+
// lift (+1 enterCount)
|
|
97
|
+
// - dragstart(draggable) [enterCount: 0]
|
|
98
|
+
// - dragenter(draggable) [enterCount: 1]
|
|
99
|
+
// leaving draggable (+0 enterCount)
|
|
100
|
+
// - dragenter(document.body) [enterCount: 2]
|
|
101
|
+
// - dragleave(draggable) [enterCount: 1]
|
|
102
|
+
// leaving window (-1 enterCount)
|
|
103
|
+
// - dragleave(document.body) [enterCount: 0] {leaving the window}
|
|
104
|
+
|
|
105
|
+
// Things to note:
|
|
106
|
+
// - dragenter and dragleave bubble
|
|
107
|
+
// - the first dragenter when entering a window might not be on `window`
|
|
108
|
+
// - it could be on an element that is pressed up against the window
|
|
109
|
+
// - (so we cannot rely on `event.target` values)
|
|
110
|
+
|
|
111
|
+
bindAll(window, [{
|
|
112
|
+
type: 'dragstart',
|
|
113
|
+
listener: function listener() {
|
|
114
|
+
state.enterCount = 0;
|
|
115
|
+
// drag start occurs in the source window
|
|
116
|
+
state.isOverWindow = true;
|
|
117
|
+
|
|
118
|
+
// When a drag first starts it will also trigger a "dragenter" on the draggable element
|
|
119
|
+
}
|
|
120
|
+
}, {
|
|
121
|
+
type: 'drop',
|
|
122
|
+
listener: resetState
|
|
123
|
+
}, {
|
|
124
|
+
type: 'dragend',
|
|
125
|
+
listener: resetState
|
|
126
|
+
}, {
|
|
127
|
+
type: 'dragenter',
|
|
128
|
+
listener: function listener(event) {
|
|
129
|
+
if (!state.isOverWindow && state.enterCount === 0) {
|
|
130
|
+
// Patching the `event` object
|
|
131
|
+
// The `event` object is shared with all event listeners for the event
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
event[safariFix.enteringWindow] = true;
|
|
134
|
+
}
|
|
135
|
+
state.isOverWindow = true;
|
|
136
|
+
state.enterCount++;
|
|
137
|
+
}
|
|
138
|
+
}, {
|
|
139
|
+
type: 'dragleave',
|
|
140
|
+
listener: function listener(event) {
|
|
141
|
+
state.enterCount--;
|
|
142
|
+
if (state.isOverWindow && state.enterCount === 0) {
|
|
143
|
+
// Patching the `event` object as it is shared with all event listeners
|
|
144
|
+
// The `event` object is shared with all event listeners for the event
|
|
145
|
+
// @ts-ignore
|
|
146
|
+
event[safariFix.leavingWindow] = true;
|
|
147
|
+
state.isOverWindow = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}],
|
|
151
|
+
// using `capture: true` so that adding event listeners
|
|
152
|
+
// in bubble phase will have the correct symbols
|
|
153
|
+
{
|
|
154
|
+
capture: true
|
|
155
|
+
});
|
|
156
|
+
})();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { bindAll } from 'bind-event-listener';
|
|
2
|
+
/** Set a `style` property on a `HTMLElement`
|
|
3
|
+
*
|
|
4
|
+
* @returns a `cleanup` function to restore the `style` property to it's original state
|
|
5
|
+
*/
|
|
6
|
+
function setStyle(el, _ref) {
|
|
7
|
+
var property = _ref.property,
|
|
8
|
+
rule = _ref.rule,
|
|
9
|
+
_ref$priority = _ref.priority,
|
|
10
|
+
priority = _ref$priority === void 0 ? '' : _ref$priority;
|
|
11
|
+
var originalValue = el.style.getPropertyValue(property);
|
|
12
|
+
var originalPriority = el.style.getPropertyPriority(property);
|
|
13
|
+
el.style.setProperty(property, rule, priority);
|
|
14
|
+
return function cleanup() {
|
|
15
|
+
el.style.setProperty(property, originalValue, originalPriority);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Allow the user to continue to interact with the element their pointer is over at the end of the drag.
|
|
21
|
+
* This is important to allow the user to be able to click, drag (etc) after they have finished a drag
|
|
22
|
+
*
|
|
23
|
+
* @returns a `cleanup` function to restore all elements under the users pointer to their original state
|
|
24
|
+
*/
|
|
25
|
+
function allowPointerEventsOnElementUnderPointer(_ref2) {
|
|
26
|
+
var current = _ref2.current;
|
|
27
|
+
var underUsersPointer = document.elementFromPoint(current.input.clientX, current.input.clientY);
|
|
28
|
+
if (!(underUsersPointer instanceof HTMLElement)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Debug note: change from 'pointer-events: none' to 'background: green'
|
|
33
|
+
// to get a better sense of what is being achieved
|
|
34
|
+
return setStyle(underUsersPointer, {
|
|
35
|
+
property: 'pointer-events',
|
|
36
|
+
rule: 'auto',
|
|
37
|
+
priority: 'important'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function blockPointerEventsOnEverything() {
|
|
41
|
+
var _element$sheet;
|
|
42
|
+
var element = document.createElement('style');
|
|
43
|
+
// Adding a data attribute so to make it super clear to consumers
|
|
44
|
+
// (and to our tests) what this temporary style tag is for
|
|
45
|
+
element.setAttribute('pdnd-post-drag-fix', 'true');
|
|
46
|
+
document.head.appendChild(element);
|
|
47
|
+
|
|
48
|
+
// Debug note: change from 'pointer-events: none' to 'background: red'
|
|
49
|
+
// to get a better sense of what is being achieved
|
|
50
|
+
(_element$sheet = element.sheet) === null || _element$sheet === void 0 ? void 0 : _element$sheet.insertRule('* { pointer-events: none !important; }');
|
|
51
|
+
return function cleanup() {
|
|
52
|
+
document.head.removeChild(element);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 🔥🤮 Fix (Chrome, Safari and Firefox) bug where the element under where the user started dragging
|
|
57
|
+
* (on the viewport) is entered into by the browser after a drag finishes ("drop" or "dragend")
|
|
58
|
+
*
|
|
59
|
+
* @description
|
|
60
|
+
*
|
|
61
|
+
* Block pointer events on all elements except for the specific element that pointer is currently over
|
|
62
|
+
*
|
|
63
|
+
* - [Visual explanation of bug](https://twitter.com/alexandereardon/status/1633614212873465856)
|
|
64
|
+
* - [Chrome bug](https://bugs.chromium.org/p/chromium/issues/detail?id=410328)
|
|
65
|
+
*/
|
|
66
|
+
export function fixPostDragPointerBug(_ref3) {
|
|
67
|
+
var current = _ref3.current;
|
|
68
|
+
// Queuing a microtask to give any opportunity for frameworks to update their UI in a microtask
|
|
69
|
+
// Note: react@18 does standard state updates in a microtask
|
|
70
|
+
// We do this so our `atDestination` gets the _actual_ element that is under the users pointer
|
|
71
|
+
// at the end of the drag.
|
|
72
|
+
queueMicrotask(function () {
|
|
73
|
+
var undoUnderPointer = allowPointerEventsOnElementUnderPointer({
|
|
74
|
+
current: current
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// This will also block pointer-events on the children of the element under the users pointer.
|
|
78
|
+
// This is what we want. If the user drops on a container element we don't want the children
|
|
79
|
+
// of the container to be incorrectly entered into
|
|
80
|
+
var undoGlobalBlock = blockPointerEventsOnEverything();
|
|
81
|
+
function cleanup() {
|
|
82
|
+
unbindEvents();
|
|
83
|
+
undoUnderPointer === null || undoUnderPointer === void 0 ? void 0 : undoUnderPointer();
|
|
84
|
+
undoGlobalBlock();
|
|
85
|
+
}
|
|
86
|
+
var unbindEvents = bindAll(window, [{
|
|
87
|
+
type: 'pointerdown',
|
|
88
|
+
listener: cleanup
|
|
89
|
+
}, {
|
|
90
|
+
type: 'pointermove',
|
|
91
|
+
listener: cleanup
|
|
92
|
+
}, {
|
|
93
|
+
type: 'focusin',
|
|
94
|
+
listener: cleanup
|
|
95
|
+
}, {
|
|
96
|
+
type: 'focusout',
|
|
97
|
+
listener: cleanup
|
|
98
|
+
},
|
|
99
|
+
// a 'pointerdown' should happen before 'dragstart', but just being super safe
|
|
100
|
+
{
|
|
101
|
+
type: 'dragstart',
|
|
102
|
+
listener: cleanup
|
|
103
|
+
}], {
|
|
104
|
+
// Using `capture` is more likely to not be impacted by consumers stopping events
|
|
105
|
+
capture: true
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function getInput(event) {
|
|
2
|
+
return {
|
|
3
|
+
altKey: event.altKey,
|
|
4
|
+
button: event.button,
|
|
5
|
+
buttons: event.buttons,
|
|
6
|
+
ctrlKey: event.ctrlKey,
|
|
7
|
+
metaKey: event.metaKey,
|
|
8
|
+
shiftKey: event.shiftKey,
|
|
9
|
+
clientX: event.clientX,
|
|
10
|
+
clientY: event.clientY,
|
|
11
|
+
pageX: event.pageX,
|
|
12
|
+
pageY: event.pageY
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Provide a function that you only ever want to be called a single time */
|
|
2
|
+
export function once(fn) {
|
|
3
|
+
var cache = null;
|
|
4
|
+
return function wrapped() {
|
|
5
|
+
if (!cache) {
|
|
6
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
7
|
+
args[_key] = arguments[_key];
|
|
8
|
+
}
|
|
9
|
+
var result = fn.apply(this, args);
|
|
10
|
+
cache = {
|
|
11
|
+
result: result
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
return cache.result;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
/**
|
|
3
|
+
* Reorder a provided `list`
|
|
4
|
+
* Returns a new array and does not modify the original array
|
|
5
|
+
*/
|
|
6
|
+
export function reorder(_ref) {
|
|
7
|
+
var list = _ref.list,
|
|
8
|
+
startIndex = _ref.startIndex,
|
|
9
|
+
finishIndex = _ref.finishIndex;
|
|
10
|
+
if (startIndex === -1 || finishIndex === -1) {
|
|
11
|
+
return list;
|
|
12
|
+
}
|
|
13
|
+
var result = Array.from(list);
|
|
14
|
+
var _result$splice = result.splice(startIndex, 1),
|
|
15
|
+
_result$splice2 = _slicedToArray(_result$splice, 1),
|
|
16
|
+
removed = _result$splice2[0];
|
|
17
|
+
result.splice(finishIndex, 0, removed);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll an `element` just enough into view so that the element becomes totally visible.
|
|
3
|
+
* If the element is already totally visible then no scrolling will occur.
|
|
4
|
+
*/
|
|
5
|
+
export function scrollJustEnoughIntoView(_ref) {
|
|
6
|
+
var element = _ref.element;
|
|
7
|
+
element.scrollIntoView({
|
|
8
|
+
block: 'nearest',
|
|
9
|
+
inline: 'nearest'
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { monitorForElements } from '../adapter/element-adapter';
|
|
2
|
+
|
|
3
|
+
/** A function to remove the element that has been added to the `container`.
|
|
4
|
+
* @example () => ReactDOM.unmountComponentAtNode(container)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** A function that will render a preview element into a `container` `HTMLElement` */
|
|
8
|
+
|
|
9
|
+
/** Any valid CSS string value
|
|
10
|
+
* @example `calc(var(--grid) * 2)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Where to place the custom drag preview
|
|
15
|
+
*
|
|
16
|
+
* `type: 'center'`: Place the center of the drag preview user the users pointer
|
|
17
|
+
*
|
|
18
|
+
* `type: 'offset-from-pointer'`: Shift the drag preview away from the users pointer
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
function setImage(_ref) {
|
|
22
|
+
var container = _ref.container,
|
|
23
|
+
placement = _ref.placement,
|
|
24
|
+
nativeSetDragImage = _ref.nativeSetDragImage;
|
|
25
|
+
if ((placement === null || placement === void 0 ? void 0 : placement.type) === 'center') {
|
|
26
|
+
var box = container.getBoundingClientRect();
|
|
27
|
+
nativeSetDragImage === null || nativeSetDragImage === void 0 ? void 0 : nativeSetDragImage(container, box.width / 2, box.height / 2);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if ((placement === null || placement === void 0 ? void 0 : placement.type) === 'offset-from-pointer') {
|
|
31
|
+
// Using a transparent border to push the drag preview away
|
|
32
|
+
// from the user's pointer.
|
|
33
|
+
// In Chrome and Safari we could use `padding`:
|
|
34
|
+
// padding: 'var(--grid)',
|
|
35
|
+
// But it does not work in Firefox which trims the padding (or inner margin)
|
|
36
|
+
Object.assign(container.style, {
|
|
37
|
+
borderLeft: "".concat(placement.x, " solid transparent"),
|
|
38
|
+
borderTop: "".concat(placement.y, " solid transparent")
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
nativeSetDragImage === null || nativeSetDragImage === void 0 ? void 0 : nativeSetDragImage(container, 0, 0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** This function provides the ability to mount an element for it to be used as the native drag preview
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* draggable({
|
|
48
|
+
* onGenerateDragPreview: ({ nativeSetDragImage }) => {
|
|
49
|
+
* setCustomNativeDragPreview({
|
|
50
|
+
* render: ({ container }) => {
|
|
51
|
+
* ReactDOM.render(<Preview item={item} />, container);
|
|
52
|
+
* return () => ReactDOM.unmountComponentAtNode(container);
|
|
53
|
+
* },
|
|
54
|
+
* nativeSetDragImage,
|
|
55
|
+
* });
|
|
56
|
+
* },
|
|
57
|
+
* });
|
|
58
|
+
*/
|
|
59
|
+
export function setCustomNativeDragPreview(_ref2) {
|
|
60
|
+
var render = _ref2.render,
|
|
61
|
+
nativeSetDragImage = _ref2.nativeSetDragImage,
|
|
62
|
+
placement = _ref2.placement;
|
|
63
|
+
var container = document.createElement('div');
|
|
64
|
+
Object.assign(container.style, {
|
|
65
|
+
// Ensuring we don't cause reflow when adding the element to the page
|
|
66
|
+
// Using `position:fixed` rather than `position:absolute` so we are
|
|
67
|
+
// positioned on the current viewport.
|
|
68
|
+
// `position:fixed` also creates a new stacking context, so we don't need to do that here
|
|
69
|
+
position: 'fixed',
|
|
70
|
+
top: 0,
|
|
71
|
+
left: 0,
|
|
72
|
+
// Using maximum possible z-index so that this element will always be on top
|
|
73
|
+
// https://stackoverflow.com/questions/491052/minimum-and-maximum-value-of-z-index
|
|
74
|
+
// Did not use `layers` in `@atlaskit/theme` because:
|
|
75
|
+
// 1. This element is not a 'layer' in the conventional sense, as this element
|
|
76
|
+
// is only created for a single frame for the browser to take a photo of it,
|
|
77
|
+
// and then it is destroyed
|
|
78
|
+
// 2. Did not want to add a dependency onto `@atlaskit/theme`
|
|
79
|
+
// 3. Want to always be on top of product UI which might have higher z-index's
|
|
80
|
+
zIndex: 2147483647,
|
|
81
|
+
// Avoiding any additional events caused by the new element (being super safe)
|
|
82
|
+
pointerEvents: 'none'
|
|
83
|
+
});
|
|
84
|
+
document.body.append(container);
|
|
85
|
+
var unmount = render({
|
|
86
|
+
container: container
|
|
87
|
+
});
|
|
88
|
+
setImage({
|
|
89
|
+
container: container,
|
|
90
|
+
placement: placement,
|
|
91
|
+
nativeSetDragImage: nativeSetDragImage
|
|
92
|
+
});
|
|
93
|
+
function cleanup() {
|
|
94
|
+
unbindMonitor();
|
|
95
|
+
unmount === null || unmount === void 0 ? void 0 : unmount();
|
|
96
|
+
document.body.removeChild(container);
|
|
97
|
+
}
|
|
98
|
+
var unbindMonitor = monitorForElements({
|
|
99
|
+
// Remove portal in the dragstart event so that the user will never see it
|
|
100
|
+
onDragStart: cleanup,
|
|
101
|
+
// Backup: remove portal when the drop finishes (this would be an error case)
|
|
102
|
+
onDrop: cleanup
|
|
103
|
+
});
|
|
104
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AllEvents, BaseEventPayload, CleanupFn, DropTargetEventPayloadMap, EventPayloadMap, Input, InternalDragType, MonitorCanMonitorArgs } from '../internal-types';
|
|
2
|
+
declare type ElementDragType = InternalDragType<'element', 'move', {
|
|
3
|
+
element: HTMLElement;
|
|
4
|
+
dragHandle: Element | null;
|
|
5
|
+
data: Record<string, unknown>;
|
|
6
|
+
}>;
|
|
7
|
+
declare type GetFeedbackArgs = {
|
|
8
|
+
/**
|
|
9
|
+
* The user input as a drag is trying to start (the `initial` input)
|
|
10
|
+
*/
|
|
11
|
+
input: Input;
|
|
12
|
+
/**
|
|
13
|
+
* The `draggable` element
|
|
14
|
+
*/
|
|
15
|
+
element: HTMLElement;
|
|
16
|
+
/**
|
|
17
|
+
* The `dragHandle` element for the `draggable`
|
|
18
|
+
*/
|
|
19
|
+
dragHandle: Element | null;
|
|
20
|
+
};
|
|
21
|
+
declare type DraggableArgs = {
|
|
22
|
+
/** The `HTMLElement` that you want to attach draggable behaviour to.
|
|
23
|
+
* `element` is our unique _key_ for a draggable.
|
|
24
|
+
* `element` is a `HTMLElement` as only a `HTMLElement`
|
|
25
|
+
* can have a "draggable" attribute
|
|
26
|
+
*/
|
|
27
|
+
element: HTMLElement;
|
|
28
|
+
/** The part of a draggable `element` that you want to use to control the dragging of the whole `element` */
|
|
29
|
+
dragHandle?: Element;
|
|
30
|
+
/** Conditionally allow a drag to occur */
|
|
31
|
+
canDrag?: (args: GetFeedbackArgs) => boolean;
|
|
32
|
+
/** Used to attach data to a drag operation. Called once just before the drag starts */
|
|
33
|
+
getInitialData?: (args: GetFeedbackArgs) => Record<string, unknown>;
|
|
34
|
+
} & Partial<AllEvents<ElementDragType>>;
|
|
35
|
+
export declare const dropTargetForElements: (args: import("../internal-types").DropTargetArgs<ElementDragType>) => CleanupFn;
|
|
36
|
+
export declare const monitorForElements: (args: import("../internal-types").MonitorArgs<ElementDragType>) => CleanupFn;
|
|
37
|
+
export declare function draggable(args: DraggableArgs): CleanupFn;
|
|
38
|
+
export declare type ElementEventBasePayload = BaseEventPayload<ElementDragType>;
|
|
39
|
+
export declare type ElementEventPayloadMap = EventPayloadMap<ElementDragType>;
|
|
40
|
+
export declare type ElementDropTargetEventPayloadMap = DropTargetEventPayloadMap<ElementDragType>;
|
|
41
|
+
export declare type ElementMonitorCanMonitorArgs = MonitorCanMonitorArgs<ElementDragType>;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseEventPayload, CleanupFn, DropTargetEventPayloadMap, EventPayloadMap, ExternalDragType, MonitorCanMonitorArgs } from '../internal-types';
|
|
2
|
+
declare type FileDragType = ExternalDragType<'file', 'copy', {
|
|
3
|
+
items: DataTransfer['items'] | null;
|
|
4
|
+
}>;
|
|
5
|
+
declare const adapter: {
|
|
6
|
+
registerUsage: () => CleanupFn;
|
|
7
|
+
dropTarget: (args: import("../internal-types").DropTargetArgs<FileDragType>) => CleanupFn;
|
|
8
|
+
monitor: (args: import("../internal-types").MonitorArgs<FileDragType>) => CleanupFn;
|
|
9
|
+
};
|
|
10
|
+
declare type StripEventsForDropTargets<T> = Omit<T, 'onDragStart' | 'onGenerateDragPreview'>;
|
|
11
|
+
declare type StripPreviewEvent<T> = Omit<T, 'onGenerateDragPreview'>;
|
|
12
|
+
export declare const dropTargetForFiles: (args: StripEventsForDropTargets<Parameters<typeof adapter.dropTarget>[0]>) => CleanupFn;
|
|
13
|
+
export declare const monitorForFiles: (args: StripPreviewEvent<Parameters<typeof adapter.monitor>[0]>) => CleanupFn;
|
|
14
|
+
export declare type FileDropTargetEventPayloadMap = StripEventsForDropTargets<DropTargetEventPayloadMap<FileDragType>>;
|
|
15
|
+
export declare type FileEventPayloadMap = StripPreviewEvent<EventPayloadMap<FileDragType>>;
|
|
16
|
+
export declare type FileEventBasePayload = BaseEventPayload<FileDragType>;
|
|
17
|
+
export declare type FileMonitorCanMonitorArgs = MonitorCanMonitorArgs<FileDragType>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { cancelUnhandled } from '../../addon/cancel-unhandled';
|