@atlaskit/top-layer 5.0.2 → 5.0.4

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,18 @@
1
1
  # @atlaskit/top-layer
2
2
 
3
+ ## 5.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 5.0.3
10
+
11
+ ### Patch Changes
12
+
13
+ - [`c441257918c88`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c441257918c88) -
14
+ Extract and document the popover focus restoration fallback without changing behavior.
15
+
3
16
  ## 5.0.2
4
17
 
5
18
  ### Patch Changes
@@ -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') {
@@ -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') {
@@ -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') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/top-layer",
3
- "version": "5.0.2",
3
+ "version": "5.0.4",
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",
@@ -40,7 +40,7 @@
40
40
  "@atlaskit/ds-lib": "^8.0.0",
41
41
  "@atlaskit/layering": "^5.2.0",
42
42
  "@atlaskit/react-compiler-gating": "^0.2.0",
43
- "@atlaskit/tokens": "^17.0.0",
43
+ "@atlaskit/tokens": "^18.0.0",
44
44
  "@babel/runtime": "^7.0.0",
45
45
  "@compiled/react": "^1.0.2",
46
46
  "bind-event-listener": "^3.0.0",