@atlaskit/navigation-system 4.2.0 → 4.4.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 (27) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/ui/page-layout/root.js +1 -2
  3. package/dist/cjs/ui/page-layout/side-nav/side-nav.js +70 -3
  4. package/dist/cjs/ui/page-layout/side-nav/toggle-button.js +5 -3
  5. package/dist/cjs/ui/page-layout/side-nav/visibility-provider.js +1 -1
  6. package/dist/cjs/ui/page-layout/top-nav/top-nav-start.js +10 -1
  7. package/dist/es2019/ui/page-layout/root.js +1 -1
  8. package/dist/es2019/ui/page-layout/side-nav/side-nav.js +70 -4
  9. package/dist/es2019/ui/page-layout/side-nav/toggle-button.js +5 -3
  10. package/dist/es2019/ui/page-layout/side-nav/visibility-provider.js +1 -1
  11. package/dist/es2019/ui/page-layout/top-nav/top-nav-start.js +10 -1
  12. package/dist/esm/ui/page-layout/root.js +1 -2
  13. package/dist/esm/ui/page-layout/side-nav/side-nav.js +70 -4
  14. package/dist/esm/ui/page-layout/side-nav/toggle-button.js +5 -3
  15. package/dist/esm/ui/page-layout/side-nav/visibility-provider.js +1 -1
  16. package/dist/esm/ui/page-layout/top-nav/top-nav-start.js +10 -1
  17. package/dist/types/ui/page-layout/root.d.ts +1 -1
  18. package/dist/types/ui/page-layout/side-nav/side-nav.d.ts +13 -2
  19. package/dist/types/ui/page-layout/side-nav/toggle-button.d.ts +1 -1
  20. package/dist/types/ui/page-layout/side-nav/visibility-provider.d.ts +1 -1
  21. package/dist/types/ui/page-layout/top-nav/top-nav-start.d.ts +1 -1
  22. package/dist/types-ts4.5/ui/page-layout/root.d.ts +1 -1
  23. package/dist/types-ts4.5/ui/page-layout/side-nav/side-nav.d.ts +13 -2
  24. package/dist/types-ts4.5/ui/page-layout/side-nav/toggle-button.d.ts +1 -1
  25. package/dist/types-ts4.5/ui/page-layout/side-nav/visibility-provider.d.ts +1 -1
  26. package/dist/types-ts4.5/ui/page-layout/top-nav/top-nav-start.d.ts +1 -1
  27. package/package.json +4 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlassian/navigation-system
2
2
 
3
+ ## 4.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`327d6a06eebb2`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/327d6a06eebb2) -
8
+ Adds `onPeekStart` and `onPeekEnd` callbacks to the `SideNav` to use for monitoring when users
9
+ peek at the side navigation when it is collapsed.
10
+
11
+ ## 4.3.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [`4bb7b31bfda3b`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4bb7b31bfda3b) -
16
+ Refactors changes that were previously behind `platform_dst_nav4_full_height_sidebar_api_changes`
17
+ to now be behind `platform_dst_nav4_side_nav_default_collapsed_api`. After rollout, both the new
18
+ and legacy APIs for defining side nav initial state will be supported.
19
+
3
20
  ## 4.2.0
4
21
 
5
22
  ### Minor Changes
@@ -36,8 +36,7 @@ function Root(_ref) {
36
36
  _ref$skipLinksLabel = _ref.skipLinksLabel,
37
37
  skipLinksLabel = _ref$skipLinksLabel === void 0 ? 'Skip to:' : _ref$skipLinksLabel,
38
38
  testId = _ref.testId,
39
- _ref$defaultSideNavCo = _ref.defaultSideNavCollapsed,
40
- defaultSideNavCollapsed = _ref$defaultSideNavCo === void 0 ? false : _ref$defaultSideNavCo;
39
+ defaultSideNavCollapsed = _ref.defaultSideNavCollapsed;
41
40
  var ref = (0, _react.useRef)(null);
42
41
  (0, _react.useEffect)(function () {
43
42
  if (process.env.NODE_ENV !== 'production') {
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  value: true
8
8
  });
9
9
  exports.SideNav = SideNav;
10
+ exports.onPeekStartDelayMs = void 0;
10
11
  require("./side-nav.compiled.css");
11
12
  var _react = _interopRequireWildcard(require("react"));
12
13
  var React = _react;
@@ -17,6 +18,7 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
17
18
  var _bindEventListener = require("bind-event-listener");
18
19
  var _reactDom = require("react-dom");
19
20
  var _mergeRefs = _interopRequireDefault(require("@atlaskit/ds-lib/merge-refs"));
21
+ var _useStableRef = _interopRequireDefault(require("@atlaskit/ds-lib/use-stable-ref"));
20
22
  var _openLayerObserver = require("@atlaskit/layering/experimental/open-layer-observer");
21
23
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
22
24
  var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
@@ -77,6 +79,7 @@ var styles = {
77
79
  fullHeightSidebar: "_165t56xv _180k1wjm _26vxoned _1mt19dtb"
78
80
  };
79
81
  var fallbackDefaultWidth = 320;
82
+ var onPeekStartDelayMs = exports.onPeekStartDelayMs = 500;
80
83
 
81
84
  /**
82
85
  * We need an additional component layer so we can wrap the side nav in a `OpenLayerObserver` and have access to the
@@ -95,6 +98,8 @@ function SideNavInternal(_ref) {
95
98
  skipLinkLabel = _ref$skipLinkLabel === void 0 ? label : _ref$skipLinkLabel,
96
99
  onExpand = _ref.onExpand,
97
100
  onCollapse = _ref.onCollapse,
101
+ onPeekStart = _ref.onPeekStart,
102
+ onPeekEnd = _ref.onPeekEnd,
98
103
  providedId = _ref.id;
99
104
  var id = (0, _idUtils.useLayoutId)({
100
105
  providedId: providedId
@@ -161,6 +166,16 @@ function SideNavInternal(_ref) {
161
166
  type: 'not-active'
162
167
  });
163
168
  var isFlyoutVisible = (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open';
169
+ var isExpandedOnDesktopRef = (0, _useStableRef.default)(isExpandedOnDesktop);
170
+ var hasPeekStartedRef = (0, _react.useRef)(false);
171
+ var onPeekStartRef = (0, _useStableRef.default)(onPeekStart);
172
+ var onPeekEndRef = (0, _useStableRef.default)(onPeekEnd);
173
+ var onPeekStartTimeoutIdRef = (0, _react.useRef)(undefined);
174
+ (0, _react.useEffect)(function () {
175
+ return function () {
176
+ clearTimeout(onPeekStartTimeoutIdRef.current);
177
+ };
178
+ }, []);
164
179
  var updateFlyoutState = (0, _react.useMemo)(function () {
165
180
  function tryAbortPendingClose() {
166
181
  if (flyoutStateRef.current.type === 'waiting-for-close') {
@@ -168,6 +183,7 @@ function SideNavInternal(_ref) {
168
183
  }
169
184
  }
170
185
  function open() {
186
+ var prevFlyoutState = flyoutStateRef.current;
171
187
  tryAbortPendingClose();
172
188
  flyoutStateRef.current = {
173
189
  type: 'open'
@@ -180,8 +196,24 @@ function SideNavInternal(_ref) {
180
196
  }
181
197
  return currentState;
182
198
  });
199
+
200
+ // Avoid redundant calls to `onPeekStart()`
201
+ if (prevFlyoutState.type === 'not-active') {
202
+ clearTimeout(onPeekStartTimeoutIdRef.current);
203
+ onPeekStartTimeoutIdRef.current = setTimeout(function () {
204
+ var _onPeekStartRef$curre;
205
+ // If the flyout isn't still open after ~500ms then we won't count the peek
206
+ // As we want to track user intention rather than all hovers
207
+ if (isExpandedOnDesktopRef.current || flyoutStateRef.current.type !== 'open') {
208
+ return;
209
+ }
210
+ hasPeekStartedRef.current = true;
211
+ (_onPeekStartRef$curre = onPeekStartRef.current) === null || _onPeekStartRef$curre === void 0 || _onPeekStartRef$curre.call(onPeekStartRef);
212
+ }, onPeekStartDelayMs);
213
+ }
183
214
  }
184
215
  function close() {
216
+ var prevFlyoutState = flyoutStateRef.current;
185
217
  tryAbortPendingClose();
186
218
  flyoutStateRef.current = {
187
219
  type: 'not-active'
@@ -194,6 +226,15 @@ function SideNavInternal(_ref) {
194
226
  }
195
227
  return currentState;
196
228
  });
229
+
230
+ // Avoid redundant calls to `onPeekEnd()`
231
+ if (prevFlyoutState.type !== 'not-active' && hasPeekStartedRef.current) {
232
+ var _onPeekEndRef$current;
233
+ hasPeekStartedRef.current = false;
234
+ (_onPeekEndRef$current = onPeekEndRef.current) === null || _onPeekEndRef$current === void 0 || _onPeekEndRef$current.call(onPeekEndRef, {
235
+ trigger: isExpandedOnDesktopRef.current ? 'side-nav-expand' : 'mouse-leave'
236
+ });
237
+ }
197
238
  }
198
239
  return function onAction(action) {
199
240
  if (action === 'drag-from-flyout-started') {
@@ -252,7 +293,7 @@ function SideNavInternal(_ref) {
252
293
  return;
253
294
  }
254
295
  };
255
- }, [openLayerObserver, setSideNavState]);
296
+ }, [isExpandedOnDesktopRef, onPeekEndRef, onPeekStartRef, openLayerObserver, setSideNavState]);
256
297
  var toggleVisibilityByScreenResize = (0, _useToggleSideNav.useToggleSideNav)({
257
298
  trigger: 'screen-resize'
258
299
  });
@@ -260,8 +301,8 @@ function SideNavInternal(_ref) {
260
301
  trigger: 'click-outside-on-mobile'
261
302
  });
262
303
  (0, _react.useEffect)(function () {
263
- if ((0, _platformFeatureFlags.fg)('platform_dst_nav4_full_height_sidebar_api_changes')) {
264
- // We are passing initial state to the Root now, so no initial sync is required
304
+ if ((0, _platformFeatureFlags.fg)('platform_dst_nav4_side_nav_default_collapsed_api')) {
305
+ // This is the old version of the hook, so we skip it when the flag is enabled
265
306
  return;
266
307
  }
267
308
 
@@ -274,6 +315,28 @@ function SideNavInternal(_ref) {
274
315
  lastTrigger: null
275
316
  });
276
317
  }, [initialDefaultCollapsed, setSideNavState]);
318
+
319
+ // Moving to `useLayoutEffect` so that there's no visual shift in non-SSR environments when using legacy API
320
+ // For SSR the new API is still necessary
321
+ (0, _react.useLayoutEffect)(function () {
322
+ if (!(0, _platformFeatureFlags.fg)('platform_dst_nav4_side_nav_default_collapsed_api')) {
323
+ // This is the new version of the hook, so we skip it when the flag is disabled
324
+ return;
325
+ }
326
+ if (sideNavState !== null) {
327
+ // Only need to do an initial sync if it hasn't been initialized from Root
328
+ return;
329
+ }
330
+
331
+ // Sync the visibility in context (provided in `<Root>`) with the local `defaultCollapsed` prop provided to `SideNav`
332
+ // after SSR hydration. This should only run once, after the initial render on the client.
333
+ setSideNavState({
334
+ desktop: initialDefaultCollapsed ? 'collapsed' : 'expanded',
335
+ mobile: 'collapsed',
336
+ flyout: 'closed',
337
+ lastTrigger: null
338
+ });
339
+ }, [initialDefaultCollapsed, setSideNavState, sideNavState]);
277
340
  var handleExpand = (0, _react.useCallback)(function (_ref2) {
278
341
  var screen = _ref2.screen,
279
342
  trigger = _ref2.trigger;
@@ -681,6 +744,8 @@ function SideNav(_ref8) {
681
744
  skipLinkLabel = _ref8$skipLinkLabel === void 0 ? label : _ref8$skipLinkLabel,
682
745
  onExpand = _ref8.onExpand,
683
746
  onCollapse = _ref8.onCollapse,
747
+ onPeekStart = _ref8.onPeekStart,
748
+ onPeekEnd = _ref8.onPeekEnd,
684
749
  id = _ref8.id;
685
750
  return /*#__PURE__*/React.createElement(_openLayerObserver.OpenLayerObserverNamespaceProvider, {
686
751
  namespace: openLayerObserverSideNavNamespace
@@ -692,6 +757,8 @@ function SideNav(_ref8) {
692
757
  skipLinkLabel: skipLinkLabel,
693
758
  onExpand: onExpand,
694
759
  onCollapse: onCollapse,
760
+ onPeekStart: onPeekStart,
761
+ onPeekEnd: onPeekEnd,
695
762
  id: id
696
763
  }, children));
697
764
  }
@@ -20,6 +20,7 @@ var _migration = require("../../top-nav-items/themed/migration");
20
20
  var _toggleButtonContext = require("./toggle-button-context");
21
21
  var _useSideNavVisibility2 = require("./use-side-nav-visibility");
22
22
  var _useToggleSideNav = require("./use-toggle-side-nav");
23
+ var _visibilityContext = require("./visibility-context");
23
24
  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); }
24
25
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
25
26
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -51,10 +52,11 @@ var SideNavToggleButton = exports.SideNavToggleButton = function SideNavToggleBu
51
52
  }),
52
53
  isSideNavExpandedOnDesktop = _useSideNavVisibility.isExpandedOnDesktop,
53
54
  isSideNavExpandedOnMobile = _useSideNavVisibility.isExpandedOnMobile;
55
+ var sideNavState = (0, _react.useContext)(_visibilityContext.SideNavVisibilityState);
54
56
 
55
- // When `platform_dst_nav4_full_height_sidebar_api_changes` is enabled,
56
- // we default to the desktop state for SSR
57
- var _useState = (0, _react.useState)((0, _platformFeatureFlags.fg)('platform_dst_nav4_full_height_sidebar_api_changes') ? isSideNavExpandedOnDesktop : !defaultCollapsed),
57
+ // When default state is provided to `Root` the state in context will already be
58
+ // initialized in SSR
59
+ var _useState = (0, _react.useState)(sideNavState === null || !(0, _platformFeatureFlags.fg)('platform_dst_nav4_side_nav_default_collapsed_api') ? !defaultCollapsed : isSideNavExpandedOnDesktop),
58
60
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
59
61
  isSideNavExpanded = _useState2[0],
60
62
  setIsSideNavExpanded = _useState2[1];
@@ -17,7 +17,7 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
17
17
  var SideNavVisibilityProvider = exports.SideNavVisibilityProvider = function SideNavVisibilityProvider(_ref) {
18
18
  var children = _ref.children,
19
19
  defaultCollapsed = _ref.defaultCollapsed;
20
- var initialState = (0, _platformFeatureFlags.fg)('platform_dst_nav4_full_height_sidebar_api_changes') ? {
20
+ var initialState = typeof defaultCollapsed === 'boolean' && (0, _platformFeatureFlags.fg)('platform_dst_nav4_side_nav_default_collapsed_api') ? {
21
21
  desktop: defaultCollapsed ? 'collapsed' : 'expanded',
22
22
  mobile: 'collapsed',
23
23
  flyout: 'closed',
@@ -16,6 +16,7 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
16
16
  var _compiled = require("@atlaskit/primitives/compiled");
17
17
  var _topNavStartContext = require("../../../context/top-nav-start/top-nav-start-context");
18
18
  var _useSideNavVisibility3 = require("../side-nav/use-side-nav-visibility");
19
+ var _visibilityContext = require("../side-nav/visibility-context");
19
20
  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); }
20
21
  /**
21
22
  * Firefox does support these reorder animations, but only partially enabling layout animations would look odd.
@@ -180,14 +181,22 @@ function TopNavStart(_ref3) {
180
181
 
181
182
  // Used to prevent the reorder animations from running on the initial render.
182
183
  var isFirstRenderRef = (0, _react.useRef)(true);
184
+ var sideNavState = (0, _react.useContext)(_visibilityContext.SideNavVisibilityState);
183
185
  (0, _react.useEffect)(function () {
184
186
  if (!(0, _platformFeatureFlags.fg)('navx-full-height-sidebar')) {
185
187
  return;
186
188
  }
189
+
190
+ // Ignore renders until the side nav state is initialized
191
+ // So that apps using the legacy API for setting side nav default state do not see
192
+ // animations when they shouldn't
193
+ if (sideNavState === null) {
194
+ return;
195
+ }
187
196
  if (isFirstRenderRef.current) {
188
197
  isFirstRenderRef.current = false;
189
198
  }
190
- }, []);
199
+ }, [sideNavState]);
191
200
 
192
201
  // Using a stable ref to avoid re-running the animation layout effect when the toggle button prop value changes, which
193
202
  // can happen a lot (e.g. if the parent re-renders)
@@ -26,7 +26,7 @@ export function Root({
26
26
  UNSAFE_dangerouslyHoistSlotSizes = false,
27
27
  skipLinksLabel = 'Skip to:',
28
28
  testId,
29
- defaultSideNavCollapsed = false
29
+ defaultSideNavCollapsed
30
30
  }) {
31
31
  const ref = useRef(null);
32
32
  useEffect(() => {
@@ -3,10 +3,11 @@ import _extends from "@babel/runtime/helpers/extends";
3
3
  import "./side-nav.compiled.css";
4
4
  import * as React from 'react';
5
5
  import { ax, ix } from "@compiled/react/runtime";
6
- import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
6
+ import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
7
7
  import { bind } from 'bind-event-listener';
8
8
  import { flushSync } from 'react-dom';
9
9
  import mergeRefs from '@atlaskit/ds-lib/merge-refs';
10
+ import useStableRef from '@atlaskit/ds-lib/use-stable-ref';
10
11
  import { OpenLayerObserverNamespaceProvider, useOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
11
12
  import { fg } from '@atlaskit/platform-feature-flags';
12
13
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
@@ -64,6 +65,7 @@ const styles = {
64
65
  fullHeightSidebar: "_165t56xv _180k1wjm _26vxoned _1mt19dtb"
65
66
  };
66
67
  const fallbackDefaultWidth = 320;
68
+ export const onPeekStartDelayMs = 500;
67
69
 
68
70
  /**
69
71
  * We need an additional component layer so we can wrap the side nav in a `OpenLayerObserver` and have access to the
@@ -78,6 +80,8 @@ function SideNavInternal({
78
80
  skipLinkLabel = label,
79
81
  onExpand,
80
82
  onCollapse,
83
+ onPeekStart,
84
+ onPeekEnd,
81
85
  id: providedId
82
86
  }) {
83
87
  var _sideNavState$lastTri;
@@ -142,6 +146,16 @@ function SideNavInternal({
142
146
  type: 'not-active'
143
147
  });
144
148
  const isFlyoutVisible = (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open';
149
+ const isExpandedOnDesktopRef = useStableRef(isExpandedOnDesktop);
150
+ const hasPeekStartedRef = useRef(false);
151
+ const onPeekStartRef = useStableRef(onPeekStart);
152
+ const onPeekEndRef = useStableRef(onPeekEnd);
153
+ const onPeekStartTimeoutIdRef = useRef(undefined);
154
+ useEffect(() => {
155
+ return () => {
156
+ clearTimeout(onPeekStartTimeoutIdRef.current);
157
+ };
158
+ }, []);
145
159
  const updateFlyoutState = useMemo(() => {
146
160
  function tryAbortPendingClose() {
147
161
  if (flyoutStateRef.current.type === 'waiting-for-close') {
@@ -149,6 +163,7 @@ function SideNavInternal({
149
163
  }
150
164
  }
151
165
  function open() {
166
+ const prevFlyoutState = flyoutStateRef.current;
152
167
  tryAbortPendingClose();
153
168
  flyoutStateRef.current = {
154
169
  type: 'open'
@@ -162,8 +177,24 @@ function SideNavInternal({
162
177
  }
163
178
  return currentState;
164
179
  });
180
+
181
+ // Avoid redundant calls to `onPeekStart()`
182
+ if (prevFlyoutState.type === 'not-active') {
183
+ clearTimeout(onPeekStartTimeoutIdRef.current);
184
+ onPeekStartTimeoutIdRef.current = setTimeout(() => {
185
+ var _onPeekStartRef$curre;
186
+ // If the flyout isn't still open after ~500ms then we won't count the peek
187
+ // As we want to track user intention rather than all hovers
188
+ if (isExpandedOnDesktopRef.current || flyoutStateRef.current.type !== 'open') {
189
+ return;
190
+ }
191
+ hasPeekStartedRef.current = true;
192
+ (_onPeekStartRef$curre = onPeekStartRef.current) === null || _onPeekStartRef$curre === void 0 ? void 0 : _onPeekStartRef$curre.call(onPeekStartRef);
193
+ }, onPeekStartDelayMs);
194
+ }
165
195
  }
166
196
  function close() {
197
+ const prevFlyoutState = flyoutStateRef.current;
167
198
  tryAbortPendingClose();
168
199
  flyoutStateRef.current = {
169
200
  type: 'not-active'
@@ -177,6 +208,15 @@ function SideNavInternal({
177
208
  }
178
209
  return currentState;
179
210
  });
211
+
212
+ // Avoid redundant calls to `onPeekEnd()`
213
+ if (prevFlyoutState.type !== 'not-active' && hasPeekStartedRef.current) {
214
+ var _onPeekEndRef$current;
215
+ hasPeekStartedRef.current = false;
216
+ (_onPeekEndRef$current = onPeekEndRef.current) === null || _onPeekEndRef$current === void 0 ? void 0 : _onPeekEndRef$current.call(onPeekEndRef, {
217
+ trigger: isExpandedOnDesktopRef.current ? 'side-nav-expand' : 'mouse-leave'
218
+ });
219
+ }
180
220
  }
181
221
  return function onAction(action) {
182
222
  if (action === 'drag-from-flyout-started') {
@@ -235,7 +275,7 @@ function SideNavInternal({
235
275
  return;
236
276
  }
237
277
  };
238
- }, [openLayerObserver, setSideNavState]);
278
+ }, [isExpandedOnDesktopRef, onPeekEndRef, onPeekStartRef, openLayerObserver, setSideNavState]);
239
279
  const toggleVisibilityByScreenResize = useToggleSideNav({
240
280
  trigger: 'screen-resize'
241
281
  });
@@ -243,8 +283,8 @@ function SideNavInternal({
243
283
  trigger: 'click-outside-on-mobile'
244
284
  });
245
285
  useEffect(() => {
246
- if (fg('platform_dst_nav4_full_height_sidebar_api_changes')) {
247
- // We are passing initial state to the Root now, so no initial sync is required
286
+ if (fg('platform_dst_nav4_side_nav_default_collapsed_api')) {
287
+ // This is the old version of the hook, so we skip it when the flag is enabled
248
288
  return;
249
289
  }
250
290
 
@@ -257,6 +297,28 @@ function SideNavInternal({
257
297
  lastTrigger: null
258
298
  });
259
299
  }, [initialDefaultCollapsed, setSideNavState]);
300
+
301
+ // Moving to `useLayoutEffect` so that there's no visual shift in non-SSR environments when using legacy API
302
+ // For SSR the new API is still necessary
303
+ useLayoutEffect(() => {
304
+ if (!fg('platform_dst_nav4_side_nav_default_collapsed_api')) {
305
+ // This is the new version of the hook, so we skip it when the flag is disabled
306
+ return;
307
+ }
308
+ if (sideNavState !== null) {
309
+ // Only need to do an initial sync if it hasn't been initialized from Root
310
+ return;
311
+ }
312
+
313
+ // Sync the visibility in context (provided in `<Root>`) with the local `defaultCollapsed` prop provided to `SideNav`
314
+ // after SSR hydration. This should only run once, after the initial render on the client.
315
+ setSideNavState({
316
+ desktop: initialDefaultCollapsed ? 'collapsed' : 'expanded',
317
+ mobile: 'collapsed',
318
+ flyout: 'closed',
319
+ lastTrigger: null
320
+ });
321
+ }, [initialDefaultCollapsed, setSideNavState, sideNavState]);
260
322
  const handleExpand = useCallback(({
261
323
  screen,
262
324
  trigger
@@ -673,6 +735,8 @@ export function SideNav({
673
735
  // Default value is defined in `SideNavInternal`
674
736
  onExpand,
675
737
  onCollapse,
738
+ onPeekStart,
739
+ onPeekEnd,
676
740
  id
677
741
  }) {
678
742
  return /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
@@ -685,6 +749,8 @@ export function SideNav({
685
749
  skipLinkLabel: skipLinkLabel,
686
750
  onExpand: onExpand,
687
751
  onCollapse: onCollapse,
752
+ onPeekStart: onPeekStart,
753
+ onPeekEnd: onPeekEnd,
688
754
  id: id
689
755
  }, children));
690
756
  }
@@ -10,6 +10,7 @@ import { IconButton } from '../../top-nav-items/themed/migration';
10
10
  import { SideNavToggleButtonAttachRef } from './toggle-button-context';
11
11
  import { useSideNavVisibility } from './use-side-nav-visibility';
12
12
  import { useToggleSideNav } from './use-toggle-side-nav';
13
+ import { SideNavVisibilityState } from './visibility-context';
13
14
  const toggleButtonTooltipOptions = {
14
15
  // We're disabling pointer events on the tooltip to prevent it from blocking mouse events, so that the side nav flyout stays open
15
16
  // when moving the mouse from the top bar to the side nav.
@@ -39,10 +40,11 @@ export const SideNavToggleButton = ({
39
40
  } = useSideNavVisibility({
40
41
  defaultCollapsed
41
42
  });
43
+ const sideNavState = useContext(SideNavVisibilityState);
42
44
 
43
- // When `platform_dst_nav4_full_height_sidebar_api_changes` is enabled,
44
- // we default to the desktop state for SSR
45
- const [isSideNavExpanded, setIsSideNavExpanded] = useState(fg('platform_dst_nav4_full_height_sidebar_api_changes') ? isSideNavExpandedOnDesktop : !defaultCollapsed);
45
+ // When default state is provided to `Root` the state in context will already be
46
+ // initialized in SSR
47
+ const [isSideNavExpanded, setIsSideNavExpanded] = useState(sideNavState === null || !fg('platform_dst_nav4_side_nav_default_collapsed_api') ? !defaultCollapsed : isSideNavExpandedOnDesktop);
46
48
  const ref = useContext(SideNavToggleButtonAttachRef);
47
49
  const elementRef = useRef(null);
48
50
 
@@ -9,7 +9,7 @@ export const SideNavVisibilityProvider = ({
9
9
  children,
10
10
  defaultCollapsed
11
11
  }) => {
12
- const initialState = fg('platform_dst_nav4_full_height_sidebar_api_changes') ? {
12
+ const initialState = typeof defaultCollapsed === 'boolean' && fg('platform_dst_nav4_side_nav_default_collapsed_api') ? {
13
13
  desktop: defaultCollapsed ? 'collapsed' : 'expanded',
14
14
  mobile: 'collapsed',
15
15
  flyout: 'closed',
@@ -7,6 +7,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
7
7
  import { UNSAFE_useMediaQuery } from '@atlaskit/primitives/compiled';
8
8
  import { TopNavStartAttachRef } from '../../../context/top-nav-start/top-nav-start-context';
9
9
  import { useSideNavVisibility } from '../side-nav/use-side-nav-visibility';
10
+ import { SideNavVisibilityState } from '../side-nav/visibility-context';
10
11
 
11
12
  /**
12
13
  * Firefox does support these reorder animations, but only partially enabling layout animations would look odd.
@@ -170,14 +171,22 @@ export function TopNavStart({
170
171
 
171
172
  // Used to prevent the reorder animations from running on the initial render.
172
173
  const isFirstRenderRef = useRef(true);
174
+ const sideNavState = useContext(SideNavVisibilityState);
173
175
  useEffect(() => {
174
176
  if (!fg('navx-full-height-sidebar')) {
175
177
  return;
176
178
  }
179
+
180
+ // Ignore renders until the side nav state is initialized
181
+ // So that apps using the legacy API for setting side nav default state do not see
182
+ // animations when they shouldn't
183
+ if (sideNavState === null) {
184
+ return;
185
+ }
177
186
  if (isFirstRenderRef.current) {
178
187
  isFirstRenderRef.current = false;
179
188
  }
180
- }, []);
189
+ }, [sideNavState]);
181
190
 
182
191
  // Using a stable ref to avoid re-running the animation layout effect when the toggle button prop value changes, which
183
192
  // can happen a lot (e.g. if the parent re-renders)
@@ -28,8 +28,7 @@ export function Root(_ref) {
28
28
  _ref$skipLinksLabel = _ref.skipLinksLabel,
29
29
  skipLinksLabel = _ref$skipLinksLabel === void 0 ? 'Skip to:' : _ref$skipLinksLabel,
30
30
  testId = _ref.testId,
31
- _ref$defaultSideNavCo = _ref.defaultSideNavCollapsed,
32
- defaultSideNavCollapsed = _ref$defaultSideNavCo === void 0 ? false : _ref$defaultSideNavCo;
31
+ defaultSideNavCollapsed = _ref.defaultSideNavCollapsed;
33
32
  var ref = useRef(null);
34
33
  useEffect(function () {
35
34
  if (process.env.NODE_ENV !== 'production') {
@@ -7,10 +7,11 @@ import * as React from 'react';
7
7
  import { ax, ix } from "@compiled/react/runtime";
8
8
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
9
9
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
10
- import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
10
+ import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
11
11
  import { bind } from 'bind-event-listener';
12
12
  import { flushSync } from 'react-dom';
13
13
  import mergeRefs from '@atlaskit/ds-lib/merge-refs';
14
+ import useStableRef from '@atlaskit/ds-lib/use-stable-ref';
14
15
  import { OpenLayerObserverNamespaceProvider, useOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer';
15
16
  import { fg } from '@atlaskit/platform-feature-flags';
16
17
  import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
@@ -68,6 +69,7 @@ var styles = {
68
69
  fullHeightSidebar: "_165t56xv _180k1wjm _26vxoned _1mt19dtb"
69
70
  };
70
71
  var fallbackDefaultWidth = 320;
72
+ export var onPeekStartDelayMs = 500;
71
73
 
72
74
  /**
73
75
  * We need an additional component layer so we can wrap the side nav in a `OpenLayerObserver` and have access to the
@@ -86,6 +88,8 @@ function SideNavInternal(_ref) {
86
88
  skipLinkLabel = _ref$skipLinkLabel === void 0 ? label : _ref$skipLinkLabel,
87
89
  onExpand = _ref.onExpand,
88
90
  onCollapse = _ref.onCollapse,
91
+ onPeekStart = _ref.onPeekStart,
92
+ onPeekEnd = _ref.onPeekEnd,
89
93
  providedId = _ref.id;
90
94
  var id = useLayoutId({
91
95
  providedId: providedId
@@ -152,6 +156,16 @@ function SideNavInternal(_ref) {
152
156
  type: 'not-active'
153
157
  });
154
158
  var isFlyoutVisible = (sideNavState === null || sideNavState === void 0 ? void 0 : sideNavState.flyout) === 'open';
159
+ var isExpandedOnDesktopRef = useStableRef(isExpandedOnDesktop);
160
+ var hasPeekStartedRef = useRef(false);
161
+ var onPeekStartRef = useStableRef(onPeekStart);
162
+ var onPeekEndRef = useStableRef(onPeekEnd);
163
+ var onPeekStartTimeoutIdRef = useRef(undefined);
164
+ useEffect(function () {
165
+ return function () {
166
+ clearTimeout(onPeekStartTimeoutIdRef.current);
167
+ };
168
+ }, []);
155
169
  var updateFlyoutState = useMemo(function () {
156
170
  function tryAbortPendingClose() {
157
171
  if (flyoutStateRef.current.type === 'waiting-for-close') {
@@ -159,6 +173,7 @@ function SideNavInternal(_ref) {
159
173
  }
160
174
  }
161
175
  function open() {
176
+ var prevFlyoutState = flyoutStateRef.current;
162
177
  tryAbortPendingClose();
163
178
  flyoutStateRef.current = {
164
179
  type: 'open'
@@ -171,8 +186,24 @@ function SideNavInternal(_ref) {
171
186
  }
172
187
  return currentState;
173
188
  });
189
+
190
+ // Avoid redundant calls to `onPeekStart()`
191
+ if (prevFlyoutState.type === 'not-active') {
192
+ clearTimeout(onPeekStartTimeoutIdRef.current);
193
+ onPeekStartTimeoutIdRef.current = setTimeout(function () {
194
+ var _onPeekStartRef$curre;
195
+ // If the flyout isn't still open after ~500ms then we won't count the peek
196
+ // As we want to track user intention rather than all hovers
197
+ if (isExpandedOnDesktopRef.current || flyoutStateRef.current.type !== 'open') {
198
+ return;
199
+ }
200
+ hasPeekStartedRef.current = true;
201
+ (_onPeekStartRef$curre = onPeekStartRef.current) === null || _onPeekStartRef$curre === void 0 || _onPeekStartRef$curre.call(onPeekStartRef);
202
+ }, onPeekStartDelayMs);
203
+ }
174
204
  }
175
205
  function close() {
206
+ var prevFlyoutState = flyoutStateRef.current;
176
207
  tryAbortPendingClose();
177
208
  flyoutStateRef.current = {
178
209
  type: 'not-active'
@@ -185,6 +216,15 @@ function SideNavInternal(_ref) {
185
216
  }
186
217
  return currentState;
187
218
  });
219
+
220
+ // Avoid redundant calls to `onPeekEnd()`
221
+ if (prevFlyoutState.type !== 'not-active' && hasPeekStartedRef.current) {
222
+ var _onPeekEndRef$current;
223
+ hasPeekStartedRef.current = false;
224
+ (_onPeekEndRef$current = onPeekEndRef.current) === null || _onPeekEndRef$current === void 0 || _onPeekEndRef$current.call(onPeekEndRef, {
225
+ trigger: isExpandedOnDesktopRef.current ? 'side-nav-expand' : 'mouse-leave'
226
+ });
227
+ }
188
228
  }
189
229
  return function onAction(action) {
190
230
  if (action === 'drag-from-flyout-started') {
@@ -243,7 +283,7 @@ function SideNavInternal(_ref) {
243
283
  return;
244
284
  }
245
285
  };
246
- }, [openLayerObserver, setSideNavState]);
286
+ }, [isExpandedOnDesktopRef, onPeekEndRef, onPeekStartRef, openLayerObserver, setSideNavState]);
247
287
  var toggleVisibilityByScreenResize = useToggleSideNav({
248
288
  trigger: 'screen-resize'
249
289
  });
@@ -251,8 +291,8 @@ function SideNavInternal(_ref) {
251
291
  trigger: 'click-outside-on-mobile'
252
292
  });
253
293
  useEffect(function () {
254
- if (fg('platform_dst_nav4_full_height_sidebar_api_changes')) {
255
- // We are passing initial state to the Root now, so no initial sync is required
294
+ if (fg('platform_dst_nav4_side_nav_default_collapsed_api')) {
295
+ // This is the old version of the hook, so we skip it when the flag is enabled
256
296
  return;
257
297
  }
258
298
 
@@ -265,6 +305,28 @@ function SideNavInternal(_ref) {
265
305
  lastTrigger: null
266
306
  });
267
307
  }, [initialDefaultCollapsed, setSideNavState]);
308
+
309
+ // Moving to `useLayoutEffect` so that there's no visual shift in non-SSR environments when using legacy API
310
+ // For SSR the new API is still necessary
311
+ useLayoutEffect(function () {
312
+ if (!fg('platform_dst_nav4_side_nav_default_collapsed_api')) {
313
+ // This is the new version of the hook, so we skip it when the flag is disabled
314
+ return;
315
+ }
316
+ if (sideNavState !== null) {
317
+ // Only need to do an initial sync if it hasn't been initialized from Root
318
+ return;
319
+ }
320
+
321
+ // Sync the visibility in context (provided in `<Root>`) with the local `defaultCollapsed` prop provided to `SideNav`
322
+ // after SSR hydration. This should only run once, after the initial render on the client.
323
+ setSideNavState({
324
+ desktop: initialDefaultCollapsed ? 'collapsed' : 'expanded',
325
+ mobile: 'collapsed',
326
+ flyout: 'closed',
327
+ lastTrigger: null
328
+ });
329
+ }, [initialDefaultCollapsed, setSideNavState, sideNavState]);
268
330
  var handleExpand = useCallback(function (_ref2) {
269
331
  var screen = _ref2.screen,
270
332
  trigger = _ref2.trigger;
@@ -672,6 +734,8 @@ export function SideNav(_ref8) {
672
734
  skipLinkLabel = _ref8$skipLinkLabel === void 0 ? label : _ref8$skipLinkLabel,
673
735
  onExpand = _ref8.onExpand,
674
736
  onCollapse = _ref8.onCollapse,
737
+ onPeekStart = _ref8.onPeekStart,
738
+ onPeekEnd = _ref8.onPeekEnd,
675
739
  id = _ref8.id;
676
740
  return /*#__PURE__*/React.createElement(OpenLayerObserverNamespaceProvider, {
677
741
  namespace: openLayerObserverSideNavNamespace
@@ -683,6 +747,8 @@ export function SideNav(_ref8) {
683
747
  skipLinkLabel: skipLinkLabel,
684
748
  onExpand: onExpand,
685
749
  onCollapse: onCollapse,
750
+ onPeekStart: onPeekStart,
751
+ onPeekEnd: onPeekEnd,
686
752
  id: id
687
753
  }, children));
688
754
  }
@@ -14,6 +14,7 @@ import { IconButton } from '../../top-nav-items/themed/migration';
14
14
  import { SideNavToggleButtonAttachRef } from './toggle-button-context';
15
15
  import { useSideNavVisibility } from './use-side-nav-visibility';
16
16
  import { useToggleSideNav } from './use-toggle-side-nav';
17
+ import { SideNavVisibilityState } from './visibility-context';
17
18
  var toggleButtonTooltipOptions = {
18
19
  // We're disabling pointer events on the tooltip to prevent it from blocking mouse events, so that the side nav flyout stays open
19
20
  // when moving the mouse from the top bar to the side nav.
@@ -42,10 +43,11 @@ export var SideNavToggleButton = function SideNavToggleButton(_ref) {
42
43
  }),
43
44
  isSideNavExpandedOnDesktop = _useSideNavVisibility.isExpandedOnDesktop,
44
45
  isSideNavExpandedOnMobile = _useSideNavVisibility.isExpandedOnMobile;
46
+ var sideNavState = useContext(SideNavVisibilityState);
45
47
 
46
- // When `platform_dst_nav4_full_height_sidebar_api_changes` is enabled,
47
- // we default to the desktop state for SSR
48
- var _useState = useState(fg('platform_dst_nav4_full_height_sidebar_api_changes') ? isSideNavExpandedOnDesktop : !defaultCollapsed),
48
+ // When default state is provided to `Root` the state in context will already be
49
+ // initialized in SSR
50
+ var _useState = useState(sideNavState === null || !fg('platform_dst_nav4_side_nav_default_collapsed_api') ? !defaultCollapsed : isSideNavExpandedOnDesktop),
49
51
  _useState2 = _slicedToArray(_useState, 2),
50
52
  isSideNavExpanded = _useState2[0],
51
53
  setIsSideNavExpanded = _useState2[1];
@@ -9,7 +9,7 @@ import { SetSideNavVisibilityState, SideNavVisibilityState } from './visibility-
9
9
  export var SideNavVisibilityProvider = function SideNavVisibilityProvider(_ref) {
10
10
  var children = _ref.children,
11
11
  defaultCollapsed = _ref.defaultCollapsed;
12
- var initialState = fg('platform_dst_nav4_full_height_sidebar_api_changes') ? {
12
+ var initialState = typeof defaultCollapsed === 'boolean' && fg('platform_dst_nav4_side_nav_default_collapsed_api') ? {
13
13
  desktop: defaultCollapsed ? 'collapsed' : 'expanded',
14
14
  mobile: 'collapsed',
15
15
  flyout: 'closed',
@@ -8,6 +8,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
8
8
  import { UNSAFE_useMediaQuery } from '@atlaskit/primitives/compiled';
9
9
  import { TopNavStartAttachRef } from '../../../context/top-nav-start/top-nav-start-context';
10
10
  import { useSideNavVisibility } from '../side-nav/use-side-nav-visibility';
11
+ import { SideNavVisibilityState } from '../side-nav/visibility-context';
11
12
 
12
13
  /**
13
14
  * Firefox does support these reorder animations, but only partially enabling layout animations would look odd.
@@ -172,14 +173,22 @@ export function TopNavStart(_ref3) {
172
173
 
173
174
  // Used to prevent the reorder animations from running on the initial render.
174
175
  var isFirstRenderRef = useRef(true);
176
+ var sideNavState = useContext(SideNavVisibilityState);
175
177
  useEffect(function () {
176
178
  if (!fg('navx-full-height-sidebar')) {
177
179
  return;
178
180
  }
181
+
182
+ // Ignore renders until the side nav state is initialized
183
+ // So that apps using the legacy API for setting side nav default state do not see
184
+ // animations when they shouldn't
185
+ if (sideNavState === null) {
186
+ return;
187
+ }
179
188
  if (isFirstRenderRef.current) {
180
189
  isFirstRenderRef.current = false;
181
190
  }
182
- }, []);
191
+ }, [sideNavState]);
183
192
 
184
193
  // Using a stable ref to avoid re-running the animation layout effect when the toggle button prop value changes, which
185
194
  // can happen a lot (e.g. if the parent re-renders)
@@ -44,7 +44,7 @@ export declare function Root({ children, xcss, UNSAFE_dangerouslyHoistSlotSizes,
44
44
  * persisted state using the `onCollapse` and `onExpand` callbacks, to ensure it is up to date
45
45
  * when the app is reloaded.
46
46
  *
47
- * __Note:__ This prop will only work when the `platform_dst_nav4_full_height_sidebar_api_changes` gate is enabled.
47
+ * __Note:__ When provided, the `defaultCollapsed` props on `SideNav` and `SideNavToggleButton` will be ignored.
48
48
  */
49
49
  defaultSideNavCollapsed?: boolean;
50
50
  }): JSX.Element;
@@ -15,7 +15,7 @@ type SideNavProps = CommonSlotProps & {
15
15
  * @deprecated
16
16
  *
17
17
  * This prop is being replaced by `defaultSideNavCollapsed` on the `Root` element,
18
- * and will be removed after `platform_dst_nav4_full_height_sidebar_api_changes` is cleaned up.
18
+ * and will be removed in the future.
19
19
  *
20
20
  * ---
21
21
  *
@@ -53,7 +53,18 @@ type SideNavProps = CommonSlotProps & {
53
53
  * Note: The trigger parameter is only provided when the `navx-full-height-sidebar` feature flag is enabled.
54
54
  */
55
55
  onCollapse?: VisibilityCallback;
56
+ /**
57
+ * Called when the side nav begins peeking / flyout.
58
+ */
59
+ onPeekStart?: () => void;
60
+ /**
61
+ * Called when the side nav stops peeking / flyout.
62
+ */
63
+ onPeekEnd?: (args: {
64
+ trigger: 'mouse-leave' | 'side-nav-expand';
65
+ }) => void;
56
66
  };
67
+ export declare const onPeekStartDelayMs = 500;
57
68
  /**
58
69
  * The side navigation layout area. It will show on the left (inline start) of the screen.
59
70
  *
@@ -64,5 +75,5 @@ type SideNavProps = CommonSlotProps & {
64
75
  */
65
76
  export declare function SideNav({ children, defaultCollapsed, defaultWidth, testId, label, // Default value is defined in `SideNavInternal`
66
77
  skipLinkLabel, // Default value is defined in `SideNavInternal`
67
- onExpand, onCollapse, id, }: SideNavProps): JSX.Element;
78
+ onExpand, onCollapse, onPeekStart, onPeekEnd, id, }: SideNavProps): JSX.Element;
68
79
  export {};
@@ -17,7 +17,7 @@ export declare const SideNavToggleButton: ({ defaultCollapsed, expandLabel, coll
17
17
  * @deprecated
18
18
  *
19
19
  * This prop is being replaced by `defaultSideNavCollapsed` on the `Root` element,
20
- * and will be removed after `platform_dst_nav4_full_height_sidebar_api_changes` is cleaned up.
20
+ * and will be removed in the future.
21
21
  *
22
22
  * ---
23
23
  *
@@ -4,5 +4,5 @@ import React from 'react';
4
4
  */
5
5
  export declare const SideNavVisibilityProvider: ({ children, defaultCollapsed, }: {
6
6
  children: React.ReactNode;
7
- defaultCollapsed: boolean;
7
+ defaultCollapsed?: boolean;
8
8
  }) => React.JSX.Element;
@@ -19,7 +19,7 @@ type TopNavStartProps = {
19
19
  *
20
20
  * You should only render `<SideNavToggleButton>` inside this slot, not as a child.
21
21
  *
22
- * After `platform_dst_nav4_full_height_sidebar_api_changes` rolls out,
22
+ * After `platform_dst_nav4_side_nav_toggle_button_slot` rolls out,
23
23
  * this prop will become required.
24
24
  *
25
25
  * Consumers that do not need a toggle button can explicitly pass `null`.
@@ -44,7 +44,7 @@ export declare function Root({ children, xcss, UNSAFE_dangerouslyHoistSlotSizes,
44
44
  * persisted state using the `onCollapse` and `onExpand` callbacks, to ensure it is up to date
45
45
  * when the app is reloaded.
46
46
  *
47
- * __Note:__ This prop will only work when the `platform_dst_nav4_full_height_sidebar_api_changes` gate is enabled.
47
+ * __Note:__ When provided, the `defaultCollapsed` props on `SideNav` and `SideNavToggleButton` will be ignored.
48
48
  */
49
49
  defaultSideNavCollapsed?: boolean;
50
50
  }): JSX.Element;
@@ -15,7 +15,7 @@ type SideNavProps = CommonSlotProps & {
15
15
  * @deprecated
16
16
  *
17
17
  * This prop is being replaced by `defaultSideNavCollapsed` on the `Root` element,
18
- * and will be removed after `platform_dst_nav4_full_height_sidebar_api_changes` is cleaned up.
18
+ * and will be removed in the future.
19
19
  *
20
20
  * ---
21
21
  *
@@ -53,7 +53,18 @@ type SideNavProps = CommonSlotProps & {
53
53
  * Note: The trigger parameter is only provided when the `navx-full-height-sidebar` feature flag is enabled.
54
54
  */
55
55
  onCollapse?: VisibilityCallback;
56
+ /**
57
+ * Called when the side nav begins peeking / flyout.
58
+ */
59
+ onPeekStart?: () => void;
60
+ /**
61
+ * Called when the side nav stops peeking / flyout.
62
+ */
63
+ onPeekEnd?: (args: {
64
+ trigger: 'mouse-leave' | 'side-nav-expand';
65
+ }) => void;
56
66
  };
67
+ export declare const onPeekStartDelayMs = 500;
57
68
  /**
58
69
  * The side navigation layout area. It will show on the left (inline start) of the screen.
59
70
  *
@@ -64,5 +75,5 @@ type SideNavProps = CommonSlotProps & {
64
75
  */
65
76
  export declare function SideNav({ children, defaultCollapsed, defaultWidth, testId, label, // Default value is defined in `SideNavInternal`
66
77
  skipLinkLabel, // Default value is defined in `SideNavInternal`
67
- onExpand, onCollapse, id, }: SideNavProps): JSX.Element;
78
+ onExpand, onCollapse, onPeekStart, onPeekEnd, id, }: SideNavProps): JSX.Element;
68
79
  export {};
@@ -17,7 +17,7 @@ export declare const SideNavToggleButton: ({ defaultCollapsed, expandLabel, coll
17
17
  * @deprecated
18
18
  *
19
19
  * This prop is being replaced by `defaultSideNavCollapsed` on the `Root` element,
20
- * and will be removed after `platform_dst_nav4_full_height_sidebar_api_changes` is cleaned up.
20
+ * and will be removed in the future.
21
21
  *
22
22
  * ---
23
23
  *
@@ -4,5 +4,5 @@ import React from 'react';
4
4
  */
5
5
  export declare const SideNavVisibilityProvider: ({ children, defaultCollapsed, }: {
6
6
  children: React.ReactNode;
7
- defaultCollapsed: boolean;
7
+ defaultCollapsed?: boolean;
8
8
  }) => React.JSX.Element;
@@ -19,7 +19,7 @@ type TopNavStartProps = {
19
19
  *
20
20
  * You should only render `<SideNavToggleButton>` inside this slot, not as a child.
21
21
  *
22
- * After `platform_dst_nav4_full_height_sidebar_api_changes` rolls out,
22
+ * After `platform_dst_nav4_side_nav_toggle_button_slot` rolls out,
23
23
  * this prop will become required.
24
24
  *
25
25
  * Consumers that do not need a toggle button can explicitly pass `null`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/navigation-system",
3
- "version": "4.2.0",
3
+ "version": "4.4.0",
4
4
  "description": "The latest navigation system for Atlassian apps.",
5
5
  "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
6
6
  "author": "Atlassian Pty Ltd",
@@ -145,6 +145,9 @@
145
145
  }
146
146
  },
147
147
  "platform-feature-flags": {
148
+ "platform_dst_nav4_side_nav_default_collapsed_api": {
149
+ "type": "boolean"
150
+ },
148
151
  "platform_dst_nav4_side_nav_toggle_ref_fix": {
149
152
  "type": "boolean"
150
153
  },
@@ -170,9 +173,6 @@
170
173
  "team25-eu-jira-logo-updates-csm-jsm": {
171
174
  "type": "boolean"
172
175
  },
173
- "platform_dst_nav4_full_height_sidebar_api_changes": {
174
- "type": "boolean"
175
- },
176
176
  "platform-dst-tooltip-shortcuts": {
177
177
  "type": "boolean"
178
178
  },