@atlaskit/navigation-system 0.174.0 → 0.175.0

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.
Files changed (81) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/afm-dev-agents/tsconfig.json +75 -0
  3. package/constellation/layout/images/layout-anatomy.png +0 -0
  4. package/constellation/layout/images/layout-do.png +0 -0
  5. package/constellation/layout/images/layout-dont.png +0 -0
  6. package/constellation/layout/usage.mdx +122 -0
  7. package/constellation/side-nav-items/images/side-nav-anatomy-1.png +0 -0
  8. package/constellation/side-nav-items/images/side-nav-anatomy-2.png +0 -0
  9. package/constellation/side-nav-items/images/side-nav-do-1.png +0 -0
  10. package/constellation/side-nav-items/images/side-nav-do-2.png +0 -0
  11. package/constellation/side-nav-items/images/side-nav-do-3.png +0 -0
  12. package/constellation/side-nav-items/images/side-nav-do-4.png +0 -0
  13. package/constellation/side-nav-items/images/side-nav-do-5.png +0 -0
  14. package/constellation/side-nav-items/images/side-nav-do-6.png +0 -0
  15. package/constellation/side-nav-items/images/side-nav-do-7.png +0 -0
  16. package/constellation/side-nav-items/images/side-nav-dont-1.png +0 -0
  17. package/constellation/side-nav-items/images/side-nav-dont-10.png +0 -0
  18. package/constellation/side-nav-items/images/side-nav-dont-2.png +0 -0
  19. package/constellation/side-nav-items/images/side-nav-dont-3.png +0 -0
  20. package/constellation/side-nav-items/images/side-nav-dont-4.png +0 -0
  21. package/constellation/side-nav-items/images/side-nav-dont-5.png +0 -0
  22. package/constellation/side-nav-items/images/side-nav-dont-6.png +0 -0
  23. package/constellation/side-nav-items/images/side-nav-dont-7.png +0 -0
  24. package/constellation/side-nav-items/images/side-nav-dont-8.png +0 -0
  25. package/constellation/side-nav-items/images/side-nav-dont-9.png +0 -0
  26. package/constellation/side-nav-items/usage.mdx +324 -0
  27. package/constellation/top-nav-items/images/top-nav-anatomy.png +0 -0
  28. package/constellation/top-nav-items/images/top-nav-do-1.png +0 -0
  29. package/constellation/top-nav-items/images/top-nav-do-2.png +0 -0
  30. package/constellation/top-nav-items/images/top-nav-dont-1.png +0 -0
  31. package/constellation/top-nav-items/images/top-nav-dont-2.png +0 -0
  32. package/constellation/top-nav-items/usage.mdx +79 -0
  33. package/dist/cjs/ui/menu-item/flyout-menu-item/flyout-menu-item-content.js +6 -1
  34. package/dist/cjs/ui/top-nav-items/nav-logo/app-logo.js +1 -0
  35. package/dist/es2019/ui/menu-item/flyout-menu-item/flyout-menu-item-content.js +6 -1
  36. package/dist/es2019/ui/top-nav-items/nav-logo/app-logo.js +1 -0
  37. package/dist/esm/ui/menu-item/flyout-menu-item/flyout-menu-item-content.js +6 -1
  38. package/dist/esm/ui/top-nav-items/nav-logo/app-logo.js +1 -0
  39. package/examples/constellation/interactive-layout.tsx +1 -0
  40. package/examples/layers-in-main.tsx +1 -0
  41. package/examples/top-navigation-custom-logo.tsx +10 -1
  42. package/package.json +7 -4
  43. package/src/ui/menu-item/__tests__/unit/flyout-menu-item.test.tsx +136 -13
  44. package/src/ui/menu-item/flyout-menu-item/flyout-menu-item-content.tsx +4 -0
  45. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-lg---with-min-widths--firefox.png +0 -0
  46. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-lg--firefox.png +0 -0
  47. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-md---with-min-widths--firefox.png +0 -0
  48. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-md--firefox.png +0 -0
  49. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-sm---with-min-widths--firefox.png +0 -0
  50. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-sm--firefox.png +0 -0
  51. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-xl---with-min-widths--firefox.png +0 -0
  52. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-xl--firefox.png +0 -0
  53. package/src/ui/page-layout/__tests__/informational-vr-tests/__snapshots__/top-nav/breakpoint-xs--firefox.png +0 -0
  54. package/src/ui/page-layout/__tests__/vr-tests/__snapshots__/page-layout/panel-default-background-color--desktop.png +0 -0
  55. package/src/ui/page-layout/__tests__/vr-tests/__snapshots__/page-layout/panel-should-have-correct-width-when-there-is-no-sidenav-mounted--desktop.png +0 -0
  56. package/src/ui/top-nav-items/__tests__/informational-vr-tests/__snapshots__/top-navigation/long-product-name-tooltip--default.png +0 -0
  57. package/src/ui/top-nav-items/__tests__/informational-vr-tests/__snapshots__/top-navigation/nav-logo-hover---custom-theming--desktop.png +0 -0
  58. package/src/ui/top-nav-items/__tests__/informational-vr-tests/__snapshots__/top-navigation/nav-logo-hover--desktop.png +0 -0
  59. package/src/ui/top-nav-items/__tests__/informational-vr-tests/__snapshots__/top-navigation/nav-logo-pressed---custom-theming--desktop.png +0 -0
  60. package/src/ui/top-nav-items/__tests__/informational-vr-tests/__snapshots__/top-navigation/nav-logo-pressed--desktop.png +0 -0
  61. package/src/ui/top-nav-items/__tests__/informational-vr-tests/__snapshots__/top-navigation/responsive-menu-items-on-click--mobile.png +0 -0
  62. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/theme-is-applied-with-an-hsl-color--desktop.png +0 -0
  63. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/theme-is-applied-with-an-rgb-color--desktop.png +0 -0
  64. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/themed-create-button-hover-state--desktop.png +0 -0
  65. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/themed-search-focus-state--default.png +0 -0
  66. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/theming-is-enabled--desktop--platform-team25-app-icon-tiles-false.png +0 -0
  67. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/theming-is-enabled--desktop--platform-team25-app-icon-tiles-true.png +0 -0
  68. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-nav-custom-profile-image--default.png +0 -0
  69. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-nav-side-nav-collapsed--desktop.png +0 -0
  70. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo200x200example--desktop.png +0 -0
  71. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo200x200example--mobile.png +0 -0
  72. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo200x20example--desktop.png +0 -0
  73. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo200x20example--mobile.png +0 -0
  74. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo20x200example--desktop.png +0 -0
  75. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo20x200example--mobile.png +0 -0
  76. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo20x20example--desktop.png +0 -0
  77. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-custom-logo20x20example--mobile.png +0 -0
  78. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-example--desktop--platform-team25-app-icon-tiles-false.png +0 -0
  79. package/src/ui/top-nav-items/__tests__/vr-tests/__snapshots__/top-navigation/top-navigation-example--desktop--platform-team25-app-icon-tiles-true.png +0 -0
  80. package/src/ui/top-nav-items/nav-logo/app-logo.tsx +1 -0
  81. package/tsconfig.dev.json +3 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlassian/navigation-system
2
2
 
3
+ ## 0.175.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#189410](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/189410)
8
+ [`5e491d9960a3f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5e491d9960a3f) -
9
+ When a `FlyoutMenuItemContent` is open, clicking outside the content will close the flyout. We
10
+ have improved this functionality to make it more resilient to application code that stops events.
11
+ This changed is behind the feature flag `"platform_dst_nav4_flyout_use_capture_outside"`
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 0.174.0
4
18
 
5
19
  ### Minor Changes
@@ -0,0 +1,75 @@
1
+ {
2
+ "extends": "../../../../tsconfig.entry-points.dev-agents.json",
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "target": "es5",
6
+ "outDir": "../../../../../dev-agents/tsDist/@atlaskit__navigation-system/app",
7
+ "rootDir": "../",
8
+ "composite": true
9
+ },
10
+ "include": [
11
+ "../src/**/*.ts",
12
+ "../src/**/*.tsx"
13
+ ],
14
+ "exclude": [
15
+ "../src/**/__tests__/*",
16
+ "../src/**/*.test.*",
17
+ "../src/**/test.*"
18
+ ],
19
+ "references": [
20
+ {
21
+ "path": "../../../analytics/analytics-next/afm-dev-agents/tsconfig.json"
22
+ },
23
+ {
24
+ "path": "../../avatar/afm-dev-agents/tsconfig.json"
25
+ },
26
+ {
27
+ "path": "../../button/afm-dev-agents/tsconfig.json"
28
+ },
29
+ {
30
+ "path": "../../css/afm-dev-agents/tsconfig.json"
31
+ },
32
+ {
33
+ "path": "../../ds-lib/afm-dev-agents/tsconfig.json"
34
+ },
35
+ {
36
+ "path": "../../icon/afm-dev-agents/tsconfig.json"
37
+ },
38
+ {
39
+ "path": "../../layering/afm-dev-agents/tsconfig.json"
40
+ },
41
+ {
42
+ "path": "../../logo/afm-dev-agents/tsconfig.json"
43
+ },
44
+ {
45
+ "path": "../../../platform/feature-flags/afm-dev-agents/tsconfig.json"
46
+ },
47
+ {
48
+ "path": "../../popup/afm-dev-agents/tsconfig.json"
49
+ },
50
+ {
51
+ "path": "../../../pragmatic-drag-and-drop/core/afm-dev-agents/tsconfig.json"
52
+ },
53
+ {
54
+ "path": "../../../pragmatic-drag-and-drop/hitbox/afm-dev-agents/tsconfig.json"
55
+ },
56
+ {
57
+ "path": "../../../pragmatic-drag-and-drop/react-drop-indicator/afm-dev-agents/tsconfig.json"
58
+ },
59
+ {
60
+ "path": "../../primitives/afm-dev-agents/tsconfig.json"
61
+ },
62
+ {
63
+ "path": "../../../navigation/temp-nav-app-icons/afm-dev-agents/tsconfig.json"
64
+ },
65
+ {
66
+ "path": "../../tokens/afm-dev-agents/tsconfig.json"
67
+ },
68
+ {
69
+ "path": "../../tooltip/afm-dev-agents/tsconfig.json"
70
+ },
71
+ {
72
+ "path": "../../visually-hidden/afm-dev-agents/tsconfig.json"
73
+ }
74
+ ]
75
+ }
@@ -0,0 +1,122 @@
1
+ ---
2
+ title: Layout
3
+ description: Layout components define a page’s structure and the areas for navigation and content.
4
+ order: 4
5
+ ---
6
+
7
+ import layoutDo from './images/layout-do.png';
8
+ import layoutDont from './images/layout-dont.png';
9
+
10
+ ## Usage
11
+
12
+ Use layout to compose the structure of your application. It also defines the page behavior and
13
+ navigational areas.
14
+
15
+ When applying components to the navigational areas,
16
+ [see navigation experience guidelines (Atlassians only)](https://hello.atlassian.net/wiki/spaces/navx/pages/5104144812).
17
+
18
+ ![Diagram of the navigation system layout areas](./images/layout-anatomy.png)
19
+
20
+ <ol>
21
+ <li>
22
+ <strong>Banner:</strong> Optional. Use to display a <a href="/components/banner">banner</a>.
23
+ </li>
24
+ <li>
25
+ <strong>Top nav:</strong> Use to display{' '}
26
+ <a href="/components/navigation-system/top-nav-items">top nav items</a>.
27
+ <ol type="a">
28
+ <li>
29
+ <strong>Top nav start:</strong> Area for left-aligned actions.
30
+ </li>
31
+ <li>
32
+ <strong>Top nav middle:</strong> Area for centre-aligned actions.
33
+ </li>
34
+ <li>
35
+ <strong>Top nav end:</strong> Area for right-aligned actions.
36
+ </li>
37
+ </ol>
38
+ </li>
39
+ <li>
40
+ <strong>Side nav:</strong> Use to display{' '}
41
+ <a href="/components/navigation-system/side-nav-items">side nav items</a>. Is resizable and
42
+ collapsible.
43
+ <ol type="a" start="4">
44
+ <li>
45
+ <strong>Side nav header:</strong> Optional. Top part of the side nav (fixed).
46
+ </li>
47
+ <li>
48
+ <strong>Side nav content:</strong> Middle part of the side nav. Acts as the scroll
49
+ container.
50
+ </li>
51
+ <li>
52
+ <strong>Side nav footer:</strong> Optional. Bottom part of the side nav (fixed).
53
+ </li>
54
+ </ol>
55
+ </li>
56
+ <li>
57
+ <strong>Main:</strong> Use for the page content. Expands to fill available space.
58
+ </li>
59
+ <li>
60
+ <strong>Aside:</strong> Optional. Use to display supporting or supplementary content. Is
61
+ resizable.
62
+ </li>
63
+ <li>
64
+ <strong>Panel:</strong> Optional. Use to display supporting or supplementary content. Is
65
+ resizable and collapsible.
66
+ </li>
67
+ </ol>
68
+
69
+ ### The difference between Aside, Panel and Modal dialog
70
+
71
+ The main difference between Aside, Panel and Modal dialog is their behaviours:
72
+
73
+ - **Aside** is not collapsible, while **Panel** can be collapsible.
74
+ - **Panel** and **Aside** present content alongside the **Main** area, while **Modal dialog** exists
75
+ in a layer above the page.
76
+ - On small viewports (1024px and below), the **Panel** becomes an overlay, while the **Aside** moves
77
+ below **Main**.
78
+
79
+ #### Usage guidance:
80
+
81
+ - Use **Aside** for content that needs to be constantly visible and accessible without requiring the
82
+ user to open it, or have the ability to close it.
83
+ - Use **Panel** for contextual information or tertiary actions that complement the user's workflow.
84
+ Panels enable greater multitasking by functioning as an additional work space, while keeping users
85
+ connected to their primary task.
86
+ - Use **Modal dialog** when you need your user to focus their attention on a single or specific
87
+ task, like requiring a decision or action before they can return to their primary task.
88
+
89
+ ## Best practices
90
+
91
+ ### Design using grid in the Main area
92
+
93
+ <DoDont
94
+ type="do"
95
+ image={{
96
+ url: layoutDo,
97
+ alt: 'A layout with a grid overlay on the Main area.',
98
+ }}
99
+ isFullWidth
100
+ >
101
+ When designing, use <a href="/foundations/grid-beta">Grid</a> to position content within the Main
102
+ area only.
103
+ </DoDont>
104
+
105
+ <DoDont
106
+ type="dont"
107
+ image={{
108
+ url: layoutDont,
109
+ alt: 'A layout with a grid overlay on the Main area, but also on the Side nav, Aside and Panel areas.',
110
+ }}
111
+ isFullWidth
112
+ >
113
+ Don't include Side nav, Aside or Panel areas as part of your Grid.
114
+ </DoDont>
115
+
116
+ ## Related
117
+
118
+ - [Page header](/components/page-header)
119
+ - [Side nav items](/components/navigation-system/side-nav-items)
120
+ - [Top nav items](/components/navigation-system/top-nav-items)
121
+ - [Navigation experience guidelines (Atlassians only)](https://hello.atlassian.net/wiki/spaces/navx/pages/5104144812)
122
+ - [Preview panel (Atlassians only)](https://atlaskit-website-staging.stg-east.frontend.public.atl-paas.net/#/packages/navigation/preview-panel)
@@ -0,0 +1,324 @@
1
+ ---
2
+ title: Side nav items
3
+ description: Menu items and elements for the side nav area.
4
+ order: 4
5
+ ---
6
+
7
+ import sideNavDo1 from './images/side-nav-do-1.png';
8
+ import sideNavDont1 from './images/side-nav-dont-1.png';
9
+ import sideNavDo2 from './images/side-nav-do-2.png';
10
+ import sideNavDont2 from './images/side-nav-dont-2.png';
11
+ import sideNavDo3 from './images/side-nav-do-3.png';
12
+ import sideNavDont3 from './images/side-nav-dont-3.png';
13
+ import sideNavDo4 from './images/side-nav-do-4.png';
14
+ import sideNavDont4 from './images/side-nav-dont-4.png';
15
+ import sideNavDo5 from './images/side-nav-do-5.png';
16
+ import sideNavDont5 from './images/side-nav-dont-5.png';
17
+ import sideNavDo6 from './images/side-nav-do-6.png';
18
+ import sideNavDont6 from './images/side-nav-dont-6.png';
19
+ import sideNavDo7 from './images/side-nav-do-7.png';
20
+ import sideNavDont7 from './images/side-nav-dont-7.png';
21
+ import sideNavDont8 from './images/side-nav-dont-8.png';
22
+ import sideNavDont9 from './images/side-nav-dont-9.png';
23
+ import sideNavDont10 from './images/side-nav-dont-10.png';
24
+
25
+ ## Usage
26
+
27
+ Use side nav items to create different sections, actions, and links in the
28
+ [side nav](/components/navigation-system/side-nav-items).
29
+
30
+ ![Diagram of the navigation system side nav](./images/side-nav-anatomy-1.png)
31
+
32
+ ![Diagram of the navigation system side nav items](./images/side-nav-anatomy-2.png)
33
+
34
+ <ol>
35
+ <li>
36
+ <strong>Menu items:</strong> The interactive elements in the side nav that help users navigate
37
+ or perform actions.
38
+ <ol type="a">
39
+ <li>
40
+ <strong>elemBefore.</strong> Optional*. Only one allowed.
41
+ </li>
42
+ <li>
43
+ <strong>Label.</strong> Text that succinctly describes the menu item.
44
+ </li>
45
+ <li>
46
+ <strong>Description.</strong> Optional*. Additional information on the menu item, such as
47
+ meta data.
48
+ </li>
49
+ <li>
50
+ <strong>elemAfter.</strong> Optional*. Disappears when actionsOnHover display.
51
+ </li>
52
+ <li>
53
+ <strong>actions</strong> or <strong>actionsOnHover</strong>. Optional*. Icon buttons that
54
+ trigger actions independent from the menu item.
55
+ </li>
56
+ </ol>
57
+ </li>
58
+ <li>
59
+ <strong>Menu section:</strong> Use to group related menu items. Acts as a landmark for assistive
60
+ technology.
61
+ </li>
62
+ <li>
63
+ <strong>Menu section heading:</strong> Both a visual heading and ARIA label to name a menu
64
+ section.
65
+ </li>
66
+ </ol>
67
+
68
+ \*Some variations exist between menu item types. View the
69
+ [menu item examples](/components/navigation-system/side-nav-items) for details.
70
+
71
+ ### Follow Atlassian's navigation patterns
72
+
73
+ The current navigation has specific menu items that are similar across apps. Make sure your side
74
+ navigation follows Atlassian patterns consistently,
75
+ [see navigation experience guidelines (Atlassians only)](https://hello.atlassian.net/wiki/spaces/navx/pages/5104144812).
76
+
77
+ ### Choose side nav menu items based on action type
78
+
79
+ There are four types of side nav menu items:
80
+
81
+ 1. Link menu items – navigates to another page.
82
+ 2. Button menu items – triggers an action.
83
+ 3. Expandable menu item – nests side nav menu items to create hierarchies.
84
+ 4. Flyout menu item – opens a popup.
85
+
86
+ View the [menu item examples](/components/navigation-system/side-nav-items) for full behavior and
87
+ guidance for each menu item.
88
+
89
+ ### Use side nav items only within the side nav
90
+
91
+ Side nav menus are reserved for use directly within the
92
+ [side nav](/components/navigation-system/side-nav-items) and the
93
+ [flyout menu content](/components/navigation-system/side-nav-items/examples#flyout-menu-item)
94
+ (popup).
95
+
96
+ Menus anywhere else in the app, including those triggered from the top navigation, should also use
97
+ regular [menu](/components/menu) or [dropdown menu](/components/dropdown-menu).
98
+
99
+ <DoDont
100
+ type="do"
101
+ image={{
102
+ url: sideNavDo1,
103
+ alt: 'A side nav with side nav items only.',
104
+ }}
105
+ >
106
+ Use side nav menus directly in the side nav or flyout menu content.
107
+ </DoDont>
108
+
109
+ <DoDont
110
+ type="dont"
111
+ image={{
112
+ url: sideNavDont1,
113
+ alt: 'Side nav items incorrectly used in the top nav.',
114
+ }}
115
+ >
116
+ Don’t use side nav menus in other parts of the app.
117
+ </DoDont>
118
+
119
+ ### Use dropdown menu for menus triggered from the side nav
120
+
121
+ Use [dropdown menu](/components/dropdown-menu) for menus triggered by `actions` or `actionsOnHover`.
122
+ Ensure you follow the general usage guidance for dropdown menu and use the following variants:
123
+
124
+ - default density (cozy)
125
+ - default placement (bottom-start; adjusts accordingly when space is limited)
126
+
127
+ <DoDont
128
+ type="do"
129
+ image={{
130
+ url: sideNavDo2,
131
+ alt: 'An open dropdown menu with a list of items.',
132
+ }}
133
+ isFullWidth
134
+ >
135
+ Use dropdown menu for menus triggered by actions or actionsOnHover.
136
+ </DoDont>
137
+
138
+ <DoDont
139
+ type="dont"
140
+ image={{
141
+ url: sideNavDont2,
142
+ alt: 'A dropdown menu with a list of items.',
143
+ }}
144
+ >
145
+ Don’t use side nav menu in dropdown menus.
146
+ </DoDont>
147
+
148
+ <DoDont
149
+ type="dont"
150
+ image={{
151
+ url: sideNavDont3,
152
+ alt: 'A dropdown menu with menu item that uses compact density.',
153
+ }}
154
+ >
155
+ Don’t use compact density for dropdown menus.
156
+ </DoDont>
157
+
158
+ <DoDont
159
+ type="dont"
160
+ image={{
161
+ url: sideNavDont4,
162
+ alt: 'A dropdown menu with menu item that does not have a selected state.',
163
+ }}
164
+ >
165
+ Don’t omit the selected state on the dropdown trigger when open.
166
+ </DoDont>
167
+
168
+ <DoDont
169
+ type="dont"
170
+ image={{
171
+ url: sideNavDont5,
172
+ alt: 'A dropdown menu with a disabled menu item.',
173
+ }}
174
+ >
175
+ Don’t use disabled menu items, see [menu](/components/menu/usage) guidance.
176
+ </DoDont>
177
+
178
+ ## Best practices
179
+
180
+ ### Use the provided slots as intended
181
+
182
+ Use [`elemBefore`](/components/navigation-system/side-nav-items/examples#elembefore),
183
+ [`elemAfter`](/components/navigation-system/side-nav-items/examples#elemafter),
184
+ [`actions`](/components/navigation-system/side-nav-items/examples#actions-and-actionsonhover), and
185
+ [`actionsOnHover`](/components/navigation-system/side-nav-items/examples#actions-and-actionsonhover)
186
+ slots for configuring menu items.
187
+
188
+ <DoDont
189
+ type="do"
190
+ image={{
191
+ url: sideNavDo3,
192
+ alt: 'A menu item with "Templates" label and "TRY" text properly placed in a designated slot on the right.',
193
+ }}
194
+ >
195
+ Use the slots in side nav menus as intended.
196
+ </DoDont>
197
+
198
+ <DoDont
199
+ type="dont"
200
+ image={{
201
+ url: sideNavDont6,
202
+ alt: 'A menu item with "Templates" label and "TRY" text incorrectly placed within the same text area.',
203
+ }}
204
+ >
205
+ Don't add custom elements where they're not intended, such as within the label.
206
+ </DoDont>
207
+
208
+ ### Apply icon sizes correctly
209
+
210
+ Consider the following when applying icon sizes:
211
+
212
+ - Use [default (medium 16px) icons](/components/icon/examples#default-16px) in `elemBefore`.
213
+ - Use [small (12px) icons](/components/icon/examples#small-12px) in `elemAfter` as well as `actions`
214
+ and `actionsOnHover` icon buttons.
215
+ - Chevrons always use small (12px) icons, regardless of where they're being applied.
216
+ - All icons in side nav menu items use [spacious padding](/components/icon/examples#spacing-props).
217
+
218
+ <DoDont
219
+ type="do"
220
+ image={{
221
+ url: sideNavDo4,
222
+ alt: 'A menu item with "Projects" label, 16px rocket icon on the left, and 12px plus and ellipsis icons on the right.',
223
+ }}
224
+ >
225
+ Use small (12px) icons for actions, actionOnHover, and elemAfter. Use default (medium 16px) icons
226
+ for elemBefore.
227
+ </DoDont>
228
+
229
+ <DoDont
230
+ type="dont"
231
+ image={{
232
+ url: sideNavDont7,
233
+ alt: 'A menu item with "Projects" label, rocket icon, and incorrectly sized plus and ellipsis icons on the right.',
234
+ }}
235
+ >
236
+ Don't use incorrect icons sizes in menu items, which can feel unbalanced.
237
+ </DoDont>
238
+
239
+ ### Apply icon button correctly
240
+
241
+ Use subtle compact [icon buttons](/components/button/icon-button/examples) in side nav menu items,
242
+ such as in `actions` and `actionsOnHover`, or `elemBefore` in expandable menu items.
243
+
244
+ For `actions` and `actionsOnHover`, when there is more than one icon button, use 4px spacing.
245
+
246
+ <DoDont
247
+ type="do"
248
+ image={{
249
+ url: sideNavDo5,
250
+ alt: 'A menu item with "Projects" label, rocket icon, and subtle compact plus and ellipsis icon buttons with hover tooltip.',
251
+ }}
252
+ >
253
+ Use subtle compact icon buttons in side nav menu items.
254
+ </DoDont>
255
+
256
+ <DoDont
257
+ type="dont"
258
+ image={{
259
+ url: sideNavDont8,
260
+ alt: 'A menu item with "Projects" label, rocket icon, and default icon buttons instead of subtle compact ones.',
261
+ }}
262
+ >
263
+ Don't use default icon buttons in side nav menu items.
264
+ </DoDont>
265
+
266
+ ### Use ContainerAvatar
267
+
268
+ <DoDont
269
+ type="do"
270
+ image={{
271
+ url: sideNavDo6,
272
+ alt: 'A menu item with "Mobile app" label and ContainerAvatar icon on the left.',
273
+ }}
274
+ >
275
+ Use{' '}
276
+ <a href="/components/navigation-system/side-nav-items/code#containeravatar">ContainerAvatar</a> in
277
+ side nav menu items, which are designed with the correct size and spacing.
278
+ </DoDont>
279
+
280
+ <DoDont
281
+ type="dont"
282
+ image={{
283
+ url: sideNavDont9,
284
+ alt: 'A menu item with "Mobile app" label and regular avatar icon instead of ContainerAvatar.',
285
+ }}
286
+ >
287
+ Don't use <a href="/components/avatar">regular avatar</a> in side nav menu items.
288
+ </DoDont>
289
+
290
+ ## Content guidelines
291
+
292
+ ### Write labels in sentence case for menu items and labels
293
+
294
+ Only capitalize the first letter of the menu item name, unless the label contains a trademarked
295
+ product or feature name that has been approved by legal.
296
+
297
+ If the menu name is user generated, display as is.
298
+
299
+ <DoDont
300
+ type="do"
301
+ image={{
302
+ url: sideNavDo7,
303
+ alt: 'A menu item with "For you" label using sentence case.',
304
+ }}
305
+ >
306
+ Only capitalize the first letter of the first word of the label.
307
+ </DoDont>
308
+
309
+ <DoDont
310
+ type="dont"
311
+ image={{
312
+ url: sideNavDont10,
313
+ alt: 'A menu item with "For You" label using title case.',
314
+ }}
315
+ >
316
+ Don't capitalize other parts of the label unless it is a trademarked product or feature name (not
317
+ all features are capitalized).
318
+ </DoDont>
319
+
320
+ ## Related
321
+
322
+ - [Layout](/components/navigation-system/layout)
323
+ - [Top nav items](/components/navigation-system/top-nav-items)
324
+ - [Navigation experience guidelines (Atlassians only)](https://hello.atlassian.net/wiki/spaces/navx/pages/5104144812)
@@ -0,0 +1,79 @@
1
+ ---
2
+ title: Top nav items
3
+ description: Buttons and elements for the top nav.
4
+ order: 3
5
+ ---
6
+
7
+ import topNavDo1 from './images/top-nav-do-1.png';
8
+ import topNavDont1 from './images/top-nav-dont-1.png';
9
+ import topNavDo2 from './images/top-nav-do-2.png';
10
+ import topNavDont2 from './images/top-nav-dont-2.png';
11
+
12
+ ## Usage
13
+
14
+ Use top nav items to create common utilities in
15
+ the [top nav](/components/navigation-system/top-nav-items).
16
+
17
+ ![Diagram of the navigation system top nav](./images/top-nav-anatomy.png)
18
+
19
+ 1. **Start items:** Left-aligned buttons.
20
+ 2. **Middle items:** Centre-aligned actions.
21
+ 3. **End items:** Right-aligned buttons.
22
+
23
+ ## Follow Atlassian's navigation patterns
24
+
25
+ The current navigation has specific menu items that are similar across apps. Make sure your top
26
+ navigation follows Atlassian patterns consistently,
27
+ [see navigation experience guidelines (Atlassians only)](https://hello.atlassian.net/wiki/spaces/navx/pages/5104144812).
28
+
29
+ ## Best practices
30
+
31
+ ### Use the top nav items provided
32
+
33
+ <DoDont
34
+ type="do"
35
+ image={{
36
+ url: topNavDo1,
37
+ alt: 'Two buttons, one outlined and one solid purple, both labeled "Button".',
38
+ }}
39
+ >
40
+ Use the top nav items provided.
41
+ </DoDont>
42
+
43
+ <DoDont
44
+ type="dont"
45
+ image={{
46
+ url: topNavDont1,
47
+ alt: 'Two buttons, one outlined and one solid purple, both labeled "Button".',
48
+ }}
49
+ >
50
+ Don't use regular button in the top nav, as it won't respect custom theming.
51
+ </DoDont>
52
+
53
+ ### Don't add elements to the top nav area
54
+
55
+ <DoDont
56
+ type="do"
57
+ image={{
58
+ url: topNavDo2,
59
+ alt: 'A segment of a top navigation bar showing standard Atlassian icons and a highlighted "ate" item.',
60
+ }}
61
+ >
62
+ Use the top nav items as intended.
63
+ </DoDont>
64
+
65
+ <DoDont
66
+ type="dont"
67
+ image={{
68
+ url: topNavDont2,
69
+ alt: 'A segment of a top navigation bar showing standard Atlassian icons with an additional "Logout" button and a diamond icon.',
70
+ }}
71
+ >
72
+ Don't add elements to the top nav, which may negatively impact consistency across apps.
73
+ </DoDont>
74
+
75
+ ## Related
76
+
77
+ - [Layout](/components/navigation-system/layout)
78
+ - [Side nav items](/components/navigation-system/side-nav-items)
79
+ - [Navigation experience guidelines (Atlassians only)](https://hello.atlassian.net/wiki/spaces/navx/pages/5104144812)
@@ -38,7 +38,12 @@ var FlyoutMenuItemContent = exports.FlyoutMenuItemContent = /*#__PURE__*/(0, _re
38
38
  return /*#__PURE__*/_react.default.createElement(_experimental.PopupContent, {
39
39
  appearance: "UNSAFE_modal-below-sm",
40
40
  onClose: handleClose,
41
- placement: "right-start",
41
+ placement: "right-start"
42
+ // Using a capture event listener so that we are more resilient against
43
+ // code that stops events. We _really_ want to close the flyout whenever
44
+ // user user clicks outside the flyout content
45
+ ,
46
+ shouldUseCaptureOnOutsideClick: (0, _platformFeatureFlags.fg)('platform_dst_nav4_flyout_use_capture_outside'),
42
47
  shouldFitViewport: true,
43
48
  testId: containerTestId,
44
49
  xcss: flyoutMenuItemContentStyles.root,
@@ -16,6 +16,7 @@ var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
16
16
  var _hasCustomThemeContext = require("../themed/has-custom-theme-context");
17
17
  var _logoRenderer = require("./logo-renderer");
18
18
  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); }
19
+ // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
19
20
  var anchorStyles = {
20
21
  root: "_2rko19bv _1e0c1txw _4cvr1h6o _4t3izwfg _1o9zidpf _ahbq1b66 _1toh1r31 _5jyqglyw _mrqmnqa1 _1w901kw7",
21
22
  interactionStates: "_irr3166n _1di61wwy",
@@ -29,7 +29,12 @@ export const FlyoutMenuItemContent = /*#__PURE__*/forwardRef(({
29
29
  return /*#__PURE__*/React.createElement(PopupContent, {
30
30
  appearance: "UNSAFE_modal-below-sm",
31
31
  onClose: handleClose,
32
- placement: "right-start",
32
+ placement: "right-start"
33
+ // Using a capture event listener so that we are more resilient against
34
+ // code that stops events. We _really_ want to close the flyout whenever
35
+ // user user clicks outside the flyout content
36
+ ,
37
+ shouldUseCaptureOnOutsideClick: fg('platform_dst_nav4_flyout_use_capture_outside'),
33
38
  shouldFitViewport: true,
34
39
  testId: containerTestId,
35
40
  xcss: flyoutMenuItemContentStyles.root,
@@ -3,6 +3,7 @@ import "./app-logo.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React, { useCallback, useRef } from 'react';
5
5
  import { cx } from '@compiled/react';
6
+ // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
6
7
  import { Anchor, Inline, Text } from '@atlaskit/primitives';
7
8
  import Tooltip from '@atlaskit/tooltip';
8
9
  import { useHasCustomTheme } from '../themed/has-custom-theme-context';
@@ -29,7 +29,12 @@ export var FlyoutMenuItemContent = /*#__PURE__*/forwardRef(function (_ref, forwa
29
29
  return /*#__PURE__*/React.createElement(PopupContent, {
30
30
  appearance: "UNSAFE_modal-below-sm",
31
31
  onClose: handleClose,
32
- placement: "right-start",
32
+ placement: "right-start"
33
+ // Using a capture event listener so that we are more resilient against
34
+ // code that stops events. We _really_ want to close the flyout whenever
35
+ // user user clicks outside the flyout content
36
+ ,
37
+ shouldUseCaptureOnOutsideClick: fg('platform_dst_nav4_flyout_use_capture_outside'),
33
38
  shouldFitViewport: true,
34
39
  testId: containerTestId,
35
40
  xcss: flyoutMenuItemContentStyles.root,
@@ -3,6 +3,7 @@ import "./app-logo.compiled.css";
3
3
  import { ax, ix } from "@compiled/react/runtime";
4
4
  import React, { useCallback, useRef } from 'react';
5
5
  import { cx } from '@compiled/react';
6
+ // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
6
7
  import { Anchor, Inline, Text } from '@atlaskit/primitives';
7
8
  import Tooltip from '@atlaskit/tooltip';
8
9
  import { useHasCustomTheme } from '../themed/has-custom-theme-context';
@@ -45,6 +45,7 @@ import {
45
45
  Search,
46
46
  Settings,
47
47
  } from '@atlaskit/navigation-system/top-nav-items';
48
+ // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
48
49
  import { Inline, Stack, Text } from '@atlaskit/primitives';
49
50
  import { token } from '@atlaskit/tokens';
50
51
 
@@ -56,6 +56,7 @@ import {
56
56
  Search,
57
57
  Settings,
58
58
  } from '@atlaskit/navigation-system/top-nav-items';
59
+ // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
59
60
  import { Inline, Stack, Text } from '@atlaskit/primitives';
60
61
  import { PopupSelect } from '@atlaskit/select';
61
62
  import { token } from '@atlaskit/tokens';
@@ -6,11 +6,17 @@ import { jsx } from '@compiled/react';
6
6
 
7
7
  import { Root } from '@atlaskit/navigation-system/layout/root';
8
8
  import { SideNavToggleButton } from '@atlaskit/navigation-system/layout/side-nav';
9
- import { TopNav, TopNavMiddle, TopNavStart } from '@atlaskit/navigation-system/layout/top-nav';
9
+ import {
10
+ TopNav,
11
+ TopNavEnd,
12
+ TopNavMiddle,
13
+ TopNavStart,
14
+ } from '@atlaskit/navigation-system/layout/top-nav';
10
15
  import {
11
16
  AppSwitcher,
12
17
  CreateButton,
13
18
  NavLogo,
19
+ Profile,
14
20
  Search,
15
21
  } from '@atlaskit/navigation-system/top-nav-items';
16
22
 
@@ -48,6 +54,9 @@ const TopNavigationCustomLogoInstance = ({
48
54
  <Search onClick={() => alert('mobile search')} label="Search" />
49
55
  <CreateButton onClick={() => alert('create')}>Create</CreateButton>
50
56
  </TopNavMiddle>
57
+ <TopNavEnd>
58
+ <Profile label="Profile" />
59
+ </TopNavEnd>
51
60
  </TopNav>
52
61
  </Root>
53
62
  </WithResponsiveViewport>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/navigation-system",
3
- "version": "0.174.0",
3
+ "version": "0.175.0",
4
4
  "description": "The latest navigation system for Atlassian products.",
5
5
  "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
6
6
  "author": "Atlassian Pty Ltd",
@@ -116,7 +116,7 @@
116
116
  "@atlaskit/button": "^23.2.0",
117
117
  "@atlaskit/css": "^0.12.0",
118
118
  "@atlaskit/ds-lib": "^4.1.0",
119
- "@atlaskit/icon": "^27.3.0",
119
+ "@atlaskit/icon": "^27.6.0",
120
120
  "@atlaskit/layering": "^3.0.0",
121
121
  "@atlaskit/logo": "^19.5.0",
122
122
  "@atlaskit/platform-feature-flags": "^1.1.0",
@@ -126,7 +126,7 @@
126
126
  "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator": "^3.2.0",
127
127
  "@atlaskit/primitives": "^14.10.0",
128
128
  "@atlaskit/temp-nav-app-icons": "^0.9.0",
129
- "@atlaskit/tokens": "^5.5.0",
129
+ "@atlaskit/tokens": "^5.6.0",
130
130
  "@atlaskit/tooltip": "^20.3.0",
131
131
  "@atlaskit/visually-hidden": "^3.0.0",
132
132
  "@babel/runtime": "^7.0.0",
@@ -146,7 +146,7 @@
146
146
  "@atlaskit/badge": "^18.1.0",
147
147
  "@atlaskit/banner": "^14.0.0",
148
148
  "@atlaskit/breadcrumbs": "^15.2.0",
149
- "@atlaskit/dropdown-menu": "^16.2.0",
149
+ "@atlaskit/dropdown-menu": "^16.3.0",
150
150
  "@atlaskit/form": "^12.0.0",
151
151
  "@atlaskit/heading": "^5.2.0",
152
152
  "@atlaskit/link": "^3.2.0",
@@ -226,6 +226,9 @@
226
226
  },
227
227
  "platform_dst_nav4_flyout_update_on_resize": {
228
228
  "type": "boolean"
229
+ },
230
+ "platform_dst_nav4_flyout_use_capture_outside": {
231
+ "type": "boolean"
229
232
  }
230
233
  },
231
234
  "homepage": "https://atlassian.design/components/navigation-system"
@@ -1,9 +1,11 @@
1
- import React from 'react';
1
+ import React, { type MouseEvent } from 'react';
2
2
 
3
3
  import { render, screen } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
5
+ import { bind } from 'bind-event-listener';
5
6
 
6
7
  import HomeIcon from '@atlaskit/icon/core/home';
8
+ import { ffTest } from '@atlassian/feature-flags-test-utils';
7
9
 
8
10
  import { ButtonMenuItem } from '../../button-menu-item';
9
11
  import { FlyoutMenuItem } from '../../flyout-menu-item/flyout-menu-item';
@@ -118,21 +120,142 @@ describe('FlyoutMenuItem', () => {
118
120
  expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
119
121
  });
120
122
 
121
- it('should close the popup when the popup is open and a click occurs outside of the popup', async () => {
122
- render(
123
- <FlyoutMenuItem isDefaultOpen>
124
- <FlyoutMenuItemTrigger>Trigger</FlyoutMenuItemTrigger>
125
- <FlyoutMenuItemContent>
126
- <ButtonMenuItem>Item 1</ButtonMenuItem>
127
- </FlyoutMenuItemContent>
128
- </FlyoutMenuItem>,
129
- );
123
+ describe('flyout content should close when clicking outside of popup', () => {
124
+ test('no event stopping', async () => {
125
+ render(
126
+ <FlyoutMenuItem isDefaultOpen>
127
+ <FlyoutMenuItemTrigger>Trigger</FlyoutMenuItemTrigger>
128
+ <FlyoutMenuItemContent>
129
+ <ButtonMenuItem>Item 1</ButtonMenuItem>
130
+ </FlyoutMenuItemContent>
131
+ </FlyoutMenuItem>,
132
+ );
130
133
 
131
- expect(screen.queryByText('Item 1')).toBeVisible();
134
+ expect(screen.queryByText('Item 1')).toBeVisible();
132
135
 
133
- await userEvent.click(document.body);
136
+ await userEvent.click(document.body);
134
137
 
135
- expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
138
+ expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
139
+ });
140
+ });
141
+
142
+ ffTest.on('platform_dst_nav4_flyout_use_capture_outside', 'Click outside of flyout', () => {
143
+ test('bubble phase event listener stops event', async () => {
144
+ const cleanup = bind(window, {
145
+ type: 'click',
146
+ listener(event) {
147
+ event.stopImmediatePropagation();
148
+ },
149
+ // bubble phase listener
150
+ options: { capture: false },
151
+ });
152
+
153
+ render(
154
+ <FlyoutMenuItem isDefaultOpen>
155
+ <FlyoutMenuItemTrigger>Trigger</FlyoutMenuItemTrigger>
156
+ <FlyoutMenuItemContent>
157
+ <ButtonMenuItem>Item 1</ButtonMenuItem>
158
+ </FlyoutMenuItemContent>
159
+ </FlyoutMenuItem>,
160
+ );
161
+
162
+ expect(screen.queryByText('Item 1')).toBeVisible();
163
+
164
+ await userEvent.click(document.body);
165
+
166
+ expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
167
+
168
+ cleanup();
169
+ });
170
+
171
+ test('high capture phase event listener stops event', async () => {
172
+ // not adding to `window` as this event listener would be added
173
+ // before the Popup one is added, and would stop the event before
174
+ // the Popup could process it
175
+ const cleanup1 = bind(document.body, {
176
+ type: 'click',
177
+ listener(event) {
178
+ event.stopImmediatePropagation();
179
+ },
180
+ // capture phase listener
181
+ options: { capture: true, once: true },
182
+ });
183
+ render(
184
+ <FlyoutMenuItem isDefaultOpen>
185
+ <FlyoutMenuItemTrigger>Trigger</FlyoutMenuItemTrigger>
186
+ <FlyoutMenuItemContent>
187
+ <ButtonMenuItem>Item 1</ButtonMenuItem>
188
+ </FlyoutMenuItemContent>
189
+ </FlyoutMenuItem>,
190
+ );
191
+ // This will be added after the added window capture listener
192
+ // used to close outside clicks, so we can add to the window
193
+ const cleanup2 = bind(window, {
194
+ type: 'click',
195
+ listener(event) {
196
+ event.stopImmediatePropagation();
197
+ },
198
+ // capture phase listener
199
+ options: { capture: true, once: true },
200
+ });
201
+
202
+ expect(screen.queryByText('Item 1')).toBeVisible();
203
+
204
+ await userEvent.click(document.body);
205
+
206
+ expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
207
+
208
+ cleanup1();
209
+ cleanup2();
210
+ });
211
+
212
+ test('react bubble event listener stops event', async () => {
213
+ const onClick = jest.fn((event: MouseEvent) => event.stopPropagation());
214
+ render(
215
+ <>
216
+ <button type="button" data-testid="my-button" onClick={onClick}>
217
+ Hi there
218
+ </button>
219
+ <FlyoutMenuItem isDefaultOpen>
220
+ <FlyoutMenuItemTrigger>Trigger</FlyoutMenuItemTrigger>
221
+ <FlyoutMenuItemContent>
222
+ <ButtonMenuItem>Item 1</ButtonMenuItem>
223
+ </FlyoutMenuItemContent>
224
+ </FlyoutMenuItem>
225
+ </>,
226
+ );
227
+
228
+ expect(screen.queryByText('Item 1')).toBeVisible();
229
+
230
+ await userEvent.click(screen.getByTestId('my-button'));
231
+
232
+ expect(onClick).toHaveBeenCalled();
233
+ expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
234
+ });
235
+
236
+ test('react capture event listener stops event', async () => {
237
+ const onClick = jest.fn((event: MouseEvent) => event.stopPropagation());
238
+ render(
239
+ <>
240
+ <button type="button" data-testid="my-button" onClickCapture={onClick}>
241
+ Hi there
242
+ </button>
243
+ <FlyoutMenuItem isDefaultOpen>
244
+ <FlyoutMenuItemTrigger>Trigger</FlyoutMenuItemTrigger>
245
+ <FlyoutMenuItemContent>
246
+ <ButtonMenuItem>Item 1</ButtonMenuItem>
247
+ </FlyoutMenuItemContent>
248
+ </FlyoutMenuItem>
249
+ </>,
250
+ );
251
+
252
+ expect(screen.queryByText('Item 1')).toBeVisible();
253
+
254
+ await userEvent.click(screen.getByTestId('my-button'));
255
+
256
+ expect(onClick).toHaveBeenCalled();
257
+ expect(screen.queryByText('Item 1')).not.toBeInTheDocument();
258
+ });
136
259
  });
137
260
 
138
261
  it('should close the popup when the escape key is pressed', async () => {
@@ -80,6 +80,10 @@ export const FlyoutMenuItemContent = forwardRef<HTMLDivElement, FlyoutMenuItemCo
80
80
  appearance="UNSAFE_modal-below-sm"
81
81
  onClose={handleClose}
82
82
  placement="right-start"
83
+ // Using a capture event listener so that we are more resilient against
84
+ // code that stops events. We _really_ want to close the flyout whenever
85
+ // user user clicks outside the flyout content
86
+ shouldUseCaptureOnOutsideClick={fg('platform_dst_nav4_flyout_use_capture_outside')}
83
87
  shouldFitViewport
84
88
  testId={containerTestId}
85
89
  xcss={flyoutMenuItemContentStyles.root}
@@ -7,6 +7,7 @@ import React, { useCallback, useRef } from 'react';
7
7
  import { cssMap, cx, jsx } from '@compiled/react';
8
8
 
9
9
  import type { LogoProps } from '@atlaskit/logo';
10
+ // eslint-disable-next-line @atlaskit/design-system/no-emotion-primitives -- to be migrated to @atlaskit/primitives/compiled – go/akcss
10
11
  import { Anchor, Inline, Text } from '@atlaskit/primitives';
11
12
  import type { IconProps as TempIconProps } from '@atlaskit/temp-nav-app-icons/types';
12
13
  import { token } from '@atlaskit/tokens';
package/tsconfig.dev.json CHANGED
@@ -157,6 +157,9 @@
157
157
  {
158
158
  "path": "../tooltip/tsconfig.app.json"
159
159
  },
160
+ {
161
+ "path": "../../platform/feature-flags-test-utils/tsconfig.app.json"
162
+ },
160
163
  {
161
164
  "path": "../../monorepo-tooling/gemini/tsconfig.app.json"
162
165
  },