@atlaskit/modal-dialog 17.0.2 → 17.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @atlaskit/modal-dialog
2
2
 
3
+ ## 17.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`cf31b7db11afe`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cf31b7db11afe) -
8
+ Isolate container content from parent entry and exit motion behind
9
+ platform-dst-motion-isolate-presence, so nested tags animate only for their own changes.
10
+ - Updated dependencies
11
+
3
12
  ## 17.0.2
4
13
 
5
14
  ### Patch Changes
@@ -18,24 +18,12 @@ import { expect, test } from '@af/integration-testing';
18
18
  const featureFlag = 'platform-dst-top-layer';
19
19
 
20
20
  test.describe('Modal dialog: top-layer focus contract', () => {
21
- test('initial focus: focus moves to first focusable element on open', async ({ page }) => {
22
- await page.visitExample<typeof import('../../examples/98-testing-initial-focus-matrix.tsx')>(
23
- 'design-system',
24
- 'modal-dialog',
25
- 'testing-initial-focus-matrix',
26
- { featureFlag },
27
- );
28
-
29
- await page.getByTestId('default-modal-trigger').click();
30
-
31
- const modal = page.getByTestId('default-modal');
32
- await expect(modal).toBeVisible();
33
-
34
- // The first focusable inside the modal is the header's close button.
35
- await expect(page.getByTestId('default-modal--close-button')).toBeFocused();
36
- });
37
-
38
- test('focus restoration: Escape restores focus to the trigger', async ({ page }) => {
21
+ // The blocking interaction fixture asserts the lifecycle during teardown.
22
+ // eslint-disable-next-line playwright/expect-expect
23
+ test('focus lifecycle: default focus moves into the modal and returns to the trigger', async ({
24
+ page,
25
+ interactionA11y,
26
+ }) => {
39
27
  await page.visitExample<typeof import('../../examples/98-testing-initial-focus-matrix.tsx')>(
40
28
  'design-system',
41
29
  'modal-dialog',
@@ -44,12 +32,14 @@ test.describe('Modal dialog: top-layer focus contract', () => {
44
32
  );
45
33
 
46
34
  const trigger = page.getByTestId('default-modal-trigger');
47
- await trigger.click();
48
- await expect(page.getByTestId('default-modal')).toBeVisible();
35
+ const modal = page.getByTestId('default-modal');
49
36
 
50
- await page.keyboard.press('Escape');
51
- await expect(page.getByTestId('default-modal')).toBeHidden();
52
- await expect(trigger).toBeFocused();
37
+ await interactionA11y.checkModalFocus({
38
+ trigger,
39
+ dialog: modal,
40
+ open: () => trigger.click(),
41
+ dismiss: () => page.keyboard.press('Escape'),
42
+ });
53
43
  });
54
44
 
55
45
  // WCAG 2.4.3 Focus Order + HTML `<dialog>` focusing steps
@@ -58,8 +48,11 @@ test.describe('Modal dialog: top-layer focus contract', () => {
58
48
  // attribute, focus must land on that element instead of the first
59
49
  // focusable. This matches both `<dialog>.showModal()` and the
60
50
  // WAI-ARIA APG Dialog pattern.
61
- test('initial focus: native [autofocus] element wins over the first focusable element', async ({
51
+ // The blocking interaction fixture asserts the lifecycle during teardown.
52
+ // eslint-disable-next-line playwright/expect-expect
53
+ test('focus lifecycle: native [autofocus] wins over the first focusable element', async ({
62
54
  page,
55
+ interactionA11y,
63
56
  }) => {
64
57
  await page.visitExample<typeof import('../../examples/98-testing-initial-focus-matrix.tsx')>(
65
58
  'design-system',
@@ -68,15 +61,15 @@ test.describe('Modal dialog: top-layer focus contract', () => {
68
61
  { featureFlag },
69
62
  );
70
63
 
71
- await page.getByTestId('native-autofocus-modal-trigger').click();
72
-
64
+ const trigger = page.getByTestId('native-autofocus-modal-trigger');
73
65
  const modal = page.getByTestId('native-autofocus-modal');
74
- await expect(modal).toBeVisible();
75
66
 
76
- // The first focusable inside the modal is the header close
77
- // button, but the body input carries `autofocus`, so focus must
78
- // land on the input.
79
- await expect(page.getByTestId('native-autofocus-input')).toBeFocused();
67
+ await interactionA11y.checkModalFocus({
68
+ trigger,
69
+ dialog: modal,
70
+ open: () => trigger.click(),
71
+ dismiss: () => page.keyboard.press('Escape'),
72
+ });
80
73
  });
81
74
 
82
75
  // WCAG 2.4.3 Focus Order. `Modal`'s `autoFocus` prop accepts a
@@ -86,7 +79,12 @@ test.describe('Modal dialog: top-layer focus contract', () => {
86
79
  // outside `useInitialFocus`, but it shares the same WCAG / APG
87
80
  // contract: the chosen element receives focus instead of the
88
81
  // natural first focusable.
89
- test('initial focus: `autoFocus` ref overrides the first focusable element', async ({ page }) => {
82
+ // The blocking interaction fixture asserts the lifecycle during teardown.
83
+ // eslint-disable-next-line playwright/expect-expect
84
+ test('focus lifecycle: `autoFocus` ref is a documented initial-focus exception', async ({
85
+ page,
86
+ interactionA11y,
87
+ }) => {
90
88
  await page.visitExample<typeof import('../../examples/98-testing-initial-focus-matrix.tsx')>(
91
89
  'design-system',
92
90
  'modal-dialog',
@@ -94,48 +92,35 @@ test.describe('Modal dialog: top-layer focus contract', () => {
94
92
  { featureFlag },
95
93
  );
96
94
 
97
- await page.getByTestId('auto-focus-ref-modal-trigger').click();
98
-
95
+ const trigger = page.getByTestId('auto-focus-ref-modal-trigger');
99
96
  const modal = page.getByTestId('auto-focus-ref-modal');
100
- await expect(modal).toBeVisible();
101
-
102
- // The header close button is the first focusable, but the
103
- // consumer pointed `autoFocus` at the body input, so focus must
104
- // land on the input.
105
- await expect(page.getByTestId('auto-focus-ref-input')).toBeFocused();
97
+ const autoFocusInput = page.getByTestId('auto-focus-ref-input');
98
+
99
+ await interactionA11y.checkModalFocus({
100
+ trigger,
101
+ dialog: modal,
102
+ open: () => trigger.click(),
103
+ dismiss: () => page.keyboard.press('Escape'),
104
+ initialFocusException: {
105
+ target: autoFocusInput,
106
+ reason: 'Characterises supported ADS Modal autoFocus ref behavior.',
107
+ },
108
+ });
106
109
  });
107
-
108
- test('focus movement: Tab cycles focus within the modal', async ({ page }) => {
110
+ test('focus movement: Tab traverses each control before wrapping', async ({ page }) => {
109
111
  await page.visitExample<typeof import('../../examples/98-testing-initial-focus-matrix.tsx')>(
110
112
  'design-system',
111
113
  'modal-dialog',
112
114
  'testing-initial-focus-matrix',
113
115
  { featureFlag },
114
116
  );
115
-
116
117
  await page.getByTestId('default-modal-trigger').click();
117
- const modal = page.getByTestId('default-modal');
118
- await expect(modal).toBeVisible();
119
-
120
- // Walk forward through every focusable element in the modal and verify
121
- // focus never escapes the dialog surface.
122
- const focusables = [
123
- page.getByTestId('default-modal--close-button'),
124
- page.getByTestId('default-modal-secondary'),
125
- page.getByTestId('default-modal-primary'),
126
- ];
127
-
128
- for (const target of focusables) {
129
- await expect(target).toBeFocused();
130
- await page.keyboard.press('Tab');
131
- }
132
-
133
- // After cycling past the last focusable, focus must remain inside the
134
- // modal (focus wrap), never on a node outside it.
135
- const activeWithinModal = await modal.evaluate(
136
- (modalElement) =>
137
- document.activeElement !== null && modalElement.contains(document.activeElement),
138
- );
139
- expect(activeWithinModal).toBe(true);
118
+ await expect(page.getByTestId('default-modal--close-button')).toBeFocused();
119
+ await page.keyboard.press('Tab');
120
+ await expect(page.getByTestId('default-modal-secondary')).toBeFocused();
121
+ await page.keyboard.press('Tab');
122
+ await expect(page.getByTestId('default-modal-primary')).toBeFocused();
123
+ await page.keyboard.press('Tab');
124
+ await expect(page.getByTestId('default-modal--close-button')).toBeFocused();
140
125
  });
141
126
  });
@@ -26,6 +26,7 @@ var _useNotifyOpenLayerObserver = require("@atlaskit/layering/use-notify-open-la
26
26
  var _motion = _interopRequireDefault(require("@atlaskit/motion/entering/motion"));
27
27
  var _useExitingPersistence = require("@atlaskit/motion/exiting-persistence/use-exiting-persistence");
28
28
  var _fadeIn = _interopRequireDefault(require("@atlaskit/motion/fade-in"));
29
+ var _motionPresenceBoundary = _interopRequireDefault(require("@atlaskit/motion/motion-presence-boundary"));
29
30
  var _fg = require("@atlaskit/platform-feature-flags/fg");
30
31
  var _portal = _interopRequireDefault(require("@atlaskit/portal/portal"));
31
32
  var _combine = require("@atlaskit/pragmatic-drag-and-drop/utils/combine");
@@ -94,7 +95,7 @@ function useModalCloseHandler(providedOnClose) {
94
95
  action: 'closed',
95
96
  componentName: 'modalDialog',
96
97
  packageName: "@atlaskit/modal-dialog",
97
- packageVersion: "17.0.1"
98
+ packageVersion: "17.0.2"
98
99
  });
99
100
  }
100
101
  function getScrollMode(_ref) {
@@ -349,7 +350,7 @@ function ModalWrapperTopLayer(props) {
349
350
  value: modalDialogContext
350
351
  }, /*#__PURE__*/React.createElement(_scrollContext.ScrollContext.Provider, {
351
352
  value: shouldScrollInViewport
352
- }, children))));
353
+ }, /*#__PURE__*/React.createElement(_motionPresenceBoundary.default, null, children)))));
353
354
  }
354
355
 
355
356
  /**
@@ -437,7 +438,7 @@ var ModalWrapperLegacy = /*#__PURE__*/(0, _react.forwardRef)(function (props, re
437
438
  isFullScreen: isFullScreen,
438
439
  UNSAFE_shouldDisableMotionUplift: UNSAFE_shouldDisableMotionUplift,
439
440
  ref: ref
440
- }, children));
441
+ }, /*#__PURE__*/React.createElement(_motionPresenceBoundary.default, null, children)));
441
442
  var returnFocus = true;
442
443
  var onDeactivation = _noop.default;
443
444
  if ('boolean' === typeof shouldReturnFocus) {
@@ -17,7 +17,7 @@ var _css = require("@atlaskit/css");
17
17
  var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
18
18
  var _noop = _interopRequireDefault(require("@atlaskit/ds-lib/noop"));
19
19
  var _useLazyCallback = _interopRequireDefault(require("@atlaskit/ds-lib/use-lazy-callback"));
20
- var _compiled = require("@atlaskit/primitives/compiled");
20
+ var _focusable = require("@atlaskit/primitives/compiled/focusable");
21
21
  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); }
22
22
  var keylineColor = "var(--ds-border, #0B120E24)";
23
23
  var styles = {
@@ -87,7 +87,7 @@ var ScrollContainer = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref) {
87
87
  unbindTargetEvent();
88
88
  };
89
89
  }, [setLazyKeylines]);
90
- return /*#__PURE__*/_react.default.createElement(_compiled.Focusable, {
90
+ return /*#__PURE__*/_react.default.createElement(_focusable.Focusable, {
91
91
  as: "div",
92
92
  isInset: true
93
93
  // tabindex is allowed here so that keyboard users can scroll content
@@ -9,7 +9,7 @@ exports.default = void 0;
9
9
  require("./modal-header.compiled.css");
10
10
  var _runtime = require("@compiled/react/runtime");
11
11
  var _react = _interopRequireDefault(require("react"));
12
- var _compiled = require("@atlaskit/primitives/compiled");
12
+ var _flex = require("@atlaskit/primitives/compiled/flex");
13
13
  var _closeButton = require("./close-button");
14
14
  var _hooks = require("./hooks");
15
15
  var styles = {
@@ -42,16 +42,16 @@ var ModalHeader = function ModalHeader(props) {
42
42
  return /*#__PURE__*/_react.default.createElement("div", {
43
43
  "data-testid": testId,
44
44
  className: (0, _runtime.ax)([styles.header])
45
- }, shouldShowCloseButton ? /*#__PURE__*/_react.default.createElement(_compiled.Flex, {
45
+ }, shouldShowCloseButton ? /*#__PURE__*/_react.default.createElement(_flex.Flex, {
46
46
  gap: "space.200",
47
47
  justifyContent: "space-between",
48
48
  xcss: styles.flex
49
- }, /*#__PURE__*/_react.default.createElement(_compiled.Flex, {
49
+ }, /*#__PURE__*/_react.default.createElement(_flex.Flex, {
50
50
  justifyContent: "end"
51
51
  }, /*#__PURE__*/_react.default.createElement(_closeButton.CloseButton, {
52
52
  onClick: onClose,
53
53
  testId: modalTestId
54
- })), /*#__PURE__*/_react.default.createElement(_compiled.Flex, {
54
+ })), /*#__PURE__*/_react.default.createElement(_flex.Flex, {
55
55
  justifyContent: "start",
56
56
  alignItems: "center",
57
57
  xcss: styles.titleContainer
@@ -17,6 +17,7 @@ import { useNotifyOpenLayerObserver } from '@atlaskit/layering/use-notify-open-l
17
17
  import Motion from '@atlaskit/motion/entering/motion';
18
18
  import { useExitingPersistence } from '@atlaskit/motion/exiting-persistence/use-exiting-persistence';
19
19
  import FadeIn from '@atlaskit/motion/fade-in';
20
+ import MotionPresenceBoundary from '@atlaskit/motion/motion-presence-boundary';
20
21
  import { fg } from '@atlaskit/platform-feature-flags/fg';
21
22
  import Portal from '@atlaskit/portal/portal';
22
23
  import { combine } from '@atlaskit/pragmatic-drag-and-drop/utils/combine';
@@ -84,7 +85,7 @@ function useModalCloseHandler(providedOnClose) {
84
85
  action: 'closed',
85
86
  componentName: 'modalDialog',
86
87
  packageName: "@atlaskit/modal-dialog",
87
- packageVersion: "17.0.1"
88
+ packageVersion: "17.0.2"
88
89
  });
89
90
  }
90
91
  function getScrollMode({
@@ -336,7 +337,7 @@ function ModalWrapperTopLayer(props) {
336
337
  value: modalDialogContext
337
338
  }, /*#__PURE__*/React.createElement(ScrollContext.Provider, {
338
339
  value: shouldScrollInViewport
339
- }, children))));
340
+ }, /*#__PURE__*/React.createElement(MotionPresenceBoundary, null, children)))));
340
341
  }
341
342
 
342
343
  /**
@@ -418,7 +419,7 @@ const ModalWrapperLegacy = /*#__PURE__*/forwardRef((props, ref) => {
418
419
  isFullScreen: isFullScreen,
419
420
  UNSAFE_shouldDisableMotionUplift: UNSAFE_shouldDisableMotionUplift,
420
421
  ref: ref
421
- }, children));
422
+ }, /*#__PURE__*/React.createElement(MotionPresenceBoundary, null, children)));
422
423
  let returnFocus = true;
423
424
  let onDeactivation = noop;
424
425
  if ('boolean' === typeof shouldReturnFocus) {
@@ -8,7 +8,7 @@ import { cx } from '@atlaskit/css';
8
8
  import mergeRefs from '@atlaskit/ds-lib/merge-refs';
9
9
  import noop from '@atlaskit/ds-lib/noop';
10
10
  import useLazyCallback from '@atlaskit/ds-lib/use-lazy-callback';
11
- import { Focusable } from '@atlaskit/primitives/compiled';
11
+ import { Focusable } from '@atlaskit/primitives/compiled/focusable';
12
12
  const keylineColor = "var(--ds-border, #0B120E24)";
13
13
  const styles = {
14
14
  base: "_kkes1kw7 _1e0c1kw7 _2lx21kw7 _16jlkb7n _6rthze3t _1pfhze3t _12l2ze3t _ahbqze3t _1reo15vq _18m91wug _1jykn7od _wzg61wug",
@@ -2,7 +2,7 @@
2
2
  import "./modal-header.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React from 'react';
5
- import { Flex } from '@atlaskit/primitives/compiled';
5
+ import { Flex } from '@atlaskit/primitives/compiled/flex';
6
6
  import { CloseButton } from './close-button';
7
7
  import { useModal } from './hooks';
8
8
  const styles = {
@@ -18,6 +18,7 @@ import { useNotifyOpenLayerObserver } from '@atlaskit/layering/use-notify-open-l
18
18
  import Motion from '@atlaskit/motion/entering/motion';
19
19
  import { useExitingPersistence } from '@atlaskit/motion/exiting-persistence/use-exiting-persistence';
20
20
  import FadeIn from '@atlaskit/motion/fade-in';
21
+ import MotionPresenceBoundary from '@atlaskit/motion/motion-presence-boundary';
21
22
  import { fg } from '@atlaskit/platform-feature-flags/fg';
22
23
  import Portal from '@atlaskit/portal/portal';
23
24
  import { combine } from '@atlaskit/pragmatic-drag-and-drop/utils/combine';
@@ -85,7 +86,7 @@ function useModalCloseHandler(providedOnClose) {
85
86
  action: 'closed',
86
87
  componentName: 'modalDialog',
87
88
  packageName: "@atlaskit/modal-dialog",
88
- packageVersion: "17.0.1"
89
+ packageVersion: "17.0.2"
89
90
  });
90
91
  }
91
92
  function getScrollMode(_ref) {
@@ -340,7 +341,7 @@ function ModalWrapperTopLayer(props) {
340
341
  value: modalDialogContext
341
342
  }, /*#__PURE__*/React.createElement(ScrollContext.Provider, {
342
343
  value: shouldScrollInViewport
343
- }, children))));
344
+ }, /*#__PURE__*/React.createElement(MotionPresenceBoundary, null, children)))));
344
345
  }
345
346
 
346
347
  /**
@@ -428,7 +429,7 @@ var ModalWrapperLegacy = /*#__PURE__*/forwardRef(function (props, ref) {
428
429
  isFullScreen: isFullScreen,
429
430
  UNSAFE_shouldDisableMotionUplift: UNSAFE_shouldDisableMotionUplift,
430
431
  ref: ref
431
- }, children));
432
+ }, /*#__PURE__*/React.createElement(MotionPresenceBoundary, null, children)));
432
433
  var returnFocus = true;
433
434
  var onDeactivation = noop;
434
435
  if ('boolean' === typeof shouldReturnFocus) {
@@ -9,7 +9,7 @@ import { cx } from '@atlaskit/css';
9
9
  import mergeRefs from '@atlaskit/ds-lib/merge-refs';
10
10
  import noop from '@atlaskit/ds-lib/noop';
11
11
  import useLazyCallback from '@atlaskit/ds-lib/use-lazy-callback';
12
- import { Focusable } from '@atlaskit/primitives/compiled';
12
+ import { Focusable } from '@atlaskit/primitives/compiled/focusable';
13
13
  var keylineColor = "var(--ds-border, #0B120E24)";
14
14
  var styles = {
15
15
  base: "_kkes1kw7 _1e0c1kw7 _2lx21kw7 _16jlkb7n _6rthze3t _1pfhze3t _12l2ze3t _ahbqze3t _1reo15vq _18m91wug _1jykn7od _wzg61wug",
@@ -2,7 +2,7 @@
2
2
  import "./modal-header.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React from 'react';
5
- import { Flex } from '@atlaskit/primitives/compiled';
5
+ import { Flex } from '@atlaskit/primitives/compiled/flex';
6
6
  import { CloseButton } from './close-button';
7
7
  import { useModal } from './hooks';
8
8
  var styles = {
@@ -1,2 +1,2 @@
1
- import { type CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';
1
+ import type { CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/internal-types';
2
2
  export declare function disableDraggingToCrossOriginIFramesForElement(): CleanupFn;
@@ -1,2 +1,2 @@
1
- import { type CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';
1
+ import type { CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/internal-types';
2
2
  export declare function disableDraggingToCrossOriginIFramesForExternal(): CleanupFn;
@@ -1,4 +1,4 @@
1
- import { type CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';
1
+ import type { CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/internal-types';
2
2
  export declare function makeFixForAdapter({ watchForInteractionStart, watchForInteractionEnd, }: {
3
3
  watchForInteractionStart: ({ start }: {
4
4
  start: () => void;
@@ -1,2 +1,2 @@
1
- import { type CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/types';
1
+ import type { CleanupFn } from '@atlaskit/pragmatic-drag-and-drop/internal-types';
2
2
  export declare function disableDraggingToCrossOriginIFramesForTextSelection(): CleanupFn;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/modal-dialog",
3
- "version": "17.0.2",
3
+ "version": "17.0.3",
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/"
@@ -44,7 +44,7 @@
44
44
  "@atlaskit/ds-lib": "^8.0.0",
45
45
  "@atlaskit/icon": "^38.0.0",
46
46
  "@atlaskit/layering": "^6.0.0",
47
- "@atlaskit/motion": "^9.3.0",
47
+ "@atlaskit/motion": "^9.4.0",
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",