@atlaskit/page-layout 3.11.6 → 3.11.8

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 (26) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/components/slots/internal/resizable-children-wrapper.js +3 -2
  3. package/dist/cjs/components/slots/left-sidebar.js +10 -4
  4. package/dist/cjs/controllers/sidebar-resize-context.js +2 -1
  5. package/dist/cjs/controllers/sidebar-resize-controller.js +14 -8
  6. package/dist/es2019/components/slots/internal/resizable-children-wrapper.js +3 -2
  7. package/dist/es2019/components/slots/left-sidebar.js +10 -4
  8. package/dist/es2019/controllers/sidebar-resize-context.js +2 -1
  9. package/dist/es2019/controllers/sidebar-resize-controller.js +14 -8
  10. package/dist/esm/components/slots/internal/resizable-children-wrapper.js +3 -2
  11. package/dist/esm/components/slots/left-sidebar.js +10 -4
  12. package/dist/esm/controllers/sidebar-resize-context.js +2 -1
  13. package/dist/esm/controllers/sidebar-resize-controller.js +14 -8
  14. package/dist/types/controllers/sidebar-resize-context.d.ts +1 -0
  15. package/dist/types-ts4.5/controllers/sidebar-resize-context.d.ts +1 -0
  16. package/package.json +8 -4
  17. package/__perf__/examples.tsx +0 -65
  18. package/__perf__/utils/perf-example.tsx +0 -80
  19. package/__perf__/utils/product-integration/atlassian-navigation.tsx +0 -118
  20. package/__perf__/utils/product-integration/create.tsx +0 -23
  21. package/__perf__/utils/product-integration/help-popup.tsx +0 -52
  22. package/__perf__/utils/product-integration/notifications-popup.tsx +0 -107
  23. package/__perf__/utils/product-integration/profile-popup.tsx +0 -75
  24. package/__perf__/utils/product-integration/sample-footer.tsx +0 -52
  25. package/__perf__/utils/product-integration/sample-header.tsx +0 -29
  26. package/__perf__/utils/product-integration/side-navigation.tsx +0 -118
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlaskit/page-layout
2
2
 
3
+ ## 3.11.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#107520](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/107520)
8
+ [`537278df4586e`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/537278df4586e) -
9
+ Fixing A11y violation scrollable-region-focusable
10
+
11
+ ## 3.11.7
12
+
13
+ ### Patch Changes
14
+
15
+ - [#103752](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/103752)
16
+ [`4b581a9ac4abd`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/4b581a9ac4abd) -
17
+ Testing behind an internal feature gate, a React 18 concurrent safe way to initialize the
18
+ LeftSidebar to avoid animation on hydration or initial client-side rendering.
19
+
3
20
  ## 3.11.6
4
21
 
5
22
  ### Patch Changes
@@ -26,7 +26,7 @@ var prefersReducedMotionStyles = (0, _react.css)((0, _motion.prefersReducedMotio
26
26
  */
27
27
  var hideLeftSidebarContentsStyles = (0, _react.css)({
28
28
  opacity: 0,
29
- transition: "opacity 0ms linear, visibility 0ms linear",
29
+ transition: 'opacity 0ms linear, visibility 0ms linear',
30
30
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
31
31
  transitionDelay: "".concat(_constants.TRANSITION_DURATION - 100, "ms"),
32
32
  visibility: 'hidden'
@@ -57,7 +57,8 @@ var ResizableChildrenWrapper = function ResizableChildrenWrapper(_ref) {
57
57
  return (0, _react.jsx)("div", {
58
58
  css: [resizableChildrenWrapperStyles, isHidden && hideLeftSidebarContentsStyles, prefersReducedMotionStyles],
59
59
  "aria-hidden": isHidden,
60
- "data-testid": testId
60
+ "data-testid": testId,
61
+ tabIndex: isHidden ? -1 : 0
61
62
  }, (0, _react.jsx)("div", {
62
63
  css: fixedChildrenWrapperStyles
63
64
  }, children));
@@ -10,6 +10,7 @@ var _react = require("react");
10
10
  var _react2 = require("@emotion/react");
11
11
  var _useCloseOnEscapePress = _interopRequireDefault(require("@atlaskit/ds-lib/use-close-on-escape-press"));
12
12
  var _motion = require("@atlaskit/motion");
13
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
14
  var _responsive = require("@atlaskit/primitives/responsive");
14
15
  var _colors = require("@atlaskit/theme/colors");
15
16
  var _constants = require("../../common/constants");
@@ -79,7 +80,8 @@ var LeftSidebar = function LeftSidebar(props) {
79
80
  flyoutLockCount = leftSidebarState.flyoutLockCount,
80
81
  isLeftSidebarCollapsed = leftSidebarState.isLeftSidebarCollapsed,
81
82
  leftSidebarWidth = leftSidebarState.leftSidebarWidth,
82
- lastLeftSidebarWidth = leftSidebarState.lastLeftSidebarWidth;
83
+ lastLeftSidebarWidth = leftSidebarState.lastLeftSidebarWidth,
84
+ hasInit = leftSidebarState.hasInit;
83
85
  var isLocked = flyoutLockCount > 0;
84
86
  var isLockedRef = (0, _react.useRef)(isLocked);
85
87
  var mouseXRef = (0, _react.useRef)(0);
@@ -144,7 +146,8 @@ var LeftSidebar = function LeftSidebar(props) {
144
146
  leftSidebarWidth: leftSidebarWidth,
145
147
  lastLeftSidebarWidth: lastLeftSidebarWidth,
146
148
  flyoutLockCount: 0,
147
- isFixed: isFixed
149
+ isFixed: isFixed,
150
+ hasInit: true
148
151
  });
149
152
  // eslint-disable-next-line react-hooks/exhaustive-deps
150
153
  }, []);
@@ -282,6 +285,9 @@ var LeftSidebar = function LeftSidebar(props) {
282
285
  onClose: closeMobileFlyout,
283
286
  isDisabled: !isFlyoutOpen
284
287
  });
288
+
289
+ // We use both the state and our effect-based ref to protect animation until initialized fully
290
+ var isReady = (0, _platformFeatureFlags.fg)('platform_dst_concurrent_left_sidebar_width') ? hasInit && notFirstRun.current : notFirstRun.current;
285
291
  return (0, _react2.jsx)(_react.Fragment, null, (mobileMediaQuery === null || mobileMediaQuery === void 0 ? void 0 : mobileMediaQuery.matches) &&
286
292
  /**
287
293
  * On desktop, the `onClick` handlers controls the temporary flyout behavior.
@@ -304,7 +310,7 @@ var LeftSidebar = function LeftSidebar(props) {
304
310
  isFixed: isFixed
305
311
  }, (0, _react2.jsx)(_slotDimensions.default, {
306
312
  variableName: _constants.VAR_LEFT_SIDEBAR_WIDTH,
307
- value: notFirstRun.current ? leftSidebarWidth : leftSidebarWidthOnMount,
313
+ value: isReady ? leftSidebarWidth : leftSidebarWidthOnMount,
308
314
  mobileValue: _constants.MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH
309
315
  }), (0, _react2.jsx)(_leftSidebarInner.default, {
310
316
  isFixed: isFixed,
@@ -312,7 +318,7 @@ var LeftSidebar = function LeftSidebar(props) {
312
318
  }, (0, _react2.jsx)(_resizableChildrenWrapper.default, {
313
319
  isFlyoutOpen: isFlyoutOpen,
314
320
  isLeftSidebarCollapsed: isLeftSidebarCollapsed,
315
- hasCollapsedState: !notFirstRun.current && collapsedState === 'collapsed',
321
+ hasCollapsedState: !isReady && collapsedState === 'collapsed',
316
322
  testId: testId && "".concat(testId, "-resize-children-wrapper")
317
323
  }, children), (0, _react2.jsx)(_resizeControl.default, {
318
324
  testId: testId,
@@ -19,7 +19,8 @@ var leftSidebarState = {
19
19
  leftSidebarWidth: 0,
20
20
  lastLeftSidebarWidth: 0,
21
21
  flyoutLockCount: 0,
22
- isFixed: true
22
+ isFixed: true,
23
+ hasInit: false
23
24
  };
24
25
 
25
26
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
@@ -36,7 +36,8 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
36
36
  leftSidebarWidth: 0,
37
37
  lastLeftSidebarWidth: 0,
38
38
  flyoutLockCount: 0,
39
- isFixed: true
39
+ isFixed: true,
40
+ hasInit: false
40
41
  }),
41
42
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
42
43
  leftSidebarState = _useState2[0],
@@ -47,7 +48,8 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
47
48
  flyoutLockCount = leftSidebarState.flyoutLockCount,
48
49
  isFixed = leftSidebarState.isFixed,
49
50
  isLeftSidebarCollapsed = leftSidebarState.isLeftSidebarCollapsed,
50
- isFlyoutOpen = leftSidebarState.isFlyoutOpen;
51
+ isFlyoutOpen = leftSidebarState.isFlyoutOpen,
52
+ hasInit = leftSidebarState.hasInit;
51
53
 
52
54
  // We put the latest callbacks into a ref so we can always have the latest
53
55
  // functions in our transitionend listeners
@@ -81,7 +83,8 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
81
83
  lastLeftSidebarWidth: leftSidebarWidth,
82
84
  isFlyoutOpen: true,
83
85
  flyoutLockCount: 0,
84
- isFixed: isFixed
86
+ isFixed: isFixed,
87
+ hasInit: hasInit
85
88
  };
86
89
  setLeftSidebarState(flyoutOpenSidebarState);
87
90
 
@@ -106,7 +109,8 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
106
109
  lastLeftSidebarWidth: lastLeftSidebarWidth,
107
110
  isResizing: isResizing,
108
111
  flyoutLockCount: flyoutLockCount,
109
- isFixed: isFixed
112
+ isFixed: isFixed,
113
+ hasInit: hasInit
110
114
  };
111
115
  setLeftSidebarState(updatedLeftSidebarState);
112
116
  function finish() {
@@ -139,7 +143,7 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
139
143
  }
140
144
  };
141
145
  transition.current = value;
142
- }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth]);
146
+ }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth, hasInit]);
143
147
  var collapseLeftSidebar = (0, _react.useCallback)(function (event, collapseWithoutTransition) {
144
148
  var _transition$current6, _transition$current7;
145
149
  if (!isOpen) {
@@ -157,7 +161,8 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
157
161
  lastLeftSidebarWidth: lastLeftSidebarWidth,
158
162
  isFlyoutOpen: false,
159
163
  flyoutLockCount: 0,
160
- isFixed: isFixed
164
+ isFixed: isFixed,
165
+ hasInit: hasInit
161
166
  };
162
167
  setLeftSidebarState(flyoutCloseSidebarState);
163
168
 
@@ -185,7 +190,8 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
185
190
  lastLeftSidebarWidth: leftSidebarWidth,
186
191
  isResizing: isResizing,
187
192
  flyoutLockCount: flyoutLockCount,
188
- isFixed: isFixed
193
+ isFixed: isFixed,
194
+ hasInit: hasInit
189
195
  };
190
196
  setLeftSidebarState(updatedLeftSidebarState);
191
197
  function finish() {
@@ -219,7 +225,7 @@ var SidebarResizeController = exports.SidebarResizeController = function Sidebar
219
225
  }
220
226
  };
221
227
  transition.current = value;
222
- }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth]);
228
+ }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth, hasInit]);
223
229
 
224
230
  /**
225
231
  * Conditionally toggle the expanding or collapsing the sidebars.
@@ -19,7 +19,7 @@ const prefersReducedMotionStyles = css(prefersReducedMotion());
19
19
  */
20
20
  const hideLeftSidebarContentsStyles = css({
21
21
  opacity: 0,
22
- transition: `opacity 0ms linear, visibility 0ms linear`,
22
+ transition: 'opacity 0ms linear, visibility 0ms linear',
23
23
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
24
24
  transitionDelay: `${TRANSITION_DURATION - 100}ms`,
25
25
  visibility: 'hidden'
@@ -48,7 +48,8 @@ const ResizableChildrenWrapper = ({
48
48
  return jsx("div", {
49
49
  css: [resizableChildrenWrapperStyles, isHidden && hideLeftSidebarContentsStyles, prefersReducedMotionStyles],
50
50
  "aria-hidden": isHidden,
51
- "data-testid": testId
51
+ "data-testid": testId,
52
+ tabIndex: isHidden ? -1 : 0
52
53
  }, jsx("div", {
53
54
  css: fixedChildrenWrapperStyles
54
55
  }, children));
@@ -9,6 +9,7 @@ import { Fragment, useCallback, useContext, useEffect, useRef } from 'react';
9
9
  import { css, jsx } from '@emotion/react';
10
10
  import useCloseOnEscapePress from '@atlaskit/ds-lib/use-close-on-escape-press';
11
11
  import { easeOut } from '@atlaskit/motion';
12
+ import { fg } from '@atlaskit/platform-feature-flags';
12
13
  import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/responsive';
13
14
  import { N100A } from '@atlaskit/theme/colors';
14
15
  import { COLLAPSED_LEFT_SIDEBAR_WIDTH, DEFAULT_LEFT_SIDEBAR_WIDTH, FLYOUT_DELAY, MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH, RESIZE_BUTTON_SELECTOR, TRANSITION_DURATION, VAR_LEFT_SIDEBAR_FLYOUT, VAR_LEFT_SIDEBAR_WIDTH } from '../../common/constants';
@@ -76,7 +77,8 @@ const LeftSidebar = props => {
76
77
  flyoutLockCount,
77
78
  isLeftSidebarCollapsed,
78
79
  leftSidebarWidth,
79
- lastLeftSidebarWidth
80
+ lastLeftSidebarWidth,
81
+ hasInit
80
82
  } = leftSidebarState;
81
83
  const isLocked = flyoutLockCount > 0;
82
84
  const isLockedRef = useRef(isLocked);
@@ -141,7 +143,8 @@ const LeftSidebar = props => {
141
143
  leftSidebarWidth,
142
144
  lastLeftSidebarWidth,
143
145
  flyoutLockCount: 0,
144
- isFixed
146
+ isFixed,
147
+ hasInit: true
145
148
  });
146
149
  // eslint-disable-next-line react-hooks/exhaustive-deps
147
150
  }, []);
@@ -283,6 +286,9 @@ const LeftSidebar = props => {
283
286
  onClose: closeMobileFlyout,
284
287
  isDisabled: !isFlyoutOpen
285
288
  });
289
+
290
+ // We use both the state and our effect-based ref to protect animation until initialized fully
291
+ const isReady = fg('platform_dst_concurrent_left_sidebar_width') ? hasInit && notFirstRun.current : notFirstRun.current;
286
292
  return jsx(Fragment, null, (mobileMediaQuery === null || mobileMediaQuery === void 0 ? void 0 : mobileMediaQuery.matches) &&
287
293
  /**
288
294
  * On desktop, the `onClick` handlers controls the temporary flyout behavior.
@@ -305,7 +311,7 @@ const LeftSidebar = props => {
305
311
  isFixed: isFixed
306
312
  }, jsx(SlotDimensions, {
307
313
  variableName: VAR_LEFT_SIDEBAR_WIDTH,
308
- value: notFirstRun.current ? leftSidebarWidth : leftSidebarWidthOnMount,
314
+ value: isReady ? leftSidebarWidth : leftSidebarWidthOnMount,
309
315
  mobileValue: MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH
310
316
  }), jsx(LeftSidebarInner, {
311
317
  isFixed: isFixed,
@@ -313,7 +319,7 @@ const LeftSidebar = props => {
313
319
  }, jsx(ResizableChildrenWrapper, {
314
320
  isFlyoutOpen: isFlyoutOpen,
315
321
  isLeftSidebarCollapsed: isLeftSidebarCollapsed,
316
- hasCollapsedState: !notFirstRun.current && collapsedState === 'collapsed',
322
+ hasCollapsedState: !isReady && collapsedState === 'collapsed',
317
323
  testId: testId && `${testId}-resize-children-wrapper`
318
324
  }, children), jsx(ResizeControl, {
319
325
  testId: testId,
@@ -7,7 +7,8 @@ const leftSidebarState = {
7
7
  leftSidebarWidth: 0,
8
8
  lastLeftSidebarWidth: 0,
9
9
  flyoutLockCount: 0,
10
- isFixed: true
10
+ isFixed: true,
11
+ hasInit: false
11
12
  };
12
13
 
13
14
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
@@ -24,7 +24,8 @@ export const SidebarResizeController = ({
24
24
  leftSidebarWidth: 0,
25
25
  lastLeftSidebarWidth: 0,
26
26
  flyoutLockCount: 0,
27
- isFixed: true
27
+ isFixed: true,
28
+ hasInit: false
28
29
  });
29
30
  const {
30
31
  leftSidebarWidth,
@@ -33,7 +34,8 @@ export const SidebarResizeController = ({
33
34
  flyoutLockCount,
34
35
  isFixed,
35
36
  isLeftSidebarCollapsed,
36
- isFlyoutOpen
37
+ isFlyoutOpen,
38
+ hasInit
37
39
  } = leftSidebarState;
38
40
 
39
41
  // We put the latest callbacks into a ref so we can always have the latest
@@ -68,7 +70,8 @@ export const SidebarResizeController = ({
68
70
  lastLeftSidebarWidth: leftSidebarWidth,
69
71
  isFlyoutOpen: true,
70
72
  flyoutLockCount: 0,
71
- isFixed
73
+ isFixed,
74
+ hasInit
72
75
  };
73
76
  setLeftSidebarState(flyoutOpenSidebarState);
74
77
 
@@ -93,7 +96,8 @@ export const SidebarResizeController = ({
93
96
  lastLeftSidebarWidth,
94
97
  isResizing,
95
98
  flyoutLockCount,
96
- isFixed
99
+ isFixed,
100
+ hasInit
97
101
  };
98
102
  setLeftSidebarState(updatedLeftSidebarState);
99
103
  function finish() {
@@ -126,7 +130,7 @@ export const SidebarResizeController = ({
126
130
  }
127
131
  };
128
132
  transition.current = value;
129
- }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth]);
133
+ }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth, hasInit]);
130
134
  const collapseLeftSidebar = useCallback((event, collapseWithoutTransition) => {
131
135
  var _transition$current6, _transition$current7;
132
136
  if (!isOpen) {
@@ -144,7 +148,8 @@ export const SidebarResizeController = ({
144
148
  lastLeftSidebarWidth,
145
149
  isFlyoutOpen: false,
146
150
  flyoutLockCount: 0,
147
- isFixed
151
+ isFixed,
152
+ hasInit
148
153
  };
149
154
  setLeftSidebarState(flyoutCloseSidebarState);
150
155
 
@@ -172,7 +177,8 @@ export const SidebarResizeController = ({
172
177
  lastLeftSidebarWidth: leftSidebarWidth,
173
178
  isResizing,
174
179
  flyoutLockCount,
175
- isFixed
180
+ isFixed,
181
+ hasInit
176
182
  };
177
183
  setLeftSidebarState(updatedLeftSidebarState);
178
184
  function finish() {
@@ -206,7 +212,7 @@ export const SidebarResizeController = ({
206
212
  }
207
213
  };
208
214
  transition.current = value;
209
- }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth]);
215
+ }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth, hasInit]);
210
216
 
211
217
  /**
212
218
  * Conditionally toggle the expanding or collapsing the sidebars.
@@ -19,7 +19,7 @@ var prefersReducedMotionStyles = css(prefersReducedMotion());
19
19
  */
20
20
  var hideLeftSidebarContentsStyles = css({
21
21
  opacity: 0,
22
- transition: "opacity 0ms linear, visibility 0ms linear",
22
+ transition: 'opacity 0ms linear, visibility 0ms linear',
23
23
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
24
24
  transitionDelay: "".concat(TRANSITION_DURATION - 100, "ms"),
25
25
  visibility: 'hidden'
@@ -50,7 +50,8 @@ var ResizableChildrenWrapper = function ResizableChildrenWrapper(_ref) {
50
50
  return jsx("div", {
51
51
  css: [resizableChildrenWrapperStyles, isHidden && hideLeftSidebarContentsStyles, prefersReducedMotionStyles],
52
52
  "aria-hidden": isHidden,
53
- "data-testid": testId
53
+ "data-testid": testId,
54
+ tabIndex: isHidden ? -1 : 0
54
55
  }, jsx("div", {
55
56
  css: fixedChildrenWrapperStyles
56
57
  }, children));
@@ -12,6 +12,7 @@ import { Fragment, useCallback, useContext, useEffect, useRef } from 'react';
12
12
  import { css, jsx } from '@emotion/react';
13
13
  import useCloseOnEscapePress from '@atlaskit/ds-lib/use-close-on-escape-press';
14
14
  import { easeOut } from '@atlaskit/motion';
15
+ import { fg } from '@atlaskit/platform-feature-flags';
15
16
  import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/responsive';
16
17
  import { N100A } from '@atlaskit/theme/colors';
17
18
  import { COLLAPSED_LEFT_SIDEBAR_WIDTH, DEFAULT_LEFT_SIDEBAR_WIDTH, FLYOUT_DELAY, MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH, RESIZE_BUTTON_SELECTOR, TRANSITION_DURATION, VAR_LEFT_SIDEBAR_FLYOUT, VAR_LEFT_SIDEBAR_WIDTH } from '../../common/constants';
@@ -76,7 +77,8 @@ var LeftSidebar = function LeftSidebar(props) {
76
77
  flyoutLockCount = leftSidebarState.flyoutLockCount,
77
78
  isLeftSidebarCollapsed = leftSidebarState.isLeftSidebarCollapsed,
78
79
  leftSidebarWidth = leftSidebarState.leftSidebarWidth,
79
- lastLeftSidebarWidth = leftSidebarState.lastLeftSidebarWidth;
80
+ lastLeftSidebarWidth = leftSidebarState.lastLeftSidebarWidth,
81
+ hasInit = leftSidebarState.hasInit;
80
82
  var isLocked = flyoutLockCount > 0;
81
83
  var isLockedRef = useRef(isLocked);
82
84
  var mouseXRef = useRef(0);
@@ -141,7 +143,8 @@ var LeftSidebar = function LeftSidebar(props) {
141
143
  leftSidebarWidth: leftSidebarWidth,
142
144
  lastLeftSidebarWidth: lastLeftSidebarWidth,
143
145
  flyoutLockCount: 0,
144
- isFixed: isFixed
146
+ isFixed: isFixed,
147
+ hasInit: true
145
148
  });
146
149
  // eslint-disable-next-line react-hooks/exhaustive-deps
147
150
  }, []);
@@ -279,6 +282,9 @@ var LeftSidebar = function LeftSidebar(props) {
279
282
  onClose: closeMobileFlyout,
280
283
  isDisabled: !isFlyoutOpen
281
284
  });
285
+
286
+ // We use both the state and our effect-based ref to protect animation until initialized fully
287
+ var isReady = fg('platform_dst_concurrent_left_sidebar_width') ? hasInit && notFirstRun.current : notFirstRun.current;
282
288
  return jsx(Fragment, null, (mobileMediaQuery === null || mobileMediaQuery === void 0 ? void 0 : mobileMediaQuery.matches) &&
283
289
  /**
284
290
  * On desktop, the `onClick` handlers controls the temporary flyout behavior.
@@ -301,7 +307,7 @@ var LeftSidebar = function LeftSidebar(props) {
301
307
  isFixed: isFixed
302
308
  }, jsx(SlotDimensions, {
303
309
  variableName: VAR_LEFT_SIDEBAR_WIDTH,
304
- value: notFirstRun.current ? leftSidebarWidth : leftSidebarWidthOnMount,
310
+ value: isReady ? leftSidebarWidth : leftSidebarWidthOnMount,
305
311
  mobileValue: MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH
306
312
  }), jsx(LeftSidebarInner, {
307
313
  isFixed: isFixed,
@@ -309,7 +315,7 @@ var LeftSidebar = function LeftSidebar(props) {
309
315
  }, jsx(ResizableChildrenWrapper, {
310
316
  isFlyoutOpen: isFlyoutOpen,
311
317
  isLeftSidebarCollapsed: isLeftSidebarCollapsed,
312
- hasCollapsedState: !notFirstRun.current && collapsedState === 'collapsed',
318
+ hasCollapsedState: !isReady && collapsedState === 'collapsed',
313
319
  testId: testId && "".concat(testId, "-resize-children-wrapper")
314
320
  }, children), jsx(ResizeControl, {
315
321
  testId: testId,
@@ -12,7 +12,8 @@ var leftSidebarState = {
12
12
  leftSidebarWidth: 0,
13
13
  lastLeftSidebarWidth: 0,
14
14
  flyoutLockCount: 0,
15
- isFixed: true
15
+ isFixed: true,
16
+ hasInit: false
16
17
  };
17
18
 
18
19
  // eslint-disable-next-line @repo/internal/react/require-jsdoc
@@ -26,7 +26,8 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
26
26
  leftSidebarWidth: 0,
27
27
  lastLeftSidebarWidth: 0,
28
28
  flyoutLockCount: 0,
29
- isFixed: true
29
+ isFixed: true,
30
+ hasInit: false
30
31
  }),
31
32
  _useState2 = _slicedToArray(_useState, 2),
32
33
  leftSidebarState = _useState2[0],
@@ -37,7 +38,8 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
37
38
  flyoutLockCount = leftSidebarState.flyoutLockCount,
38
39
  isFixed = leftSidebarState.isFixed,
39
40
  isLeftSidebarCollapsed = leftSidebarState.isLeftSidebarCollapsed,
40
- isFlyoutOpen = leftSidebarState.isFlyoutOpen;
41
+ isFlyoutOpen = leftSidebarState.isFlyoutOpen,
42
+ hasInit = leftSidebarState.hasInit;
41
43
 
42
44
  // We put the latest callbacks into a ref so we can always have the latest
43
45
  // functions in our transitionend listeners
@@ -71,7 +73,8 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
71
73
  lastLeftSidebarWidth: leftSidebarWidth,
72
74
  isFlyoutOpen: true,
73
75
  flyoutLockCount: 0,
74
- isFixed: isFixed
76
+ isFixed: isFixed,
77
+ hasInit: hasInit
75
78
  };
76
79
  setLeftSidebarState(flyoutOpenSidebarState);
77
80
 
@@ -96,7 +99,8 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
96
99
  lastLeftSidebarWidth: lastLeftSidebarWidth,
97
100
  isResizing: isResizing,
98
101
  flyoutLockCount: flyoutLockCount,
99
- isFixed: isFixed
102
+ isFixed: isFixed,
103
+ hasInit: hasInit
100
104
  };
101
105
  setLeftSidebarState(updatedLeftSidebarState);
102
106
  function finish() {
@@ -129,7 +133,7 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
129
133
  }
130
134
  };
131
135
  transition.current = value;
132
- }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth]);
136
+ }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth, hasInit]);
133
137
  var collapseLeftSidebar = useCallback(function (event, collapseWithoutTransition) {
134
138
  var _transition$current6, _transition$current7;
135
139
  if (!isOpen) {
@@ -147,7 +151,8 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
147
151
  lastLeftSidebarWidth: lastLeftSidebarWidth,
148
152
  isFlyoutOpen: false,
149
153
  flyoutLockCount: 0,
150
- isFixed: isFixed
154
+ isFixed: isFixed,
155
+ hasInit: hasInit
151
156
  };
152
157
  setLeftSidebarState(flyoutCloseSidebarState);
153
158
 
@@ -175,7 +180,8 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
175
180
  lastLeftSidebarWidth: leftSidebarWidth,
176
181
  isResizing: isResizing,
177
182
  flyoutLockCount: flyoutLockCount,
178
- isFixed: isFixed
183
+ isFixed: isFixed,
184
+ hasInit: hasInit
179
185
  };
180
186
  setLeftSidebarState(updatedLeftSidebarState);
181
187
  function finish() {
@@ -209,7 +215,7 @@ export var SidebarResizeController = function SidebarResizeController(_ref) {
209
215
  }
210
216
  };
211
217
  transition.current = value;
212
- }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth]);
218
+ }, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth, hasInit]);
213
219
 
214
220
  /**
215
221
  * Conditionally toggle the expanding or collapsing the sidebars.
@@ -7,6 +7,7 @@ export type LeftSidebarState = {
7
7
  lastLeftSidebarWidth: number;
8
8
  flyoutLockCount: number;
9
9
  isFixed: boolean;
10
+ hasInit: boolean;
10
11
  };
11
12
  export type SidebarResizeContextValue = {
12
13
  isLeftSidebarCollapsed: boolean;
@@ -7,6 +7,7 @@ export type LeftSidebarState = {
7
7
  lastLeftSidebarWidth: number;
8
8
  flyoutLockCount: number;
9
9
  isFixed: boolean;
10
+ hasInit: boolean;
10
11
  };
11
12
  export type SidebarResizeContextValue = {
12
13
  isLeftSidebarCollapsed: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/page-layout",
3
- "version": "3.11.6",
3
+ "version": "3.11.8",
4
4
  "description": "A collection of components which let you compose an application's page layout.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -42,12 +42,13 @@
42
42
  "homepage": "https://atlassian.design/components/page-layout/",
43
43
  "dependencies": {
44
44
  "@atlaskit/ds-lib": "^3.3.0",
45
- "@atlaskit/icon": "^23.3.0",
45
+ "@atlaskit/icon": "^23.4.0",
46
46
  "@atlaskit/link": "^2.0.0",
47
47
  "@atlaskit/motion": "^1.9.0",
48
+ "@atlaskit/platform-feature-flags": "^0.3.0",
48
49
  "@atlaskit/primitives": "^13.3.0",
49
50
  "@atlaskit/theme": "^14.0.0",
50
- "@atlaskit/tokens": "^3.0.0",
51
+ "@atlaskit/tokens": "^3.2.0",
51
52
  "@babel/runtime": "^7.0.0",
52
53
  "@emotion/react": "^11.7.1",
53
54
  "bind-event-listener": "^3.0.0",
@@ -68,7 +69,7 @@
68
69
  "@atlaskit/notification-indicator": "^9.4.0",
69
70
  "@atlaskit/notification-log-client": "^6.1.0",
70
71
  "@atlaskit/popup": "^1.30.0",
71
- "@atlaskit/side-navigation": "^3.6.0",
72
+ "@atlaskit/side-navigation": "^4.0.0",
72
73
  "@atlaskit/ssr": "*",
73
74
  "@atlaskit/toggle": "^14.0.0",
74
75
  "@atlaskit/tooltip": "^19.0.0",
@@ -85,6 +86,9 @@
85
86
  "platform-feature-flags": {
86
87
  "platform_dst_popup-disable-focuslock": {
87
88
  "type": "boolean"
89
+ },
90
+ "platform_dst_concurrent_left_sidebar_width": {
91
+ "type": "boolean"
88
92
  }
89
93
  },
90
94
  "keywords": [
@@ -1,65 +0,0 @@
1
- import React from 'react';
2
-
3
- import { findByTestId, findByText, fireEvent, getByTestId } from '@testing-library/dom'; // eslint-disable-line import/no-extraneous-dependencies
4
- // eslint-disable-next-line import/no-extraneous-dependencies
5
- import { type InteractionTaskArgs, type PublicInteractionTask } from 'storybook-addon-performance'; // eslint-disable-line import/no-extraneous-dependencies
6
-
7
- import ProductExample from './utils/perf-example';
8
-
9
- const interactionTasks: PublicInteractionTask[] = [
10
- {
11
- name: 'Side nav: Opening nested side nav',
12
- description: 'Open a nested item in side-navigation',
13
-
14
- run: async ({ container }: InteractionTaskArgs): Promise<void> => {
15
- const element: HTMLElement | null = getByTestId(container, 'nav-side-queues--item');
16
- fireEvent.click(element);
17
- await findByText(container, 'Untriaged', undefined, { timeout: 2000 });
18
- },
19
- },
20
- {
21
- name: 'Global nav: Open dropdown',
22
- description: 'Open a dropdown in side-navigation',
23
-
24
- run: async ({ container }: InteractionTaskArgs): Promise<void> => {
25
- const element: HTMLElement | null = getByTestId(container, 'nav-help');
26
- fireEvent.click(element);
27
- await findByTestId(container.parentElement || container, 'nav-help-content', undefined, {
28
- timeout: 2000,
29
- });
30
- },
31
- },
32
- {
33
- name: 'Global nav: Notifications',
34
- description: 'Open the notifications panel in global navigation',
35
-
36
- run: async ({ container }: InteractionTaskArgs): Promise<void> => {
37
- const element: HTMLElement | null = getByTestId(container, 'nav-notifications');
38
- fireEvent.click(element);
39
- await findByTestId(container.parentElement || container, 'jira-notifications', undefined, {
40
- timeout: 2000,
41
- });
42
- },
43
- },
44
- ];
45
-
46
- const performance = () => {
47
- return (
48
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
49
- <div style={{ margin: '-1rem 0 0 -1rem', height: '100vh' }}>
50
- <ProductExample />
51
- </div>
52
- );
53
- };
54
-
55
- performance.story = {
56
- name: 'Performance',
57
-
58
- parameters: {
59
- performance: {
60
- interactions: interactionTasks,
61
- },
62
- },
63
- };
64
-
65
- export default performance;
@@ -1,80 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
-
6
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
7
- import { css, jsx } from '@emotion/react';
8
-
9
- import { token } from '@atlaskit/tokens';
10
-
11
- import { Content, LeftSidebar, Main, PageLayout, TopNavigation } from '../../src';
12
-
13
- import JiraIntegrationExample from './product-integration/atlassian-navigation';
14
- import Sidebar from './product-integration/side-navigation';
15
-
16
- const wrapperStyles = css({
17
- boxSizing: 'border-box',
18
- height: '100%',
19
- padding: token('space.100', '8px'),
20
- backgroundColor: token('color.background.neutral.subtle'),
21
- outlineOffset: -4,
22
- overflowY: 'auto',
23
- });
24
-
25
- const Wrapper = ({
26
- borderColor,
27
- children,
28
- noOutline,
29
- noHorizontalScrollbar,
30
- }: {
31
- borderColor: string;
32
- children: React.ReactNode;
33
- noOutline?: boolean;
34
- noHorizontalScrollbar?: boolean;
35
- }) => (
36
- <div
37
- css={wrapperStyles}
38
- style={{
39
- outline: noOutline ? 'none' : `2px dashed ${borderColor}`,
40
- overflowX: noHorizontalScrollbar ? 'hidden' : 'auto',
41
- }}
42
- >
43
- {children}
44
- </div>
45
- );
46
-
47
- const sidebarWrapperStyles = css({
48
- height: '100%',
49
- // eslint-disable-next-line @atlaskit/design-system/no-nested-styles, @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
50
- nav: {
51
- minWidth: 20,
52
- overflowX: 'hidden',
53
- },
54
- });
55
-
56
- const slotLabelStyles = css({ textAlign: 'center' });
57
-
58
- const BasicGrid = () => {
59
- return (
60
- <PageLayout>
61
- <TopNavigation height={60} isFixed={true}>
62
- <JiraIntegrationExample />
63
- </TopNavigation>
64
- <Content testId="content">
65
- <LeftSidebar testId="left-sidebar" isFixed={false} width={450}>
66
- <div css={sidebarWrapperStyles}>
67
- <Sidebar />
68
- </div>
69
- </LeftSidebar>
70
- <Main>
71
- <Wrapper noOutline borderColor={token('color.border')}>
72
- <h3 css={slotLabelStyles}>Main</h3>
73
- </Wrapper>
74
- </Main>
75
- </Content>
76
- </PageLayout>
77
- );
78
- };
79
-
80
- export default BasicGrid;
@@ -1,118 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
- import { Fragment, type MouseEvent, useState } from 'react';
6
-
7
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
- import { jsx } from '@emotion/react';
9
-
10
- // AFP-1799 storybook examples in src cause issues
11
- import {
12
- AtlassianNavigation,
13
- PrimaryButton,
14
- ProductHome,
15
- Search,
16
- Settings,
17
- } from '@atlaskit/atlassian-navigation';
18
- import Drawer from '@atlaskit/drawer';
19
- import { JiraIcon, JiraLogo } from '@atlaskit/logo';
20
-
21
- import { DefaultCreate } from './create';
22
- import { HelpPopup } from './help-popup';
23
- import { NotificationsPopup } from './notifications-popup';
24
- import { ProfilePopup } from './profile-popup';
25
-
26
- const drawerLabelText = {
27
- search: 'Search drawer',
28
- settings: 'Settings drawer',
29
- };
30
-
31
- const { search, settings } = drawerLabelText;
32
-
33
- const ProductHomeExample = () => (
34
- <ProductHome icon={JiraIcon} logo={JiraLogo} siteTitle="Extranet" />
35
- );
36
-
37
- const SearchDrawer = () => {
38
- const [isOpen, setIsOpen] = useState(false);
39
-
40
- const onClick = () => {
41
- setIsOpen(!isOpen);
42
- };
43
-
44
- const onClose = () => {
45
- setIsOpen(false);
46
- };
47
-
48
- return (
49
- <Fragment>
50
- <Search
51
- onClick={onClick}
52
- testId="nav-search"
53
- placeholder="Search..."
54
- tooltip="Search"
55
- label="Search"
56
- />
57
- <Drawer label={search} isOpen={isOpen} onClose={onClose}>
58
- <div>{search}</div>
59
- </Drawer>
60
- </Fragment>
61
- );
62
- };
63
-
64
- const SettingsDrawer = () => {
65
- const [isOpen, setIsOpen] = useState(false);
66
-
67
- const onClick = () => {
68
- setIsOpen(!isOpen);
69
- };
70
-
71
- const onClose = () => {
72
- setIsOpen(false);
73
- };
74
-
75
- return (
76
- <Fragment>
77
- <Settings isSelected={isOpen} onClick={onClick} tooltip="Settings" />
78
- <Drawer label={settings} isOpen={isOpen} onClose={onClose}>
79
- {settings}
80
- </Drawer>
81
- </Fragment>
82
- );
83
- };
84
-
85
- const buttonClick = (toLog: string) => (e: MouseEvent<HTMLElement | HTMLAnchorElement>) => {
86
- if (e.ctrlKey || e.metaKey) {
87
- return;
88
- }
89
- e.preventDefault();
90
- };
91
-
92
- const primaryItems = [
93
- <PrimaryButton onClick={buttonClick('Projects')}>Projects</PrimaryButton>,
94
- <PrimaryButton onClick={buttonClick('Filters')} isHighlighted>
95
- Filters
96
- </PrimaryButton>,
97
- <PrimaryButton onClick={buttonClick('Dashboards')}>Dashboards</PrimaryButton>,
98
- <PrimaryButton onClick={buttonClick('Apps')}>Apps</PrimaryButton>,
99
- ];
100
-
101
- const PerfExample = () => (
102
- <Fragment>
103
- <AtlassianNavigation
104
- label="site"
105
- moreLabel="More"
106
- primaryItems={primaryItems}
107
- renderCreate={DefaultCreate}
108
- renderHelp={HelpPopup}
109
- renderNotifications={NotificationsPopup}
110
- renderProductHome={ProductHomeExample}
111
- renderProfile={ProfilePopup}
112
- renderSearch={SearchDrawer}
113
- renderSettings={SettingsDrawer}
114
- />
115
- </Fragment>
116
- );
117
-
118
- export default PerfExample;
@@ -1,23 +0,0 @@
1
- import React from 'react';
2
-
3
- import { Create } from '@atlaskit/atlassian-navigation';
4
- import noop from '@atlaskit/ds-lib/noop';
5
- import { token } from '@atlaskit/tokens';
6
-
7
- const StyledTooltip = () => (
8
- <span>
9
- Create
10
- {/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
11
- <span style={{ color: token('color.text.accent.orange', 'orange') }}> [c]</span>
12
- </span>
13
- );
14
-
15
- export const DefaultCreate = () => (
16
- <Create
17
- buttonTooltip={<StyledTooltip />}
18
- iconButtonTooltip="Create button"
19
- onClick={noop}
20
- text="Create"
21
- testId="create-cta"
22
- />
23
- );
@@ -1,52 +0,0 @@
1
- import React, { useState } from 'react';
2
-
3
- import { Help } from '@atlaskit/atlassian-navigation';
4
- import { ButtonItem, MenuGroup, Section } from '@atlaskit/menu';
5
- import Popup from '@atlaskit/popup';
6
-
7
- const HelpContent = () => (
8
- <MenuGroup testId={'nav-help-content'}>
9
- <Section title="Help">
10
- <ButtonItem>Atlassian Documentation</ButtonItem>
11
- <ButtonItem>Atlassian Community</ButtonItem>
12
- <ButtonItem>What's New</ButtonItem>
13
- <ButtonItem>Get Jira Mobile</ButtonItem>
14
- <ButtonItem>Keyboard shortcuts</ButtonItem>
15
- <ButtonItem>About Jira</ButtonItem>
16
- </Section>
17
- <Section title="Legal" hasSeparator>
18
- <ButtonItem>Terms of use</ButtonItem>
19
- <ButtonItem>Privacy Policy</ButtonItem>
20
- </Section>
21
- </MenuGroup>
22
- );
23
-
24
- export const HelpPopup = () => {
25
- const [isOpen, setIsOpen] = useState(false);
26
-
27
- const onClick = () => {
28
- setIsOpen(!isOpen);
29
- };
30
-
31
- const onClose = () => {
32
- setIsOpen(false);
33
- };
34
-
35
- return (
36
- <Popup
37
- placement="bottom-start"
38
- content={HelpContent}
39
- isOpen={isOpen}
40
- onClose={onClose}
41
- trigger={(triggerProps) => (
42
- <Help
43
- testId={'nav-help'}
44
- isSelected={isOpen}
45
- onClick={onClick}
46
- tooltip="Help"
47
- {...triggerProps}
48
- />
49
- )}
50
- />
51
- );
52
- };
@@ -1,107 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
- import { useState } from 'react';
6
-
7
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
- import { css, jsx } from '@emotion/react';
9
-
10
- import { Notifications } from '@atlaskit/atlassian-navigation';
11
- import { Notifications as NotificationsIframe } from '@atlaskit/atlassian-notifications';
12
- import { NotificationIndicator } from '@atlaskit/notification-indicator';
13
- import { NotificationLogClient } from '@atlaskit/notification-log-client';
14
- import Popup from '@atlaskit/popup';
15
-
16
- const wrapperStyles = css({
17
- display: 'flex',
18
- width: 540,
19
- height: 'calc(100vh - 200px)',
20
- // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage
21
- paddingBlockStart: 18,
22
- // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage
23
- paddingInlineStart: 18,
24
- });
25
-
26
- const NotificationsContent = () => (
27
- <div css={wrapperStyles}>
28
- <NotificationsIframe
29
- // _url="https://start.stg.atlassian.com/notificationsDrawer/iframe.html?scope=user&product=uchi&locale=en"
30
- _url="https://start.stg.atlassian.com/notificationsDrawer/iframe.html"
31
- locale="en"
32
- product="jira"
33
- testId="jira-notifications"
34
- title="Notifications"
35
- />
36
- </div>
37
- );
38
-
39
- class MockNotificationLogClient extends NotificationLogClient {
40
- mockedCount = 0;
41
- constructor(mockedCount: number) {
42
- super('', '');
43
- this.mockedCount = mockedCount;
44
- }
45
-
46
- public async countUnseenNotifications() {
47
- return Promise.resolve({ count: this.mockedCount });
48
- }
49
- }
50
-
51
- const client = new MockNotificationLogClient(5);
52
- const emptyClient = new MockNotificationLogClient(0);
53
-
54
- export const NotificationsPopup = () => {
55
- const [isOpen, setIsOpen] = useState(false);
56
- const [interacted, setInteracted] = useState(false);
57
- const [buttonLabel, setButtonLabel] = useState<number | undefined>();
58
-
59
- const NotificationsBadge = () => (
60
- <NotificationIndicator
61
- onCountUpdated={updateButtonLabel}
62
- // force a zero-count after the drawer has been opened
63
- notificationLogProvider={Promise.resolve(interacted ? emptyClient : client)}
64
- />
65
- );
66
-
67
- const updateButtonLabel = ({
68
- newCount,
69
- oldCount,
70
- source,
71
- }: {
72
- newCount: number;
73
- oldCount?: number;
74
- source?: string;
75
- }) => {
76
- setButtonLabel(newCount || 0);
77
- };
78
-
79
- const onClick = () => {
80
- // let the badge icon know to clear its count
81
- setInteracted(true);
82
- setIsOpen(!isOpen);
83
- };
84
-
85
- const onClose = () => {
86
- setIsOpen(false);
87
- };
88
-
89
- return (
90
- <Popup
91
- placement="bottom-start"
92
- content={NotificationsContent}
93
- isOpen={isOpen}
94
- onClose={onClose}
95
- trigger={(triggerProps) => (
96
- <Notifications
97
- badge={NotificationsBadge}
98
- onClick={onClick}
99
- tooltip={`Notifications (${buttonLabel})`}
100
- isSelected={isOpen}
101
- testId={'nav-notifications'}
102
- {...triggerProps}
103
- />
104
- )}
105
- />
106
- );
107
- };
@@ -1,75 +0,0 @@
1
- import React, { useState } from 'react';
2
-
3
- import { Profile } from '@atlaskit/atlassian-navigation';
4
- import noop from '@atlaskit/ds-lib/noop';
5
- import { ButtonItem, MenuGroup, Section } from '@atlaskit/menu';
6
- import Popup from '@atlaskit/popup';
7
-
8
- export const DefaultProfile = () => (
9
- <Profile
10
- icon={<img src={avatarUrl} alt="Your profile and settings" />}
11
- onClick={noop}
12
- tooltip="Your profile and settings"
13
- />
14
- );
15
-
16
- export const avatarUrl =
17
- 'data:image/png;base64,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';
18
-
19
- const ProfileContent = () => (
20
- <MenuGroup>
21
- <Section>
22
- <ButtonItem>Give us feedback</ButtonItem>
23
- </Section>
24
- <Section title="Jira" hasSeparator>
25
- <ButtonItem>Settings</ButtonItem>
26
- </Section>
27
- <Section title="John Smith" hasSeparator>
28
- <ButtonItem>Profile</ButtonItem>
29
- <ButtonItem>Account settings</ButtonItem>
30
- <ButtonItem>Logout</ButtonItem>
31
- </Section>
32
- </MenuGroup>
33
- );
34
-
35
- const imgCSS = {
36
- borderRadius: '100%',
37
- height: 24,
38
- width: 24,
39
- };
40
- export const ProfilePopup = () => {
41
- const [isOpen, setIsOpen] = useState(false);
42
-
43
- const onClick = () => {
44
- setIsOpen(!isOpen);
45
- };
46
-
47
- const onClose = () => {
48
- setIsOpen(false);
49
- };
50
-
51
- return (
52
- <Popup
53
- placement="bottom-start"
54
- content={ProfileContent}
55
- isOpen={isOpen}
56
- onClose={onClose}
57
- trigger={(triggerProps) => (
58
- <Profile
59
- icon={
60
- <img
61
- // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
62
- style={imgCSS}
63
- src={avatarUrl}
64
- alt="Your profile and settings"
65
- />
66
- }
67
- onClick={onClick}
68
- isSelected={isOpen}
69
- tooltip="Your profile and settings"
70
- {...triggerProps}
71
- />
72
- )}
73
- />
74
- );
75
- };
@@ -1,52 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
- import { Fragment } from 'react';
6
-
7
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
- import { css, jsx } from '@emotion/react';
9
-
10
- import { type CustomItemComponentProps } from '@atlaskit/menu';
11
- import { Footer } from '@atlaskit/side-navigation';
12
- import { B400, N200 } from '@atlaskit/theme/colors';
13
- import { token } from '@atlaskit/tokens';
14
-
15
- const Container = (props: CustomItemComponentProps) => {
16
- // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
17
- return <div {...props} />;
18
- };
19
-
20
- const linkStyles = css({
21
- color: token('color.text.subtle', N200),
22
- '&:hover': {
23
- color: token('color.link', B400),
24
- cursor: 'pointer',
25
- textDecoration: 'none',
26
- },
27
- });
28
-
29
- // This example footer conforms to a design taken from Jira designs found at
30
- // https://www.figma.com/file/GA22za6unqO2WsBWM0Ddxk/Jira-navigation-3?node-id=124%3A7194
31
- const ExampleFooter = () => {
32
- return (
33
- <Footer
34
- component={Container}
35
- description={
36
- <Fragment>
37
- <a href="https://www.atlassian.com/company/contact" css={linkStyles}>
38
- Give feedback
39
- </a>
40
- {' ∙ '}
41
- <a href="http://www.atlassian.com" css={linkStyles}>
42
- Learn more
43
- </a>
44
- </Fragment>
45
- }
46
- >
47
- You're in a next-gen project
48
- </Footer>
49
- );
50
- };
51
-
52
- export default ExampleFooter;
@@ -1,29 +0,0 @@
1
- /**
2
- * @jsxRuntime classic
3
- * @jsx jsx
4
- */
5
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
6
- import { jsx } from '@emotion/react';
7
-
8
- import Icon from '@atlaskit/icon';
9
- import { type CustomItemComponentProps } from '@atlaskit/menu';
10
- import { Header } from '@atlaskit/side-navigation';
11
-
12
- const Container = (props: CustomItemComponentProps) => {
13
- // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
14
- return <div {...props} />;
15
- };
16
-
17
- const ExampleHeader = () => {
18
- return (
19
- <Header
20
- component={Container}
21
- description="Next-gen service desk"
22
- iconBefore={<Icon label="" size="medium" />}
23
- >
24
- NXTGen Industries
25
- </Header>
26
- );
27
- };
28
-
29
- export default ExampleHeader;
@@ -1,118 +0,0 @@
1
- /* eslint-disable @atlaskit/design-system/no-legacy-icons -- TODO - https://product-fabric.atlassian.net/browse/DSP-20400 */
2
- /**
3
- * @jsxRuntime classic
4
- * @jsx jsx
5
- */
6
-
7
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
- import { jsx } from '@emotion/react';
9
-
10
- import DropboxIcon from '@atlaskit/icon/glyph/dropbox';
11
- import FilterIcon from '@atlaskit/icon/glyph/filter';
12
- import WorkIcon from '@atlaskit/icon/glyph/folder';
13
- import CustomerIcon from '@atlaskit/icon/glyph/person';
14
- import QueueIcon from '@atlaskit/icon/glyph/queues';
15
- import SettingsIcon from '@atlaskit/icon/glyph/settings';
16
- import LanguageIcon from '@atlaskit/icon/glyph/world';
17
- import {
18
- ButtonItem,
19
- LinkItem,
20
- NavigationFooter,
21
- NavigationHeader,
22
- NestableNavigationContent,
23
- NestingItem,
24
- Section,
25
- SideNavigation,
26
- } from '@atlaskit/side-navigation';
27
-
28
- import SampleFooter from './sample-footer';
29
- import SampleHeader from './sample-header';
30
-
31
- const LanguageSettings = () => {
32
- return (
33
- <NestingItem iconBefore={<LanguageIcon label="" />} id="3-1" title="Language settings">
34
- <ButtonItem>Customize</ButtonItem>
35
-
36
- <NestingItem id="3-1-1" title="German Settings">
37
- <ButtonItem>Hallo Welt!</ButtonItem>
38
- </NestingItem>
39
- <NestingItem id="3-1-2" title="English Settings">
40
- <ButtonItem>Hello World!</ButtonItem>
41
- </NestingItem>
42
- </NestingItem>
43
- );
44
- };
45
-
46
- const PerfExample = () => {
47
- return (
48
- <SideNavigation label="project" testId="side-navigation">
49
- <NavigationHeader>
50
- <SampleHeader />
51
- </NavigationHeader>
52
- <NestableNavigationContent initialStack={[]}>
53
- <Section>
54
- <ButtonItem iconBefore={<WorkIcon label="" />}>Your work</ButtonItem>
55
- <LinkItem
56
- href="https://www.atlassian.com/customers"
57
- iconBefore={<CustomerIcon label="" />}
58
- >
59
- Your customers
60
- </LinkItem>
61
- <NestingItem
62
- id="1"
63
- isSelected
64
- title="Queues view"
65
- testId="nav-side-queues"
66
- iconBefore={<QueueIcon label="" />}
67
- >
68
- <Section title="Queues">
69
- <ButtonItem>Untriaged</ButtonItem>
70
- <ButtonItem>My feature work</ButtonItem>
71
- <ButtonItem>My bugfix work</ButtonItem>
72
- <ButtonItem>Signals</ButtonItem>
73
- <ButtonItem>Assigned to me</ButtonItem>
74
- </Section>
75
- <Section hasSeparator>
76
- <ButtonItem>New queue</ButtonItem>
77
- </Section>
78
- </NestingItem>
79
- <NestingItem
80
- id="2"
81
- testId="filter-nesting-item"
82
- title="Filters"
83
- iconBefore={<FilterIcon label="" />}
84
- >
85
- <Section>
86
- <ButtonItem>Search issues</ButtonItem>
87
- </Section>
88
- <Section title="Starred">
89
- <ButtonItem>Everything me</ButtonItem>
90
- <ButtonItem>My open issues</ButtonItem>
91
- <ButtonItem>Reported by me</ButtonItem>
92
- </Section>
93
- <Section hasSeparator title="Other">
94
- <ButtonItem>All issues</ButtonItem>
95
- <ButtonItem>Open issues</ButtonItem>
96
- <ButtonItem>Created recently</ButtonItem>
97
- <ButtonItem>Resolved recently</ButtonItem>
98
- </Section>
99
- <Section hasSeparator>
100
- <ButtonItem>View all filters</ButtonItem>
101
- </Section>
102
- </NestingItem>
103
- <NestingItem id="3" iconBefore={<SettingsIcon label="" />} title="Settings">
104
- <LanguageSettings />
105
- </NestingItem>
106
- <NestingItem id="4" iconBefore={<DropboxIcon label="" />} title="Dropbox" isDisabled>
107
- <span />
108
- </NestingItem>
109
- </Section>
110
- </NestableNavigationContent>
111
- <NavigationFooter>
112
- <SampleFooter />
113
- </NavigationFooter>
114
- </SideNavigation>
115
- );
116
- };
117
-
118
- export default PerfExample;