@atlaskit/modal-dialog 12.15.7 → 12.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 +19 -0
- package/dist/cjs/internal/components/modal-dialog.js +15 -0
- package/dist/cjs/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element.js +84 -0
- package/dist/cjs/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external.js +31 -0
- package/dist/cjs/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/make-fix-for-adapter.js +123 -0
- package/dist/cjs/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection.js +104 -0
- package/dist/cjs/modal-wrapper.js +1 -1
- package/dist/es2019/internal/components/modal-dialog.js +17 -1
- package/dist/es2019/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element.js +80 -0
- package/dist/es2019/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external.js +27 -0
- package/dist/es2019/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/make-fix-for-adapter.js +116 -0
- package/dist/es2019/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection.js +100 -0
- package/dist/es2019/modal-wrapper.js +1 -1
- package/dist/esm/internal/components/modal-dialog.js +17 -1
- package/dist/esm/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element.js +78 -0
- package/dist/esm/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external.js +25 -0
- package/dist/esm/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/make-fix-for-adapter.js +116 -0
- package/dist/esm/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection.js +98 -0
- package/dist/esm/modal-wrapper.js +1 -1
- package/dist/types/internal/components/modal-dialog.d.ts +4 -0
- package/dist/types/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element.d.ts +2 -0
- package/dist/types/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external.d.ts +2 -0
- package/dist/types/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/make-fix-for-adapter.d.ts +11 -0
- package/dist/types/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection.d.ts +2 -0
- package/dist/types-ts4.5/internal/components/modal-dialog.d.ts +4 -0
- package/dist/types-ts4.5/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element.d.ts +2 -0
- package/dist/types-ts4.5/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external.d.ts +2 -0
- package/dist/types-ts4.5/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/make-fix-for-adapter.d.ts +11 -0
- package/dist/types-ts4.5/internal/pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection.d.ts +2 -0
- package/package.json +9 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @atlaskit/modal-dialog
|
|
2
2
|
|
|
3
|
+
## 12.17.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#144047](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/144047)
|
|
8
|
+
[`de70c65e3e5ff`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/de70c65e3e5ff) -
|
|
9
|
+
The Chrome bug workaround shipped in `12.16.0` behind a feature flag is now turned on for everyone
|
|
10
|
+
and is no longer behind a feature flag.
|
|
11
|
+
|
|
12
|
+
## 12.16.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- [#141279](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/141279)
|
|
17
|
+
[`a38f3af4bfc79`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/a38f3af4bfc79) -
|
|
18
|
+
[ux] Adding a workaround for a Chrome bug where drag and drop cannot occur in an element
|
|
19
|
+
positioned on top of an `<iframe>` on a different origin. The workaround is being added behind a
|
|
20
|
+
feature flag.
|
|
21
|
+
|
|
3
22
|
## 12.15.7
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -17,12 +17,16 @@ var _useAutoFocus = _interopRequireDefault(require("@atlaskit/ds-lib/use-auto-fo
|
|
|
17
17
|
var _focusRing = _interopRequireDefault(require("@atlaskit/focus-ring"));
|
|
18
18
|
var _layering = require("@atlaskit/layering");
|
|
19
19
|
var _fadeIn = _interopRequireDefault(require("@atlaskit/motion/fade-in"));
|
|
20
|
+
var _combine = require("@atlaskit/pragmatic-drag-and-drop/combine");
|
|
20
21
|
var _primitives = require("@atlaskit/primitives");
|
|
21
22
|
var _colors = require("@atlaskit/theme/colors");
|
|
22
23
|
var _tokens = require("@atlaskit/tokens");
|
|
23
24
|
var _constants = require("../constants");
|
|
24
25
|
var _context = require("../context");
|
|
25
26
|
var _useOnMotionFinish3 = _interopRequireDefault(require("../hooks/use-on-motion-finish"));
|
|
27
|
+
var _element = require("../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element");
|
|
28
|
+
var _external = require("../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external");
|
|
29
|
+
var _textSelection = require("../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection");
|
|
26
30
|
var _utils = require("../utils");
|
|
27
31
|
var _positioner = _interopRequireDefault(require("./positioner"));
|
|
28
32
|
var _css;
|
|
@@ -88,6 +92,17 @@ var ModalDialog = function ModalDialog(props) {
|
|
|
88
92
|
testId = props.testId;
|
|
89
93
|
var id = (0, _reactUid.useId)();
|
|
90
94
|
var titleId = "modal-dialog-title-".concat(id);
|
|
95
|
+
(0, _react.useEffect)(function () {
|
|
96
|
+
// Modal dialogs can appear on top of iframe elements that are on another domain.
|
|
97
|
+
// There is a Chrome bug where drag and drop in an element on top of a cross domain
|
|
98
|
+
// iframe is not working. We are applying the workaround for this bug in modal so
|
|
99
|
+
// that consumers of our modal don't have to worry about this bug and are free to
|
|
100
|
+
// create whatever drag and drop experience they like inside a modal
|
|
101
|
+
//
|
|
102
|
+
// Chrome bug: https://issues.chromium.org/issues/362301053
|
|
103
|
+
|
|
104
|
+
return (0, _combine.combine)((0, _element.disableDraggingToCrossOriginIFramesForElement)(), (0, _textSelection.disableDraggingToCrossOriginIFramesForTextSelection)(), (0, _external.disableDraggingToCrossOriginIFramesForExternal)());
|
|
105
|
+
}, []);
|
|
91
106
|
(0, _useAutoFocus.default)((0, _typeof2.default)(autoFocus) === 'object' ? autoFocus : undefined,
|
|
92
107
|
// When a user supplies a ref to focus we enable this hook
|
|
93
108
|
(0, _typeof2.default)(autoFocus) === 'object');
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.disableDraggingToCrossOriginIFramesForElement = disableDraggingToCrossOriginIFramesForElement;
|
|
7
|
+
var _bindEventListener = require("bind-event-listener");
|
|
8
|
+
var _combine = require("@atlaskit/pragmatic-drag-and-drop/combine");
|
|
9
|
+
var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
|
|
10
|
+
var _makeFixForAdapter = require("./make-fix-for-adapter");
|
|
11
|
+
function watchForInteractionEnd(_ref) {
|
|
12
|
+
var stop = _ref.stop;
|
|
13
|
+
var isDragging = false;
|
|
14
|
+
function stopIfNotDragging() {
|
|
15
|
+
if (isDragging) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
stop();
|
|
19
|
+
}
|
|
20
|
+
var unbindEvents = (0, _bindEventListener.bindAll)(window, [{
|
|
21
|
+
// Another interaction is starting, this fix should be removed.
|
|
22
|
+
type: 'pointerdown',
|
|
23
|
+
listener: stop
|
|
24
|
+
}, {
|
|
25
|
+
// The user did not start a drag
|
|
26
|
+
type: 'pointerup',
|
|
27
|
+
listener: stopIfNotDragging
|
|
28
|
+
}, {
|
|
29
|
+
// if a "dragstart" occurs and the flag is not set,
|
|
30
|
+
// then a drag has not started.
|
|
31
|
+
// Note: could not use "pointercancel" as it is not
|
|
32
|
+
// published in Safari
|
|
33
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=222632
|
|
34
|
+
type: 'dragstart',
|
|
35
|
+
listener: stopIfNotDragging,
|
|
36
|
+
// Need to come after the element adapter
|
|
37
|
+
options: {
|
|
38
|
+
capture: false
|
|
39
|
+
}
|
|
40
|
+
}], {
|
|
41
|
+
// Listening in the capture phase to increase resilience
|
|
42
|
+
// against events being stopped.
|
|
43
|
+
capture: true,
|
|
44
|
+
// Being super clear these should only run once
|
|
45
|
+
once: true
|
|
46
|
+
});
|
|
47
|
+
var unbindMonitor = (0, _adapter.monitorForElements)({
|
|
48
|
+
onGenerateDragPreview: function onGenerateDragPreview() {
|
|
49
|
+
isDragging = true;
|
|
50
|
+
},
|
|
51
|
+
onDrop: function onDrop() {
|
|
52
|
+
isDragging = false;
|
|
53
|
+
stop();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return (0, _combine.combine)(unbindEvents, unbindMonitor);
|
|
57
|
+
}
|
|
58
|
+
function watchForInteractionStart(_ref2) {
|
|
59
|
+
var start = _ref2.start;
|
|
60
|
+
return (0, _bindEventListener.bind)(window, {
|
|
61
|
+
// Note: Using "mousedown" rather than "pointerdown" due to a Safari bug.
|
|
62
|
+
// Safari not publish a "pointerdown" on the interaction after a drag
|
|
63
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=279749
|
|
64
|
+
type: 'mousedown',
|
|
65
|
+
listener: function listener(event) {
|
|
66
|
+
// Only starting if pressing down inside a draggable element
|
|
67
|
+
// At this point, we are not sure which if:
|
|
68
|
+
// 1. a text selection drag is starting
|
|
69
|
+
// 2. a draggable managed by pdnd is going to be dragged
|
|
70
|
+
// 3. a draggable not managed by pdnd is going to be dragged
|
|
71
|
+
// 4. The user will be dragging anything at all (might be doing a click)
|
|
72
|
+
if (event.target instanceof HTMLElement && event.target.closest('[draggable="true"]')) {
|
|
73
|
+
start();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
var api = (0, _makeFixForAdapter.makeFixForAdapter)({
|
|
79
|
+
watchForInteractionStart: watchForInteractionStart,
|
|
80
|
+
watchForInteractionEnd: watchForInteractionEnd
|
|
81
|
+
});
|
|
82
|
+
function disableDraggingToCrossOriginIFramesForElement() {
|
|
83
|
+
return api.registerUsage();
|
|
84
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.disableDraggingToCrossOriginIFramesForExternal = disableDraggingToCrossOriginIFramesForExternal;
|
|
7
|
+
var _adapter = require("@atlaskit/pragmatic-drag-and-drop/external/adapter");
|
|
8
|
+
var _makeFixForAdapter = require("./make-fix-for-adapter");
|
|
9
|
+
function watchForInteractionStart(_ref) {
|
|
10
|
+
var start = _ref.start;
|
|
11
|
+
return (0, _adapter.monitorForExternal)({
|
|
12
|
+
onDragStart: function onDragStart() {
|
|
13
|
+
start();
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function watchForInteractionEnd(_ref2) {
|
|
18
|
+
var stop = _ref2.stop;
|
|
19
|
+
return (0, _adapter.monitorForExternal)({
|
|
20
|
+
onDrop: function onDrop() {
|
|
21
|
+
stop();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
var api = (0, _makeFixForAdapter.makeFixForAdapter)({
|
|
26
|
+
watchForInteractionStart: watchForInteractionStart,
|
|
27
|
+
watchForInteractionEnd: watchForInteractionEnd
|
|
28
|
+
});
|
|
29
|
+
function disableDraggingToCrossOriginIFramesForExternal() {
|
|
30
|
+
return api.registerUsage();
|
|
31
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.makeFixForAdapter = makeFixForAdapter;
|
|
8
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
9
|
+
var _combine = require("@atlaskit/pragmatic-drag-and-drop/combine");
|
|
10
|
+
/**
|
|
11
|
+
* Set a `style` property on a `HTMLElement`
|
|
12
|
+
*
|
|
13
|
+
* @returns a `cleanup` function to restore the `style` property to it's original state
|
|
14
|
+
*/
|
|
15
|
+
function setStyle(el, _ref) {
|
|
16
|
+
var property = _ref.property,
|
|
17
|
+
rule = _ref.rule,
|
|
18
|
+
_ref$priority = _ref.priority,
|
|
19
|
+
priority = _ref$priority === void 0 ? '' : _ref$priority;
|
|
20
|
+
var originalValue = el.style.getPropertyValue(property);
|
|
21
|
+
var originalPriority = el.style.getPropertyPriority(property);
|
|
22
|
+
el.style.setProperty(property, rule, priority);
|
|
23
|
+
return function cleanup() {
|
|
24
|
+
el.style.setProperty(property, originalValue, originalPriority);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function hasSameOrigin(href1, href2) {
|
|
28
|
+
var url1;
|
|
29
|
+
var url2;
|
|
30
|
+
try {
|
|
31
|
+
url1 = new URL(href1);
|
|
32
|
+
url2 = new URL(href2);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
// failed to parse a href
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
|
|
39
|
+
return url1.protocol === url2.protocol && url1.host === url2.host && url1.port === url2.port;
|
|
40
|
+
}
|
|
41
|
+
function isIframeOnAnotherDomain(iframe) {
|
|
42
|
+
/**
|
|
43
|
+
* iframe with contents defined inline. Runs on the current origin.
|
|
44
|
+
* `<iframe srcdoc="<!doctype html><body>Hello</body>" />`
|
|
45
|
+
*/
|
|
46
|
+
if (iframe.srcdoc) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* iframe with contents defined inline. Runs on the current origin.
|
|
52
|
+
* `<iframe src={`data:text/html;charset=utf-8,${encodeURI('<!doctype html><body>Hello</body>')}`} />`
|
|
53
|
+
*/
|
|
54
|
+
if (iframe.src.startsWith('data:')) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return !hasSameOrigin(window.location.href, iframe.src);
|
|
58
|
+
}
|
|
59
|
+
var registry = new Map();
|
|
60
|
+
function applyFix(watchForEndOfInteraction) {
|
|
61
|
+
var iframes = Array.from(document.querySelectorAll('iframe')).filter(isIframeOnAnotherDomain);
|
|
62
|
+
var cleanups = iframes.map(function (iframe) {
|
|
63
|
+
var entry = registry.get(iframe);
|
|
64
|
+
if (!entry) {
|
|
65
|
+
entry = {
|
|
66
|
+
reset: setStyle(iframe, {
|
|
67
|
+
property: 'pointer-events',
|
|
68
|
+
rule: 'none',
|
|
69
|
+
priority: 'important'
|
|
70
|
+
}),
|
|
71
|
+
count: 1
|
|
72
|
+
};
|
|
73
|
+
registry.set(iframe, entry);
|
|
74
|
+
} else {
|
|
75
|
+
// pointer-events:none already applied to the iframe
|
|
76
|
+
// increment how many things requested the fix
|
|
77
|
+
entry.count++;
|
|
78
|
+
}
|
|
79
|
+
return function cleanup() {
|
|
80
|
+
entry.count--;
|
|
81
|
+
if (entry.count < 1) {
|
|
82
|
+
entry.reset();
|
|
83
|
+
registry.delete(iframe);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
function stop() {
|
|
88
|
+
cleanupWatcher();
|
|
89
|
+
_combine.combine.apply(void 0, (0, _toConsumableArray2.default)(cleanups))();
|
|
90
|
+
}
|
|
91
|
+
var cleanupWatcher = watchForEndOfInteraction({
|
|
92
|
+
stop: stop
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function makeFixForAdapter(_ref2) {
|
|
96
|
+
var watchForInteractionStart = _ref2.watchForInteractionStart,
|
|
97
|
+
watchForInteractionEnd = _ref2.watchForInteractionEnd;
|
|
98
|
+
var registrationCount = 0;
|
|
99
|
+
var stopWatchingInteractionStart = null;
|
|
100
|
+
function start() {
|
|
101
|
+
applyFix(watchForInteractionEnd);
|
|
102
|
+
}
|
|
103
|
+
function registerUsage() {
|
|
104
|
+
if (registrationCount === 0) {
|
|
105
|
+
stopWatchingInteractionStart = watchForInteractionStart({
|
|
106
|
+
start: start
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
registrationCount++;
|
|
110
|
+
return function unregisterUsage() {
|
|
111
|
+
var _stopWatchingInteract;
|
|
112
|
+
registrationCount--;
|
|
113
|
+
if (registrationCount !== 0) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
(_stopWatchingInteract = stopWatchingInteractionStart) === null || _stopWatchingInteract === void 0 || _stopWatchingInteract();
|
|
117
|
+
stopWatchingInteractionStart = null;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
registerUsage: registerUsage
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.disableDraggingToCrossOriginIFramesForTextSelection = disableDraggingToCrossOriginIFramesForTextSelection;
|
|
7
|
+
var _bindEventListener = require("bind-event-listener");
|
|
8
|
+
var _combine = require("@atlaskit/pragmatic-drag-and-drop/combine");
|
|
9
|
+
var _adapter = require("@atlaskit/pragmatic-drag-and-drop/text-selection/adapter");
|
|
10
|
+
var _makeFixForAdapter = require("./make-fix-for-adapter");
|
|
11
|
+
function watchForInteractionEnd(_ref) {
|
|
12
|
+
var stop = _ref.stop;
|
|
13
|
+
var isDragging = false;
|
|
14
|
+
function stopIfNotDragging() {
|
|
15
|
+
if (isDragging) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
stop();
|
|
19
|
+
}
|
|
20
|
+
var frameId = null;
|
|
21
|
+
var unbindEvents = (0, _bindEventListener.bindAll)(window, [{
|
|
22
|
+
// User is starting another interaction
|
|
23
|
+
type: 'pointerdown',
|
|
24
|
+
listener: stop
|
|
25
|
+
}, {
|
|
26
|
+
// User did not start a drag.
|
|
27
|
+
// "pointerdown" won't be fired if a drag started
|
|
28
|
+
type: 'pointerup',
|
|
29
|
+
listener: stopIfNotDragging
|
|
30
|
+
}, {
|
|
31
|
+
type: 'dragstart',
|
|
32
|
+
listener: function listener() {
|
|
33
|
+
/**
|
|
34
|
+
* The pdnd `onDragStart()` fires in the frame after "dragstart"
|
|
35
|
+
* So we are delaying our isDragging check to give a chance
|
|
36
|
+
* for `onDragStart()` to set the value correctly.
|
|
37
|
+
*
|
|
38
|
+
* Note: could not use "pointercancel" as it is not
|
|
39
|
+
* published in Safari → https://bugs.webkit.org/show_bug.cgi?id=222632
|
|
40
|
+
*/
|
|
41
|
+
frameId = requestAnimationFrame(function () {
|
|
42
|
+
frameId = null;
|
|
43
|
+
stopIfNotDragging();
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
// need to schedule our frame after the text-selection
|
|
47
|
+
// adapter queues it's `onDragStart` frame.
|
|
48
|
+
options: {
|
|
49
|
+
capture: false
|
|
50
|
+
}
|
|
51
|
+
}], {
|
|
52
|
+
// Listening in the capture phase to increase resilience
|
|
53
|
+
// against events being stopped.
|
|
54
|
+
capture: true,
|
|
55
|
+
// being super clear these should only run once
|
|
56
|
+
once: true
|
|
57
|
+
});
|
|
58
|
+
var unbindMonitor = (0, _adapter.monitorForTextSelection)({
|
|
59
|
+
onDragStart: function onDragStart() {
|
|
60
|
+
isDragging = true;
|
|
61
|
+
},
|
|
62
|
+
onDrop: function onDrop() {
|
|
63
|
+
isDragging = false;
|
|
64
|
+
stop();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return (0, _combine.combine)(unbindEvents, unbindMonitor, function abortFrame() {
|
|
68
|
+
if (frameId != null) {
|
|
69
|
+
cancelAnimationFrame(frameId);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function watchForInteractionStart(_ref2) {
|
|
74
|
+
var start = _ref2.start;
|
|
75
|
+
return (0, _bindEventListener.bind)(window, {
|
|
76
|
+
// Note: Using "mousedown" rather than "pointerdown" due to a Safari bug.
|
|
77
|
+
// Safari not publish a "pointerdown" on the interaction after a drag
|
|
78
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=279749
|
|
79
|
+
type: 'mousedown',
|
|
80
|
+
listener: function listener() {
|
|
81
|
+
// A text selection drag will only start when there is
|
|
82
|
+
// an active text selection.
|
|
83
|
+
var selection = window.getSelection();
|
|
84
|
+
|
|
85
|
+
// No selection object found
|
|
86
|
+
if (!selection) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// `isCollapsed` is "true" if there is currently no selected text
|
|
91
|
+
if (selection.isCollapsed) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
start();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
var api = (0, _makeFixForAdapter.makeFixForAdapter)({
|
|
99
|
+
watchForInteractionStart: watchForInteractionStart,
|
|
100
|
+
watchForInteractionEnd: watchForInteractionEnd
|
|
101
|
+
});
|
|
102
|
+
function disableDraggingToCrossOriginIFramesForTextSelection() {
|
|
103
|
+
return api.registerUsage();
|
|
104
|
+
}
|
|
@@ -102,7 +102,7 @@ var ModalWrapper = function ModalWrapper(props) {
|
|
|
102
102
|
action: 'closed',
|
|
103
103
|
componentName: 'modalDialog',
|
|
104
104
|
packageName: "@atlaskit/modal-dialog",
|
|
105
|
-
packageVersion: "12.
|
|
105
|
+
packageVersion: "12.17.0"
|
|
106
106
|
});
|
|
107
107
|
var onBlanketClicked = (0, _react.useCallback)(function (e) {
|
|
108
108
|
if (shouldCloseOnOverlayClick) {
|
|
@@ -3,7 +3,8 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
3
3
|
* @jsxRuntime classic
|
|
4
4
|
* @jsx jsx
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
import { useEffect, useMemo } from 'react';
|
|
7
8
|
import { css, jsx } from '@emotion/react';
|
|
8
9
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
9
10
|
import { useId } from '@atlaskit/ds-lib/react-uid';
|
|
@@ -11,12 +12,16 @@ import useAutoFocus from '@atlaskit/ds-lib/use-auto-focus';
|
|
|
11
12
|
import FocusRing from '@atlaskit/focus-ring';
|
|
12
13
|
import { UNSAFE_useLayering, useCloseOnEscapePress } from '@atlaskit/layering';
|
|
13
14
|
import FadeIn from '@atlaskit/motion/fade-in';
|
|
15
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
14
16
|
import { media } from '@atlaskit/primitives';
|
|
15
17
|
import { N0, N30A, N60A } from '@atlaskit/theme/colors';
|
|
16
18
|
import { CURRENT_SURFACE_CSS_VAR } from '@atlaskit/tokens';
|
|
17
19
|
import { borderRadius, textColor } from '../constants';
|
|
18
20
|
import { ModalContext, ScrollContext } from '../context';
|
|
19
21
|
import useOnMotionFinish from '../hooks/use-on-motion-finish';
|
|
22
|
+
import { disableDraggingToCrossOriginIFramesForElement } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element';
|
|
23
|
+
import { disableDraggingToCrossOriginIFramesForExternal } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external';
|
|
24
|
+
import { disableDraggingToCrossOriginIFramesForTextSelection } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection';
|
|
20
25
|
import { dialogHeight, dialogWidth } from '../utils';
|
|
21
26
|
import Positioner from './positioner';
|
|
22
27
|
const dialogStyles = css({
|
|
@@ -89,6 +94,17 @@ const ModalDialog = props => {
|
|
|
89
94
|
} = props;
|
|
90
95
|
const id = useId();
|
|
91
96
|
const titleId = `modal-dialog-title-${id}`;
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
// Modal dialogs can appear on top of iframe elements that are on another domain.
|
|
99
|
+
// There is a Chrome bug where drag and drop in an element on top of a cross domain
|
|
100
|
+
// iframe is not working. We are applying the workaround for this bug in modal so
|
|
101
|
+
// that consumers of our modal don't have to worry about this bug and are free to
|
|
102
|
+
// create whatever drag and drop experience they like inside a modal
|
|
103
|
+
//
|
|
104
|
+
// Chrome bug: https://issues.chromium.org/issues/362301053
|
|
105
|
+
|
|
106
|
+
return combine(disableDraggingToCrossOriginIFramesForElement(), disableDraggingToCrossOriginIFramesForTextSelection(), disableDraggingToCrossOriginIFramesForExternal());
|
|
107
|
+
}, []);
|
|
92
108
|
useAutoFocus(typeof autoFocus === 'object' ? autoFocus : undefined,
|
|
93
109
|
// When a user supplies a ref to focus we enable this hook
|
|
94
110
|
typeof autoFocus === 'object');
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { bind, bindAll } from 'bind-event-listener';
|
|
2
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
3
|
+
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
4
|
+
import { makeFixForAdapter } from './make-fix-for-adapter';
|
|
5
|
+
function watchForInteractionEnd({
|
|
6
|
+
stop
|
|
7
|
+
}) {
|
|
8
|
+
let isDragging = false;
|
|
9
|
+
function stopIfNotDragging() {
|
|
10
|
+
if (isDragging) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
stop();
|
|
14
|
+
}
|
|
15
|
+
const unbindEvents = bindAll(window, [{
|
|
16
|
+
// Another interaction is starting, this fix should be removed.
|
|
17
|
+
type: 'pointerdown',
|
|
18
|
+
listener: stop
|
|
19
|
+
}, {
|
|
20
|
+
// The user did not start a drag
|
|
21
|
+
type: 'pointerup',
|
|
22
|
+
listener: stopIfNotDragging
|
|
23
|
+
}, {
|
|
24
|
+
// if a "dragstart" occurs and the flag is not set,
|
|
25
|
+
// then a drag has not started.
|
|
26
|
+
// Note: could not use "pointercancel" as it is not
|
|
27
|
+
// published in Safari
|
|
28
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=222632
|
|
29
|
+
type: 'dragstart',
|
|
30
|
+
listener: stopIfNotDragging,
|
|
31
|
+
// Need to come after the element adapter
|
|
32
|
+
options: {
|
|
33
|
+
capture: false
|
|
34
|
+
}
|
|
35
|
+
}], {
|
|
36
|
+
// Listening in the capture phase to increase resilience
|
|
37
|
+
// against events being stopped.
|
|
38
|
+
capture: true,
|
|
39
|
+
// Being super clear these should only run once
|
|
40
|
+
once: true
|
|
41
|
+
});
|
|
42
|
+
const unbindMonitor = monitorForElements({
|
|
43
|
+
onGenerateDragPreview() {
|
|
44
|
+
isDragging = true;
|
|
45
|
+
},
|
|
46
|
+
onDrop() {
|
|
47
|
+
isDragging = false;
|
|
48
|
+
stop();
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return combine(unbindEvents, unbindMonitor);
|
|
52
|
+
}
|
|
53
|
+
function watchForInteractionStart({
|
|
54
|
+
start
|
|
55
|
+
}) {
|
|
56
|
+
return bind(window, {
|
|
57
|
+
// Note: Using "mousedown" rather than "pointerdown" due to a Safari bug.
|
|
58
|
+
// Safari not publish a "pointerdown" on the interaction after a drag
|
|
59
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=279749
|
|
60
|
+
type: 'mousedown',
|
|
61
|
+
listener(event) {
|
|
62
|
+
// Only starting if pressing down inside a draggable element
|
|
63
|
+
// At this point, we are not sure which if:
|
|
64
|
+
// 1. a text selection drag is starting
|
|
65
|
+
// 2. a draggable managed by pdnd is going to be dragged
|
|
66
|
+
// 3. a draggable not managed by pdnd is going to be dragged
|
|
67
|
+
// 4. The user will be dragging anything at all (might be doing a click)
|
|
68
|
+
if (event.target instanceof HTMLElement && event.target.closest('[draggable="true"]')) {
|
|
69
|
+
start();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const api = makeFixForAdapter({
|
|
75
|
+
watchForInteractionStart,
|
|
76
|
+
watchForInteractionEnd
|
|
77
|
+
});
|
|
78
|
+
export function disableDraggingToCrossOriginIFramesForElement() {
|
|
79
|
+
return api.registerUsage();
|
|
80
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter';
|
|
2
|
+
import { makeFixForAdapter } from './make-fix-for-adapter';
|
|
3
|
+
function watchForInteractionStart({
|
|
4
|
+
start
|
|
5
|
+
}) {
|
|
6
|
+
return monitorForExternal({
|
|
7
|
+
onDragStart() {
|
|
8
|
+
start();
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function watchForInteractionEnd({
|
|
13
|
+
stop
|
|
14
|
+
}) {
|
|
15
|
+
return monitorForExternal({
|
|
16
|
+
onDrop() {
|
|
17
|
+
stop();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const api = makeFixForAdapter({
|
|
22
|
+
watchForInteractionStart,
|
|
23
|
+
watchForInteractionEnd
|
|
24
|
+
});
|
|
25
|
+
export function disableDraggingToCrossOriginIFramesForExternal() {
|
|
26
|
+
return api.registerUsage();
|
|
27
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
2
|
+
/**
|
|
3
|
+
* Set a `style` property on a `HTMLElement`
|
|
4
|
+
*
|
|
5
|
+
* @returns a `cleanup` function to restore the `style` property to it's original state
|
|
6
|
+
*/
|
|
7
|
+
function setStyle(el, {
|
|
8
|
+
property,
|
|
9
|
+
rule,
|
|
10
|
+
priority = ''
|
|
11
|
+
}) {
|
|
12
|
+
const originalValue = el.style.getPropertyValue(property);
|
|
13
|
+
const originalPriority = el.style.getPropertyPriority(property);
|
|
14
|
+
el.style.setProperty(property, rule, priority);
|
|
15
|
+
return function cleanup() {
|
|
16
|
+
el.style.setProperty(property, originalValue, originalPriority);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function hasSameOrigin(href1, href2) {
|
|
20
|
+
let url1;
|
|
21
|
+
let url2;
|
|
22
|
+
try {
|
|
23
|
+
url1 = new URL(href1);
|
|
24
|
+
url2 = new URL(href2);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
// failed to parse a href
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
|
|
31
|
+
return url1.protocol === url2.protocol && url1.host === url2.host && url1.port === url2.port;
|
|
32
|
+
}
|
|
33
|
+
function isIframeOnAnotherDomain(iframe) {
|
|
34
|
+
/**
|
|
35
|
+
* iframe with contents defined inline. Runs on the current origin.
|
|
36
|
+
* `<iframe srcdoc="<!doctype html><body>Hello</body>" />`
|
|
37
|
+
*/
|
|
38
|
+
if (iframe.srcdoc) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* iframe with contents defined inline. Runs on the current origin.
|
|
44
|
+
* `<iframe src={`data:text/html;charset=utf-8,${encodeURI('<!doctype html><body>Hello</body>')}`} />`
|
|
45
|
+
*/
|
|
46
|
+
if (iframe.src.startsWith('data:')) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return !hasSameOrigin(window.location.href, iframe.src);
|
|
50
|
+
}
|
|
51
|
+
const registry = new Map();
|
|
52
|
+
function applyFix(watchForEndOfInteraction) {
|
|
53
|
+
const iframes = Array.from(document.querySelectorAll('iframe')).filter(isIframeOnAnotherDomain);
|
|
54
|
+
const cleanups = iframes.map(iframe => {
|
|
55
|
+
let entry = registry.get(iframe);
|
|
56
|
+
if (!entry) {
|
|
57
|
+
entry = {
|
|
58
|
+
reset: setStyle(iframe, {
|
|
59
|
+
property: 'pointer-events',
|
|
60
|
+
rule: 'none',
|
|
61
|
+
priority: 'important'
|
|
62
|
+
}),
|
|
63
|
+
count: 1
|
|
64
|
+
};
|
|
65
|
+
registry.set(iframe, entry);
|
|
66
|
+
} else {
|
|
67
|
+
// pointer-events:none already applied to the iframe
|
|
68
|
+
// increment how many things requested the fix
|
|
69
|
+
entry.count++;
|
|
70
|
+
}
|
|
71
|
+
return function cleanup() {
|
|
72
|
+
entry.count--;
|
|
73
|
+
if (entry.count < 1) {
|
|
74
|
+
entry.reset();
|
|
75
|
+
registry.delete(iframe);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
function stop() {
|
|
80
|
+
cleanupWatcher();
|
|
81
|
+
combine(...cleanups)();
|
|
82
|
+
}
|
|
83
|
+
const cleanupWatcher = watchForEndOfInteraction({
|
|
84
|
+
stop
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
export function makeFixForAdapter({
|
|
88
|
+
watchForInteractionStart,
|
|
89
|
+
watchForInteractionEnd
|
|
90
|
+
}) {
|
|
91
|
+
let registrationCount = 0;
|
|
92
|
+
let stopWatchingInteractionStart = null;
|
|
93
|
+
function start() {
|
|
94
|
+
applyFix(watchForInteractionEnd);
|
|
95
|
+
}
|
|
96
|
+
function registerUsage() {
|
|
97
|
+
if (registrationCount === 0) {
|
|
98
|
+
stopWatchingInteractionStart = watchForInteractionStart({
|
|
99
|
+
start
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
registrationCount++;
|
|
103
|
+
return function unregisterUsage() {
|
|
104
|
+
var _stopWatchingInteract;
|
|
105
|
+
registrationCount--;
|
|
106
|
+
if (registrationCount !== 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
(_stopWatchingInteract = stopWatchingInteractionStart) === null || _stopWatchingInteract === void 0 ? void 0 : _stopWatchingInteract();
|
|
110
|
+
stopWatchingInteractionStart = null;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
registerUsage
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { bind, bindAll } from 'bind-event-listener';
|
|
2
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
3
|
+
import { monitorForTextSelection } from '@atlaskit/pragmatic-drag-and-drop/text-selection/adapter';
|
|
4
|
+
import { makeFixForAdapter } from './make-fix-for-adapter';
|
|
5
|
+
function watchForInteractionEnd({
|
|
6
|
+
stop
|
|
7
|
+
}) {
|
|
8
|
+
let isDragging = false;
|
|
9
|
+
function stopIfNotDragging() {
|
|
10
|
+
if (isDragging) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
stop();
|
|
14
|
+
}
|
|
15
|
+
let frameId = null;
|
|
16
|
+
const unbindEvents = bindAll(window, [{
|
|
17
|
+
// User is starting another interaction
|
|
18
|
+
type: 'pointerdown',
|
|
19
|
+
listener: stop
|
|
20
|
+
}, {
|
|
21
|
+
// User did not start a drag.
|
|
22
|
+
// "pointerdown" won't be fired if a drag started
|
|
23
|
+
type: 'pointerup',
|
|
24
|
+
listener: stopIfNotDragging
|
|
25
|
+
}, {
|
|
26
|
+
type: 'dragstart',
|
|
27
|
+
listener() {
|
|
28
|
+
/**
|
|
29
|
+
* The pdnd `onDragStart()` fires in the frame after "dragstart"
|
|
30
|
+
* So we are delaying our isDragging check to give a chance
|
|
31
|
+
* for `onDragStart()` to set the value correctly.
|
|
32
|
+
*
|
|
33
|
+
* Note: could not use "pointercancel" as it is not
|
|
34
|
+
* published in Safari → https://bugs.webkit.org/show_bug.cgi?id=222632
|
|
35
|
+
*/
|
|
36
|
+
frameId = requestAnimationFrame(() => {
|
|
37
|
+
frameId = null;
|
|
38
|
+
stopIfNotDragging();
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
// need to schedule our frame after the text-selection
|
|
42
|
+
// adapter queues it's `onDragStart` frame.
|
|
43
|
+
options: {
|
|
44
|
+
capture: false
|
|
45
|
+
}
|
|
46
|
+
}], {
|
|
47
|
+
// Listening in the capture phase to increase resilience
|
|
48
|
+
// against events being stopped.
|
|
49
|
+
capture: true,
|
|
50
|
+
// being super clear these should only run once
|
|
51
|
+
once: true
|
|
52
|
+
});
|
|
53
|
+
const unbindMonitor = monitorForTextSelection({
|
|
54
|
+
onDragStart() {
|
|
55
|
+
isDragging = true;
|
|
56
|
+
},
|
|
57
|
+
onDrop() {
|
|
58
|
+
isDragging = false;
|
|
59
|
+
stop();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return combine(unbindEvents, unbindMonitor, function abortFrame() {
|
|
63
|
+
if (frameId != null) {
|
|
64
|
+
cancelAnimationFrame(frameId);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function watchForInteractionStart({
|
|
69
|
+
start
|
|
70
|
+
}) {
|
|
71
|
+
return bind(window, {
|
|
72
|
+
// Note: Using "mousedown" rather than "pointerdown" due to a Safari bug.
|
|
73
|
+
// Safari not publish a "pointerdown" on the interaction after a drag
|
|
74
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=279749
|
|
75
|
+
type: 'mousedown',
|
|
76
|
+
listener() {
|
|
77
|
+
// A text selection drag will only start when there is
|
|
78
|
+
// an active text selection.
|
|
79
|
+
const selection = window.getSelection();
|
|
80
|
+
|
|
81
|
+
// No selection object found
|
|
82
|
+
if (!selection) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// `isCollapsed` is "true" if there is currently no selected text
|
|
87
|
+
if (selection.isCollapsed) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
start();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const api = makeFixForAdapter({
|
|
95
|
+
watchForInteractionStart,
|
|
96
|
+
watchForInteractionEnd
|
|
97
|
+
});
|
|
98
|
+
export function disableDraggingToCrossOriginIFramesForTextSelection() {
|
|
99
|
+
return api.registerUsage();
|
|
100
|
+
}
|
|
@@ -87,7 +87,7 @@ const ModalWrapper = props => {
|
|
|
87
87
|
action: 'closed',
|
|
88
88
|
componentName: 'modalDialog',
|
|
89
89
|
packageName: "@atlaskit/modal-dialog",
|
|
90
|
-
packageVersion: "12.
|
|
90
|
+
packageVersion: "12.17.0"
|
|
91
91
|
});
|
|
92
92
|
const onBlanketClicked = useCallback(e => {
|
|
93
93
|
if (shouldCloseOnOverlayClick) {
|
|
@@ -7,7 +7,8 @@ var _css;
|
|
|
7
7
|
* @jsxRuntime classic
|
|
8
8
|
* @jsx jsx
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
import { useEffect, useMemo } from 'react';
|
|
11
12
|
import { css, jsx } from '@emotion/react';
|
|
12
13
|
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
|
|
13
14
|
import { useId } from '@atlaskit/ds-lib/react-uid';
|
|
@@ -15,12 +16,16 @@ import useAutoFocus from '@atlaskit/ds-lib/use-auto-focus';
|
|
|
15
16
|
import FocusRing from '@atlaskit/focus-ring';
|
|
16
17
|
import { UNSAFE_useLayering, useCloseOnEscapePress } from '@atlaskit/layering';
|
|
17
18
|
import FadeIn from '@atlaskit/motion/fade-in';
|
|
19
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
18
20
|
import { media } from '@atlaskit/primitives';
|
|
19
21
|
import { N0, N30A, N60A } from '@atlaskit/theme/colors';
|
|
20
22
|
import { CURRENT_SURFACE_CSS_VAR } from '@atlaskit/tokens';
|
|
21
23
|
import { borderRadius, textColor } from '../constants';
|
|
22
24
|
import { ModalContext, ScrollContext } from '../context';
|
|
23
25
|
import useOnMotionFinish from '../hooks/use-on-motion-finish';
|
|
26
|
+
import { disableDraggingToCrossOriginIFramesForElement } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element';
|
|
27
|
+
import { disableDraggingToCrossOriginIFramesForExternal } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external';
|
|
28
|
+
import { disableDraggingToCrossOriginIFramesForTextSelection } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection';
|
|
24
29
|
import { dialogHeight, dialogWidth } from '../utils';
|
|
25
30
|
import Positioner from './positioner';
|
|
26
31
|
var dialogStyles = css((_css = {
|
|
@@ -81,6 +86,17 @@ var ModalDialog = function ModalDialog(props) {
|
|
|
81
86
|
testId = props.testId;
|
|
82
87
|
var id = useId();
|
|
83
88
|
var titleId = "modal-dialog-title-".concat(id);
|
|
89
|
+
useEffect(function () {
|
|
90
|
+
// Modal dialogs can appear on top of iframe elements that are on another domain.
|
|
91
|
+
// There is a Chrome bug where drag and drop in an element on top of a cross domain
|
|
92
|
+
// iframe is not working. We are applying the workaround for this bug in modal so
|
|
93
|
+
// that consumers of our modal don't have to worry about this bug and are free to
|
|
94
|
+
// create whatever drag and drop experience they like inside a modal
|
|
95
|
+
//
|
|
96
|
+
// Chrome bug: https://issues.chromium.org/issues/362301053
|
|
97
|
+
|
|
98
|
+
return combine(disableDraggingToCrossOriginIFramesForElement(), disableDraggingToCrossOriginIFramesForTextSelection(), disableDraggingToCrossOriginIFramesForExternal());
|
|
99
|
+
}, []);
|
|
84
100
|
useAutoFocus(_typeof(autoFocus) === 'object' ? autoFocus : undefined,
|
|
85
101
|
// When a user supplies a ref to focus we enable this hook
|
|
86
102
|
_typeof(autoFocus) === 'object');
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { bind, bindAll } from 'bind-event-listener';
|
|
2
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
3
|
+
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
4
|
+
import { makeFixForAdapter } from './make-fix-for-adapter';
|
|
5
|
+
function watchForInteractionEnd(_ref) {
|
|
6
|
+
var stop = _ref.stop;
|
|
7
|
+
var isDragging = false;
|
|
8
|
+
function stopIfNotDragging() {
|
|
9
|
+
if (isDragging) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
stop();
|
|
13
|
+
}
|
|
14
|
+
var unbindEvents = bindAll(window, [{
|
|
15
|
+
// Another interaction is starting, this fix should be removed.
|
|
16
|
+
type: 'pointerdown',
|
|
17
|
+
listener: stop
|
|
18
|
+
}, {
|
|
19
|
+
// The user did not start a drag
|
|
20
|
+
type: 'pointerup',
|
|
21
|
+
listener: stopIfNotDragging
|
|
22
|
+
}, {
|
|
23
|
+
// if a "dragstart" occurs and the flag is not set,
|
|
24
|
+
// then a drag has not started.
|
|
25
|
+
// Note: could not use "pointercancel" as it is not
|
|
26
|
+
// published in Safari
|
|
27
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=222632
|
|
28
|
+
type: 'dragstart',
|
|
29
|
+
listener: stopIfNotDragging,
|
|
30
|
+
// Need to come after the element adapter
|
|
31
|
+
options: {
|
|
32
|
+
capture: false
|
|
33
|
+
}
|
|
34
|
+
}], {
|
|
35
|
+
// Listening in the capture phase to increase resilience
|
|
36
|
+
// against events being stopped.
|
|
37
|
+
capture: true,
|
|
38
|
+
// Being super clear these should only run once
|
|
39
|
+
once: true
|
|
40
|
+
});
|
|
41
|
+
var unbindMonitor = monitorForElements({
|
|
42
|
+
onGenerateDragPreview: function onGenerateDragPreview() {
|
|
43
|
+
isDragging = true;
|
|
44
|
+
},
|
|
45
|
+
onDrop: function onDrop() {
|
|
46
|
+
isDragging = false;
|
|
47
|
+
stop();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return combine(unbindEvents, unbindMonitor);
|
|
51
|
+
}
|
|
52
|
+
function watchForInteractionStart(_ref2) {
|
|
53
|
+
var start = _ref2.start;
|
|
54
|
+
return bind(window, {
|
|
55
|
+
// Note: Using "mousedown" rather than "pointerdown" due to a Safari bug.
|
|
56
|
+
// Safari not publish a "pointerdown" on the interaction after a drag
|
|
57
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=279749
|
|
58
|
+
type: 'mousedown',
|
|
59
|
+
listener: function listener(event) {
|
|
60
|
+
// Only starting if pressing down inside a draggable element
|
|
61
|
+
// At this point, we are not sure which if:
|
|
62
|
+
// 1. a text selection drag is starting
|
|
63
|
+
// 2. a draggable managed by pdnd is going to be dragged
|
|
64
|
+
// 3. a draggable not managed by pdnd is going to be dragged
|
|
65
|
+
// 4. The user will be dragging anything at all (might be doing a click)
|
|
66
|
+
if (event.target instanceof HTMLElement && event.target.closest('[draggable="true"]')) {
|
|
67
|
+
start();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
var api = makeFixForAdapter({
|
|
73
|
+
watchForInteractionStart: watchForInteractionStart,
|
|
74
|
+
watchForInteractionEnd: watchForInteractionEnd
|
|
75
|
+
});
|
|
76
|
+
export function disableDraggingToCrossOriginIFramesForElement() {
|
|
77
|
+
return api.registerUsage();
|
|
78
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { monitorForExternal } from '@atlaskit/pragmatic-drag-and-drop/external/adapter';
|
|
2
|
+
import { makeFixForAdapter } from './make-fix-for-adapter';
|
|
3
|
+
function watchForInteractionStart(_ref) {
|
|
4
|
+
var start = _ref.start;
|
|
5
|
+
return monitorForExternal({
|
|
6
|
+
onDragStart: function onDragStart() {
|
|
7
|
+
start();
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function watchForInteractionEnd(_ref2) {
|
|
12
|
+
var stop = _ref2.stop;
|
|
13
|
+
return monitorForExternal({
|
|
14
|
+
onDrop: function onDrop() {
|
|
15
|
+
stop();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
var api = makeFixForAdapter({
|
|
20
|
+
watchForInteractionStart: watchForInteractionStart,
|
|
21
|
+
watchForInteractionEnd: watchForInteractionEnd
|
|
22
|
+
});
|
|
23
|
+
export function disableDraggingToCrossOriginIFramesForExternal() {
|
|
24
|
+
return api.registerUsage();
|
|
25
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
2
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
3
|
+
/**
|
|
4
|
+
* Set a `style` property on a `HTMLElement`
|
|
5
|
+
*
|
|
6
|
+
* @returns a `cleanup` function to restore the `style` property to it's original state
|
|
7
|
+
*/
|
|
8
|
+
function setStyle(el, _ref) {
|
|
9
|
+
var property = _ref.property,
|
|
10
|
+
rule = _ref.rule,
|
|
11
|
+
_ref$priority = _ref.priority,
|
|
12
|
+
priority = _ref$priority === void 0 ? '' : _ref$priority;
|
|
13
|
+
var originalValue = el.style.getPropertyValue(property);
|
|
14
|
+
var originalPriority = el.style.getPropertyPriority(property);
|
|
15
|
+
el.style.setProperty(property, rule, priority);
|
|
16
|
+
return function cleanup() {
|
|
17
|
+
el.style.setProperty(property, originalValue, originalPriority);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function hasSameOrigin(href1, href2) {
|
|
21
|
+
var url1;
|
|
22
|
+
var url2;
|
|
23
|
+
try {
|
|
24
|
+
url1 = new URL(href1);
|
|
25
|
+
url2 = new URL(href2);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
// failed to parse a href
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
|
|
32
|
+
return url1.protocol === url2.protocol && url1.host === url2.host && url1.port === url2.port;
|
|
33
|
+
}
|
|
34
|
+
function isIframeOnAnotherDomain(iframe) {
|
|
35
|
+
/**
|
|
36
|
+
* iframe with contents defined inline. Runs on the current origin.
|
|
37
|
+
* `<iframe srcdoc="<!doctype html><body>Hello</body>" />`
|
|
38
|
+
*/
|
|
39
|
+
if (iframe.srcdoc) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* iframe with contents defined inline. Runs on the current origin.
|
|
45
|
+
* `<iframe src={`data:text/html;charset=utf-8,${encodeURI('<!doctype html><body>Hello</body>')}`} />`
|
|
46
|
+
*/
|
|
47
|
+
if (iframe.src.startsWith('data:')) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return !hasSameOrigin(window.location.href, iframe.src);
|
|
51
|
+
}
|
|
52
|
+
var registry = new Map();
|
|
53
|
+
function applyFix(watchForEndOfInteraction) {
|
|
54
|
+
var iframes = Array.from(document.querySelectorAll('iframe')).filter(isIframeOnAnotherDomain);
|
|
55
|
+
var cleanups = iframes.map(function (iframe) {
|
|
56
|
+
var entry = registry.get(iframe);
|
|
57
|
+
if (!entry) {
|
|
58
|
+
entry = {
|
|
59
|
+
reset: setStyle(iframe, {
|
|
60
|
+
property: 'pointer-events',
|
|
61
|
+
rule: 'none',
|
|
62
|
+
priority: 'important'
|
|
63
|
+
}),
|
|
64
|
+
count: 1
|
|
65
|
+
};
|
|
66
|
+
registry.set(iframe, entry);
|
|
67
|
+
} else {
|
|
68
|
+
// pointer-events:none already applied to the iframe
|
|
69
|
+
// increment how many things requested the fix
|
|
70
|
+
entry.count++;
|
|
71
|
+
}
|
|
72
|
+
return function cleanup() {
|
|
73
|
+
entry.count--;
|
|
74
|
+
if (entry.count < 1) {
|
|
75
|
+
entry.reset();
|
|
76
|
+
registry.delete(iframe);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
function stop() {
|
|
81
|
+
cleanupWatcher();
|
|
82
|
+
combine.apply(void 0, _toConsumableArray(cleanups))();
|
|
83
|
+
}
|
|
84
|
+
var cleanupWatcher = watchForEndOfInteraction({
|
|
85
|
+
stop: stop
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
export function makeFixForAdapter(_ref2) {
|
|
89
|
+
var watchForInteractionStart = _ref2.watchForInteractionStart,
|
|
90
|
+
watchForInteractionEnd = _ref2.watchForInteractionEnd;
|
|
91
|
+
var registrationCount = 0;
|
|
92
|
+
var stopWatchingInteractionStart = null;
|
|
93
|
+
function start() {
|
|
94
|
+
applyFix(watchForInteractionEnd);
|
|
95
|
+
}
|
|
96
|
+
function registerUsage() {
|
|
97
|
+
if (registrationCount === 0) {
|
|
98
|
+
stopWatchingInteractionStart = watchForInteractionStart({
|
|
99
|
+
start: start
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
registrationCount++;
|
|
103
|
+
return function unregisterUsage() {
|
|
104
|
+
var _stopWatchingInteract;
|
|
105
|
+
registrationCount--;
|
|
106
|
+
if (registrationCount !== 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
(_stopWatchingInteract = stopWatchingInteractionStart) === null || _stopWatchingInteract === void 0 || _stopWatchingInteract();
|
|
110
|
+
stopWatchingInteractionStart = null;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
registerUsage: registerUsage
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { bind, bindAll } from 'bind-event-listener';
|
|
2
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
3
|
+
import { monitorForTextSelection } from '@atlaskit/pragmatic-drag-and-drop/text-selection/adapter';
|
|
4
|
+
import { makeFixForAdapter } from './make-fix-for-adapter';
|
|
5
|
+
function watchForInteractionEnd(_ref) {
|
|
6
|
+
var stop = _ref.stop;
|
|
7
|
+
var isDragging = false;
|
|
8
|
+
function stopIfNotDragging() {
|
|
9
|
+
if (isDragging) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
stop();
|
|
13
|
+
}
|
|
14
|
+
var frameId = null;
|
|
15
|
+
var unbindEvents = bindAll(window, [{
|
|
16
|
+
// User is starting another interaction
|
|
17
|
+
type: 'pointerdown',
|
|
18
|
+
listener: stop
|
|
19
|
+
}, {
|
|
20
|
+
// User did not start a drag.
|
|
21
|
+
// "pointerdown" won't be fired if a drag started
|
|
22
|
+
type: 'pointerup',
|
|
23
|
+
listener: stopIfNotDragging
|
|
24
|
+
}, {
|
|
25
|
+
type: 'dragstart',
|
|
26
|
+
listener: function listener() {
|
|
27
|
+
/**
|
|
28
|
+
* The pdnd `onDragStart()` fires in the frame after "dragstart"
|
|
29
|
+
* So we are delaying our isDragging check to give a chance
|
|
30
|
+
* for `onDragStart()` to set the value correctly.
|
|
31
|
+
*
|
|
32
|
+
* Note: could not use "pointercancel" as it is not
|
|
33
|
+
* published in Safari → https://bugs.webkit.org/show_bug.cgi?id=222632
|
|
34
|
+
*/
|
|
35
|
+
frameId = requestAnimationFrame(function () {
|
|
36
|
+
frameId = null;
|
|
37
|
+
stopIfNotDragging();
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
// need to schedule our frame after the text-selection
|
|
41
|
+
// adapter queues it's `onDragStart` frame.
|
|
42
|
+
options: {
|
|
43
|
+
capture: false
|
|
44
|
+
}
|
|
45
|
+
}], {
|
|
46
|
+
// Listening in the capture phase to increase resilience
|
|
47
|
+
// against events being stopped.
|
|
48
|
+
capture: true,
|
|
49
|
+
// being super clear these should only run once
|
|
50
|
+
once: true
|
|
51
|
+
});
|
|
52
|
+
var unbindMonitor = monitorForTextSelection({
|
|
53
|
+
onDragStart: function onDragStart() {
|
|
54
|
+
isDragging = true;
|
|
55
|
+
},
|
|
56
|
+
onDrop: function onDrop() {
|
|
57
|
+
isDragging = false;
|
|
58
|
+
stop();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return combine(unbindEvents, unbindMonitor, function abortFrame() {
|
|
62
|
+
if (frameId != null) {
|
|
63
|
+
cancelAnimationFrame(frameId);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function watchForInteractionStart(_ref2) {
|
|
68
|
+
var start = _ref2.start;
|
|
69
|
+
return bind(window, {
|
|
70
|
+
// Note: Using "mousedown" rather than "pointerdown" due to a Safari bug.
|
|
71
|
+
// Safari not publish a "pointerdown" on the interaction after a drag
|
|
72
|
+
// → https://bugs.webkit.org/show_bug.cgi?id=279749
|
|
73
|
+
type: 'mousedown',
|
|
74
|
+
listener: function listener() {
|
|
75
|
+
// A text selection drag will only start when there is
|
|
76
|
+
// an active text selection.
|
|
77
|
+
var selection = window.getSelection();
|
|
78
|
+
|
|
79
|
+
// No selection object found
|
|
80
|
+
if (!selection) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// `isCollapsed` is "true" if there is currently no selected text
|
|
85
|
+
if (selection.isCollapsed) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
start();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
var api = makeFixForAdapter({
|
|
93
|
+
watchForInteractionStart: watchForInteractionStart,
|
|
94
|
+
watchForInteractionEnd: watchForInteractionEnd
|
|
95
|
+
});
|
|
96
|
+
export function disableDraggingToCrossOriginIFramesForTextSelection() {
|
|
97
|
+
return api.registerUsage();
|
|
98
|
+
}
|
|
@@ -92,7 +92,7 @@ var ModalWrapper = function ModalWrapper(props) {
|
|
|
92
92
|
action: 'closed',
|
|
93
93
|
componentName: 'modalDialog',
|
|
94
94
|
packageName: "@atlaskit/modal-dialog",
|
|
95
|
-
packageVersion: "12.
|
|
95
|
+
packageVersion: "12.17.0"
|
|
96
96
|
});
|
|
97
97
|
var onBlanketClicked = useCallback(function (e) {
|
|
98
98
|
if (shouldCloseOnOverlayClick) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';
|
|
2
|
+
export declare function makeFixForAdapter({ watchForInteractionStart, watchForInteractionEnd, }: {
|
|
3
|
+
watchForInteractionStart: ({ start }: {
|
|
4
|
+
start: () => void;
|
|
5
|
+
}) => CleanupFn;
|
|
6
|
+
watchForInteractionEnd: ({ stop }: {
|
|
7
|
+
stop: () => void;
|
|
8
|
+
}) => CleanupFn;
|
|
9
|
+
}): {
|
|
10
|
+
registerUsage: () => CleanupFn;
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';
|
|
2
|
+
export declare function makeFixForAdapter({ watchForInteractionStart, watchForInteractionEnd, }: {
|
|
3
|
+
watchForInteractionStart: ({ start }: {
|
|
4
|
+
start: () => void;
|
|
5
|
+
}) => CleanupFn;
|
|
6
|
+
watchForInteractionEnd: ({ stop }: {
|
|
7
|
+
stop: () => void;
|
|
8
|
+
}) => CleanupFn;
|
|
9
|
+
}): {
|
|
10
|
+
registerUsage: () => CleanupFn;
|
|
11
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/modal-dialog",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.17.0",
|
|
4
4
|
"description": "A modal dialog displays content that requires user interaction, in a layer above the page.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -29,16 +29,17 @@
|
|
|
29
29
|
"@atlaskit/analytics-next": "^10.1.0",
|
|
30
30
|
"@atlaskit/blanket": "^13.3.0",
|
|
31
31
|
"@atlaskit/codemod-utils": "^4.2.0",
|
|
32
|
-
"@atlaskit/ds-lib": "^2.
|
|
32
|
+
"@atlaskit/ds-lib": "^2.6.0",
|
|
33
33
|
"@atlaskit/focus-ring": "^1.6.0",
|
|
34
|
-
"@atlaskit/icon": "^22.
|
|
34
|
+
"@atlaskit/icon": "^22.18.0",
|
|
35
35
|
"@atlaskit/layering": "^0.4.0",
|
|
36
36
|
"@atlaskit/motion": "^1.9.0",
|
|
37
37
|
"@atlaskit/platform-feature-flags": "^0.3.0",
|
|
38
38
|
"@atlaskit/portal": "^4.9.0",
|
|
39
|
-
"@atlaskit/
|
|
39
|
+
"@atlaskit/pragmatic-drag-and-drop": "^1.3.0",
|
|
40
|
+
"@atlaskit/primitives": "^12.2.0",
|
|
40
41
|
"@atlaskit/theme": "^13.0.0",
|
|
41
|
-
"@atlaskit/tokens": "^1.
|
|
42
|
+
"@atlaskit/tokens": "^1.61.0",
|
|
42
43
|
"@babel/runtime": "^7.0.0",
|
|
43
44
|
"@emotion/react": "^11.7.1",
|
|
44
45
|
"bind-event-listener": "^3.0.0",
|
|
@@ -57,9 +58,9 @@
|
|
|
57
58
|
"@atlaskit/button": "*",
|
|
58
59
|
"@atlaskit/checkbox": "^14.0.0",
|
|
59
60
|
"@atlaskit/dropdown-menu": "^12.18.0",
|
|
60
|
-
"@atlaskit/popup": "^1.
|
|
61
|
+
"@atlaskit/popup": "^1.27.0",
|
|
61
62
|
"@atlaskit/radio": "^6.5.0",
|
|
62
|
-
"@atlaskit/select": "^17.
|
|
63
|
+
"@atlaskit/select": "^17.19.0",
|
|
63
64
|
"@atlaskit/ssr": "*",
|
|
64
65
|
"@atlaskit/textfield": "^6.5.0",
|
|
65
66
|
"@atlaskit/tooltip": "^18.7.0",
|
|
@@ -74,6 +75,7 @@
|
|
|
74
75
|
"react-dom": "^16.8.0",
|
|
75
76
|
"react-lorem-component": "^0.13.0",
|
|
76
77
|
"storybook-addon-performance": "^0.16.0",
|
|
78
|
+
"tiny-invariant": "^1.2.0",
|
|
77
79
|
"typescript": "~5.4.2",
|
|
78
80
|
"wait-for-expect": "^1.2.0"
|
|
79
81
|
},
|