@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 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
@@ -1,4 +1,4 @@
1
- /* dialog-content.tsx generated by @compiled/babel-plugin v3.0.1 */
1
+ /* dialog-content.tsx generated by @compiled/babel-plugin v3.0.2 */
2
2
  "use strict";
3
3
 
4
4
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
@@ -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 */
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(_ref, ref) {
127
- var children = _ref.children,
128
- _ref$mode = _ref.mode,
129
- modeProp = _ref$mode === void 0 ? 'auto' : _ref$mode,
130
- onClose = _ref.onClose,
131
- onEnterFinish = _ref.onEnterFinish,
132
- onExitFinish = _ref.onExitFinish,
133
- _ref$shouldAnimate = _ref.shouldAnimate,
134
- shouldAnimate = _ref$shouldAnimate === void 0 ? false : _ref$shouldAnimate,
135
- placement = _ref.placement,
136
- testId = _ref.testId,
137
- isOpen = _ref.isOpen,
138
- enteringAnimationXcss = _ref.enteringAnimationXcss,
139
- exitingAnimationXcss = _ref.exitingAnimationXcss,
140
- role = _ref.role,
141
- label = _ref.label,
142
- labelledBy = _ref.labelledBy,
143
- idProp = _ref.id;
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
- // Snapshot of pre-open focus, used to restore focus for nested popovers
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
- // Check before closing so focus already on body is not mistaken for focus lost during close.
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
- if (focusRestorationTarget) {
224
- var ownerDocument = popover.ownerDocument;
225
- // Native restoration has finished. Preserve focus moved outside the popover.
226
- var activeElementAfterClose = ownerDocument.activeElement;
227
- if (activeElementAfterClose === ownerDocument.body || popover.contains(activeElementAfterClose)) {
228
- // Match native popover restoration, which does not scroll the viewport.
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
- /* popover-surface.tsx generated by @compiled/babel-plugin v3.0.1 */
1
+ /* popover-surface.tsx generated by @compiled/babel-plugin v3.0.2 */
2
2
  "use strict";
3
3
 
4
4
  var _typeof = require("@babel/runtime/helpers/typeof");
@@ -1,4 +1,4 @@
1
- /* dialog-content.tsx generated by @compiled/babel-plugin v3.0.1 */
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 */
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
- // Snapshot of pre-open focus, used to restore focus for nested popovers
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
- // Check before closing so focus already on body is not mistaken for focus lost during close.
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
- if (focusRestorationTarget) {
220
- const {
221
- ownerDocument
222
- } = popover;
223
- // Native restoration has finished. Preserve focus moved outside the popover.
224
- const activeElementAfterClose = ownerDocument.activeElement;
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
- /* popover-surface.tsx generated by @compiled/babel-plugin v3.0.1 */
1
+ /* popover-surface.tsx generated by @compiled/babel-plugin v3.0.2 */
2
2
  import "./popover-surface.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
@@ -1,4 +1,4 @@
1
- /* dialog-content.tsx generated by @compiled/babel-plugin v3.0.1 */
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 */
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(_ref, ref) {
118
- var children = _ref.children,
119
- _ref$mode = _ref.mode,
120
- modeProp = _ref$mode === void 0 ? 'auto' : _ref$mode,
121
- onClose = _ref.onClose,
122
- onEnterFinish = _ref.onEnterFinish,
123
- onExitFinish = _ref.onExitFinish,
124
- _ref$shouldAnimate = _ref.shouldAnimate,
125
- shouldAnimate = _ref$shouldAnimate === void 0 ? false : _ref$shouldAnimate,
126
- placement = _ref.placement,
127
- testId = _ref.testId,
128
- isOpen = _ref.isOpen,
129
- enteringAnimationXcss = _ref.enteringAnimationXcss,
130
- exitingAnimationXcss = _ref.exitingAnimationXcss,
131
- role = _ref.role,
132
- label = _ref.label,
133
- labelledBy = _ref.labelledBy,
134
- idProp = _ref.id;
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
- // Snapshot of pre-open focus, used to restore focus for nested popovers
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
- // Check before closing so focus already on body is not mistaken for focus lost during close.
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
- if (focusRestorationTarget) {
215
- var ownerDocument = popover.ownerDocument;
216
- // Native restoration has finished. Preserve focus moved outside the popover.
217
- var activeElementAfterClose = ownerDocument.activeElement;
218
- if (activeElementAfterClose === ownerDocument.body || popover.contains(activeElementAfterClose)) {
219
- // Match native popover restoration, which does not scroll the viewport.
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') {
@@ -1,4 +1,4 @@
1
- /* popover-surface.tsx generated by @compiled/babel-plugin v3.0.1 */
1
+ /* popover-surface.tsx generated by @compiled/babel-plugin v3.0.2 */
2
2
  import "./popover-surface.compiled.css";
3
3
  import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "5.0.1",
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",