@atlaskit/modal-dialog 17.0.3 → 17.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 +21 -0
- package/__tests__/playwright/top-layer-escape.spec.tsx +286 -0
- package/__tests__/playwright/top-layer-focus.spec.tsx +1 -0
- package/dist/cjs/internal/components/modal-wrapper.js +39 -28
- package/dist/cjs/modal-header.js +3 -1
- package/dist/es2019/internal/components/modal-wrapper.js +40 -28
- package/dist/es2019/modal-header.js +3 -1
- package/dist/esm/internal/components/modal-wrapper.js +39 -28
- package/dist/esm/modal-header.js +3 -1
- package/dist/types/modal-header.d.ts +4 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @atlaskit/modal-dialog
|
|
2
2
|
|
|
3
|
+
## 17.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`f026aadea067f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f026aadea067f) -
|
|
8
|
+
On the top-layer path (`platform-dst-top-layer`), `onClose` now runs in the same cases as on the
|
|
9
|
+
legacy path while the modal is open, and the modal stays open until you unmount it. Unlike legacy,
|
|
10
|
+
Escape and backdrop clicks during the exit animation do not call `onClose` again.
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
13
|
+
## 17.1.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [`62c3c0411e84b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/62c3c0411e84b) -
|
|
18
|
+
Cleanup `feature_gate` `platform_dst-a11y_accessible-error-modal`. The accessible modal error
|
|
19
|
+
experience is now permanent. `ModalTrigger` and `FullScreenModalTrigger` support localized
|
|
20
|
+
`title`, `errorText`, and `errorCloseText` strings for the default error fallback. `ModalTrigger`
|
|
21
|
+
also supports a per-trigger `errorFallback`. `ModalHeader` supports a localized close-button
|
|
22
|
+
label.
|
|
23
|
+
|
|
3
24
|
## 17.0.3
|
|
4
25
|
|
|
5
26
|
### Patch Changes
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/* eslint-disable @repo/internal/dom-events/no-unsafe-event-listeners -- `page.evaluate` code runs in the page and cannot import `bind-event-listener` */
|
|
2
|
+
|
|
3
|
+
import { expect, type Page, test } from '@af/integration-testing';
|
|
4
|
+
|
|
5
|
+
const featureFlag = 'platform-dst-top-layer';
|
|
6
|
+
|
|
7
|
+
// Dialog takes the Escape `keydown`, so the browser makes no close request and never closes
|
|
8
|
+
// the `<dialog>` itself, even after many refused Escapes (the close-watcher rule in Chrome and
|
|
9
|
+
// Firefox 149+).
|
|
10
|
+
test.describe('Modal dialog: top-layer Escape never closes the dialog natively', () => {
|
|
11
|
+
test('when onClose keeps the modal open', async ({ page }) => {
|
|
12
|
+
await openModal({ page, trigger: 'refusing-trigger' });
|
|
13
|
+
const focused = page.getByTestId('modal-body-button');
|
|
14
|
+
await focused.focus();
|
|
15
|
+
await recordDialogState({ page });
|
|
16
|
+
|
|
17
|
+
await mashEscape({ page, onSpacedPress: (i) => expectCloseCount({ page, count: i }) });
|
|
18
|
+
|
|
19
|
+
// A held key asks once: 5 + 20 + 1.
|
|
20
|
+
await expectCloseCount({ page, count: 26 });
|
|
21
|
+
await expectNeverClosed({ page, escapes: 45, focusedTestId: 'modal-body-button' });
|
|
22
|
+
await expect(focused).toBeFocused();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('when shouldCloseOnEscapePress is false', async ({ page }) => {
|
|
26
|
+
await openModal({ page, trigger: 'escape-disabled-trigger' });
|
|
27
|
+
const focused = page.getByTestId('modal-body-button');
|
|
28
|
+
await focused.focus();
|
|
29
|
+
await recordDialogState({ page });
|
|
30
|
+
|
|
31
|
+
await mashEscape({ page, onSpacedPress: () => nextFrames({ page }) });
|
|
32
|
+
|
|
33
|
+
await expectNeverClosed({ page, escapes: 45, focusedTestId: 'modal-body-button' });
|
|
34
|
+
await expectCloseCount({ page, count: 0 });
|
|
35
|
+
await expect(focused).toBeFocused();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// A click on the title moves focus to the `<dialog>`, so the modal still takes the Escape.
|
|
39
|
+
test('after a click on the title', async ({ page }) => {
|
|
40
|
+
await openModal({ page, trigger: 'refusing-trigger' });
|
|
41
|
+
await page.getByText('Escape refused', { exact: true }).click();
|
|
42
|
+
await expect(page.getByTestId('modal')).toBeFocused();
|
|
43
|
+
await recordDialogState({ page });
|
|
44
|
+
|
|
45
|
+
await mashEscape({ page, onSpacedPress: (i) => expectCloseCount({ page, count: i }) });
|
|
46
|
+
|
|
47
|
+
await expectCloseCount({ page, count: 26 });
|
|
48
|
+
await expectNeverClosed({ page, escapes: 45, focusedTestId: 'modal' });
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('a child popup takes the first Escape, the modal is asked the rest', async ({ page }) => {
|
|
52
|
+
await openModal({ page, trigger: 'refusing-trigger' });
|
|
53
|
+
await page.getByTestId('child-popup-trigger').click();
|
|
54
|
+
await expect(page.getByTestId('child-popup-button')).toBeVisible();
|
|
55
|
+
await page.getByTestId('child-popup-button').focus();
|
|
56
|
+
await recordDialogState({ page });
|
|
57
|
+
|
|
58
|
+
await page.keyboard.press('Escape');
|
|
59
|
+
await expect(page.getByTestId('child-popup-button')).toBeHidden();
|
|
60
|
+
await expectCloseCount({ page, count: 0 });
|
|
61
|
+
// Not every engine restores focus to the trigger, so focus a button.
|
|
62
|
+
const focused = page.getByTestId('modal-body-button');
|
|
63
|
+
await focused.focus();
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < 20; i++) {
|
|
66
|
+
await page.keyboard.press('Escape');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await expectCloseCount({ page, count: 20 });
|
|
70
|
+
await expectNeverClosed({ page, escapes: 21, focusedTestId: 'modal-body-button', skip: 1 });
|
|
71
|
+
await expect(focused).toBeFocused();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Focus on `<body>`: focus was last in the modal, so it takes the Escape and asks once per press,
|
|
76
|
+
// as legacy does. No close request, so the close-watcher rule (Chrome, Firefox 149+) never forces
|
|
77
|
+
// a close. Nothing runs between the Escapes: Playwright's `page.evaluate` and `expect` grant user
|
|
78
|
+
// activation, which would hide a forced close.
|
|
79
|
+
test('Modal dialog: top-layer Escape after the focused element is removed asks once per press', async ({
|
|
80
|
+
page,
|
|
81
|
+
}) => {
|
|
82
|
+
await openModal({ page, trigger: 'refusing-trigger' });
|
|
83
|
+
await page.getByTestId('removable-button').focus();
|
|
84
|
+
await page.keyboard.press('Enter');
|
|
85
|
+
await expect(page.getByTestId('removable-button')).toHaveCount(0);
|
|
86
|
+
await recordDialogState({ page });
|
|
87
|
+
|
|
88
|
+
for (let i = 0; i < 20; i++) {
|
|
89
|
+
await page.keyboard.press('Escape');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await expectCloseCount({ page, count: 20 });
|
|
93
|
+
await expectNeverClosed({ page, escapes: 20 });
|
|
94
|
+
expect(await page.evaluate(() => document.activeElement === document.body)).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// As in Forge: the modal is inside an open popup. Escape closes only the modal.
|
|
98
|
+
test('Modal dialog: top-layer Escape in a modal inside a popup closes only the modal', async ({
|
|
99
|
+
page,
|
|
100
|
+
}) => {
|
|
101
|
+
await page.visitExample<typeof import('../../examples/104-testing-escape-refused.tsx')>(
|
|
102
|
+
'design-system',
|
|
103
|
+
'modal-dialog',
|
|
104
|
+
'testing-escape-refused',
|
|
105
|
+
{ featureFlag },
|
|
106
|
+
);
|
|
107
|
+
await page.getByTestId('host-popup-trigger').click();
|
|
108
|
+
await page.getByTestId('hosted-modal-trigger').click();
|
|
109
|
+
await expect(page.getByTestId('hosted-modal')).toBeVisible();
|
|
110
|
+
await page.getByTestId('hosted-modal-button').focus();
|
|
111
|
+
|
|
112
|
+
await page.keyboard.press('Escape');
|
|
113
|
+
|
|
114
|
+
await expect(page.getByTestId('hosted-modal')).toHaveCount(0);
|
|
115
|
+
await expect(page.getByTestId('host-popup-content')).toBeVisible();
|
|
116
|
+
await expect(page.getByTestId('host-popup-close-count')).toHaveText('0');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Unlike legacy: an Escape during the exit, with focus back on the trigger, does not call onClose
|
|
120
|
+
// again. The modal is already closing.
|
|
121
|
+
test('Modal dialog: top-layer Escape during the exit does not call onClose again', async ({
|
|
122
|
+
page,
|
|
123
|
+
}) => {
|
|
124
|
+
await openModal({ page, trigger: 'closing-trigger' });
|
|
125
|
+
await page.getByTestId('modal-body-button').focus();
|
|
126
|
+
// Hold the exit open, so the next Escape is during the exit.
|
|
127
|
+
await page.addStyleTag({
|
|
128
|
+
content: 'dialog, dialog::backdrop { animation-duration: 100s !important; }',
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
await page.keyboard.press('Escape');
|
|
132
|
+
await expect(page.getByTestId('closing-trigger')).toBeFocused();
|
|
133
|
+
await expect(page.getByTestId('modal')).toHaveCount(1);
|
|
134
|
+
await page.keyboard.press('Escape');
|
|
135
|
+
|
|
136
|
+
await expectCloseCount({ page, count: 1 });
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Unlike legacy: an Escape during a nested modal's exit, with focus back on its trigger in the
|
|
140
|
+
// outer modal, asks the outer modal. The nested modal is not asked again.
|
|
141
|
+
test('Modal dialog: top-layer Escape during a nested modal exit asks the outer modal', async ({
|
|
142
|
+
page,
|
|
143
|
+
}) => {
|
|
144
|
+
await openModal({ page, trigger: 'refusing-trigger' });
|
|
145
|
+
await page.getByTestId('nested-modal-trigger').click();
|
|
146
|
+
await expect(page.getByTestId('nested-modal')).toBeVisible();
|
|
147
|
+
await page.getByTestId('nested-modal-button').focus();
|
|
148
|
+
// Hold the exit open, so the next Escape is during the exit.
|
|
149
|
+
await page.addStyleTag({
|
|
150
|
+
content: 'dialog, dialog::backdrop { animation-duration: 100s !important; }',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
await page.keyboard.press('Escape');
|
|
154
|
+
await expect(page.getByTestId('nested-modal-trigger')).toBeFocused();
|
|
155
|
+
await expect(page.getByTestId('nested-modal')).toHaveCount(1);
|
|
156
|
+
await page.keyboard.press('Escape');
|
|
157
|
+
|
|
158
|
+
await expectCloseCount({ page, count: 1 });
|
|
159
|
+
await expect(page.getByTestId('nested-close-count')).toHaveText('1');
|
|
160
|
+
// The outer modal refuses, so it stays open.
|
|
161
|
+
await expect(page.getByTestId('modal')).toHaveAttribute('open', '');
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
async function openModal({ page, trigger }: { page: Page; trigger: string }) {
|
|
165
|
+
await page.visitExample<typeof import('../../examples/104-testing-escape-refused.tsx')>(
|
|
166
|
+
'design-system',
|
|
167
|
+
'modal-dialog',
|
|
168
|
+
'testing-escape-refused',
|
|
169
|
+
{ featureFlag },
|
|
170
|
+
);
|
|
171
|
+
await page.getByTestId(trigger).click();
|
|
172
|
+
await expect(page.getByTestId('modal')).toBeVisible();
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function expectCloseCount({ page, count }: { page: Page; count: number }) {
|
|
176
|
+
await expect(page.getByTestId('close-count')).toHaveText(String(count));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function nextFrames({ page }: { page: Page }) {
|
|
180
|
+
await page.evaluate(
|
|
181
|
+
() => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve))),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 5 spaced presses, then 20 back to back, then 20 held (repeated `keydown`, one `keyup`).
|
|
186
|
+
async function mashEscape({
|
|
187
|
+
page,
|
|
188
|
+
onSpacedPress,
|
|
189
|
+
}: {
|
|
190
|
+
page: Page;
|
|
191
|
+
onSpacedPress: (pressCount: number) => Promise<void>;
|
|
192
|
+
}) {
|
|
193
|
+
for (let i = 1; i <= 5; i++) {
|
|
194
|
+
await page.keyboard.press('Escape');
|
|
195
|
+
await onSpacedPress(i);
|
|
196
|
+
}
|
|
197
|
+
for (let i = 0; i < 20; i++) {
|
|
198
|
+
await page.keyboard.press('Escape');
|
|
199
|
+
}
|
|
200
|
+
for (let i = 0; i < 20; i++) {
|
|
201
|
+
await page.keyboard.down('Escape');
|
|
202
|
+
}
|
|
203
|
+
await page.keyboard.up('Escape');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
type TDialogLog = {
|
|
207
|
+
escapes: number;
|
|
208
|
+
// The Escape count when each `cancel` fired.
|
|
209
|
+
cancelsAtEscape: number[];
|
|
210
|
+
nativeCloses: number;
|
|
211
|
+
closedToggles: number;
|
|
212
|
+
closedSamples: number;
|
|
213
|
+
focusedTestIds: (string | null)[];
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Records native close events, and samples `dialog.open` on every Escape and every frame.
|
|
217
|
+
async function recordDialogState({ page }: { page: Page }) {
|
|
218
|
+
await page.evaluate(() => {
|
|
219
|
+
const dialog = document.querySelector('dialog');
|
|
220
|
+
if (!dialog) {
|
|
221
|
+
throw new Error('No dialog');
|
|
222
|
+
}
|
|
223
|
+
const log: TDialogLog = {
|
|
224
|
+
escapes: 0,
|
|
225
|
+
cancelsAtEscape: [],
|
|
226
|
+
nativeCloses: 0,
|
|
227
|
+
closedToggles: 0,
|
|
228
|
+
closedSamples: 0,
|
|
229
|
+
focusedTestIds: [],
|
|
230
|
+
};
|
|
231
|
+
const sample = () => {
|
|
232
|
+
if (!dialog.open) {
|
|
233
|
+
log.closedSamples++;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
dialog.addEventListener('cancel', () => log.cancelsAtEscape.push(log.escapes));
|
|
237
|
+
dialog.addEventListener('close', () => log.nativeCloses++);
|
|
238
|
+
dialog.addEventListener('toggle', (event) => {
|
|
239
|
+
if ((event as ToggleEvent).newState === 'closed') {
|
|
240
|
+
log.closedToggles++;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
window.addEventListener(
|
|
244
|
+
'keydown',
|
|
245
|
+
(event) => {
|
|
246
|
+
if (event.key === 'Escape') {
|
|
247
|
+
log.escapes++;
|
|
248
|
+
log.focusedTestIds.push(document.activeElement?.getAttribute('data-testid') ?? null);
|
|
249
|
+
sample();
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
true,
|
|
253
|
+
);
|
|
254
|
+
window.addEventListener('keyup', sample);
|
|
255
|
+
const onFrame = () => {
|
|
256
|
+
sample();
|
|
257
|
+
requestAnimationFrame(onFrame);
|
|
258
|
+
};
|
|
259
|
+
requestAnimationFrame(onFrame);
|
|
260
|
+
(window as unknown as { dialogLog: TDialogLog }).dialogLog = log;
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function expectNeverClosed({
|
|
265
|
+
page,
|
|
266
|
+
escapes,
|
|
267
|
+
focusedTestId,
|
|
268
|
+
skip = 0,
|
|
269
|
+
}: {
|
|
270
|
+
page: Page;
|
|
271
|
+
escapes: number;
|
|
272
|
+
focusedTestId?: string;
|
|
273
|
+
skip?: number;
|
|
274
|
+
}) {
|
|
275
|
+
const log = await page.evaluate(() => (window as unknown as { dialogLog: TDialogLog }).dialogLog);
|
|
276
|
+
expect(log.escapes).toBe(escapes);
|
|
277
|
+
// No close request after `skip`: ModalDialog took every Escape.
|
|
278
|
+
expect(log.cancelsAtEscape.filter((escape) => escape > skip)).toEqual([]);
|
|
279
|
+
expect(log.nativeCloses).toBe(0);
|
|
280
|
+
expect(log.closedToggles).toBe(0);
|
|
281
|
+
expect(log.closedSamples).toBe(0);
|
|
282
|
+
if (focusedTestId) {
|
|
283
|
+
expect(log.focusedTestIds.slice(skip)).toEqual(Array(escapes - skip).fill(focusedTestId));
|
|
284
|
+
}
|
|
285
|
+
await expect(page.getByTestId('modal')).toHaveAttribute('open', '');
|
|
286
|
+
}
|
|
@@ -107,6 +107,7 @@ test.describe('Modal dialog: top-layer focus contract', () => {
|
|
|
107
107
|
},
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
|
+
|
|
110
111
|
test('focus movement: Tab traverses each control before wrapping', async ({ page }) => {
|
|
111
112
|
await page.visitExample<typeof import('../../examples/98-testing-initial-focus-matrix.tsx')>(
|
|
112
113
|
'design-system',
|
|
@@ -13,7 +13,6 @@ var React = _react;
|
|
|
13
13
|
var _runtime = require("@compiled/react/runtime");
|
|
14
14
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
15
15
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
16
|
-
var _bindEventListener = require("bind-event-listener");
|
|
17
16
|
var _reactFocusLock = _interopRequireDefault(require("react-focus-lock"));
|
|
18
17
|
var _reactScrolllock = _interopRequireWildcard(require("react-scrolllock"));
|
|
19
18
|
var _usePlatformLeafEventHandler = require("@atlaskit/analytics-next/usePlatformLeafEventHandler");
|
|
@@ -95,7 +94,7 @@ function useModalCloseHandler(providedOnClose) {
|
|
|
95
94
|
action: 'closed',
|
|
96
95
|
componentName: 'modalDialog',
|
|
97
96
|
packageName: "@atlaskit/modal-dialog",
|
|
98
|
-
packageVersion: "17.0
|
|
97
|
+
packageVersion: "17.1.0"
|
|
99
98
|
});
|
|
100
99
|
}
|
|
101
100
|
function getScrollMode(_ref) {
|
|
@@ -153,7 +152,7 @@ function getTopLayerSurfaceHeight(input) {
|
|
|
153
152
|
}
|
|
154
153
|
return input;
|
|
155
154
|
}
|
|
156
|
-
function
|
|
155
|
+
function getDismissedBy(_ref2) {
|
|
157
156
|
var shouldCloseOnEscapePress = _ref2.shouldCloseOnEscapePress,
|
|
158
157
|
shouldCloseOnOverlayClick = _ref2.shouldCloseOnOverlayClick;
|
|
159
158
|
if (shouldCloseOnEscapePress && shouldCloseOnOverlayClick) {
|
|
@@ -162,6 +161,10 @@ function getDialogDismissedBy(_ref2) {
|
|
|
162
161
|
if (shouldCloseOnEscapePress) {
|
|
163
162
|
return 'escape';
|
|
164
163
|
}
|
|
164
|
+
// Backdrop clicks only: `Dialog` asks on both, and `onDialogAsk` ignores Escape.
|
|
165
|
+
if (shouldCloseOnOverlayClick) {
|
|
166
|
+
return 'escape-and-outside-click';
|
|
167
|
+
}
|
|
165
168
|
return 'none';
|
|
166
169
|
}
|
|
167
170
|
|
|
@@ -173,7 +176,11 @@ function getDialogDismissedBy(_ref2) {
|
|
|
173
176
|
*
|
|
174
177
|
* Key decisions:
|
|
175
178
|
* - Animation: CSS transitions via @starting-style / allow-discrete.
|
|
176
|
-
* - Close gating: Dialog
|
|
179
|
+
* - Close gating: matches legacy while open. Dialog asks on Escape and backdrop
|
|
180
|
+
* clicks (the consumer may refuse any number of times). During the exit they
|
|
181
|
+
* do not call `onClose` again.
|
|
182
|
+
* - A close that Dialog did not ask about (e.g. `<form method="dialog">`): not
|
|
183
|
+
* supported. Dialog shows the modal again, and `onClose` does not run.
|
|
177
184
|
* - onClose event param: undefined - consumers should use close reason.
|
|
178
185
|
* - Focus restoration: native <dialog> behavior replaces react-focus-lock's
|
|
179
186
|
* returnFocus (see accessibility-criteria.md).
|
|
@@ -241,38 +248,39 @@ function ModalWrapperTopLayer(props) {
|
|
|
241
248
|
};
|
|
242
249
|
}, [defaultTestId, titleId, onCloseHandler, hasProvidedOnClose, isFullScreen]);
|
|
243
250
|
|
|
244
|
-
//
|
|
245
|
-
//
|
|
251
|
+
// Pass a synthetic event to satisfy the KeyboardOrMouseEvent contract. Dialog calls this
|
|
252
|
+
// for an allowed Escape or backdrop click.
|
|
246
253
|
var onDialogClose = (0, _react.useCallback)(function (_ref3) {
|
|
247
254
|
var reason = _ref3.reason;
|
|
248
255
|
onCloseHandler((0, _createCloseEvent.createCloseEvent)({
|
|
249
256
|
reason: reason
|
|
250
257
|
}));
|
|
251
258
|
}, [onCloseHandler]);
|
|
252
|
-
var dismissedBy = getDialogDismissedBy({
|
|
253
|
-
shouldCloseOnEscapePress: shouldCloseOnEscapePress,
|
|
254
|
-
shouldCloseOnOverlayClick: shouldCloseOnOverlayClick
|
|
255
|
-
});
|
|
256
|
-
var shouldShimCloseOnOverlayClick = shouldCloseOnOverlayClick && !shouldCloseOnEscapePress;
|
|
257
259
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
/**
|
|
261
|
+
* Dialog asks on an allowed Escape or backdrop click. Ignoring an Escape ask refuses it:
|
|
262
|
+
* Dialog still cancels the Escape `keydown`, so nothing else closes.
|
|
263
|
+
*/
|
|
264
|
+
var onDialogAsk = (0, _react.useCallback)(function (_ref4) {
|
|
265
|
+
var reason = _ref4.reason;
|
|
266
|
+
if (reason === 'escape' && !shouldCloseOnEscapePress) {
|
|
263
267
|
return;
|
|
264
268
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
listener: function listener(event) {
|
|
268
|
-
if (event.target === event.currentTarget) {
|
|
269
|
-
onDialogClose({
|
|
270
|
-
reason: 'overlay-click'
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
}
|
|
269
|
+
onDialogClose({
|
|
270
|
+
reason: reason
|
|
274
271
|
});
|
|
275
|
-
}, [onDialogClose,
|
|
272
|
+
}, [onDialogClose, shouldCloseOnEscapePress]);
|
|
273
|
+
|
|
274
|
+
// Unlike legacy, Escape and backdrop clicks during the exit do not call `onClose` again.
|
|
275
|
+
// See `@atlaskit/top-layer` notes: `decisions/dialog-close-flow.md`.
|
|
276
|
+
|
|
277
|
+
// Dialog could not reopen after a close it did not ask about (its parent layer is closed), so
|
|
278
|
+
// the `<dialog>` is already gone. End the exit.
|
|
279
|
+
(0, _react.useEffect)(function () {
|
|
280
|
+
if (isExiting && !dialogRef.current) {
|
|
281
|
+
onExitFinish === null || onExitFinish === void 0 || onExitFinish();
|
|
282
|
+
}
|
|
283
|
+
}, [isExiting, onExitFinish]);
|
|
276
284
|
|
|
277
285
|
// ExitingPersistence: isExiting → isOpen={false} → Dialog exit animation →
|
|
278
286
|
// onExitFinish → onCloseComplete + unmount.
|
|
@@ -321,8 +329,11 @@ function ModalWrapperTopLayer(props) {
|
|
|
321
329
|
});
|
|
322
330
|
return /*#__PURE__*/React.createElement(_dialogContent.Dialog, (0, _extends2.default)({
|
|
323
331
|
ref: dialogRef,
|
|
324
|
-
onClose:
|
|
325
|
-
dismissedBy:
|
|
332
|
+
onClose: onDialogAsk,
|
|
333
|
+
dismissedBy: getDismissedBy({
|
|
334
|
+
shouldCloseOnEscapePress: shouldCloseOnEscapePress,
|
|
335
|
+
shouldCloseOnOverlayClick: shouldCloseOnOverlayClick
|
|
336
|
+
}),
|
|
326
337
|
onExitFinish: handleDialogExitFinish,
|
|
327
338
|
shouldAnimate: !isFullScreen,
|
|
328
339
|
isOpen: !isExiting,
|
package/dist/cjs/modal-header.js
CHANGED
|
@@ -30,7 +30,8 @@ var ModalHeader = function ModalHeader(props) {
|
|
|
30
30
|
var children = props.children,
|
|
31
31
|
userDefinedTestId = props.testId,
|
|
32
32
|
_props$hasCloseButton = props.hasCloseButton,
|
|
33
|
-
hasCloseButton = _props$hasCloseButton === void 0 ? false : _props$hasCloseButton
|
|
33
|
+
hasCloseButton = _props$hasCloseButton === void 0 ? false : _props$hasCloseButton,
|
|
34
|
+
closeButtonLabel = props.closeButtonLabel;
|
|
34
35
|
var _useModal = (0, _hooks.useModal)(),
|
|
35
36
|
hasProvidedOnClose = _useModal.hasProvidedOnClose,
|
|
36
37
|
onClose = _useModal.onClose,
|
|
@@ -49,6 +50,7 @@ var ModalHeader = function ModalHeader(props) {
|
|
|
49
50
|
}, /*#__PURE__*/_react.default.createElement(_flex.Flex, {
|
|
50
51
|
justifyContent: "end"
|
|
51
52
|
}, /*#__PURE__*/_react.default.createElement(_closeButton.CloseButton, {
|
|
53
|
+
label: closeButtonLabel,
|
|
52
54
|
onClick: onClose,
|
|
53
55
|
testId: modalTestId
|
|
54
56
|
})), /*#__PURE__*/_react.default.createElement(_flex.Flex, {
|
|
@@ -4,7 +4,6 @@ import "./modal-wrapper.compiled.css";
|
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { ax, ix } from "@compiled/react/runtime";
|
|
6
6
|
import { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
7
|
-
import { bind } from 'bind-event-listener';
|
|
8
7
|
import FocusLock from 'react-focus-lock';
|
|
9
8
|
import ScrollLock, { TouchScrollable } from 'react-scrolllock';
|
|
10
9
|
import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next/usePlatformLeafEventHandler';
|
|
@@ -85,7 +84,7 @@ function useModalCloseHandler(providedOnClose) {
|
|
|
85
84
|
action: 'closed',
|
|
86
85
|
componentName: 'modalDialog',
|
|
87
86
|
packageName: "@atlaskit/modal-dialog",
|
|
88
|
-
packageVersion: "17.0
|
|
87
|
+
packageVersion: "17.1.0"
|
|
89
88
|
});
|
|
90
89
|
}
|
|
91
90
|
function getScrollMode({
|
|
@@ -144,7 +143,7 @@ function getTopLayerSurfaceHeight(input) {
|
|
|
144
143
|
}
|
|
145
144
|
return input;
|
|
146
145
|
}
|
|
147
|
-
function
|
|
146
|
+
function getDismissedBy({
|
|
148
147
|
shouldCloseOnEscapePress,
|
|
149
148
|
shouldCloseOnOverlayClick
|
|
150
149
|
}) {
|
|
@@ -154,6 +153,10 @@ function getDialogDismissedBy({
|
|
|
154
153
|
if (shouldCloseOnEscapePress) {
|
|
155
154
|
return 'escape';
|
|
156
155
|
}
|
|
156
|
+
// Backdrop clicks only: `Dialog` asks on both, and `onDialogAsk` ignores Escape.
|
|
157
|
+
if (shouldCloseOnOverlayClick) {
|
|
158
|
+
return 'escape-and-outside-click';
|
|
159
|
+
}
|
|
157
160
|
return 'none';
|
|
158
161
|
}
|
|
159
162
|
|
|
@@ -165,7 +168,11 @@ function getDialogDismissedBy({
|
|
|
165
168
|
*
|
|
166
169
|
* Key decisions:
|
|
167
170
|
* - Animation: CSS transitions via @starting-style / allow-discrete.
|
|
168
|
-
* - Close gating: Dialog
|
|
171
|
+
* - Close gating: matches legacy while open. Dialog asks on Escape and backdrop
|
|
172
|
+
* clicks (the consumer may refuse any number of times). During the exit they
|
|
173
|
+
* do not call `onClose` again.
|
|
174
|
+
* - A close that Dialog did not ask about (e.g. `<form method="dialog">`): not
|
|
175
|
+
* supported. Dialog shows the modal again, and `onClose` does not run.
|
|
169
176
|
* - onClose event param: undefined - consumers should use close reason.
|
|
170
177
|
* - Focus restoration: native <dialog> behavior replaces react-focus-lock's
|
|
171
178
|
* returnFocus (see accessibility-criteria.md).
|
|
@@ -227,8 +234,8 @@ function ModalWrapperTopLayer(props) {
|
|
|
227
234
|
isFullScreen: isFullScreen !== null && isFullScreen !== void 0 ? isFullScreen : false
|
|
228
235
|
}), [defaultTestId, titleId, onCloseHandler, hasProvidedOnClose, isFullScreen]);
|
|
229
236
|
|
|
230
|
-
//
|
|
231
|
-
//
|
|
237
|
+
// Pass a synthetic event to satisfy the KeyboardOrMouseEvent contract. Dialog calls this
|
|
238
|
+
// for an allowed Escape or backdrop click.
|
|
232
239
|
const onDialogClose = useCallback(({
|
|
233
240
|
reason
|
|
234
241
|
}) => {
|
|
@@ -236,30 +243,32 @@ function ModalWrapperTopLayer(props) {
|
|
|
236
243
|
reason
|
|
237
244
|
}));
|
|
238
245
|
}, [onCloseHandler]);
|
|
239
|
-
const dismissedBy = getDialogDismissedBy({
|
|
240
|
-
shouldCloseOnEscapePress,
|
|
241
|
-
shouldCloseOnOverlayClick
|
|
242
|
-
});
|
|
243
|
-
const shouldShimCloseOnOverlayClick = shouldCloseOnOverlayClick && !shouldCloseOnEscapePress;
|
|
244
246
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Dialog asks on an allowed Escape or backdrop click. Ignoring an Escape ask refuses it:
|
|
249
|
+
* Dialog still cancels the Escape `keydown`, so nothing else closes.
|
|
250
|
+
*/
|
|
251
|
+
const onDialogAsk = useCallback(({
|
|
252
|
+
reason
|
|
253
|
+
}) => {
|
|
254
|
+
if (reason === 'escape' && !shouldCloseOnEscapePress) {
|
|
250
255
|
return;
|
|
251
256
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
listener(event) {
|
|
255
|
-
if (event.target === event.currentTarget) {
|
|
256
|
-
onDialogClose({
|
|
257
|
-
reason: 'overlay-click'
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
}
|
|
257
|
+
onDialogClose({
|
|
258
|
+
reason
|
|
261
259
|
});
|
|
262
|
-
}, [onDialogClose,
|
|
260
|
+
}, [onDialogClose, shouldCloseOnEscapePress]);
|
|
261
|
+
|
|
262
|
+
// Unlike legacy, Escape and backdrop clicks during the exit do not call `onClose` again.
|
|
263
|
+
// See `@atlaskit/top-layer` notes: `decisions/dialog-close-flow.md`.
|
|
264
|
+
|
|
265
|
+
// Dialog could not reopen after a close it did not ask about (its parent layer is closed), so
|
|
266
|
+
// the `<dialog>` is already gone. End the exit.
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
if (isExiting && !dialogRef.current) {
|
|
269
|
+
onExitFinish === null || onExitFinish === void 0 ? void 0 : onExitFinish();
|
|
270
|
+
}
|
|
271
|
+
}, [isExiting, onExitFinish]);
|
|
263
272
|
|
|
264
273
|
// ExitingPersistence: isExiting → isOpen={false} → Dialog exit animation →
|
|
265
274
|
// onExitFinish → onCloseComplete + unmount.
|
|
@@ -308,8 +317,11 @@ function ModalWrapperTopLayer(props) {
|
|
|
308
317
|
});
|
|
309
318
|
return /*#__PURE__*/React.createElement(Dialog, _extends({
|
|
310
319
|
ref: dialogRef,
|
|
311
|
-
onClose:
|
|
312
|
-
dismissedBy:
|
|
320
|
+
onClose: onDialogAsk,
|
|
321
|
+
dismissedBy: getDismissedBy({
|
|
322
|
+
shouldCloseOnEscapePress,
|
|
323
|
+
shouldCloseOnOverlayClick
|
|
324
|
+
}),
|
|
313
325
|
onExitFinish: handleDialogExitFinish,
|
|
314
326
|
shouldAnimate: !isFullScreen,
|
|
315
327
|
isOpen: !isExiting,
|
|
@@ -23,7 +23,8 @@ const ModalHeader = props => {
|
|
|
23
23
|
const {
|
|
24
24
|
children,
|
|
25
25
|
testId: userDefinedTestId,
|
|
26
|
-
hasCloseButton = false
|
|
26
|
+
hasCloseButton = false,
|
|
27
|
+
closeButtonLabel
|
|
27
28
|
} = props;
|
|
28
29
|
const {
|
|
29
30
|
hasProvidedOnClose,
|
|
@@ -44,6 +45,7 @@ const ModalHeader = props => {
|
|
|
44
45
|
}, /*#__PURE__*/React.createElement(Flex, {
|
|
45
46
|
justifyContent: "end"
|
|
46
47
|
}, /*#__PURE__*/React.createElement(CloseButton, {
|
|
48
|
+
label: closeButtonLabel,
|
|
47
49
|
onClick: onClose,
|
|
48
50
|
testId: modalTestId
|
|
49
51
|
})), /*#__PURE__*/React.createElement(Flex, {
|
|
@@ -5,7 +5,6 @@ import "./modal-wrapper.compiled.css";
|
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import { ax, ix } from "@compiled/react/runtime";
|
|
7
7
|
import { forwardRef, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
8
|
-
import { bind } from 'bind-event-listener';
|
|
9
8
|
import FocusLock from 'react-focus-lock';
|
|
10
9
|
import ScrollLock, { TouchScrollable } from 'react-scrolllock';
|
|
11
10
|
import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next/usePlatformLeafEventHandler';
|
|
@@ -86,7 +85,7 @@ function useModalCloseHandler(providedOnClose) {
|
|
|
86
85
|
action: 'closed',
|
|
87
86
|
componentName: 'modalDialog',
|
|
88
87
|
packageName: "@atlaskit/modal-dialog",
|
|
89
|
-
packageVersion: "17.0
|
|
88
|
+
packageVersion: "17.1.0"
|
|
90
89
|
});
|
|
91
90
|
}
|
|
92
91
|
function getScrollMode(_ref) {
|
|
@@ -144,7 +143,7 @@ function getTopLayerSurfaceHeight(input) {
|
|
|
144
143
|
}
|
|
145
144
|
return input;
|
|
146
145
|
}
|
|
147
|
-
function
|
|
146
|
+
function getDismissedBy(_ref2) {
|
|
148
147
|
var shouldCloseOnEscapePress = _ref2.shouldCloseOnEscapePress,
|
|
149
148
|
shouldCloseOnOverlayClick = _ref2.shouldCloseOnOverlayClick;
|
|
150
149
|
if (shouldCloseOnEscapePress && shouldCloseOnOverlayClick) {
|
|
@@ -153,6 +152,10 @@ function getDialogDismissedBy(_ref2) {
|
|
|
153
152
|
if (shouldCloseOnEscapePress) {
|
|
154
153
|
return 'escape';
|
|
155
154
|
}
|
|
155
|
+
// Backdrop clicks only: `Dialog` asks on both, and `onDialogAsk` ignores Escape.
|
|
156
|
+
if (shouldCloseOnOverlayClick) {
|
|
157
|
+
return 'escape-and-outside-click';
|
|
158
|
+
}
|
|
156
159
|
return 'none';
|
|
157
160
|
}
|
|
158
161
|
|
|
@@ -164,7 +167,11 @@ function getDialogDismissedBy(_ref2) {
|
|
|
164
167
|
*
|
|
165
168
|
* Key decisions:
|
|
166
169
|
* - Animation: CSS transitions via @starting-style / allow-discrete.
|
|
167
|
-
* - Close gating: Dialog
|
|
170
|
+
* - Close gating: matches legacy while open. Dialog asks on Escape and backdrop
|
|
171
|
+
* clicks (the consumer may refuse any number of times). During the exit they
|
|
172
|
+
* do not call `onClose` again.
|
|
173
|
+
* - A close that Dialog did not ask about (e.g. `<form method="dialog">`): not
|
|
174
|
+
* supported. Dialog shows the modal again, and `onClose` does not run.
|
|
168
175
|
* - onClose event param: undefined - consumers should use close reason.
|
|
169
176
|
* - Focus restoration: native <dialog> behavior replaces react-focus-lock's
|
|
170
177
|
* returnFocus (see accessibility-criteria.md).
|
|
@@ -232,38 +239,39 @@ function ModalWrapperTopLayer(props) {
|
|
|
232
239
|
};
|
|
233
240
|
}, [defaultTestId, titleId, onCloseHandler, hasProvidedOnClose, isFullScreen]);
|
|
234
241
|
|
|
235
|
-
//
|
|
236
|
-
//
|
|
242
|
+
// Pass a synthetic event to satisfy the KeyboardOrMouseEvent contract. Dialog calls this
|
|
243
|
+
// for an allowed Escape or backdrop click.
|
|
237
244
|
var onDialogClose = useCallback(function (_ref3) {
|
|
238
245
|
var reason = _ref3.reason;
|
|
239
246
|
onCloseHandler(createCloseEvent({
|
|
240
247
|
reason: reason
|
|
241
248
|
}));
|
|
242
249
|
}, [onCloseHandler]);
|
|
243
|
-
var dismissedBy = getDialogDismissedBy({
|
|
244
|
-
shouldCloseOnEscapePress: shouldCloseOnEscapePress,
|
|
245
|
-
shouldCloseOnOverlayClick: shouldCloseOnOverlayClick
|
|
246
|
-
});
|
|
247
|
-
var shouldShimCloseOnOverlayClick = shouldCloseOnOverlayClick && !shouldCloseOnEscapePress;
|
|
248
250
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
/**
|
|
252
|
+
* Dialog asks on an allowed Escape or backdrop click. Ignoring an Escape ask refuses it:
|
|
253
|
+
* Dialog still cancels the Escape `keydown`, so nothing else closes.
|
|
254
|
+
*/
|
|
255
|
+
var onDialogAsk = useCallback(function (_ref4) {
|
|
256
|
+
var reason = _ref4.reason;
|
|
257
|
+
if (reason === 'escape' && !shouldCloseOnEscapePress) {
|
|
254
258
|
return;
|
|
255
259
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
listener: function listener(event) {
|
|
259
|
-
if (event.target === event.currentTarget) {
|
|
260
|
-
onDialogClose({
|
|
261
|
-
reason: 'overlay-click'
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
}
|
|
260
|
+
onDialogClose({
|
|
261
|
+
reason: reason
|
|
265
262
|
});
|
|
266
|
-
}, [onDialogClose,
|
|
263
|
+
}, [onDialogClose, shouldCloseOnEscapePress]);
|
|
264
|
+
|
|
265
|
+
// Unlike legacy, Escape and backdrop clicks during the exit do not call `onClose` again.
|
|
266
|
+
// See `@atlaskit/top-layer` notes: `decisions/dialog-close-flow.md`.
|
|
267
|
+
|
|
268
|
+
// Dialog could not reopen after a close it did not ask about (its parent layer is closed), so
|
|
269
|
+
// the `<dialog>` is already gone. End the exit.
|
|
270
|
+
useEffect(function () {
|
|
271
|
+
if (isExiting && !dialogRef.current) {
|
|
272
|
+
onExitFinish === null || onExitFinish === void 0 || onExitFinish();
|
|
273
|
+
}
|
|
274
|
+
}, [isExiting, onExitFinish]);
|
|
267
275
|
|
|
268
276
|
// ExitingPersistence: isExiting → isOpen={false} → Dialog exit animation →
|
|
269
277
|
// onExitFinish → onCloseComplete + unmount.
|
|
@@ -312,8 +320,11 @@ function ModalWrapperTopLayer(props) {
|
|
|
312
320
|
});
|
|
313
321
|
return /*#__PURE__*/React.createElement(Dialog, _extends({
|
|
314
322
|
ref: dialogRef,
|
|
315
|
-
onClose:
|
|
316
|
-
dismissedBy:
|
|
323
|
+
onClose: onDialogAsk,
|
|
324
|
+
dismissedBy: getDismissedBy({
|
|
325
|
+
shouldCloseOnEscapePress: shouldCloseOnEscapePress,
|
|
326
|
+
shouldCloseOnOverlayClick: shouldCloseOnOverlayClick
|
|
327
|
+
}),
|
|
317
328
|
onExitFinish: handleDialogExitFinish,
|
|
318
329
|
shouldAnimate: !isFullScreen,
|
|
319
330
|
isOpen: !isExiting,
|
package/dist/esm/modal-header.js
CHANGED
|
@@ -23,7 +23,8 @@ var ModalHeader = function ModalHeader(props) {
|
|
|
23
23
|
var children = props.children,
|
|
24
24
|
userDefinedTestId = props.testId,
|
|
25
25
|
_props$hasCloseButton = props.hasCloseButton,
|
|
26
|
-
hasCloseButton = _props$hasCloseButton === void 0 ? false : _props$hasCloseButton
|
|
26
|
+
hasCloseButton = _props$hasCloseButton === void 0 ? false : _props$hasCloseButton,
|
|
27
|
+
closeButtonLabel = props.closeButtonLabel;
|
|
27
28
|
var _useModal = useModal(),
|
|
28
29
|
hasProvidedOnClose = _useModal.hasProvidedOnClose,
|
|
29
30
|
onClose = _useModal.onClose,
|
|
@@ -42,6 +43,7 @@ var ModalHeader = function ModalHeader(props) {
|
|
|
42
43
|
}, /*#__PURE__*/React.createElement(Flex, {
|
|
43
44
|
justifyContent: "end"
|
|
44
45
|
}, /*#__PURE__*/React.createElement(CloseButton, {
|
|
46
|
+
label: closeButtonLabel,
|
|
45
47
|
onClick: onClose,
|
|
46
48
|
testId: modalTestId
|
|
47
49
|
})), /*#__PURE__*/React.createElement(Flex, {
|
|
@@ -13,6 +13,10 @@ export interface ModalHeaderProps {
|
|
|
13
13
|
* @default false
|
|
14
14
|
*/
|
|
15
15
|
hasCloseButton?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The accessible name for the close button when `hasCloseButton` is true.
|
|
18
|
+
*/
|
|
19
|
+
closeButtonLabel?: string;
|
|
16
20
|
/**
|
|
17
21
|
* A `testId` prop is provided for specified elements,
|
|
18
22
|
* which is a unique string that appears as a data attribute `data-testid` in the rendered code,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/modal-dialog",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.1.1",
|
|
4
4
|
"description": "A modal dialog displays content that requires user interaction, in a layer above the page.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@atlaskit/analytics-next": "^12.6.0",
|
|
41
41
|
"@atlaskit/blanket": "^16.4.0",
|
|
42
|
-
"@atlaskit/button": "^25.
|
|
42
|
+
"@atlaskit/button": "^25.5.0",
|
|
43
43
|
"@atlaskit/css": "^1.1.0",
|
|
44
44
|
"@atlaskit/ds-lib": "^8.0.0",
|
|
45
45
|
"@atlaskit/icon": "^38.0.0",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"@atlaskit/platform-feature-flags": "^2.2.0",
|
|
49
49
|
"@atlaskit/portal": "^7.0.0",
|
|
50
50
|
"@atlaskit/pragmatic-drag-and-drop": "^4.0.0",
|
|
51
|
-
"@atlaskit/primitives": "^22.
|
|
51
|
+
"@atlaskit/primitives": "^22.6.0",
|
|
52
52
|
"@atlaskit/react-compiler-gating": "^0.2.0",
|
|
53
53
|
"@atlaskit/theme": "^28.2.0",
|
|
54
|
-
"@atlaskit/tokens": "^20.
|
|
55
|
-
"@atlaskit/top-layer": "^6.
|
|
54
|
+
"@atlaskit/tokens": "^20.6.0",
|
|
55
|
+
"@atlaskit/top-layer": "^6.4.0",
|
|
56
56
|
"@babel/runtime": "^7.0.0",
|
|
57
57
|
"@compiled/react": "^1.0.2",
|
|
58
58
|
"bind-event-listener": "^3.0.0",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@atlaskit/form": "^18.2.0",
|
|
81
81
|
"@atlaskit/heading": "^8.0.0",
|
|
82
82
|
"@atlaskit/link": "^5.1.0",
|
|
83
|
-
"@atlaskit/popup": "^
|
|
83
|
+
"@atlaskit/popup": "^10.0.0",
|
|
84
84
|
"@atlaskit/radio": "^10.2.0",
|
|
85
85
|
"@atlaskit/section-message": "^10.2.0",
|
|
86
86
|
"@atlaskit/select": "^23.1.0",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"@atlassian/feature-flags-test-utils": "^1.3.0",
|
|
91
91
|
"@atlassian/ssr-tests": "workspace:^",
|
|
92
92
|
"@atlassian/structured-docs-types": "workspace:^",
|
|
93
|
-
"@atlassian/testing-library": "^0.
|
|
93
|
+
"@atlassian/testing-library": "^0.12.0",
|
|
94
94
|
"@atlassian/workbench": "workspace:*",
|
|
95
95
|
"@testing-library/dom": "^10.1.0",
|
|
96
96
|
"@types/raf-schd": "^4.0.1",
|