@atlaskit/dropdown-menu 16.10.6 → 17.0.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 CHANGED
@@ -1,5 +1,40 @@
1
1
  # @atlaskit/dropdown-menu
2
2
 
3
+ ## 17.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`ee28cf33718b0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ee28cf33718b0) -
8
+ Add @atlassian/react-compiler-gating as a runtime dependency to enable React Compiler platform
9
+ gating.
10
+ - Updated dependencies
11
+
12
+ ## 17.0.0
13
+
14
+ ### Major Changes
15
+
16
+ - [`f2dc9097319f0`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f2dc9097319f0) - ###
17
+ Dropped support for _legacy_ Typescript 4 types. **Typescript 5 is now the new minimum**.
18
+
19
+ Removes the `typesVersions` property and `dist/types-ts4.5` directory from the dist.
20
+
21
+ Types are now exclusively via the `"types": "dist/types/index.d.ts"` property.
22
+
23
+ ```diff
24
+ - "typesVersions": {
25
+ - ">=4.5 <4.9": {
26
+ - "*": [
27
+ - "dist/types-ts4.5/*",
28
+ - "dist/types-ts4.5/index.d.ts"
29
+ - ]
30
+ - }
31
+ - },
32
+ ```
33
+
34
+ ### Patch Changes
35
+
36
+ - Updated dependencies
37
+
3
38
  ## 16.10.6
4
39
 
5
40
  ### Patch Changes
@@ -0,0 +1,165 @@
1
+ import invariant from 'tiny-invariant';
2
+
3
+ import { expect, test } from '@af/integration-testing';
4
+
5
+ /**
6
+ * Dropdown menu: focus contract on the top-layer code path.
7
+ *
8
+ * `DropdownMenu` renders a `role="menu"` popover. The focus contract is:
9
+ *
10
+ * 1. Initial focus moves to the first menu item on open.
11
+ * 2. Escape closes the menu and restores focus to the trigger.
12
+ * 3. ArrowDown moves focus to the next menu item within the menu.
13
+ *
14
+ * `DropdownMenu` also exposes an `autoFocus` boolean prop that overrides
15
+ * the trigger-source heuristic (focus the first item only when the
16
+ * trigger was activated via the keyboard) and forces focus to the first
17
+ * menu item whenever the menu opens. This spec exercises both variants.
18
+ *
19
+ * See: `platform/packages/design-system/top-layer/notes/architecture/focus.md`.
20
+ */
21
+
22
+ const featureFlag = 'platform-dst-top-layer';
23
+
24
+ test.describe('Dropdown menu: top-layer focus contract', () => {
25
+ test('initial focus: focus moves to the first menu item on open', async ({ page }) => {
26
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
27
+ 'design-system',
28
+ 'dropdown-menu',
29
+ 'testing-top-layer-focus',
30
+ { featureFlag },
31
+ );
32
+
33
+ await page.getByTestId('dropdown--trigger').click();
34
+
35
+ await expect(page.getByTestId('dropdown-item-1')).toBeFocused();
36
+ });
37
+
38
+ test('focus restoration: Escape restores focus to the trigger', async ({ page }) => {
39
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
40
+ 'design-system',
41
+ 'dropdown-menu',
42
+ 'testing-top-layer-focus',
43
+ { featureFlag },
44
+ );
45
+
46
+ const trigger = page.getByTestId('dropdown--trigger');
47
+ await trigger.click();
48
+ await expect(page.getByTestId('dropdown-item-1')).toBeFocused();
49
+
50
+ await page.keyboard.press('Escape');
51
+ await expect(trigger).toBeFocused();
52
+ });
53
+
54
+ test('focus movement: ArrowDown moves focus between menu items', async ({ page }) => {
55
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
56
+ 'design-system',
57
+ 'dropdown-menu',
58
+ 'testing-top-layer-focus',
59
+ { featureFlag },
60
+ );
61
+
62
+ await page.getByTestId('dropdown--trigger').click();
63
+ await expect(page.getByTestId('dropdown-item-1')).toBeFocused();
64
+
65
+ await page.keyboard.press('ArrowDown');
66
+ await expect(page.getByTestId('dropdown-item-2')).toBeFocused();
67
+
68
+ await page.keyboard.press('ArrowDown');
69
+ await expect(page.getByTestId('dropdown-item-3')).toBeFocused();
70
+ });
71
+
72
+ // WCAG 2.4.3 Focus Order + WAI-ARIA APG Menu Button pattern
73
+ // (https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/).
74
+ // "Enter / Space / Down Arrow: Opens the menu and moves focus to the
75
+ // first menu item." Keyboard activation must move focus to the
76
+ // first menu item even when `autoFocus` is left at its default.
77
+ test('initial focus: keyboard-triggered open focuses the first menu item (default `autoFocus={false}`)', async ({
78
+ page,
79
+ }) => {
80
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
81
+ 'design-system',
82
+ 'dropdown-menu',
83
+ 'testing-top-layer-focus',
84
+ { featureFlag },
85
+ );
86
+
87
+ const trigger = page.getByTestId('dropdown--trigger');
88
+ await trigger.focus();
89
+ await page.keyboard.press('Enter');
90
+
91
+ await expect(page.getByTestId('dropdown-item-1')).toBeFocused();
92
+ });
93
+
94
+ // WCAG 2.4.3 Focus Order + WAI-ARIA APG Menu Button pattern. The
95
+ // `defaultOpen` prop mounts the menu in the open state, so there is
96
+ // no trigger interaction to source focus from. The menu must still
97
+ // move focus to the first menu item on mount, exercising the
98
+ // mount-time open path of `useInitialFocus`.
99
+ test('initial focus: `defaultOpen` focuses the first menu item on mount', async ({ page }) => {
100
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
101
+ 'design-system',
102
+ 'dropdown-menu',
103
+ 'testing-top-layer-focus',
104
+ { featureFlag },
105
+ );
106
+
107
+ await expect(page.getByTestId('dropdown-default-open-item-1')).toBeFocused();
108
+ });
109
+
110
+ // WCAG 2.4.3 Focus Order. `returnFocusRef` lets a consumer redirect
111
+ // Escape-restoration to a different element than the trigger. The
112
+ // dropdown's focus-restoration code runs after the browser's native
113
+ // trigger restoration, so the consumer-supplied target must win.
114
+ test('focus restoration: `returnFocusRef` redirects Escape focus to a sibling element', async ({
115
+ page,
116
+ }) => {
117
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
118
+ 'design-system',
119
+ 'dropdown-menu',
120
+ 'testing-top-layer-focus',
121
+ { featureFlag },
122
+ );
123
+
124
+ const trigger = page.getByTestId('dropdown-return-focus-ref--trigger');
125
+ await trigger.focus();
126
+ await page.keyboard.press('Enter');
127
+
128
+ await expect(page.getByTestId('dropdown-return-focus-ref-item-1')).toBeFocused();
129
+
130
+ await page.keyboard.press('Escape');
131
+
132
+ // Focus must land on the consumer-supplied target, not on the
133
+ // trigger that opened the menu.
134
+ await expect(page.getByTestId('dropdown-return-focus-ref-target')).toBeFocused();
135
+ });
136
+
137
+ // WCAG 2.4.3 Focus Order + WAI-ARIA APG Menu Button pattern. The
138
+ // `autoFocus` prop is an opt-in override of the default
139
+ // trigger-source heuristic (focus the first item only on keyboard
140
+ // open). With `autoFocus={true}`, focus must move to the first
141
+ // menu item regardless of how the trigger was activated, which is
142
+ // the strict APG behaviour.
143
+ test('initial focus: `autoFocus={true}` focuses the first menu item even on real mouse open', async ({
144
+ page,
145
+ }) => {
146
+ await page.visitExample<typeof import('../../examples/testing-top-layer-focus.tsx')>(
147
+ 'design-system',
148
+ 'dropdown-menu',
149
+ 'testing-top-layer-focus',
150
+ { featureFlag },
151
+ );
152
+
153
+ const trigger = page.getByTestId('dropdown-autofocus--trigger');
154
+ const box = await trigger.boundingBox();
155
+ invariant(box, 'autoFocus dropdown trigger should have a bounding box');
156
+
157
+ // Drive a real mouse click with non-zero coordinates so the
158
+ // dropdown's trigger-source heuristic classifies it as a mouse
159
+ // (not keyboard) activation. `autoFocus={true}` must still
160
+ // pull focus onto the first menu item.
161
+ await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
162
+
163
+ await expect(page.getByTestId('dropdown-autofocus-item-1')).toBeFocused();
164
+ });
165
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "16.10.6",
3
+ "version": "17.0.1",
4
4
  "description": "A dropdown menu displays a list of actions or options to a user.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -31,20 +31,21 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@atlaskit/button": "^23.11.0",
35
- "@atlaskit/css": "^0.19.0",
36
- "@atlaskit/ds-lib": "^7.0.0",
37
- "@atlaskit/icon": "^35.4.0",
38
- "@atlaskit/layering": "^3.8.0",
39
- "@atlaskit/menu": "^8.5.0",
40
- "@atlaskit/platform-feature-flags": "^1.1.0",
41
- "@atlaskit/popup": "^4.25.0",
42
- "@atlaskit/primitives": "^19.0.0",
43
- "@atlaskit/spinner": "^19.1.0",
44
- "@atlaskit/theme": "^25.0.0",
45
- "@atlaskit/tokens": "^13.4.0",
46
- "@atlaskit/top-layer": "^0.18.0",
47
- "@atlaskit/visually-hidden": "^3.1.0",
34
+ "@atlaskit/button": "^24.1.0",
35
+ "@atlaskit/css": "^1.0.0",
36
+ "@atlaskit/ds-lib": "^8.0.0",
37
+ "@atlaskit/icon": "^36.0.0",
38
+ "@atlaskit/layering": "^4.0.0",
39
+ "@atlaskit/menu": "^9.0.0",
40
+ "@atlaskit/platform-feature-flags": "^2.0.0",
41
+ "@atlaskit/popup": "^5.0.0",
42
+ "@atlaskit/primitives": "^20.0.0",
43
+ "@atlaskit/spinner": "^20.0.0",
44
+ "@atlaskit/theme": "^26.0.0",
45
+ "@atlaskit/tokens": "^15.0.0",
46
+ "@atlaskit/top-layer": "^1.0.0",
47
+ "@atlaskit/visually-hidden": "^4.0.0",
48
+ "@atlassian/react-compiler-gating": "^0.2.0",
48
49
  "@babel/runtime": "^7.0.0",
49
50
  "@compiled/react": "^0.20.0",
50
51
  "bind-event-listener": "^3.0.0"
@@ -57,29 +58,29 @@
57
58
  "@af/accessibility-testing": "workspace:^",
58
59
  "@af/integration-testing": "workspace:^",
59
60
  "@af/visual-regression": "workspace:^",
60
- "@atlaskit/app-provider": "^4.3.0",
61
- "@atlaskit/atlassian-navigation": "^5.7.0",
62
- "@atlaskit/avatar": "^25.15.0",
63
- "@atlaskit/checkbox": "^17.3.0",
64
- "@atlaskit/docs": "^11.8.0",
65
- "@atlaskit/form": "^15.5.0",
66
- "@atlaskit/heading": "^5.4.0",
67
- "@atlaskit/link": "^3.4.0",
68
- "@atlaskit/lozenge": "^13.9.0",
69
- "@atlaskit/modal-dialog": "^15.3.0",
70
- "@atlaskit/section-message": "^8.13.0",
71
- "@atlaskit/textfield": "^8.3.0",
72
- "@atlaskit/toggle": "^16.1.0",
61
+ "@atlaskit/app-provider": "^5.0.0",
62
+ "@atlaskit/atlassian-navigation": "^6.0.0",
63
+ "@atlaskit/avatar": "^26.0.0",
64
+ "@atlaskit/checkbox": "^18.0.0",
65
+ "@atlaskit/docs": "^12.0.0",
66
+ "@atlaskit/form": "^16.0.0",
67
+ "@atlaskit/heading": "^6.0.0",
68
+ "@atlaskit/link": "^4.0.0",
69
+ "@atlaskit/lozenge": "^14.0.0",
70
+ "@atlaskit/modal-dialog": "^16.0.0",
71
+ "@atlaskit/section-message": "^9.1.0",
72
+ "@atlaskit/textfield": "^9.0.0",
73
+ "@atlaskit/toggle": "^17.0.0",
73
74
  "@atlassian/a11y-jest-testing": "^0.12.0",
74
75
  "@atlassian/feature-flags-test-utils": "^1.1.0",
75
- "@atlassian/react-compiler-gating": "workspace:^",
76
76
  "@atlassian/structured-docs-types": "workspace:^",
77
77
  "@testing-library/react": "^16.3.0",
78
78
  "@testing-library/user-event": "^14.4.3",
79
79
  "jest-in-case": "^1.0.2",
80
80
  "raf-stub": "^2.0.1",
81
81
  "react": "^18.2.0",
82
- "react-dom": "^18.2.0"
82
+ "react-dom": "^18.2.0",
83
+ "tiny-invariant": "^1.2.0"
83
84
  },
84
85
  "keywords": [
85
86
  "atlaskit",
@@ -129,13 +130,5 @@
129
130
  "deprecation": "no-deprecated-imports"
130
131
  }
131
132
  },
132
- "typesVersions": {
133
- ">=4.5 <4.9": {
134
- "*": [
135
- "dist/types-ts4.5/*",
136
- "dist/types-ts4.5/index.d.ts"
137
- ]
138
- }
139
- },
140
133
  "homepage": "https://atlassian.design/components/dropdown-menu/"
141
134
  }