@atlaskit/top-layer 5.0.1 → 5.0.3
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 +14 -0
- package/dist/cjs/dialog/dialog-content.js +1 -1
- package/dist/cjs/internal/anchor-positioning/apply-anchor-positioning.js +32 -0
- package/dist/cjs/popover/popover.js +54 -33
- package/dist/cjs/popover-surface/popover-surface.js +1 -1
- package/dist/es2019/dialog/dialog-content.js +1 -1
- package/dist/es2019/internal/anchor-positioning/apply-anchor-positioning.js +32 -0
- package/dist/es2019/popover/popover.js +39 -17
- package/dist/es2019/popover-surface/popover-surface.js +1 -1
- package/dist/esm/dialog/dialog-content.js +1 -1
- package/dist/esm/internal/anchor-positioning/apply-anchor-positioning.js +32 -0
- package/dist/esm/popover/popover.js +54 -33
- package/dist/esm/popover-surface/popover-surface.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 5.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`c441257918c88`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c441257918c88) -
|
|
8
|
+
Extract and document the popover focus restoration fallback without changing behavior.
|
|
9
|
+
|
|
10
|
+
## 5.0.2
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- [`e8dcde6cc4e85`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e8dcde6cc4e85) -
|
|
15
|
+
Anchored Popovers now always stay visible, even if the element they are anchored to is invisible
|
|
16
|
+
|
|
3
17
|
## 5.0.1
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -57,6 +57,38 @@ function applyAnchorPositioning(_ref) {
|
|
|
57
57
|
placement: placement
|
|
58
58
|
})
|
|
59
59
|
},
|
|
60
|
+
/**
|
|
61
|
+
* **`position-visibility: always`**
|
|
62
|
+
*
|
|
63
|
+
* `position-visibility` is used to control the visibility of an anchored
|
|
64
|
+
* popover based on the visibility of the element being anchored to (the target).
|
|
65
|
+
*
|
|
66
|
+
* Default `position-visibility` value: `anchors-visible` → hide the anchored
|
|
67
|
+
* popover when the target is fully clipped by an ancestor (eg a scroll container)
|
|
68
|
+
* or is `visibility:hidden`.
|
|
69
|
+
* Sadly this "automatic hiding" does not actually "close" the popover,
|
|
70
|
+
* so things like `:popover-open` are still active, even though the popover
|
|
71
|
+
* is no longer painted and no longer receives pointer input. Chrome keeps it
|
|
72
|
+
* focusable and in the accessibility tree, so keyboard and screen reader users
|
|
73
|
+
* can still land inside a surface that is not painted.
|
|
74
|
+
* Per-engine behaviour: `notes/decisions/position-visibility-always.md`.
|
|
75
|
+
*
|
|
76
|
+
* Generally we have not run into issues with the default (`anchors-visible`)
|
|
77
|
+
*
|
|
78
|
+
* Exceptions:
|
|
79
|
+
* - Target is intentionally not visible (eg `position:absolute` moving it outside of
|
|
80
|
+
* its parent's "clipped boundary", or a `visibility:hidden` trigger)
|
|
81
|
+
* - A trigger is scrolled out of its scroll container while the popover is open.
|
|
82
|
+
*
|
|
83
|
+
* We are switching from `anchors-visible` → `always` _for now_ to force no
|
|
84
|
+
* automatic hiding of the popover. There seems to be no compelling reason to use
|
|
85
|
+
* the default value. If one arises in the future, we could look towards making
|
|
86
|
+
* this behaviour configurable.
|
|
87
|
+
*/
|
|
88
|
+
{
|
|
89
|
+
property: 'position-visibility',
|
|
90
|
+
value: 'always'
|
|
91
|
+
},
|
|
60
92
|
// Reset browser default popover positioning that conflicts
|
|
61
93
|
// with anchor positioning (UA: `inset: 0; margin: auto;`)
|
|
62
94
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* popover.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* popover.tsx generated by @compiled/babel-plugin v3.0.2 */
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
@@ -21,6 +21,29 @@ var _useAnimatedVisibility = require("../internal/use-animated-visibility");
|
|
|
21
21
|
var _useFocusWrap = require("../internal/use-focus-wrap");
|
|
22
22
|
var _useInitialFocus = require("../internal/use-initial-focus");
|
|
23
23
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
24
|
+
/**
|
|
25
|
+
* Native restoration only covers the first popover in an auto/hint stack, not each nested popover.
|
|
26
|
+
* This fallback also supports manual popovers, which have no native restoration target.
|
|
27
|
+
* See https://html.spec.whatwg.org/multipage/popover.html#show-popover (step 15.8).
|
|
28
|
+
*/
|
|
29
|
+
function restoreFocus(_ref) {
|
|
30
|
+
var popover = _ref.popover,
|
|
31
|
+
focusRestorationTarget = _ref.focusRestorationTarget;
|
|
32
|
+
if (!focusRestorationTarget) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
var ownerDocument = popover.ownerDocument;
|
|
36
|
+
// Native restoration has finished. Preserve focus moved outside the popover.
|
|
37
|
+
var activeElementAfterClose = ownerDocument.activeElement;
|
|
38
|
+
// Before close, we checked that focus was inside. Body can now mean focus was lost during close.
|
|
39
|
+
if (activeElementAfterClose === ownerDocument.body || popover.contains(activeElementAfterClose)) {
|
|
40
|
+
// Match native popover restoration, which does not scroll the viewport.
|
|
41
|
+
focusRestorationTarget.focus({
|
|
42
|
+
preventScroll: true
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
24
47
|
/**
|
|
25
48
|
* Detects `popover="hint"` support via DOM reflection. SSR-safe, cached.
|
|
26
49
|
*/
|
|
@@ -123,24 +146,24 @@ var POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', '
|
|
|
123
146
|
* should defer the open past the in-flight gesture; see
|
|
124
147
|
* `Select.openMenuAfterPointerUp`.
|
|
125
148
|
*/
|
|
126
|
-
var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Popover(
|
|
127
|
-
var children =
|
|
128
|
-
|
|
129
|
-
modeProp =
|
|
130
|
-
onClose =
|
|
131
|
-
onEnterFinish =
|
|
132
|
-
onExitFinish =
|
|
133
|
-
|
|
134
|
-
shouldAnimate =
|
|
135
|
-
placement =
|
|
136
|
-
testId =
|
|
137
|
-
isOpen =
|
|
138
|
-
enteringAnimationXcss =
|
|
139
|
-
exitingAnimationXcss =
|
|
140
|
-
role =
|
|
141
|
-
label =
|
|
142
|
-
labelledBy =
|
|
143
|
-
idProp =
|
|
149
|
+
var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Popover(_ref2, ref) {
|
|
150
|
+
var children = _ref2.children,
|
|
151
|
+
_ref2$mode = _ref2.mode,
|
|
152
|
+
modeProp = _ref2$mode === void 0 ? 'auto' : _ref2$mode,
|
|
153
|
+
onClose = _ref2.onClose,
|
|
154
|
+
onEnterFinish = _ref2.onEnterFinish,
|
|
155
|
+
onExitFinish = _ref2.onExitFinish,
|
|
156
|
+
_ref2$shouldAnimate = _ref2.shouldAnimate,
|
|
157
|
+
shouldAnimate = _ref2$shouldAnimate === void 0 ? false : _ref2$shouldAnimate,
|
|
158
|
+
placement = _ref2.placement,
|
|
159
|
+
testId = _ref2.testId,
|
|
160
|
+
isOpen = _ref2.isOpen,
|
|
161
|
+
enteringAnimationXcss = _ref2.enteringAnimationXcss,
|
|
162
|
+
exitingAnimationXcss = _ref2.exitingAnimationXcss,
|
|
163
|
+
role = _ref2.role,
|
|
164
|
+
label = _ref2.label,
|
|
165
|
+
labelledBy = _ref2.labelledBy,
|
|
166
|
+
idProp = _ref2.id;
|
|
144
167
|
var autoId = (0, _react.useId)();
|
|
145
168
|
var ownRef = (0, _react.useRef)(null);
|
|
146
169
|
var combinedRef = (0, _mergeRefs.default)([ownRef, ref].filter(Boolean));
|
|
@@ -189,8 +212,7 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
|
|
|
189
212
|
// Tracks the close reason, including our own hidePopover() calls.
|
|
190
213
|
var closeReasonRef = (0, _react.useRef)('light-dismiss');
|
|
191
214
|
|
|
192
|
-
//
|
|
193
|
-
// because the browser only restores the outermost.
|
|
215
|
+
// Pre-open focus target, cleared before close when restoration is not eligible.
|
|
194
216
|
var focusRestorationTargetRef = (0, _react.useRef)(null);
|
|
195
217
|
var handleBeforeToggle = (0, _react.useCallback)(function (event) {
|
|
196
218
|
var popover = event.currentTarget;
|
|
@@ -204,7 +226,11 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
|
|
|
204
226
|
return;
|
|
205
227
|
}
|
|
206
228
|
|
|
207
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Like native restoration, leave external focus alone and skip light dismiss.
|
|
231
|
+
* Check before closing so focus already on body is not mistaken for focus lost during close.
|
|
232
|
+
* See https://html.spec.whatwg.org/multipage/popover.html#hide-popover-algorithm (step 20.2).
|
|
233
|
+
*/
|
|
208
234
|
if (closeReasonRef.current === 'light-dismiss' || !popover.contains(activeElement)) {
|
|
209
235
|
focusRestorationTargetRef.current = null;
|
|
210
236
|
}
|
|
@@ -220,17 +246,12 @@ var Popover = exports.Popover = /*#__PURE__*/(0, _react.forwardRef)(function Pop
|
|
|
220
246
|
// Reset reason so a stale 'escape' from a race with Escape keydown
|
|
221
247
|
// does not corrupt the next browser-dismiss cycle.
|
|
222
248
|
closeReasonRef.current = 'light-dismiss';
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
focusRestorationTarget.focus({
|
|
230
|
-
preventScroll: true
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
}
|
|
249
|
+
|
|
250
|
+
// Run after native restoration, before notifying the consumer, which may move focus itself.
|
|
251
|
+
restoreFocus({
|
|
252
|
+
popover: popover,
|
|
253
|
+
focusRestorationTarget: focusRestorationTarget
|
|
254
|
+
});
|
|
234
255
|
|
|
235
256
|
// Programmatic closes are already known to the consumer.
|
|
236
257
|
if (reason !== 'programmatic') {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* dialog-content.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* dialog-content.tsx generated by @compiled/babel-plugin v3.0.2 */
|
|
2
2
|
import "./dialog-content.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
4
|
import React, { forwardRef, useCallback, useId, useLayoutEffect, useRef } from 'react';
|
|
@@ -51,6 +51,38 @@ export function applyAnchorPositioning({
|
|
|
51
51
|
placement
|
|
52
52
|
})
|
|
53
53
|
},
|
|
54
|
+
/**
|
|
55
|
+
* **`position-visibility: always`**
|
|
56
|
+
*
|
|
57
|
+
* `position-visibility` is used to control the visibility of an anchored
|
|
58
|
+
* popover based on the visibility of the element being anchored to (the target).
|
|
59
|
+
*
|
|
60
|
+
* Default `position-visibility` value: `anchors-visible` → hide the anchored
|
|
61
|
+
* popover when the target is fully clipped by an ancestor (eg a scroll container)
|
|
62
|
+
* or is `visibility:hidden`.
|
|
63
|
+
* Sadly this "automatic hiding" does not actually "close" the popover,
|
|
64
|
+
* so things like `:popover-open` are still active, even though the popover
|
|
65
|
+
* is no longer painted and no longer receives pointer input. Chrome keeps it
|
|
66
|
+
* focusable and in the accessibility tree, so keyboard and screen reader users
|
|
67
|
+
* can still land inside a surface that is not painted.
|
|
68
|
+
* Per-engine behaviour: `notes/decisions/position-visibility-always.md`.
|
|
69
|
+
*
|
|
70
|
+
* Generally we have not run into issues with the default (`anchors-visible`)
|
|
71
|
+
*
|
|
72
|
+
* Exceptions:
|
|
73
|
+
* - Target is intentionally not visible (eg `position:absolute` moving it outside of
|
|
74
|
+
* its parent's "clipped boundary", or a `visibility:hidden` trigger)
|
|
75
|
+
* - A trigger is scrolled out of its scroll container while the popover is open.
|
|
76
|
+
*
|
|
77
|
+
* We are switching from `anchors-visible` → `always` _for now_ to force no
|
|
78
|
+
* automatic hiding of the popover. There seems to be no compelling reason to use
|
|
79
|
+
* the default value. If one arises in the future, we could look towards making
|
|
80
|
+
* this behaviour configurable.
|
|
81
|
+
*/
|
|
82
|
+
{
|
|
83
|
+
property: 'position-visibility',
|
|
84
|
+
value: 'always'
|
|
85
|
+
},
|
|
54
86
|
// Reset browser default popover positioning that conflicts
|
|
55
87
|
// with anchor positioning (UA: `inset: 0; margin: auto;`)
|
|
56
88
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* popover.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* popover.tsx generated by @compiled/babel-plugin v3.0.2 */
|
|
2
2
|
import "./popover.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
4
|
import React, { forwardRef, useCallback, useId, useLayoutEffect, useMemo, useRef } from 'react';
|
|
@@ -12,6 +12,32 @@ import { resolvePlacement } from '../internal/resolve-placement';
|
|
|
12
12
|
import { useAnimatedVisibility } from '../internal/use-animated-visibility';
|
|
13
13
|
import { useFocusWrap } from '../internal/use-focus-wrap';
|
|
14
14
|
import { useInitialFocus } from '../internal/use-initial-focus';
|
|
15
|
+
/**
|
|
16
|
+
* Native restoration only covers the first popover in an auto/hint stack, not each nested popover.
|
|
17
|
+
* This fallback also supports manual popovers, which have no native restoration target.
|
|
18
|
+
* See https://html.spec.whatwg.org/multipage/popover.html#show-popover (step 15.8).
|
|
19
|
+
*/
|
|
20
|
+
function restoreFocus({
|
|
21
|
+
popover,
|
|
22
|
+
focusRestorationTarget
|
|
23
|
+
}) {
|
|
24
|
+
if (!focusRestorationTarget) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const {
|
|
28
|
+
ownerDocument
|
|
29
|
+
} = popover;
|
|
30
|
+
// Native restoration has finished. Preserve focus moved outside the popover.
|
|
31
|
+
const activeElementAfterClose = ownerDocument.activeElement;
|
|
32
|
+
// Before close, we checked that focus was inside. Body can now mean focus was lost during close.
|
|
33
|
+
if (activeElementAfterClose === ownerDocument.body || popover.contains(activeElementAfterClose)) {
|
|
34
|
+
// Match native popover restoration, which does not scroll the viewport.
|
|
35
|
+
focusRestorationTarget.focus({
|
|
36
|
+
preventScroll: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
15
41
|
/**
|
|
16
42
|
* Detects `popover="hint"` support via DOM reflection. SSR-safe, cached.
|
|
17
43
|
*/
|
|
@@ -181,8 +207,7 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
181
207
|
// Tracks the close reason, including our own hidePopover() calls.
|
|
182
208
|
const closeReasonRef = useRef('light-dismiss');
|
|
183
209
|
|
|
184
|
-
//
|
|
185
|
-
// because the browser only restores the outermost.
|
|
210
|
+
// Pre-open focus target, cleared before close when restoration is not eligible.
|
|
186
211
|
const focusRestorationTargetRef = useRef(null);
|
|
187
212
|
const handleBeforeToggle = useCallback(event => {
|
|
188
213
|
const popover = event.currentTarget;
|
|
@@ -200,7 +225,11 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
200
225
|
return;
|
|
201
226
|
}
|
|
202
227
|
|
|
203
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Like native restoration, leave external focus alone and skip light dismiss.
|
|
230
|
+
* Check before closing so focus already on body is not mistaken for focus lost during close.
|
|
231
|
+
* See https://html.spec.whatwg.org/multipage/popover.html#hide-popover-algorithm (step 20.2).
|
|
232
|
+
*/
|
|
204
233
|
if (closeReasonRef.current === 'light-dismiss' || !popover.contains(activeElement)) {
|
|
205
234
|
focusRestorationTargetRef.current = null;
|
|
206
235
|
}
|
|
@@ -216,19 +245,12 @@ export const Popover = /*#__PURE__*/forwardRef(function Popover({
|
|
|
216
245
|
// Reset reason so a stale 'escape' from a race with Escape keydown
|
|
217
246
|
// does not corrupt the next browser-dismiss cycle.
|
|
218
247
|
closeReasonRef.current = 'light-dismiss';
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (activeElementAfterClose === ownerDocument.body || popover.contains(activeElementAfterClose)) {
|
|
226
|
-
// Match native popover restoration, which does not scroll the viewport.
|
|
227
|
-
focusRestorationTarget.focus({
|
|
228
|
-
preventScroll: true
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
}
|
|
248
|
+
|
|
249
|
+
// Run after native restoration, before notifying the consumer, which may move focus itself.
|
|
250
|
+
restoreFocus({
|
|
251
|
+
popover,
|
|
252
|
+
focusRestorationTarget
|
|
253
|
+
});
|
|
232
254
|
|
|
233
255
|
// Programmatic closes are already known to the consumer.
|
|
234
256
|
if (reason !== 'programmatic') {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* dialog-content.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* dialog-content.tsx generated by @compiled/babel-plugin v3.0.2 */
|
|
2
2
|
import "./dialog-content.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
4
|
import React, { forwardRef, useCallback, useId, useLayoutEffect, useRef } from 'react';
|
|
@@ -51,6 +51,38 @@ export function applyAnchorPositioning(_ref) {
|
|
|
51
51
|
placement: placement
|
|
52
52
|
})
|
|
53
53
|
},
|
|
54
|
+
/**
|
|
55
|
+
* **`position-visibility: always`**
|
|
56
|
+
*
|
|
57
|
+
* `position-visibility` is used to control the visibility of an anchored
|
|
58
|
+
* popover based on the visibility of the element being anchored to (the target).
|
|
59
|
+
*
|
|
60
|
+
* Default `position-visibility` value: `anchors-visible` → hide the anchored
|
|
61
|
+
* popover when the target is fully clipped by an ancestor (eg a scroll container)
|
|
62
|
+
* or is `visibility:hidden`.
|
|
63
|
+
* Sadly this "automatic hiding" does not actually "close" the popover,
|
|
64
|
+
* so things like `:popover-open` are still active, even though the popover
|
|
65
|
+
* is no longer painted and no longer receives pointer input. Chrome keeps it
|
|
66
|
+
* focusable and in the accessibility tree, so keyboard and screen reader users
|
|
67
|
+
* can still land inside a surface that is not painted.
|
|
68
|
+
* Per-engine behaviour: `notes/decisions/position-visibility-always.md`.
|
|
69
|
+
*
|
|
70
|
+
* Generally we have not run into issues with the default (`anchors-visible`)
|
|
71
|
+
*
|
|
72
|
+
* Exceptions:
|
|
73
|
+
* - Target is intentionally not visible (eg `position:absolute` moving it outside of
|
|
74
|
+
* its parent's "clipped boundary", or a `visibility:hidden` trigger)
|
|
75
|
+
* - A trigger is scrolled out of its scroll container while the popover is open.
|
|
76
|
+
*
|
|
77
|
+
* We are switching from `anchors-visible` → `always` _for now_ to force no
|
|
78
|
+
* automatic hiding of the popover. There seems to be no compelling reason to use
|
|
79
|
+
* the default value. If one arises in the future, we could look towards making
|
|
80
|
+
* this behaviour configurable.
|
|
81
|
+
*/
|
|
82
|
+
{
|
|
83
|
+
property: 'position-visibility',
|
|
84
|
+
value: 'always'
|
|
85
|
+
},
|
|
54
86
|
// Reset browser default popover positioning that conflicts
|
|
55
87
|
// with anchor positioning (UA: `inset: 0; margin: auto;`)
|
|
56
88
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* popover.tsx generated by @compiled/babel-plugin v3.0.
|
|
1
|
+
/* popover.tsx generated by @compiled/babel-plugin v3.0.2 */
|
|
2
2
|
import "./popover.compiled.css";
|
|
3
3
|
import { ax, ix } from "@compiled/react/runtime";
|
|
4
4
|
import React, { forwardRef, useCallback, useId, useLayoutEffect, useMemo, useRef } from 'react';
|
|
@@ -12,6 +12,29 @@ import { resolvePlacement } from '../internal/resolve-placement';
|
|
|
12
12
|
import { useAnimatedVisibility } from '../internal/use-animated-visibility';
|
|
13
13
|
import { useFocusWrap } from '../internal/use-focus-wrap';
|
|
14
14
|
import { useInitialFocus } from '../internal/use-initial-focus';
|
|
15
|
+
/**
|
|
16
|
+
* Native restoration only covers the first popover in an auto/hint stack, not each nested popover.
|
|
17
|
+
* This fallback also supports manual popovers, which have no native restoration target.
|
|
18
|
+
* See https://html.spec.whatwg.org/multipage/popover.html#show-popover (step 15.8).
|
|
19
|
+
*/
|
|
20
|
+
function restoreFocus(_ref) {
|
|
21
|
+
var popover = _ref.popover,
|
|
22
|
+
focusRestorationTarget = _ref.focusRestorationTarget;
|
|
23
|
+
if (!focusRestorationTarget) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
var ownerDocument = popover.ownerDocument;
|
|
27
|
+
// Native restoration has finished. Preserve focus moved outside the popover.
|
|
28
|
+
var activeElementAfterClose = ownerDocument.activeElement;
|
|
29
|
+
// Before close, we checked that focus was inside. Body can now mean focus was lost during close.
|
|
30
|
+
if (activeElementAfterClose === ownerDocument.body || popover.contains(activeElementAfterClose)) {
|
|
31
|
+
// Match native popover restoration, which does not scroll the viewport.
|
|
32
|
+
focusRestorationTarget.focus({
|
|
33
|
+
preventScroll: true
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
/**
|
|
16
39
|
* Detects `popover="hint"` support via DOM reflection. SSR-safe, cached.
|
|
17
40
|
*/
|
|
@@ -114,24 +137,24 @@ var POPUP_ROLES = new Set(['menu', 'listbox', 'dialog', 'alertdialog', 'tree', '
|
|
|
114
137
|
* should defer the open past the in-flight gesture; see
|
|
115
138
|
* `Select.openMenuAfterPointerUp`.
|
|
116
139
|
*/
|
|
117
|
-
export var Popover = /*#__PURE__*/forwardRef(function Popover(
|
|
118
|
-
var children =
|
|
119
|
-
|
|
120
|
-
modeProp =
|
|
121
|
-
onClose =
|
|
122
|
-
onEnterFinish =
|
|
123
|
-
onExitFinish =
|
|
124
|
-
|
|
125
|
-
shouldAnimate =
|
|
126
|
-
placement =
|
|
127
|
-
testId =
|
|
128
|
-
isOpen =
|
|
129
|
-
enteringAnimationXcss =
|
|
130
|
-
exitingAnimationXcss =
|
|
131
|
-
role =
|
|
132
|
-
label =
|
|
133
|
-
labelledBy =
|
|
134
|
-
idProp =
|
|
140
|
+
export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref2, ref) {
|
|
141
|
+
var children = _ref2.children,
|
|
142
|
+
_ref2$mode = _ref2.mode,
|
|
143
|
+
modeProp = _ref2$mode === void 0 ? 'auto' : _ref2$mode,
|
|
144
|
+
onClose = _ref2.onClose,
|
|
145
|
+
onEnterFinish = _ref2.onEnterFinish,
|
|
146
|
+
onExitFinish = _ref2.onExitFinish,
|
|
147
|
+
_ref2$shouldAnimate = _ref2.shouldAnimate,
|
|
148
|
+
shouldAnimate = _ref2$shouldAnimate === void 0 ? false : _ref2$shouldAnimate,
|
|
149
|
+
placement = _ref2.placement,
|
|
150
|
+
testId = _ref2.testId,
|
|
151
|
+
isOpen = _ref2.isOpen,
|
|
152
|
+
enteringAnimationXcss = _ref2.enteringAnimationXcss,
|
|
153
|
+
exitingAnimationXcss = _ref2.exitingAnimationXcss,
|
|
154
|
+
role = _ref2.role,
|
|
155
|
+
label = _ref2.label,
|
|
156
|
+
labelledBy = _ref2.labelledBy,
|
|
157
|
+
idProp = _ref2.id;
|
|
135
158
|
var autoId = useId();
|
|
136
159
|
var ownRef = useRef(null);
|
|
137
160
|
var combinedRef = mergeRefs([ownRef, ref].filter(Boolean));
|
|
@@ -180,8 +203,7 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
180
203
|
// Tracks the close reason, including our own hidePopover() calls.
|
|
181
204
|
var closeReasonRef = useRef('light-dismiss');
|
|
182
205
|
|
|
183
|
-
//
|
|
184
|
-
// because the browser only restores the outermost.
|
|
206
|
+
// Pre-open focus target, cleared before close when restoration is not eligible.
|
|
185
207
|
var focusRestorationTargetRef = useRef(null);
|
|
186
208
|
var handleBeforeToggle = useCallback(function (event) {
|
|
187
209
|
var popover = event.currentTarget;
|
|
@@ -195,7 +217,11 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
195
217
|
return;
|
|
196
218
|
}
|
|
197
219
|
|
|
198
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Like native restoration, leave external focus alone and skip light dismiss.
|
|
222
|
+
* Check before closing so focus already on body is not mistaken for focus lost during close.
|
|
223
|
+
* See https://html.spec.whatwg.org/multipage/popover.html#hide-popover-algorithm (step 20.2).
|
|
224
|
+
*/
|
|
199
225
|
if (closeReasonRef.current === 'light-dismiss' || !popover.contains(activeElement)) {
|
|
200
226
|
focusRestorationTargetRef.current = null;
|
|
201
227
|
}
|
|
@@ -211,17 +237,12 @@ export var Popover = /*#__PURE__*/forwardRef(function Popover(_ref, ref) {
|
|
|
211
237
|
// Reset reason so a stale 'escape' from a race with Escape keydown
|
|
212
238
|
// does not corrupt the next browser-dismiss cycle.
|
|
213
239
|
closeReasonRef.current = 'light-dismiss';
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
focusRestorationTarget.focus({
|
|
221
|
-
preventScroll: true
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
240
|
+
|
|
241
|
+
// Run after native restoration, before notifying the consumer, which may move focus itself.
|
|
242
|
+
restoreFocus({
|
|
243
|
+
popover: popover,
|
|
244
|
+
focusRestorationTarget: focusRestorationTarget
|
|
245
|
+
});
|
|
225
246
|
|
|
226
247
|
// Programmatic closes are already known to the consumer.
|
|
227
248
|
if (reason !== 'programmatic') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/top-layer",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3",
|
|
4
4
|
"description": "Low-level layering primitives based on popover and dialog",
|
|
5
5
|
"homepage": "https://atlassian.design/components/top-layer",
|
|
6
6
|
"repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
|