@atlaskit/top-layer 6.0.0 → 6.1.1
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 +28 -0
- package/README.md +23 -25
- package/dist/cjs/dialog/create-close-event.js +2 -1
- package/dist/cjs/internal/use-animated-visibility.js +24 -3
- package/dist/cjs/internal/use-focus-wrap.js +1 -1
- package/dist/cjs/internal/use-initial-focus.js +1 -1
- package/dist/cjs/placement-map/index.js +1 -1
- package/dist/cjs/popover/create-close-event.js +2 -1
- package/dist/cjs/testing/flush-popover-exit.js +94 -0
- package/dist/cjs/use-arrow-navigation/use-arrow-navigation.js +2 -1
- package/dist/es2019/dialog/create-close-event.js +2 -1
- package/dist/es2019/internal/use-animated-visibility.js +25 -3
- package/dist/es2019/internal/use-focus-wrap.js +1 -1
- package/dist/es2019/internal/use-initial-focus.js +1 -1
- package/dist/es2019/placement-map/index.js +1 -1
- package/dist/es2019/popover/create-close-event.js +2 -1
- package/dist/es2019/testing/flush-popover-exit.js +57 -0
- package/dist/es2019/use-arrow-navigation/use-arrow-navigation.js +2 -1
- package/dist/esm/dialog/create-close-event.js +2 -1
- package/dist/esm/internal/use-animated-visibility.js +24 -3
- package/dist/esm/internal/use-focus-wrap.js +1 -1
- package/dist/esm/internal/use-initial-focus.js +1 -1
- package/dist/esm/placement-map/index.js +1 -1
- package/dist/esm/popover/create-close-event.js +2 -1
- package/dist/esm/testing/flush-popover-exit.js +87 -0
- package/dist/esm/use-arrow-navigation/use-arrow-navigation.js +2 -1
- package/dist/types/dialog/create-close-event.d.ts +2 -1
- package/dist/types/internal/use-animated-visibility.d.ts +1 -0
- package/dist/types/placement-map/index.d.ts +1 -1
- package/dist/types/popover/create-close-event.d.ts +2 -1
- package/dist/types/testing/flush-popover-exit.d.ts +22 -0
- package/dist/types/use-arrow-navigation/use-arrow-navigation.d.ts +2 -1
- package/package.json +5 -5
- package/testing/flush-popover-exit/package.json +10 -0
- package/dist/cjs/internal/should-focus-into-popover.js +0 -19
- package/dist/es2019/internal/should-focus-into-popover.js +0 -14
- package/dist/esm/internal/should-focus-into-popover.js +0 -13
- package/dist/types/internal/should-focus-into-popover.d.ts +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @atlaskit/top-layer
|
|
2
2
|
|
|
3
|
+
## 6.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`1849f66e0bf17`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1849f66e0bf17) -
|
|
8
|
+
Remove an unused internal focus helper and fix stale README examples and import paths.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
|
|
11
|
+
## 6.1.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [`457c77d8f6992`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/457c77d8f6992) -
|
|
16
|
+
Adds a `@atlaskit/top-layer/testing/flush-popover-exit` entrypoint exporting `flushPopoverExit()`,
|
|
17
|
+
a Jest helper for jsdom. Top-layer settles a `Popover` exit in a native promise microtask after
|
|
18
|
+
the closed `toggle`, which Jest fake timers do not drain, so a synchronous
|
|
19
|
+
`act(() => jest.runOnlyPendingTimers())` returns before `onExitFinish` fires and the host
|
|
20
|
+
unmounts. `await flushPopoverExit()` runs the pending fake timers and yields once inside an async
|
|
21
|
+
`act` (or waits one real task when fake timers are off) so tests can assert the closed state.
|
|
22
|
+
Requires React 18.3 or newer. Browser behaviour is unchanged.
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- [`457c77d8f6992`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/457c77d8f6992) -
|
|
27
|
+
`Popover` and `Dialog` no longer keep their exit styles when they reopen straight after a browser
|
|
28
|
+
dismiss, or when React StrictMode runs effects twice.
|
|
29
|
+
- Updated dependencies
|
|
30
|
+
|
|
3
31
|
## 6.0.0
|
|
4
32
|
|
|
5
33
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -12,14 +12,15 @@ placement or size — compose it with the `useAnchoredPopover` hook when you nee
|
|
|
12
12
|
content.
|
|
13
13
|
|
|
14
14
|
```tsx
|
|
15
|
-
import { useRef } from 'react';
|
|
15
|
+
import { useRef, useState } from 'react';
|
|
16
16
|
import { getAriaForTrigger } from '@atlaskit/top-layer/get-aria-for-trigger';
|
|
17
|
-
import { Popover } from '@atlaskit/top-layer/popover';
|
|
17
|
+
import { Popover } from '@atlaskit/top-layer/popover/popover';
|
|
18
18
|
import { PopoverSurface } from '@atlaskit/top-layer/popover-surface';
|
|
19
19
|
import { usePopoverId } from '@atlaskit/top-layer/use-popover-id';
|
|
20
20
|
import { useAnchoredPopover } from '@atlaskit/top-layer/use-anchored-popover';
|
|
21
21
|
|
|
22
|
-
function MyPopup(
|
|
22
|
+
function MyPopup() {
|
|
23
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
23
24
|
const triggerRef = useRef<HTMLButtonElement>(null);
|
|
24
25
|
const popoverRef = useRef<HTMLDivElement>(null);
|
|
25
26
|
const popoverId = usePopoverId();
|
|
@@ -35,7 +36,7 @@ function MyPopup({ isOpen, onClose }: { isOpen: boolean; onClose: () => void })
|
|
|
35
36
|
<>
|
|
36
37
|
<button
|
|
37
38
|
ref={triggerRef}
|
|
38
|
-
onClick={() =>
|
|
39
|
+
onClick={() => setIsOpen((value) => !value)}
|
|
39
40
|
{...getAriaForTrigger({ role: 'dialog', isOpen, popoverId })}
|
|
40
41
|
>
|
|
41
42
|
Open
|
|
@@ -47,7 +48,7 @@ function MyPopup({ isOpen, onClose }: { isOpen: boolean; onClose: () => void })
|
|
|
47
48
|
label="Settings"
|
|
48
49
|
isOpen={isOpen}
|
|
49
50
|
shouldAnimate
|
|
50
|
-
onClose={
|
|
51
|
+
onClose={() => setIsOpen(false)}
|
|
51
52
|
>
|
|
52
53
|
<PopoverSurface>Content here</PopoverSurface>
|
|
53
54
|
</Popover>
|
|
@@ -72,27 +73,24 @@ function MyPopup({ isOpen, onClose }: { isOpen: boolean; onClose: () => void })
|
|
|
72
73
|
|
|
73
74
|
## Dialog
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
A modal dialog on the native `<dialog>` element. `isOpen` calls `showModal()` and `close()`. It has
|
|
77
|
+
no visual opinions (no width, surface or layout); consumers such as `@atlaskit/modal-dialog` add
|
|
78
|
+
their own. A `label` or `labelledBy` is required.
|
|
76
79
|
|
|
77
80
|
```tsx
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<Dialog.Title>Heading</Dialog.Title>
|
|
85
|
-
<Dialog.CloseButton />
|
|
86
|
-
</Dialog.Header>
|
|
87
|
-
<Dialog.Body>Content</Dialog.Body>
|
|
88
|
-
<Dialog.Footer>Actions</Dialog.Footer>
|
|
89
|
-
</Dialog.Surface>
|
|
90
|
-
</Dialog.Content>
|
|
91
|
-
</Dialog>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
81
|
+
import { Dialog } from '@atlaskit/top-layer/dialog-content';
|
|
82
|
+
|
|
83
|
+
<Dialog isOpen={isOpen} onClose={() => setIsOpen(false)} labelledBy={titleId}>
|
|
84
|
+
<h2 id={titleId}>Heading</h2>
|
|
85
|
+
Content
|
|
86
|
+
</Dialog>;
|
|
94
87
|
```
|
|
95
88
|
|
|
89
|
+
- `onClose({ reason })` fires after an allowed Escape (`'escape'`) or backdrop click
|
|
90
|
+
(`'overlay-click'`). Set `isOpen={false}` in response.
|
|
91
|
+
- `dismissedBy` limits user dismissal: `'escape-and-outside-click'` (default), `'escape'` or
|
|
92
|
+
`'none'`.
|
|
93
|
+
|
|
96
94
|
## Animations
|
|
97
95
|
|
|
98
96
|
Both `Popover` and `Dialog` support CSS-based entry/exit animations via the `shouldAnimate` prop.
|
|
@@ -106,9 +104,9 @@ for entry and
|
|
|
106
104
|
Pass `shouldAnimate` to enable the default popover entry and exit animation:
|
|
107
105
|
|
|
108
106
|
```tsx
|
|
109
|
-
import { Popover } from '@atlaskit/top-layer/popover';
|
|
107
|
+
import { Popover } from '@atlaskit/top-layer/popover/popover';
|
|
110
108
|
|
|
111
|
-
<Popover shouldAnimate role="dialog" label="My popover" isOpen={isOpen}>
|
|
109
|
+
<Popover shouldAnimate role="dialog" label="My popover" isOpen={isOpen} onClose={onClose}>
|
|
112
110
|
Content
|
|
113
111
|
</Popover>;
|
|
114
112
|
```
|
|
@@ -124,7 +122,7 @@ the phase-specific animation styles.
|
|
|
124
122
|
Pass `shouldAnimate` to enable the default dialog entry and exit animation:
|
|
125
123
|
|
|
126
124
|
```tsx
|
|
127
|
-
import { Dialog } from '@atlaskit/top-layer/dialog';
|
|
125
|
+
import { Dialog } from '@atlaskit/top-layer/dialog-content';
|
|
128
126
|
|
|
129
127
|
<Dialog shouldAnimate isOpen={isOpen} onClose={onClose} label="My dialog">
|
|
130
128
|
Content
|
|
@@ -16,7 +16,8 @@ exports.createCloseEvent = createCloseEvent;
|
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```tsx
|
|
19
|
-
* import { createCloseEvent
|
|
19
|
+
* import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
20
|
+
* import { type TDialogCloseReason } from '@atlaskit/top-layer/dialog/types';
|
|
20
21
|
*
|
|
21
22
|
* function onDialogClose({ reason }: { reason: TDialogCloseReason }) {
|
|
22
23
|
* legacyOnClose(createCloseEvent({ reason }));
|
|
@@ -71,6 +71,7 @@ function runOnAnimationsSettled(_ref2) {
|
|
|
71
71
|
* interrupts: entering → exiting (close mid-entry)
|
|
72
72
|
* exiting → entering (reopen mid-exit, animated)
|
|
73
73
|
* exiting → open (reopen mid-handshake, non-animated)
|
|
74
|
+
* exiting → open (native reopen while controlled intent is open)
|
|
74
75
|
* ```
|
|
75
76
|
*/
|
|
76
77
|
|
|
@@ -134,6 +135,19 @@ function getNextVisibilityState(state, action) {
|
|
|
134
135
|
phase: 'exiting'
|
|
135
136
|
});
|
|
136
137
|
}
|
|
138
|
+
|
|
139
|
+
// A browser dismiss started the exit, and something showed the element
|
|
140
|
+
// again before the exit settled, while controlled intent stayed open. For
|
|
141
|
+
// example, `@atlaskit/tooltip` re-shows after a light dismiss in the same
|
|
142
|
+
// task. The element never painted closed, so go back to `open`.
|
|
143
|
+
if (action.type === 'native-open-started') {
|
|
144
|
+
if (state.phase !== 'exiting' || state.controlledIntent !== 'open') {
|
|
145
|
+
return state;
|
|
146
|
+
}
|
|
147
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
148
|
+
phase: 'open'
|
|
149
|
+
});
|
|
150
|
+
}
|
|
137
151
|
if (action.type === 'entry-settled') {
|
|
138
152
|
if (state.phase !== 'entering') {
|
|
139
153
|
return state;
|
|
@@ -251,9 +265,16 @@ function useAnimatedVisibility(_ref4) {
|
|
|
251
265
|
cancelExitSettlementRef.current();
|
|
252
266
|
// Snapshot currentTarget because the DOM clears it after event dispatch.
|
|
253
267
|
var element = event.currentTarget;
|
|
254
|
-
if (event.newState === 'open'
|
|
255
|
-
element
|
|
256
|
-
|
|
268
|
+
if (event.newState === 'open') {
|
|
269
|
+
if (element instanceof HTMLElement) {
|
|
270
|
+
element.removeAttribute('inert');
|
|
271
|
+
element.removeAttribute('aria-hidden');
|
|
272
|
+
}
|
|
273
|
+
// Dispatched on every native open. The reducer only acts when a browser
|
|
274
|
+
// dismiss left the host `exiting` while `isOpen` stayed `true`.
|
|
275
|
+
dispatch({
|
|
276
|
+
type: 'native-open-started'
|
|
277
|
+
});
|
|
257
278
|
}
|
|
258
279
|
if (event.newState === 'closed') {
|
|
259
280
|
if (element instanceof HTMLElement) {
|
|
@@ -27,7 +27,7 @@ var _isNestedLayerFocused = require("../focus/is-nested-layer-focused");
|
|
|
27
27
|
* impossible to implement generically here. The consumer component
|
|
28
28
|
* (e.g. `dropdown-menu`) owns all menu keyboard navigation.
|
|
29
29
|
*
|
|
30
|
-
* See: notes/
|
|
30
|
+
* See: notes/decisions/menu-keyboard.md
|
|
31
31
|
*/
|
|
32
32
|
function roleRequiresFocusWrap(role) {
|
|
33
33
|
return role === 'dialog' || role === 'alertdialog';
|
|
@@ -150,7 +150,7 @@ function getInitialFocusTarget(_ref2) {
|
|
|
150
150
|
// type-ahead, Enter/Space, submenu coordination) is the responsibility
|
|
151
151
|
// of the consumer component (e.g. dropdown-menu), because menu keyboard
|
|
152
152
|
// behavior varies by context (orientation, nesting, item type, control
|
|
153
|
-
// pattern). See: notes/
|
|
153
|
+
// pattern). See: notes/decisions/menu-keyboard.md
|
|
154
154
|
return (0, _getFirstFocusable.getFirstFocusable)({
|
|
155
155
|
container: container
|
|
156
156
|
});
|
|
@@ -43,7 +43,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
43
43
|
*
|
|
44
44
|
* @example
|
|
45
45
|
* ```ts
|
|
46
|
-
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map';
|
|
46
|
+
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
|
|
47
47
|
*
|
|
48
48
|
* // In a migration from @atlaskit/popup:
|
|
49
49
|
* const oldPlacement: TLegacyPlacement = 'bottom-start';
|
|
@@ -18,7 +18,8 @@ exports.createPopoverCloseEvent = createPopoverCloseEvent;
|
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
20
20
|
* ```tsx
|
|
21
|
-
* import { createPopoverCloseEvent
|
|
21
|
+
* import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
|
|
22
|
+
* import { type TPopoverCloseReason } from '@atlaskit/top-layer/popover/types';
|
|
22
23
|
*
|
|
23
24
|
* function onPopoverClose({ reason }: { reason: TPopoverCloseReason }) {
|
|
24
25
|
* legacyOnClose(createPopoverCloseEvent({ reason }));
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.flushPopoverExit = flushPopoverExit;
|
|
8
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
9
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
10
|
+
var _react = require("react");
|
|
11
|
+
/**
|
|
12
|
+
* Flushes a `Popover` exit in jsdom so that `onExitFinish` has fired and the
|
|
13
|
+
* host element has unmounted before the caller asserts.
|
|
14
|
+
*
|
|
15
|
+
* Requires React 18.3 or newer (`act` is imported from `react`).
|
|
16
|
+
*
|
|
17
|
+
* Hiding is two steps: the testing polyfill fires the closed `toggle` as a task,
|
|
18
|
+
* then top-layer settles the exit in a native promise microtask. Jest fake
|
|
19
|
+
* timers drain the task but not that microtask, so a synchronous
|
|
20
|
+
* `act(() => jest.runOnlyPendingTimers())` returns too early. Real browsers are
|
|
21
|
+
* unaffected. See `notes/architecture/animations.md` ("settles in a microtask").
|
|
22
|
+
*
|
|
23
|
+
* Flush any delay before `hidePopover()` first (for example the `delay` prop on
|
|
24
|
+
* `@atlaskit/tooltip`). Only `Popover` is covered - `Dialog` chains a second
|
|
25
|
+
* timer for its `close` event, which this helper does not wait for.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* rerender(<Popover isOpen={false} shouldAnimate onExitFinish={onExitFinish} />);
|
|
29
|
+
* await flushPopoverExit();
|
|
30
|
+
* expect(onExitFinish).toHaveBeenCalledTimes(1);
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
// `react` is a peer dependency, so this entrypoint adds no testing-library dependency.
|
|
34
|
+
|
|
35
|
+
// Mirrors `jestFakeTimersAreEnabled` in `@testing-library/dom`.
|
|
36
|
+
function areJestFakeTimersEnabled() {
|
|
37
|
+
if (typeof jest === 'undefined') {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
var timer = setTimeout;
|
|
41
|
+
// Legacy fake timers mark the function. Modern (sinon) fake timers attach a `clock`.
|
|
42
|
+
return timer._isMockFunction === true || Object.prototype.hasOwnProperty.call(setTimeout, 'clock');
|
|
43
|
+
}
|
|
44
|
+
function waitForOneRealTask() {
|
|
45
|
+
return new Promise(function (resolve) {
|
|
46
|
+
setTimeout(resolve, 0);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function flushPopoverExit() {
|
|
50
|
+
return _flushPopoverExit.apply(this, arguments);
|
|
51
|
+
}
|
|
52
|
+
function _flushPopoverExit() {
|
|
53
|
+
_flushPopoverExit = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
54
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
55
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
56
|
+
case 0:
|
|
57
|
+
if (!(typeof _react.act !== 'function')) {
|
|
58
|
+
_context2.next = 1;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
throw new Error('flushPopoverExit() requires React 18.3 or newer: `act` is not exported by this version of `react`');
|
|
62
|
+
case 1:
|
|
63
|
+
_context2.next = 2;
|
|
64
|
+
return (0, _react.act)( /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
65
|
+
return _regenerator.default.wrap(function (_context) {
|
|
66
|
+
while (1) switch (_context.prev = _context.next) {
|
|
67
|
+
case 0:
|
|
68
|
+
if (!areJestFakeTimersEnabled()) {
|
|
69
|
+
_context.next = 2;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
jest.runOnlyPendingTimers();
|
|
73
|
+
// Yield once so the settlement job runs before `act` commits.
|
|
74
|
+
_context.next = 1;
|
|
75
|
+
return Promise.resolve();
|
|
76
|
+
case 1:
|
|
77
|
+
return _context.abrupt("return");
|
|
78
|
+
case 2:
|
|
79
|
+
_context.next = 3;
|
|
80
|
+
return waitForOneRealTask();
|
|
81
|
+
case 3:
|
|
82
|
+
case "end":
|
|
83
|
+
return _context.stop();
|
|
84
|
+
}
|
|
85
|
+
}, _callee);
|
|
86
|
+
})));
|
|
87
|
+
case 2:
|
|
88
|
+
case "end":
|
|
89
|
+
return _context2.stop();
|
|
90
|
+
}
|
|
91
|
+
}, _callee2);
|
|
92
|
+
}));
|
|
93
|
+
return _flushPopoverExit.apply(this, arguments);
|
|
94
|
+
}
|
|
@@ -53,7 +53,8 @@ var menuScope = '[role="menu"]';
|
|
|
53
53
|
*
|
|
54
54
|
* @example With nested menu filter
|
|
55
55
|
* ```tsx
|
|
56
|
-
* import {
|
|
56
|
+
* import { isAtCurrentMenuLevel } from '@atlaskit/top-layer/is-at-current-menu-level';
|
|
57
|
+
* import { useArrowNavigation } from '@atlaskit/top-layer/use-arrow-navigation/use-arrow-navigation';
|
|
57
58
|
*
|
|
58
59
|
* useArrowNavigation({
|
|
59
60
|
* containerRef: menuRef,
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```tsx
|
|
13
|
-
* import { createCloseEvent
|
|
13
|
+
* import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
14
|
+
* import { type TDialogCloseReason } from '@atlaskit/top-layer/dialog/types';
|
|
14
15
|
*
|
|
15
16
|
* function onDialogClose({ reason }: { reason: TDialogCloseReason }) {
|
|
16
17
|
* legacyOnClose(createCloseEvent({ reason }));
|
|
@@ -60,6 +60,7 @@ function runOnAnimationsSettled({
|
|
|
60
60
|
* interrupts: entering → exiting (close mid-entry)
|
|
61
61
|
* exiting → entering (reopen mid-exit, animated)
|
|
62
62
|
* exiting → open (reopen mid-handshake, non-animated)
|
|
63
|
+
* exiting → open (native reopen while controlled intent is open)
|
|
63
64
|
* ```
|
|
64
65
|
*/
|
|
65
66
|
|
|
@@ -127,6 +128,20 @@ function getNextVisibilityState(state, action) {
|
|
|
127
128
|
phase: 'exiting'
|
|
128
129
|
};
|
|
129
130
|
}
|
|
131
|
+
|
|
132
|
+
// A browser dismiss started the exit, and something showed the element
|
|
133
|
+
// again before the exit settled, while controlled intent stayed open. For
|
|
134
|
+
// example, `@atlaskit/tooltip` re-shows after a light dismiss in the same
|
|
135
|
+
// task. The element never painted closed, so go back to `open`.
|
|
136
|
+
if (action.type === 'native-open-started') {
|
|
137
|
+
if (state.phase !== 'exiting' || state.controlledIntent !== 'open') {
|
|
138
|
+
return state;
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
...state,
|
|
142
|
+
phase: 'open'
|
|
143
|
+
};
|
|
144
|
+
}
|
|
130
145
|
if (action.type === 'entry-settled') {
|
|
131
146
|
if (state.phase !== 'entering') {
|
|
132
147
|
return state;
|
|
@@ -246,9 +261,16 @@ export function useAnimatedVisibility({
|
|
|
246
261
|
cancelExitSettlementRef.current();
|
|
247
262
|
// Snapshot currentTarget because the DOM clears it after event dispatch.
|
|
248
263
|
const element = event.currentTarget;
|
|
249
|
-
if (event.newState === 'open'
|
|
250
|
-
element
|
|
251
|
-
|
|
264
|
+
if (event.newState === 'open') {
|
|
265
|
+
if (element instanceof HTMLElement) {
|
|
266
|
+
element.removeAttribute('inert');
|
|
267
|
+
element.removeAttribute('aria-hidden');
|
|
268
|
+
}
|
|
269
|
+
// Dispatched on every native open. The reducer only acts when a browser
|
|
270
|
+
// dismiss left the host `exiting` while `isOpen` stayed `true`.
|
|
271
|
+
dispatch({
|
|
272
|
+
type: 'native-open-started'
|
|
273
|
+
});
|
|
252
274
|
}
|
|
253
275
|
if (event.newState === 'closed') {
|
|
254
276
|
if (element instanceof HTMLElement) {
|
|
@@ -21,7 +21,7 @@ import { isNestedLayerFocused } from '../focus/is-nested-layer-focused';
|
|
|
21
21
|
* impossible to implement generically here. The consumer component
|
|
22
22
|
* (e.g. `dropdown-menu`) owns all menu keyboard navigation.
|
|
23
23
|
*
|
|
24
|
-
* See: notes/
|
|
24
|
+
* See: notes/decisions/menu-keyboard.md
|
|
25
25
|
*/
|
|
26
26
|
function roleRequiresFocusWrap(role) {
|
|
27
27
|
return role === 'dialog' || role === 'alertdialog';
|
|
@@ -144,7 +144,7 @@ function getInitialFocusTarget({
|
|
|
144
144
|
// type-ahead, Enter/Space, submenu coordination) is the responsibility
|
|
145
145
|
// of the consumer component (e.g. dropdown-menu), because menu keyboard
|
|
146
146
|
// behavior varies by context (orientation, nesting, item type, control
|
|
147
|
-
// pattern). See: notes/
|
|
147
|
+
// pattern). See: notes/decisions/menu-keyboard.md
|
|
148
148
|
return getFirstFocusable({
|
|
149
149
|
container
|
|
150
150
|
});
|
|
@@ -33,7 +33,7 @@ import { placementMapping } from './placement-mapping';
|
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```ts
|
|
36
|
-
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map';
|
|
36
|
+
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
|
|
37
37
|
*
|
|
38
38
|
* // In a migration from @atlaskit/popup:
|
|
39
39
|
* const oldPlacement: TLegacyPlacement = 'bottom-start';
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```tsx
|
|
15
|
-
* import { createPopoverCloseEvent
|
|
15
|
+
* import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
|
|
16
|
+
* import { type TPopoverCloseReason } from '@atlaskit/top-layer/popover/types';
|
|
16
17
|
*
|
|
17
18
|
* function onPopoverClose({ reason }: { reason: TPopoverCloseReason }) {
|
|
18
19
|
* legacyOnClose(createPopoverCloseEvent({ reason }));
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flushes a `Popover` exit in jsdom so that `onExitFinish` has fired and the
|
|
3
|
+
* host element has unmounted before the caller asserts.
|
|
4
|
+
*
|
|
5
|
+
* Requires React 18.3 or newer (`act` is imported from `react`).
|
|
6
|
+
*
|
|
7
|
+
* Hiding is two steps: the testing polyfill fires the closed `toggle` as a task,
|
|
8
|
+
* then top-layer settles the exit in a native promise microtask. Jest fake
|
|
9
|
+
* timers drain the task but not that microtask, so a synchronous
|
|
10
|
+
* `act(() => jest.runOnlyPendingTimers())` returns too early. Real browsers are
|
|
11
|
+
* unaffected. See `notes/architecture/animations.md` ("settles in a microtask").
|
|
12
|
+
*
|
|
13
|
+
* Flush any delay before `hidePopover()` first (for example the `delay` prop on
|
|
14
|
+
* `@atlaskit/tooltip`). Only `Popover` is covered - `Dialog` chains a second
|
|
15
|
+
* timer for its `close` event, which this helper does not wait for.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* rerender(<Popover isOpen={false} shouldAnimate onExitFinish={onExitFinish} />);
|
|
19
|
+
* await flushPopoverExit();
|
|
20
|
+
* expect(onExitFinish).toHaveBeenCalledTimes(1);
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// `react` is a peer dependency, so this entrypoint adds no testing-library dependency.
|
|
24
|
+
import { act } from 'react';
|
|
25
|
+
|
|
26
|
+
// Mirrors `jestFakeTimersAreEnabled` in `@testing-library/dom`.
|
|
27
|
+
function areJestFakeTimersEnabled() {
|
|
28
|
+
if (typeof jest === 'undefined') {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
const timer = setTimeout;
|
|
32
|
+
// Legacy fake timers mark the function. Modern (sinon) fake timers attach a `clock`.
|
|
33
|
+
return timer._isMockFunction === true || Object.prototype.hasOwnProperty.call(setTimeout, 'clock');
|
|
34
|
+
}
|
|
35
|
+
function waitForOneRealTask() {
|
|
36
|
+
return new Promise(resolve => {
|
|
37
|
+
setTimeout(resolve, 0);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export async function flushPopoverExit() {
|
|
41
|
+
// The peer range allows React 18.2, which does not export `act`. A plain throw rather than
|
|
42
|
+
// `tiny-invariant`, which is only a devDependency here.
|
|
43
|
+
if (typeof act !== 'function') {
|
|
44
|
+
throw new Error('flushPopoverExit() requires React 18.3 or newer: `act` is not exported by this version of `react`');
|
|
45
|
+
}
|
|
46
|
+
await act(async () => {
|
|
47
|
+
if (areJestFakeTimersEnabled()) {
|
|
48
|
+
jest.runOnlyPendingTimers();
|
|
49
|
+
// Yield once so the settlement job runs before `act` commits.
|
|
50
|
+
await Promise.resolve();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// The polyfill's `toggle` task was queued first, so it and its settlement microtask both
|
|
54
|
+
// run before this timer resolves.
|
|
55
|
+
await waitForOneRealTask();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -47,7 +47,8 @@ const menuScope = '[role="menu"]';
|
|
|
47
47
|
*
|
|
48
48
|
* @example With nested menu filter
|
|
49
49
|
* ```tsx
|
|
50
|
-
* import {
|
|
50
|
+
* import { isAtCurrentMenuLevel } from '@atlaskit/top-layer/is-at-current-menu-level';
|
|
51
|
+
* import { useArrowNavigation } from '@atlaskit/top-layer/use-arrow-navigation/use-arrow-navigation';
|
|
51
52
|
*
|
|
52
53
|
* useArrowNavigation({
|
|
53
54
|
* containerRef: menuRef,
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```tsx
|
|
13
|
-
* import { createCloseEvent
|
|
13
|
+
* import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
14
|
+
* import { type TDialogCloseReason } from '@atlaskit/top-layer/dialog/types';
|
|
14
15
|
*
|
|
15
16
|
* function onDialogClose({ reason }: { reason: TDialogCloseReason }) {
|
|
16
17
|
* legacyOnClose(createCloseEvent({ reason }));
|
|
@@ -64,6 +64,7 @@ function runOnAnimationsSettled(_ref2) {
|
|
|
64
64
|
* interrupts: entering → exiting (close mid-entry)
|
|
65
65
|
* exiting → entering (reopen mid-exit, animated)
|
|
66
66
|
* exiting → open (reopen mid-handshake, non-animated)
|
|
67
|
+
* exiting → open (native reopen while controlled intent is open)
|
|
67
68
|
* ```
|
|
68
69
|
*/
|
|
69
70
|
|
|
@@ -127,6 +128,19 @@ function getNextVisibilityState(state, action) {
|
|
|
127
128
|
phase: 'exiting'
|
|
128
129
|
});
|
|
129
130
|
}
|
|
131
|
+
|
|
132
|
+
// A browser dismiss started the exit, and something showed the element
|
|
133
|
+
// again before the exit settled, while controlled intent stayed open. For
|
|
134
|
+
// example, `@atlaskit/tooltip` re-shows after a light dismiss in the same
|
|
135
|
+
// task. The element never painted closed, so go back to `open`.
|
|
136
|
+
if (action.type === 'native-open-started') {
|
|
137
|
+
if (state.phase !== 'exiting' || state.controlledIntent !== 'open') {
|
|
138
|
+
return state;
|
|
139
|
+
}
|
|
140
|
+
return _objectSpread(_objectSpread({}, state), {}, {
|
|
141
|
+
phase: 'open'
|
|
142
|
+
});
|
|
143
|
+
}
|
|
130
144
|
if (action.type === 'entry-settled') {
|
|
131
145
|
if (state.phase !== 'entering') {
|
|
132
146
|
return state;
|
|
@@ -244,9 +258,16 @@ export function useAnimatedVisibility(_ref4) {
|
|
|
244
258
|
cancelExitSettlementRef.current();
|
|
245
259
|
// Snapshot currentTarget because the DOM clears it after event dispatch.
|
|
246
260
|
var element = event.currentTarget;
|
|
247
|
-
if (event.newState === 'open'
|
|
248
|
-
element
|
|
249
|
-
|
|
261
|
+
if (event.newState === 'open') {
|
|
262
|
+
if (element instanceof HTMLElement) {
|
|
263
|
+
element.removeAttribute('inert');
|
|
264
|
+
element.removeAttribute('aria-hidden');
|
|
265
|
+
}
|
|
266
|
+
// Dispatched on every native open. The reducer only acts when a browser
|
|
267
|
+
// dismiss left the host `exiting` while `isOpen` stayed `true`.
|
|
268
|
+
dispatch({
|
|
269
|
+
type: 'native-open-started'
|
|
270
|
+
});
|
|
250
271
|
}
|
|
251
272
|
if (event.newState === 'closed') {
|
|
252
273
|
if (element instanceof HTMLElement) {
|
|
@@ -21,7 +21,7 @@ import { isNestedLayerFocused } from '../focus/is-nested-layer-focused';
|
|
|
21
21
|
* impossible to implement generically here. The consumer component
|
|
22
22
|
* (e.g. `dropdown-menu`) owns all menu keyboard navigation.
|
|
23
23
|
*
|
|
24
|
-
* See: notes/
|
|
24
|
+
* See: notes/decisions/menu-keyboard.md
|
|
25
25
|
*/
|
|
26
26
|
function roleRequiresFocusWrap(role) {
|
|
27
27
|
return role === 'dialog' || role === 'alertdialog';
|
|
@@ -144,7 +144,7 @@ function getInitialFocusTarget(_ref2) {
|
|
|
144
144
|
// type-ahead, Enter/Space, submenu coordination) is the responsibility
|
|
145
145
|
// of the consumer component (e.g. dropdown-menu), because menu keyboard
|
|
146
146
|
// behavior varies by context (orientation, nesting, item type, control
|
|
147
|
-
// pattern). See: notes/
|
|
147
|
+
// pattern). See: notes/decisions/menu-keyboard.md
|
|
148
148
|
return getFirstFocusable({
|
|
149
149
|
container: container
|
|
150
150
|
});
|
|
@@ -37,7 +37,7 @@ import { placementMapping } from './placement-mapping';
|
|
|
37
37
|
*
|
|
38
38
|
* @example
|
|
39
39
|
* ```ts
|
|
40
|
-
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map';
|
|
40
|
+
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
|
|
41
41
|
*
|
|
42
42
|
* // In a migration from @atlaskit/popup:
|
|
43
43
|
* const oldPlacement: TLegacyPlacement = 'bottom-start';
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* ```tsx
|
|
15
|
-
* import { createPopoverCloseEvent
|
|
15
|
+
* import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
|
|
16
|
+
* import { type TPopoverCloseReason } from '@atlaskit/top-layer/popover/types';
|
|
16
17
|
*
|
|
17
18
|
* function onPopoverClose({ reason }: { reason: TPopoverCloseReason }) {
|
|
18
19
|
* legacyOnClose(createPopoverCloseEvent({ reason }));
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
|
+
/**
|
|
4
|
+
* Flushes a `Popover` exit in jsdom so that `onExitFinish` has fired and the
|
|
5
|
+
* host element has unmounted before the caller asserts.
|
|
6
|
+
*
|
|
7
|
+
* Requires React 18.3 or newer (`act` is imported from `react`).
|
|
8
|
+
*
|
|
9
|
+
* Hiding is two steps: the testing polyfill fires the closed `toggle` as a task,
|
|
10
|
+
* then top-layer settles the exit in a native promise microtask. Jest fake
|
|
11
|
+
* timers drain the task but not that microtask, so a synchronous
|
|
12
|
+
* `act(() => jest.runOnlyPendingTimers())` returns too early. Real browsers are
|
|
13
|
+
* unaffected. See `notes/architecture/animations.md` ("settles in a microtask").
|
|
14
|
+
*
|
|
15
|
+
* Flush any delay before `hidePopover()` first (for example the `delay` prop on
|
|
16
|
+
* `@atlaskit/tooltip`). Only `Popover` is covered - `Dialog` chains a second
|
|
17
|
+
* timer for its `close` event, which this helper does not wait for.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* rerender(<Popover isOpen={false} shouldAnimate onExitFinish={onExitFinish} />);
|
|
21
|
+
* await flushPopoverExit();
|
|
22
|
+
* expect(onExitFinish).toHaveBeenCalledTimes(1);
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// `react` is a peer dependency, so this entrypoint adds no testing-library dependency.
|
|
26
|
+
import { act } from 'react';
|
|
27
|
+
|
|
28
|
+
// Mirrors `jestFakeTimersAreEnabled` in `@testing-library/dom`.
|
|
29
|
+
function areJestFakeTimersEnabled() {
|
|
30
|
+
if (typeof jest === 'undefined') {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
var timer = setTimeout;
|
|
34
|
+
// Legacy fake timers mark the function. Modern (sinon) fake timers attach a `clock`.
|
|
35
|
+
return timer._isMockFunction === true || Object.prototype.hasOwnProperty.call(setTimeout, 'clock');
|
|
36
|
+
}
|
|
37
|
+
function waitForOneRealTask() {
|
|
38
|
+
return new Promise(function (resolve) {
|
|
39
|
+
setTimeout(resolve, 0);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function flushPopoverExit() {
|
|
43
|
+
return _flushPopoverExit.apply(this, arguments);
|
|
44
|
+
}
|
|
45
|
+
function _flushPopoverExit() {
|
|
46
|
+
_flushPopoverExit = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
47
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
48
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
49
|
+
case 0:
|
|
50
|
+
if (!(typeof act !== 'function')) {
|
|
51
|
+
_context2.next = 1;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
throw new Error('flushPopoverExit() requires React 18.3 or newer: `act` is not exported by this version of `react`');
|
|
55
|
+
case 1:
|
|
56
|
+
_context2.next = 2;
|
|
57
|
+
return act( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
58
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
59
|
+
while (1) switch (_context.prev = _context.next) {
|
|
60
|
+
case 0:
|
|
61
|
+
if (!areJestFakeTimersEnabled()) {
|
|
62
|
+
_context.next = 2;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
jest.runOnlyPendingTimers();
|
|
66
|
+
// Yield once so the settlement job runs before `act` commits.
|
|
67
|
+
_context.next = 1;
|
|
68
|
+
return Promise.resolve();
|
|
69
|
+
case 1:
|
|
70
|
+
return _context.abrupt("return");
|
|
71
|
+
case 2:
|
|
72
|
+
_context.next = 3;
|
|
73
|
+
return waitForOneRealTask();
|
|
74
|
+
case 3:
|
|
75
|
+
case "end":
|
|
76
|
+
return _context.stop();
|
|
77
|
+
}
|
|
78
|
+
}, _callee);
|
|
79
|
+
})));
|
|
80
|
+
case 2:
|
|
81
|
+
case "end":
|
|
82
|
+
return _context2.stop();
|
|
83
|
+
}
|
|
84
|
+
}, _callee2);
|
|
85
|
+
}));
|
|
86
|
+
return _flushPopoverExit.apply(this, arguments);
|
|
87
|
+
}
|
|
@@ -47,7 +47,8 @@ var menuScope = '[role="menu"]';
|
|
|
47
47
|
*
|
|
48
48
|
* @example With nested menu filter
|
|
49
49
|
* ```tsx
|
|
50
|
-
* import {
|
|
50
|
+
* import { isAtCurrentMenuLevel } from '@atlaskit/top-layer/is-at-current-menu-level';
|
|
51
|
+
* import { useArrowNavigation } from '@atlaskit/top-layer/use-arrow-navigation/use-arrow-navigation';
|
|
51
52
|
*
|
|
52
53
|
* useArrowNavigation({
|
|
53
54
|
* containerRef: menuRef,
|
|
@@ -11,7 +11,8 @@ import type { TDialogCloseReason } from './types';
|
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```tsx
|
|
14
|
-
* import { createCloseEvent
|
|
14
|
+
* import { createCloseEvent } from '@atlaskit/top-layer/create-close-event';
|
|
15
|
+
* import { type TDialogCloseReason } from '@atlaskit/top-layer/dialog/types';
|
|
15
16
|
*
|
|
16
17
|
* function onDialogClose({ reason }: { reason: TDialogCloseReason }) {
|
|
17
18
|
* legacyOnClose(createCloseEvent({ reason }));
|
|
@@ -70,6 +70,7 @@ type TUseAnimatedVisibilityResult = {
|
|
|
70
70
|
* interrupts: entering → exiting (close mid-entry)
|
|
71
71
|
* exiting → entering (reopen mid-exit, animated)
|
|
72
72
|
* exiting → open (reopen mid-handshake, non-animated)
|
|
73
|
+
* exiting → open (native reopen while controlled intent is open)
|
|
73
74
|
* ```
|
|
74
75
|
*/
|
|
75
76
|
export type TPhase = 'closed' | 'entering' | 'open' | 'exiting';
|
|
@@ -33,7 +33,7 @@ import type { TLegacyPlacement } from './legacy-placements';
|
|
|
33
33
|
*
|
|
34
34
|
* @example
|
|
35
35
|
* ```ts
|
|
36
|
-
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map';
|
|
36
|
+
* import { fromLegacyPlacement } from '@atlaskit/top-layer/placement-map/index';
|
|
37
37
|
*
|
|
38
38
|
* // In a migration from @atlaskit/popup:
|
|
39
39
|
* const oldPlacement: TLegacyPlacement = 'bottom-start';
|
|
@@ -13,7 +13,8 @@ import type { TPopoverCloseReason } from './types';
|
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* ```tsx
|
|
16
|
-
* import { createPopoverCloseEvent
|
|
16
|
+
* import { createPopoverCloseEvent } from '@atlaskit/top-layer/popover/create-close-event';
|
|
17
|
+
* import { type TPopoverCloseReason } from '@atlaskit/top-layer/popover/types';
|
|
17
18
|
*
|
|
18
19
|
* function onPopoverClose({ reason }: { reason: TPopoverCloseReason }) {
|
|
19
20
|
* legacyOnClose(createPopoverCloseEvent({ reason }));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flushes a `Popover` exit in jsdom so that `onExitFinish` has fired and the
|
|
3
|
+
* host element has unmounted before the caller asserts.
|
|
4
|
+
*
|
|
5
|
+
* Requires React 18.3 or newer (`act` is imported from `react`).
|
|
6
|
+
*
|
|
7
|
+
* Hiding is two steps: the testing polyfill fires the closed `toggle` as a task,
|
|
8
|
+
* then top-layer settles the exit in a native promise microtask. Jest fake
|
|
9
|
+
* timers drain the task but not that microtask, so a synchronous
|
|
10
|
+
* `act(() => jest.runOnlyPendingTimers())` returns too early. Real browsers are
|
|
11
|
+
* unaffected. See `notes/architecture/animations.md` ("settles in a microtask").
|
|
12
|
+
*
|
|
13
|
+
* Flush any delay before `hidePopover()` first (for example the `delay` prop on
|
|
14
|
+
* `@atlaskit/tooltip`). Only `Popover` is covered - `Dialog` chains a second
|
|
15
|
+
* timer for its `close` event, which this helper does not wait for.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* rerender(<Popover isOpen={false} shouldAnimate onExitFinish={onExitFinish} />);
|
|
19
|
+
* await flushPopoverExit();
|
|
20
|
+
* expect(onExitFinish).toHaveBeenCalledTimes(1);
|
|
21
|
+
*/
|
|
22
|
+
export declare function flushPopoverExit(): Promise<void>;
|
|
@@ -89,7 +89,8 @@ export type TUseArrowNavigationArgs = {
|
|
|
89
89
|
*
|
|
90
90
|
* @example With nested menu filter
|
|
91
91
|
* ```tsx
|
|
92
|
-
* import {
|
|
92
|
+
* import { isAtCurrentMenuLevel } from '@atlaskit/top-layer/is-at-current-menu-level';
|
|
93
|
+
* import { useArrowNavigation } from '@atlaskit/top-layer/use-arrow-navigation/use-arrow-navigation';
|
|
93
94
|
*
|
|
94
95
|
* useArrowNavigation({
|
|
95
96
|
* containerRef: menuRef,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/top-layer",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.1",
|
|
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": "^6.0.0",
|
|
42
42
|
"@atlaskit/react-compiler-gating": "^0.2.0",
|
|
43
|
-
"@atlaskit/tokens": "^20.
|
|
43
|
+
"@atlaskit/tokens": "^20.3.0",
|
|
44
44
|
"@babel/runtime": "^7.0.0",
|
|
45
45
|
"@compiled/react": "^1.0.2",
|
|
46
46
|
"bind-event-listener": "^3.0.0",
|
|
@@ -54,12 +54,12 @@
|
|
|
54
54
|
"@af/integration-testing": "workspace:^",
|
|
55
55
|
"@af/visual-regression": "workspace:^",
|
|
56
56
|
"@atlaskit/button": "^25.4.0",
|
|
57
|
-
"@atlaskit/checkbox": "^19.
|
|
57
|
+
"@atlaskit/checkbox": "^19.3.0",
|
|
58
58
|
"@atlaskit/heading": "^8.0.0",
|
|
59
|
-
"@atlaskit/lozenge": "^
|
|
59
|
+
"@atlaskit/lozenge": "^17.0.0",
|
|
60
60
|
"@atlaskit/pragmatic-drag-and-drop": "^4.0.0",
|
|
61
61
|
"@atlaskit/primitives": "^22.5.0",
|
|
62
|
-
"@atlaskit/select": "^23.
|
|
62
|
+
"@atlaskit/select": "^23.1.0",
|
|
63
63
|
"@atlaskit/ssr": "workspace:^",
|
|
64
64
|
"@atlaskit/textfield": "^10.2.0",
|
|
65
65
|
"@atlaskit/toggle": "^17.3.0",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlaskit/top-layer/testing/flush-popover-exit",
|
|
3
|
+
"main": "../../dist/cjs/testing/flush-popover-exit.js",
|
|
4
|
+
"module": "../../dist/esm/testing/flush-popover-exit.js",
|
|
5
|
+
"module:es2019": "../../dist/es2019/testing/flush-popover-exit.js",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"*.compiled.css"
|
|
8
|
+
],
|
|
9
|
+
"types": "../../dist/types/testing/flush-popover-exit.d.ts"
|
|
10
|
+
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.shouldFocusIntoPopover = shouldFocusIntoPopover;
|
|
7
|
-
var rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Returns `true` when the given popover role moves focus into the popover
|
|
11
|
-
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
12
|
-
*/
|
|
13
|
-
function shouldFocusIntoPopover(_ref) {
|
|
14
|
-
var role = _ref.role;
|
|
15
|
-
if (!role) {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
return rolesThatMoveFocus.has(role);
|
|
19
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns `true` when the given popover role moves focus into the popover
|
|
5
|
-
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
6
|
-
*/
|
|
7
|
-
export function shouldFocusIntoPopover({
|
|
8
|
-
role
|
|
9
|
-
}) {
|
|
10
|
-
if (!role) {
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
return rolesThatMoveFocus.has(role);
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
var rolesThatMoveFocus = new Set(['dialog', 'alertdialog', 'menu', 'listbox', 'tree', 'grid']);
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Returns `true` when the given popover role moves focus into the popover
|
|
5
|
-
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
6
|
-
*/
|
|
7
|
-
export function shouldFocusIntoPopover(_ref) {
|
|
8
|
-
var role = _ref.role;
|
|
9
|
-
if (!role) {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
return rolesThatMoveFocus.has(role);
|
|
13
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { TRoleRequiringAccessibleName, TRoleWithImplicitName } from './role-types';
|
|
2
|
-
/**
|
|
3
|
-
* Returns `true` when the given popover role moves focus into the popover
|
|
4
|
-
* on open, and `false` otherwise (including when `role` is `undefined`).
|
|
5
|
-
*/
|
|
6
|
-
export declare function shouldFocusIntoPopover({ role, }: {
|
|
7
|
-
role: TRoleRequiringAccessibleName | TRoleWithImplicitName | undefined;
|
|
8
|
-
}): boolean;
|