@atlaskit/page-layout 1.6.4 → 1.7.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.
- package/CHANGELOG.md +14 -0
- package/__perf__/utils/product-integration/sample-footer.tsx +2 -2
- package/__perf__/utils/product-integration/sample-header.tsx +1 -3
- package/dist/cjs/common/constants.js +5 -1
- package/dist/cjs/components/resize-control/index.js +16 -24
- package/dist/cjs/components/resize-control/resize-button.js +10 -4
- package/dist/cjs/components/skip-links/skip-link-components.js +1 -1
- package/dist/cjs/components/slots/internal/left-sidebar-inner.js +29 -2
- package/dist/cjs/components/slots/internal/left-sidebar-outer.js +40 -7
- package/dist/cjs/components/slots/internal/resizable-children-wrapper.js +1 -1
- package/dist/cjs/components/slots/left-sidebar.js +137 -39
- package/dist/cjs/components/slots/main.js +1 -1
- package/dist/cjs/components/slots/page-layout.js +10 -1
- package/dist/cjs/components/slots/slot-dimensions.js +5 -2
- package/dist/cjs/controllers/sidebar-resize-context.js +2 -1
- package/dist/cjs/controllers/sidebar-resize-controller.js +96 -35
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/common/constants.js +2 -0
- package/dist/es2019/components/resize-control/index.js +15 -23
- package/dist/es2019/components/resize-control/resize-button.js +13 -4
- package/dist/es2019/components/skip-links/skip-link-components.js +1 -1
- package/dist/es2019/components/slots/internal/left-sidebar-inner.js +34 -3
- package/dist/es2019/components/slots/internal/left-sidebar-outer.js +51 -8
- package/dist/es2019/components/slots/internal/resizable-children-wrapper.js +1 -1
- package/dist/es2019/components/slots/left-sidebar.js +142 -42
- package/dist/es2019/components/slots/main.js +1 -1
- package/dist/es2019/components/slots/page-layout.js +17 -1
- package/dist/es2019/components/slots/slot-dimensions.js +5 -2
- package/dist/es2019/controllers/sidebar-resize-context.js +2 -1
- package/dist/es2019/controllers/sidebar-resize-controller.js +96 -38
- package/dist/es2019/version.json +1 -1
- package/dist/esm/common/constants.js +2 -0
- package/dist/esm/components/resize-control/index.js +15 -23
- package/dist/esm/components/resize-control/resize-button.js +10 -4
- package/dist/esm/components/skip-links/skip-link-components.js +1 -1
- package/dist/esm/components/slots/internal/left-sidebar-inner.js +29 -3
- package/dist/esm/components/slots/internal/left-sidebar-outer.js +42 -9
- package/dist/esm/components/slots/internal/resizable-children-wrapper.js +1 -1
- package/dist/esm/components/slots/left-sidebar.js +140 -42
- package/dist/esm/components/slots/main.js +1 -1
- package/dist/esm/components/slots/page-layout.js +10 -1
- package/dist/esm/components/slots/slot-dimensions.js +5 -2
- package/dist/esm/controllers/sidebar-resize-context.js +2 -1
- package/dist/esm/controllers/sidebar-resize-controller.js +96 -35
- package/dist/esm/version.json +1 -1
- package/dist/types/common/constants.d.ts +2 -0
- package/dist/types/components/resize-control/types.d.ts +0 -2
- package/dist/types/components/slots/internal/left-sidebar-outer.d.ts +1 -1
- package/dist/types/components/slots/left-sidebar.d.ts +6 -0
- package/dist/types/components/slots/slot-dimensions.d.ts +2 -1
- package/dist/types/controllers/sidebar-resize-context.d.ts +10 -0
- package/dist/types-ts4.5/common/constants.d.ts +2 -0
- package/dist/types-ts4.5/components/resize-control/types.d.ts +0 -2
- package/dist/types-ts4.5/components/slots/internal/left-sidebar-outer.d.ts +1 -1
- package/dist/types-ts4.5/components/slots/left-sidebar.d.ts +6 -0
- package/dist/types-ts4.5/components/slots/slot-dimensions.d.ts +2 -1
- package/dist/types-ts4.5/controllers/sidebar-resize-context.d.ts +10 -0
- package/package.json +12 -6
- package/report.api.md +7 -6
- package/tmp/api-report-tmp.d.ts +174 -0
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/* eslint-disable @repo/internal/dom-events/no-unsafe-event-listeners */
|
|
2
2
|
/** @jsx jsx */
|
|
3
|
-
import { useContext, useEffect, useRef } from 'react';
|
|
4
|
-
import { jsx } from '@emotion/react';
|
|
5
|
-
import
|
|
3
|
+
import { Fragment, useCallback, useContext, useEffect, useRef } from 'react';
|
|
4
|
+
import { css, jsx } from '@emotion/react';
|
|
5
|
+
import useCloseOnEscapePress from '@atlaskit/ds-lib/use-close-on-escape-press';
|
|
6
|
+
import { easeOut } from '@atlaskit/motion';
|
|
7
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
8
|
+
import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/responsive';
|
|
9
|
+
import { N100A } from '@atlaskit/theme/colors';
|
|
10
|
+
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';
|
|
6
11
|
import { getGridStateFromStorage, mergeGridStateIntoStorage, resolveDimension } from '../../common/utils';
|
|
7
12
|
import { publishGridState, SidebarResizeContext, useSkipLink } from '../../controllers';
|
|
8
13
|
import ResizeControl from '../resize-control';
|
|
@@ -11,11 +16,32 @@ import LeftSidebarOuter from './internal/left-sidebar-outer';
|
|
|
11
16
|
import ResizableChildrenWrapper from './internal/resizable-children-wrapper';
|
|
12
17
|
import SlotDimensions from './slot-dimensions';
|
|
13
18
|
|
|
19
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- With a feature flag, this does not apply
|
|
20
|
+
const openBackdropStyles = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ? css({
|
|
21
|
+
width: '100%',
|
|
22
|
+
height: '100%',
|
|
23
|
+
position: 'absolute',
|
|
24
|
+
background: `var(--ds-blanket, ${N100A})`,
|
|
25
|
+
opacity: 1
|
|
26
|
+
}) : undefined;
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- With a feature flag, this does not apply
|
|
29
|
+
const hiddenBackdropStyles = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ? css({
|
|
30
|
+
opacity: 0,
|
|
31
|
+
transition: `opacity ${TRANSITION_DURATION}ms ${easeOut} 0s`
|
|
32
|
+
}) : undefined;
|
|
33
|
+
|
|
14
34
|
/**
|
|
15
35
|
* __Left sidebar__
|
|
16
36
|
*
|
|
17
37
|
* Provides a slot for a left sidebar within the PageLayout.
|
|
18
38
|
*
|
|
39
|
+
* [Behind a feature-flag 'platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g']:
|
|
40
|
+
* On smaller viewports, the left sidebar can no longer be expanded. Instead, expanding it will
|
|
41
|
+
* put it into our "flyout mode" to lay overtop (which in desktop is explicitly a hover state).
|
|
42
|
+
* This ensures the contents behind do not reflow oddly and allows for a better experience
|
|
43
|
+
* resizing between mobile and desktop.
|
|
44
|
+
*
|
|
19
45
|
* - [Examples](https://atlassian.design/components/page-layout/examples)
|
|
20
46
|
* - [Code](https://atlassian.design/components/page-layout/code)
|
|
21
47
|
*/
|
|
@@ -75,10 +101,10 @@ const LeftSidebar = props => {
|
|
|
75
101
|
}
|
|
76
102
|
if (!isLocked && handlerRef.current) {
|
|
77
103
|
if (mouseXRef.current >= lastLeftSidebarWidth) {
|
|
78
|
-
setLeftSidebarState({
|
|
79
|
-
...
|
|
104
|
+
setLeftSidebarState(current => ({
|
|
105
|
+
...current,
|
|
80
106
|
isFlyoutOpen: false
|
|
81
|
-
});
|
|
107
|
+
}));
|
|
82
108
|
}
|
|
83
109
|
document.removeEventListener('mousemove', handlerRef.current);
|
|
84
110
|
handlerRef.current = null;
|
|
@@ -88,7 +114,7 @@ const LeftSidebar = props => {
|
|
|
88
114
|
document.removeEventListener('mousemove', handlerRef.current);
|
|
89
115
|
}
|
|
90
116
|
};
|
|
91
|
-
}, [isLocked, lastLeftSidebarWidth,
|
|
117
|
+
}, [isLocked, lastLeftSidebarWidth, setLeftSidebarState]);
|
|
92
118
|
const _width = Math.max(width || 0, DEFAULT_LEFT_SIDEBAR_WIDTH);
|
|
93
119
|
const collapsedStateOverrideOpen = collapsedState === 'expanded';
|
|
94
120
|
let leftSidebarWidthOnMount;
|
|
@@ -196,40 +222,114 @@ const LeftSidebar = props => {
|
|
|
196
222
|
}));
|
|
197
223
|
}, FLYOUT_DELAY);
|
|
198
224
|
};
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
225
|
+
const mobileMediaQuery = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ?
|
|
226
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- Does not apply to being feature flagged.
|
|
227
|
+
useMediaQuery('below.md') : null;
|
|
228
|
+
const openMobileFlyout = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ?
|
|
229
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- Does not apply to being feature flagged.
|
|
230
|
+
useCallback(() => {
|
|
231
|
+
if (!(mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
setLeftSidebarState(current => {
|
|
235
|
+
if (current.isFlyoutOpen) {
|
|
236
|
+
return current;
|
|
237
|
+
}
|
|
238
|
+
onExpand === null || onExpand === void 0 ? void 0 : onExpand();
|
|
239
|
+
return {
|
|
240
|
+
...current,
|
|
241
|
+
isFlyoutOpen: true
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
}, [setLeftSidebarState, onExpand, mobileMediaQuery]) : undefined;
|
|
245
|
+
const closeMobileFlyout = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ?
|
|
246
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- Does not apply to being feature flagged.
|
|
247
|
+
useCallback(() => {
|
|
248
|
+
if (!(mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
setLeftSidebarState(current => {
|
|
252
|
+
if (!current.isFlyoutOpen) {
|
|
253
|
+
return current;
|
|
254
|
+
}
|
|
255
|
+
onCollapse === null || onCollapse === void 0 ? void 0 : onCollapse();
|
|
256
|
+
return {
|
|
257
|
+
...current,
|
|
258
|
+
isFlyoutOpen: false
|
|
259
|
+
};
|
|
260
|
+
});
|
|
261
|
+
}, [setLeftSidebarState, onCollapse, mobileMediaQuery]) : undefined;
|
|
262
|
+
if (getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g')) {
|
|
263
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- Does not apply to being feature flagged.
|
|
264
|
+
useMediaQuery('below.md', event => {
|
|
265
|
+
setLeftSidebarState(current => {
|
|
266
|
+
if (event.matches && !current.isLeftSidebarCollapsed) {
|
|
267
|
+
// Sidebar was previously open when resizing downwards, convert the sidebar being open to a flyout being open
|
|
268
|
+
return {
|
|
269
|
+
...current,
|
|
270
|
+
isResizing: false,
|
|
271
|
+
isLeftSidebarCollapsed: true,
|
|
272
|
+
leftSidebarWidth: COLLAPSED_LEFT_SIDEBAR_WIDTH,
|
|
273
|
+
lastLeftSidebarWidth: current.leftSidebarWidth,
|
|
274
|
+
isFlyoutOpen: true
|
|
275
|
+
};
|
|
276
|
+
} else if (!event.matches && current.isFlyoutOpen) {
|
|
277
|
+
// The user is resizing "upwards", eg. going from mobile to desktop.
|
|
278
|
+
// Flyout was previously open, let's keep it open by moving to the un-collapsed sidebar instead
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
...current,
|
|
282
|
+
isResizing: false,
|
|
283
|
+
isLeftSidebarCollapsed: false,
|
|
284
|
+
leftSidebarWidth: Math.max(current.lastLeftSidebarWidth, DEFAULT_LEFT_SIDEBAR_WIDTH),
|
|
285
|
+
isFlyoutOpen: false
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return current;
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Close the flyout when the "escape" key is pressed.
|
|
293
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- Does not apply to being feature flagged.
|
|
294
|
+
useCloseOnEscapePress({
|
|
295
|
+
onClose: closeMobileFlyout,
|
|
296
|
+
isDisabled: !isFlyoutOpen
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
return jsx(Fragment, null, (mobileMediaQuery === null || mobileMediaQuery === void 0 ? void 0 : mobileMediaQuery.matches) && getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') && jsx("div", {
|
|
300
|
+
"aria-hidden": "true",
|
|
301
|
+
css: [hiddenBackdropStyles, isFlyoutOpen && openBackdropStyles],
|
|
302
|
+
onClick: closeMobileFlyout
|
|
303
|
+
}), jsx(LeftSidebarOuter, {
|
|
304
|
+
ref: leftSideBarRef,
|
|
305
|
+
testId: testId,
|
|
306
|
+
onMouseOver: !(mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches) ? onMouseOver : undefined,
|
|
307
|
+
onMouseLeave: !(mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches) ? onMouseLeave : undefined,
|
|
308
|
+
onClick: mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches ? openMobileFlyout : undefined,
|
|
309
|
+
id: id,
|
|
310
|
+
isFixed: isFixed
|
|
311
|
+
}, jsx(SlotDimensions, {
|
|
312
|
+
variableName: VAR_LEFT_SIDEBAR_WIDTH,
|
|
313
|
+
value: notFirstRun.current ? leftSidebarWidth : leftSidebarWidthOnMount,
|
|
314
|
+
mobileValue: MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH
|
|
315
|
+
}), jsx(LeftSidebarInner, {
|
|
316
|
+
isFixed: isFixed,
|
|
317
|
+
isFlyoutOpen: isFlyoutOpen
|
|
318
|
+
}, jsx(ResizableChildrenWrapper, {
|
|
319
|
+
isFlyoutOpen: isFlyoutOpen,
|
|
320
|
+
isLeftSidebarCollapsed: isLeftSidebarCollapsed,
|
|
321
|
+
hasCollapsedState: !notFirstRun.current && collapsedState === 'collapsed'
|
|
322
|
+
}, children), jsx(ResizeControl, {
|
|
323
|
+
testId: testId,
|
|
324
|
+
resizeGrabAreaLabel: resizeGrabAreaLabel,
|
|
325
|
+
resizeButtonLabel: resizeButtonLabel
|
|
326
|
+
// eslint-disable-next-line @repo/internal/react/no-unsafe-overrides
|
|
327
|
+
,
|
|
328
|
+
overrides: overrides,
|
|
329
|
+
onCollapse: onCollapse,
|
|
330
|
+
onExpand: onExpand,
|
|
331
|
+
onResizeStart: onResizeStart,
|
|
332
|
+
onResizeEnd: onResizeEnd
|
|
333
|
+
}))));
|
|
234
334
|
};
|
|
235
335
|
export default LeftSidebar;
|
|
@@ -10,7 +10,7 @@ import { getPageLayoutSlotSelector } from '../../common/utils';
|
|
|
10
10
|
import { SidebarResizeContext, useSkipLink } from '../../controllers';
|
|
11
11
|
import SlotFocusRing from './internal/slot-focus-ring';
|
|
12
12
|
|
|
13
|
-
// eslint-disable-next-line @
|
|
13
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
|
|
14
14
|
const prefersReducedMotionStyles = css(prefersReducedMotion());
|
|
15
15
|
const mainStyles = css({
|
|
16
16
|
minWidth: 0,
|
|
@@ -2,12 +2,19 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
/** @jsx jsx */
|
|
3
3
|
import { Fragment } from 'react';
|
|
4
4
|
import { css, jsx } from '@emotion/react';
|
|
5
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
6
|
+
import { UNSAFE_media as media } from '@atlaskit/primitives/responsive';
|
|
5
7
|
import { BANNER, BANNER_HEIGHT, CONTENT, DEFAULT_I18N_PROPS_SKIP_LINKS, LEFT_PANEL, LEFT_PANEL_WIDTH, PAGE_LAYOUT_CONTAINER_SELECTOR, RIGHT_PANEL, RIGHT_PANEL_WIDTH, TOP_NAVIGATION, TOP_NAVIGATION_HEIGHT } from '../../common/constants';
|
|
6
8
|
import { SidebarResizeController, SkipLinksController } from '../../controllers';
|
|
7
9
|
import { SkipLinkWrapper } from '../skip-links';
|
|
8
10
|
const pageLayoutSelector = {
|
|
9
11
|
[PAGE_LAYOUT_CONTAINER_SELECTOR]: true
|
|
10
12
|
};
|
|
13
|
+
const gridTemplateAreasMobile = `
|
|
14
|
+
"${LEFT_PANEL} ${BANNER}"
|
|
15
|
+
"${LEFT_PANEL} ${TOP_NAVIGATION}"
|
|
16
|
+
"${LEFT_PANEL} ${CONTENT}"
|
|
17
|
+
`;
|
|
11
18
|
const gridTemplateAreas = `
|
|
12
19
|
"${LEFT_PANEL} ${BANNER} ${RIGHT_PANEL}"
|
|
13
20
|
"${LEFT_PANEL} ${TOP_NAVIGATION} ${RIGHT_PANEL}"
|
|
@@ -22,6 +29,15 @@ const gridStyles = css({
|
|
|
22
29
|
outline: 'none'
|
|
23
30
|
});
|
|
24
31
|
|
|
32
|
+
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- With a feature flag, this does not apply
|
|
33
|
+
const gridStylesMobile = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ? css({
|
|
34
|
+
// eslint-disable-next-line @repo/internal/styles/no-nested-styles
|
|
35
|
+
[media.below.md]: {
|
|
36
|
+
gridTemplateAreas: gridTemplateAreasMobile,
|
|
37
|
+
gridTemplateColumns: `${LEFT_PANEL_WIDTH} minmax(0, 1fr)`
|
|
38
|
+
}
|
|
39
|
+
}) : undefined;
|
|
40
|
+
|
|
25
41
|
/**
|
|
26
42
|
* __Page layout__
|
|
27
43
|
*
|
|
@@ -41,7 +57,7 @@ const PageLayout = ({
|
|
|
41
57
|
skipLinksLabel: skipLinksLabel
|
|
42
58
|
}), jsx("div", _extends({}, pageLayoutSelector, {
|
|
43
59
|
"data-testid": testId,
|
|
44
|
-
css: gridStyles,
|
|
60
|
+
css: [gridStyles, gridStylesMobile],
|
|
45
61
|
tabIndex: -1
|
|
46
62
|
}), jsx(SidebarResizeController, {
|
|
47
63
|
onLeftSidebarCollapse: onLeftSidebarCollapse,
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
3
|
+
import { UNSAFE_media as media } from '@atlaskit/primitives/responsive';
|
|
2
4
|
export default (({
|
|
3
5
|
variableName,
|
|
4
|
-
value
|
|
5
|
-
|
|
6
|
+
value,
|
|
7
|
+
mobileValue
|
|
8
|
+
}) => /*#__PURE__*/React.createElement("style", null, `:root{--${variableName}:${value}px;}`, getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') && mobileValue && `${media.below.md} { :root{--${variableName}:${mobileValue}px;} }`));
|
|
@@ -15,7 +15,8 @@ export const SidebarResizeContext = /*#__PURE__*/createContext({
|
|
|
15
15
|
expandLeftSidebar: noop,
|
|
16
16
|
collapseLeftSidebar: noop,
|
|
17
17
|
leftSidebarState,
|
|
18
|
-
setLeftSidebarState: noop
|
|
18
|
+
setLeftSidebarState: noop,
|
|
19
|
+
toggleLeftSidebar: noop
|
|
19
20
|
});
|
|
20
21
|
export const usePageLayoutResize = () => {
|
|
21
22
|
const {
|
|
@@ -2,10 +2,12 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
|
2
2
|
import { bind } from 'bind-event-listener';
|
|
3
3
|
import noop from '@atlaskit/ds-lib/noop';
|
|
4
4
|
import { isReducedMotion } from '@atlaskit/motion';
|
|
5
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
6
|
+
import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/responsive';
|
|
5
7
|
import { COLLAPSED_LEFT_SIDEBAR_WIDTH, DEFAULT_LEFT_SIDEBAR_WIDTH, IS_SIDEBAR_COLLAPSING } from '../common/constants';
|
|
6
8
|
import { getPageLayoutSlotCSSSelector } from '../common/utils';
|
|
7
9
|
import { SidebarResizeContext } from './sidebar-resize-context';
|
|
8
|
-
const handleDataAttributesAndCb = (callback = noop,
|
|
10
|
+
const handleDataAttributesAndCb = (callback = noop, leftSidebarState) => {
|
|
9
11
|
document.documentElement.removeAttribute(IS_SIDEBAR_COLLAPSING);
|
|
10
12
|
callback(leftSidebarState);
|
|
11
13
|
};
|
|
@@ -26,7 +28,13 @@ export const SidebarResizeController = ({
|
|
|
26
28
|
isFixed: true
|
|
27
29
|
});
|
|
28
30
|
const {
|
|
29
|
-
|
|
31
|
+
leftSidebarWidth,
|
|
32
|
+
lastLeftSidebarWidth,
|
|
33
|
+
isResizing,
|
|
34
|
+
flyoutLockCount,
|
|
35
|
+
isFixed,
|
|
36
|
+
isLeftSidebarCollapsed,
|
|
37
|
+
isFlyoutOpen
|
|
30
38
|
} = leftSidebarState;
|
|
31
39
|
|
|
32
40
|
// We put the latest callbacks into a ref so we can always have the latest
|
|
@@ -40,25 +48,46 @@ export const SidebarResizeController = ({
|
|
|
40
48
|
onExpand,
|
|
41
49
|
onCollapse
|
|
42
50
|
};
|
|
43
|
-
});
|
|
51
|
+
}, [onExpand, onCollapse]);
|
|
44
52
|
const transition = useRef(null);
|
|
53
|
+
const mobileMediaQuery = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ?
|
|
54
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- With the feature flag, this does not apply as it should be static.
|
|
55
|
+
useMediaQuery('below.md') : null;
|
|
56
|
+
const isOpen = mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches ? isFlyoutOpen : !isLeftSidebarCollapsed;
|
|
45
57
|
const expandLeftSidebar = useCallback(() => {
|
|
46
|
-
var _transition$
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
var _transition$current2, _transition$current3;
|
|
59
|
+
if (isOpen) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// If the user is at a mobile viewport when this runs, we handle it differently
|
|
64
|
+
// We don't expand at mobile widths; instead we use a flyout which is treated the same otherwise
|
|
65
|
+
if (mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches) {
|
|
66
|
+
var _transition$current;
|
|
67
|
+
const flyoutOpenSidebarState = {
|
|
68
|
+
isResizing: false,
|
|
69
|
+
isLeftSidebarCollapsed: true,
|
|
70
|
+
leftSidebarWidth: COLLAPSED_LEFT_SIDEBAR_WIDTH,
|
|
71
|
+
lastLeftSidebarWidth: leftSidebarWidth,
|
|
72
|
+
isFlyoutOpen: true,
|
|
73
|
+
flyoutLockCount: 0,
|
|
74
|
+
isFixed
|
|
75
|
+
};
|
|
76
|
+
setLeftSidebarState(flyoutOpenSidebarState);
|
|
77
|
+
|
|
78
|
+
// Flush the desktop transitions, cleanup, and call the `onExpand` still
|
|
79
|
+
(_transition$current = transition.current) === null || _transition$current === void 0 ? void 0 : _transition$current.complete();
|
|
80
|
+
handleDataAttributesAndCb(stableRef.current.onExpand, flyoutOpenSidebarState);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
54
83
|
if (isResizing || !isLeftSidebarCollapsed ||
|
|
55
84
|
// already expanding
|
|
56
|
-
((_transition$
|
|
85
|
+
((_transition$current2 = transition.current) === null || _transition$current2 === void 0 ? void 0 : _transition$current2.action) === 'expand') {
|
|
57
86
|
return;
|
|
58
87
|
}
|
|
59
88
|
|
|
60
89
|
// flush existing transition
|
|
61
|
-
(_transition$
|
|
90
|
+
(_transition$current3 = transition.current) === null || _transition$current3 === void 0 ? void 0 : _transition$current3.complete();
|
|
62
91
|
const width = Math.max(lastLeftSidebarWidth, DEFAULT_LEFT_SIDEBAR_WIDTH);
|
|
63
92
|
const updatedLeftSidebarState = {
|
|
64
93
|
isLeftSidebarCollapsed: false,
|
|
@@ -71,9 +100,7 @@ export const SidebarResizeController = ({
|
|
|
71
100
|
};
|
|
72
101
|
setLeftSidebarState(updatedLeftSidebarState);
|
|
73
102
|
function finish() {
|
|
74
|
-
handleDataAttributesAndCb(stableRef.current.onExpand,
|
|
75
|
-
// isCollapsed
|
|
76
|
-
updatedLeftSidebarState);
|
|
103
|
+
handleDataAttributesAndCb(stableRef.current.onExpand, updatedLeftSidebarState);
|
|
77
104
|
}
|
|
78
105
|
const sidebar = document.querySelector(leftSidebarSelector);
|
|
79
106
|
// onTransitionEnd isn't triggered when a user prefers reduced motion
|
|
@@ -85,8 +112,8 @@ export const SidebarResizeController = ({
|
|
|
85
112
|
type: 'transitionend',
|
|
86
113
|
listener(event) {
|
|
87
114
|
if (event.target === sidebar && event.propertyName === 'width') {
|
|
88
|
-
var _transition$
|
|
89
|
-
(_transition$
|
|
115
|
+
var _transition$current4;
|
|
116
|
+
(_transition$current4 = transition.current) === null || _transition$current4 === void 0 ? void 0 : _transition$current4.complete();
|
|
90
117
|
}
|
|
91
118
|
}
|
|
92
119
|
});
|
|
@@ -102,24 +129,41 @@ export const SidebarResizeController = ({
|
|
|
102
129
|
}
|
|
103
130
|
};
|
|
104
131
|
transition.current = value;
|
|
105
|
-
}, [
|
|
132
|
+
}, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, lastLeftSidebarWidth, flyoutLockCount, isFixed, leftSidebarWidth]);
|
|
106
133
|
const collapseLeftSidebar = useCallback((event, collapseWithoutTransition) => {
|
|
107
|
-
var _transition$
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
134
|
+
var _transition$current6, _transition$current7;
|
|
135
|
+
if (!isOpen) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// If the user is at a mobile viewport when this runs, we handle it differently
|
|
140
|
+
// We don't collapse at mobile widths; instead we close the flyout.
|
|
141
|
+
if (mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches) {
|
|
142
|
+
var _transition$current5;
|
|
143
|
+
const flyoutCloseSidebarState = {
|
|
144
|
+
isResizing: false,
|
|
145
|
+
isLeftSidebarCollapsed: true,
|
|
146
|
+
leftSidebarWidth: COLLAPSED_LEFT_SIDEBAR_WIDTH,
|
|
147
|
+
lastLeftSidebarWidth,
|
|
148
|
+
isFlyoutOpen: false,
|
|
149
|
+
flyoutLockCount: 0,
|
|
150
|
+
isFixed
|
|
151
|
+
};
|
|
152
|
+
setLeftSidebarState(flyoutCloseSidebarState);
|
|
153
|
+
|
|
154
|
+
// Flush the desktop transitions, cleanup, and call the `onCollapse` still
|
|
155
|
+
(_transition$current5 = transition.current) === null || _transition$current5 === void 0 ? void 0 : _transition$current5.complete();
|
|
156
|
+
handleDataAttributesAndCb(stableRef.current.onCollapse, flyoutCloseSidebarState);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
115
159
|
if (isResizing || isLeftSidebarCollapsed ||
|
|
116
160
|
// already collapsing
|
|
117
|
-
((_transition$
|
|
161
|
+
((_transition$current6 = transition.current) === null || _transition$current6 === void 0 ? void 0 : _transition$current6.action) === 'collapse') {
|
|
118
162
|
return;
|
|
119
163
|
}
|
|
120
164
|
|
|
121
165
|
// flush existing transition
|
|
122
|
-
(_transition$
|
|
166
|
+
(_transition$current7 = transition.current) === null || _transition$current7 === void 0 ? void 0 : _transition$current7.complete();
|
|
123
167
|
|
|
124
168
|
// data-attribute is used as a CSS selector to sync the hiding/showing
|
|
125
169
|
// of the nav contents with expand/collapse animation
|
|
@@ -135,7 +179,7 @@ export const SidebarResizeController = ({
|
|
|
135
179
|
};
|
|
136
180
|
setLeftSidebarState(updatedLeftSidebarState);
|
|
137
181
|
function finish() {
|
|
138
|
-
handleDataAttributesAndCb(stableRef.current.onCollapse,
|
|
182
|
+
handleDataAttributesAndCb(stableRef.current.onCollapse, updatedLeftSidebarState);
|
|
139
183
|
}
|
|
140
184
|
const sidebar = document.querySelector(leftSidebarSelector);
|
|
141
185
|
|
|
@@ -148,8 +192,8 @@ export const SidebarResizeController = ({
|
|
|
148
192
|
type: 'transitionend',
|
|
149
193
|
listener(event) {
|
|
150
194
|
if (sidebar === event.target && event.propertyName === 'width') {
|
|
151
|
-
var _transition$
|
|
152
|
-
(_transition$
|
|
195
|
+
var _transition$current8;
|
|
196
|
+
(_transition$current8 = transition.current) === null || _transition$current8 === void 0 ? void 0 : _transition$current8.complete();
|
|
153
197
|
}
|
|
154
198
|
}
|
|
155
199
|
});
|
|
@@ -165,22 +209,36 @@ export const SidebarResizeController = ({
|
|
|
165
209
|
}
|
|
166
210
|
};
|
|
167
211
|
transition.current = value;
|
|
168
|
-
}, [
|
|
212
|
+
}, [isOpen, mobileMediaQuery, isResizing, isLeftSidebarCollapsed, leftSidebarWidth, flyoutLockCount, isFixed, lastLeftSidebarWidth]);
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Conditionally toggle the expanding or collapsing the sidebars.
|
|
216
|
+
* This supports our mobile flyout mode as well.
|
|
217
|
+
*/
|
|
218
|
+
const toggleLeftSidebar = useCallback((event, collapseWithoutTransition) => {
|
|
219
|
+
if (isOpen) {
|
|
220
|
+
collapseLeftSidebar(event, collapseWithoutTransition);
|
|
221
|
+
} else {
|
|
222
|
+
expandLeftSidebar();
|
|
223
|
+
}
|
|
224
|
+
}, [isOpen, expandLeftSidebar, collapseLeftSidebar]);
|
|
169
225
|
|
|
170
226
|
// Make sure we finish any lingering transitions when unmounting
|
|
171
227
|
useEffect(function mount() {
|
|
172
228
|
return function unmount() {
|
|
173
|
-
var _transition$
|
|
174
|
-
(_transition$
|
|
229
|
+
var _transition$current9;
|
|
230
|
+
(_transition$current9 = transition.current) === null || _transition$current9 === void 0 ? void 0 : _transition$current9.abort();
|
|
175
231
|
};
|
|
176
232
|
}, []);
|
|
177
233
|
const context = useMemo(() => ({
|
|
178
|
-
isLeftSidebarCollapsed,
|
|
234
|
+
isLeftSidebarCollapsed: !isOpen,
|
|
235
|
+
// Technically this isn't quite true, but with mobile it's a bit safer if products are using this to roll their own collapse/expand
|
|
179
236
|
expandLeftSidebar,
|
|
180
237
|
collapseLeftSidebar,
|
|
181
238
|
leftSidebarState,
|
|
182
|
-
setLeftSidebarState
|
|
183
|
-
|
|
239
|
+
setLeftSidebarState,
|
|
240
|
+
toggleLeftSidebar
|
|
241
|
+
}), [isOpen, expandLeftSidebar, collapseLeftSidebar, leftSidebarState, toggleLeftSidebar]);
|
|
184
242
|
return /*#__PURE__*/React.createElement(SidebarResizeContext.Provider, {
|
|
185
243
|
value: context
|
|
186
244
|
}, children);
|
package/dist/es2019/version.json
CHANGED
|
@@ -28,9 +28,11 @@ export var DEFAULT_LEFT_PANEL_WIDTH = 368;
|
|
|
28
28
|
|
|
29
29
|
// Other constants
|
|
30
30
|
export var COLLAPSED_LEFT_SIDEBAR_WIDTH = 20;
|
|
31
|
+
export var MOBILE_COLLAPSED_LEFT_SIDEBAR_WIDTH = 16;
|
|
31
32
|
export var MIN_LEFT_SIDEBAR_WIDTH = 80;
|
|
32
33
|
export var DEFAULT_LEFT_SIDEBAR_FLYOUT_WIDTH = 240;
|
|
33
34
|
export var MIN_LEFT_SIDEBAR_DRAG_THRESHOLD = 200;
|
|
35
|
+
export var MAX_MOBILE_SIDEBAR_FLYOUT_WIDTH = 350;
|
|
34
36
|
export var TRANSITION_DURATION = 300;
|
|
35
37
|
export var FLYOUT_DELAY = 200;
|
|
36
38
|
export var LEFT_SIDEBAR_EXPANDED_WIDTH = 'expandedLeftSidebarWidth';
|
|
@@ -8,7 +8,9 @@ import { Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState
|
|
|
8
8
|
import { css, Global, jsx } from '@emotion/react';
|
|
9
9
|
import { bindAll } from 'bind-event-listener';
|
|
10
10
|
import rafSchd from 'raf-schd';
|
|
11
|
-
import {
|
|
11
|
+
import { getBooleanFF } from '@atlaskit/platform-feature-flags';
|
|
12
|
+
import { UNSAFE_useMediaQuery as useMediaQuery } from '@atlaskit/primitives/responsive';
|
|
13
|
+
import { COLLAPSED_LEFT_SIDEBAR_WIDTH, DEFAULT_LEFT_SIDEBAR_WIDTH, IS_SIDEBAR_DRAGGING, MIN_LEFT_SIDEBAR_DRAG_THRESHOLD, RESIZE_CONTROL_SELECTOR, VAR_LEFT_SIDEBAR_WIDTH } from '../../common/constants';
|
|
12
14
|
import { getLeftPanelWidth, getLeftSidebarPercentage } from '../../common/utils';
|
|
13
15
|
import { SidebarResizeContext } from '../../controllers/sidebar-resize-context';
|
|
14
16
|
/* import useUpdateCssVar from '../../controllers/use-update-css-vars'; */
|
|
@@ -65,12 +67,11 @@ var ResizeControl = function ResizeControl(_ref) {
|
|
|
65
67
|
onResizeStart = _ref.onResizeStart,
|
|
66
68
|
onResizeEnd = _ref.onResizeEnd;
|
|
67
69
|
var _useContext = useContext(SidebarResizeContext),
|
|
68
|
-
|
|
70
|
+
toggleLeftSidebar = _useContext.toggleLeftSidebar,
|
|
69
71
|
collapseLeftSidebar = _useContext.collapseLeftSidebar,
|
|
70
72
|
leftSidebarState = _useContext.leftSidebarState,
|
|
71
73
|
setLeftSidebarState = _useContext.setLeftSidebarState;
|
|
72
|
-
var isLeftSidebarCollapsed = leftSidebarState.isLeftSidebarCollapsed
|
|
73
|
-
isResizing = leftSidebarState.isResizing;
|
|
74
|
+
var isLeftSidebarCollapsed = leftSidebarState.isLeftSidebarCollapsed;
|
|
74
75
|
var sidebarWidth = useRef(leftSidebarState[VAR_LEFT_SIDEBAR_WIDTH]);
|
|
75
76
|
// Distance of mouse from left sidebar onMouseDown
|
|
76
77
|
var offset = useRef(0);
|
|
@@ -80,6 +81,9 @@ var ResizeControl = function ResizeControl(_ref) {
|
|
|
80
81
|
isGrabAreaFocused = _useState2[0],
|
|
81
82
|
setIsGrabAreaFocused = _useState2[1];
|
|
82
83
|
var unbindEvents = useRef(null);
|
|
84
|
+
var mobileMediaQuery = getBooleanFF('platform.design-system-team.responsive-page-layout-left-sidebar_p8r7g') ?
|
|
85
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks -- With the feature flag, this does not apply as it should be static.
|
|
86
|
+
useMediaQuery('below.md') : null;
|
|
83
87
|
|
|
84
88
|
// Used in some cases to ensure function references don't have to change
|
|
85
89
|
// TODO: more functions could use `stableSidebarState` rather than `leftSidebarState`
|
|
@@ -87,23 +91,11 @@ var ResizeControl = function ResizeControl(_ref) {
|
|
|
87
91
|
useEffect(function () {
|
|
88
92
|
stableSidebarState.current = leftSidebarState;
|
|
89
93
|
}, [leftSidebarState]);
|
|
90
|
-
var toggleSideBar = function
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
expandLeftSidebar();
|
|
96
|
-
} else {
|
|
97
|
-
collapseLeftSidebar();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Bring focus to the resize button if the grab area is
|
|
101
|
-
// "clicked" using enter/space on keyboard.
|
|
102
|
-
if (e && e.nativeEvent.detail === 0) {
|
|
103
|
-
var _resizeButton = document.querySelector("[".concat(RESIZE_BUTTON_SELECTOR, "]"));
|
|
104
|
-
_resizeButton && _resizeButton.focus();
|
|
105
|
-
}
|
|
106
|
-
};
|
|
94
|
+
var toggleSideBar = useCallback(function (event) {
|
|
95
|
+
// don't cascade down to the LeftSidebarOuter
|
|
96
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
97
|
+
toggleLeftSidebar();
|
|
98
|
+
}, [toggleLeftSidebar]);
|
|
107
99
|
var onMouseDown = function onMouseDown(event) {
|
|
108
100
|
if (isLeftSidebarCollapsed) {
|
|
109
101
|
return;
|
|
@@ -335,7 +327,7 @@ var ResizeControl = function ResizeControl(_ref) {
|
|
|
335
327
|
css: [resizeControlStyles, (isGrabAreaFocused || isLeftSidebarCollapsed) && showResizeButtonStyles]
|
|
336
328
|
}), jsx(Shadow, {
|
|
337
329
|
testId: testId && "".concat(testId, "-shadow")
|
|
338
|
-
}), jsx(GrabArea, {
|
|
330
|
+
}), !(mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches) && jsx(GrabArea, {
|
|
339
331
|
role: "separator",
|
|
340
332
|
"aria-label": resizeGrabAreaLabel,
|
|
341
333
|
"aria-valuenow": leftSidebarPercentageExpanded,
|
|
@@ -350,7 +342,7 @@ var ResizeControl = function ResizeControl(_ref) {
|
|
|
350
342
|
isLeftSidebarCollapsed: isLeftSidebarCollapsed,
|
|
351
343
|
disabled: isLeftSidebarCollapsed
|
|
352
344
|
}), resizeButton.render(ResizeButton, {
|
|
353
|
-
isLeftSidebarCollapsed: isLeftSidebarCollapsed,
|
|
345
|
+
isLeftSidebarCollapsed: mobileMediaQuery !== null && mobileMediaQuery !== void 0 && mobileMediaQuery.matches ? !leftSidebarState.isFlyoutOpen : isLeftSidebarCollapsed,
|
|
354
346
|
label: resizeButtonLabel,
|
|
355
347
|
onClick: toggleSideBar,
|
|
356
348
|
testId: testId && "".concat(testId, "-resize-button")
|