@atlaskit/page-layout 1.1.0 → 1.2.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/README.md +3 -3
- package/__perf__/utils/perf-example.tsx +24 -17
- package/__perf__/utils/product-integration/NotificationsPopup.tsx +6 -5
- package/__perf__/utils/product-integration/SampleFooter.tsx +13 -13
- package/dist/cjs/common/hooks/index.js +23 -0
- package/dist/cjs/common/hooks/use-is-sidebar-collapsing.js +46 -0
- package/dist/cjs/common/hooks/use-is-sidebar-dragging.js +46 -0
- package/dist/cjs/components/resize-control/grab-area.js +42 -4
- package/dist/cjs/components/resize-control/index.js +22 -20
- package/dist/cjs/components/resize-control/resize-button.js +59 -4
- package/dist/cjs/components/resize-control/shadow.js +48 -0
- package/dist/cjs/components/skip-links/skip-link-components.js +49 -5
- package/dist/cjs/components/slots/banner.js +27 -11
- package/dist/cjs/components/slots/content.js +9 -2
- package/dist/cjs/components/slots/internal/left-sidebar-inner.js +65 -0
- package/dist/cjs/components/slots/internal/left-sidebar-outer.js +100 -0
- package/dist/cjs/components/slots/internal/resizable-children-wrapper.js +63 -0
- package/dist/cjs/components/slots/internal/slot-focus-ring.js +61 -0
- package/dist/cjs/components/slots/left-panel.js +26 -11
- package/dist/cjs/components/slots/left-sidebar-without-resize.js +10 -10
- package/dist/cjs/components/slots/left-sidebar.js +21 -16
- package/dist/cjs/components/slots/main.js +53 -6
- package/dist/cjs/components/slots/page-layout.js +10 -3
- package/dist/cjs/components/slots/right-panel.js +26 -11
- package/dist/cjs/components/slots/right-sidebar.js +57 -13
- package/dist/cjs/components/slots/top-navigation.js +27 -11
- package/dist/cjs/controllers/sidebar-resize-context.js +2 -1
- package/dist/cjs/controllers/sidebar-resize-controller.js +10 -5
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/common/hooks/index.js +2 -0
- package/dist/es2019/common/hooks/use-is-sidebar-collapsing.js +29 -0
- package/dist/es2019/common/hooks/use-is-sidebar-dragging.js +29 -0
- package/dist/es2019/components/resize-control/grab-area.js +46 -4
- package/dist/es2019/components/resize-control/index.js +12 -9
- package/dist/es2019/components/resize-control/resize-button.js +61 -4
- package/dist/es2019/components/resize-control/shadow.js +43 -0
- package/dist/es2019/components/skip-links/skip-link-components.js +47 -5
- package/dist/es2019/components/slots/banner.js +21 -7
- package/dist/es2019/components/slots/content.js +8 -2
- package/dist/es2019/components/slots/internal/left-sidebar-inner.js +52 -0
- package/dist/es2019/components/slots/internal/left-sidebar-outer.js +79 -0
- package/dist/es2019/components/slots/internal/resizable-children-wrapper.js +49 -0
- package/dist/es2019/components/slots/internal/slot-focus-ring.js +50 -0
- package/dist/es2019/components/slots/left-panel.js +20 -7
- package/dist/es2019/components/slots/left-sidebar-without-resize.js +10 -11
- package/dist/es2019/components/slots/left-sidebar.js +20 -17
- package/dist/es2019/components/slots/main.js +46 -6
- package/dist/es2019/components/slots/page-layout.js +15 -3
- package/dist/es2019/components/slots/right-panel.js +20 -7
- package/dist/es2019/components/slots/right-sidebar.js +50 -8
- package/dist/es2019/components/slots/top-navigation.js +21 -7
- package/dist/es2019/controllers/sidebar-resize-context.js +2 -1
- package/dist/es2019/controllers/sidebar-resize-controller.js +10 -5
- package/dist/es2019/version.json +1 -1
- package/dist/esm/common/hooks/index.js +2 -0
- package/dist/esm/common/hooks/use-is-sidebar-collapsing.js +34 -0
- package/dist/esm/common/hooks/use-is-sidebar-dragging.js +34 -0
- package/dist/esm/components/resize-control/grab-area.js +42 -4
- package/dist/esm/components/resize-control/index.js +23 -20
- package/dist/esm/components/resize-control/resize-button.js +57 -4
- package/dist/esm/components/resize-control/shadow.js +37 -0
- package/dist/esm/components/skip-links/skip-link-components.js +47 -5
- package/dist/esm/components/slots/banner.js +27 -12
- package/dist/esm/components/slots/content.js +8 -2
- package/dist/esm/components/slots/internal/left-sidebar-inner.js +53 -0
- package/dist/esm/components/slots/internal/left-sidebar-outer.js +82 -0
- package/dist/esm/components/slots/internal/resizable-children-wrapper.js +51 -0
- package/dist/esm/components/slots/internal/slot-focus-ring.js +51 -0
- package/dist/esm/components/slots/left-panel.js +26 -12
- package/dist/esm/components/slots/left-sidebar-without-resize.js +10 -10
- package/dist/esm/components/slots/left-sidebar.js +20 -16
- package/dist/esm/components/slots/main.js +49 -8
- package/dist/esm/components/slots/page-layout.js +12 -3
- package/dist/esm/components/slots/right-panel.js +26 -12
- package/dist/esm/components/slots/right-sidebar.js +57 -14
- package/dist/esm/components/slots/top-navigation.js +27 -12
- package/dist/esm/controllers/sidebar-resize-context.js +2 -1
- package/dist/esm/controllers/sidebar-resize-controller.js +10 -5
- package/dist/esm/version.json +1 -1
- package/dist/types/common/hooks/index.d.ts +2 -0
- package/dist/types/common/hooks/use-is-sidebar-collapsing.d.ts +2 -0
- package/dist/types/common/hooks/use-is-sidebar-dragging.d.ts +2 -0
- package/dist/types/components/resize-control/shadow.d.ts +6 -0
- package/dist/types/components/slots/internal/left-sidebar-inner.d.ts +9 -0
- package/dist/types/components/slots/internal/left-sidebar-outer.d.ts +13 -0
- package/dist/types/components/slots/internal/resizable-children-wrapper.d.ts +10 -0
- package/dist/types/components/slots/internal/slot-focus-ring.d.ts +19 -0
- package/dist/types/controllers/sidebar-resize-context.d.ts +1 -0
- package/package.json +8 -5
- package/dist/cjs/components/resize-control/styles.js +0 -158
- package/dist/cjs/components/skip-links/styles.js +0 -58
- package/dist/cjs/components/slots/left-sidebar-styles.js +0 -116
- package/dist/cjs/components/slots/styles.js +0 -154
- package/dist/es2019/components/resize-control/styles.js +0 -139
- package/dist/es2019/components/skip-links/styles.js +0 -41
- package/dist/es2019/components/slots/left-sidebar-styles.js +0 -96
- package/dist/es2019/components/slots/styles.js +0 -130
- package/dist/esm/components/resize-control/styles.js +0 -133
- package/dist/esm/components/skip-links/styles.js +0 -45
- package/dist/esm/components/slots/left-sidebar-styles.js +0 -94
- package/dist/esm/components/slots/styles.js +0 -117
- package/dist/types/components/resize-control/styles.d.ts +0 -41
- package/dist/types/components/skip-links/styles.d.ts +0 -2
- package/dist/types/components/slots/left-sidebar-styles.d.ts +0 -5
- package/dist/types/components/slots/styles.d.ts +0 -23
|
@@ -2,12 +2,23 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
|
|
3
3
|
/** @jsx jsx */
|
|
4
4
|
import { useEffect } from 'react';
|
|
5
|
-
import { jsx } from '@emotion/core';
|
|
6
|
-
import { DEFAULT_BANNER_HEIGHT, VAR_BANNER_HEIGHT } from '../../common/constants';
|
|
5
|
+
import { css, jsx } from '@emotion/core';
|
|
6
|
+
import { BANNER, BANNER_HEIGHT, DEFAULT_BANNER_HEIGHT, LEFT_PANEL_WIDTH, RIGHT_PANEL_WIDTH, VAR_BANNER_HEIGHT } from '../../common/constants';
|
|
7
7
|
import { getPageLayoutSlotSelector, resolveDimension } from '../../common/utils';
|
|
8
8
|
import { publishGridState, useSkipLink } from '../../controllers';
|
|
9
|
+
import SlotFocusRing from './internal/slot-focus-ring';
|
|
9
10
|
import SlotDimensions from './slot-dimensions';
|
|
10
|
-
|
|
11
|
+
const bannerStyles = css({
|
|
12
|
+
height: BANNER_HEIGHT,
|
|
13
|
+
gridArea: BANNER
|
|
14
|
+
});
|
|
15
|
+
const bannerFixedStyles = css({
|
|
16
|
+
position: 'fixed',
|
|
17
|
+
zIndex: 2,
|
|
18
|
+
top: 0,
|
|
19
|
+
right: RIGHT_PANEL_WIDTH,
|
|
20
|
+
left: LEFT_PANEL_WIDTH
|
|
21
|
+
});
|
|
11
22
|
|
|
12
23
|
const Banner = props => {
|
|
13
24
|
const {
|
|
@@ -28,17 +39,20 @@ const Banner = props => {
|
|
|
28
39
|
publishGridState({
|
|
29
40
|
[VAR_BANNER_HEIGHT]: 0
|
|
30
41
|
});
|
|
31
|
-
};
|
|
42
|
+
};
|
|
32
43
|
}, [bannerHeight]);
|
|
33
44
|
useSkipLink(id, skipLinkTitle);
|
|
34
|
-
return jsx(
|
|
35
|
-
|
|
45
|
+
return jsx(SlotFocusRing, null, ({
|
|
46
|
+
className
|
|
47
|
+
}) => jsx("div", _extends({
|
|
48
|
+
css: [bannerStyles, isFixed && bannerFixedStyles],
|
|
49
|
+
className: className,
|
|
36
50
|
"data-testid": testId,
|
|
37
51
|
id: id
|
|
38
52
|
}, getPageLayoutSlotSelector('banner')), jsx(SlotDimensions, {
|
|
39
53
|
variableName: VAR_BANNER_HEIGHT,
|
|
40
54
|
value: bannerHeight
|
|
41
|
-
}), children);
|
|
55
|
+
}), children));
|
|
42
56
|
};
|
|
43
57
|
|
|
44
58
|
export default Banner;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/** @jsx jsx */
|
|
2
|
-
import { jsx } from '@emotion/core';
|
|
3
|
-
import {
|
|
2
|
+
import { css, jsx } from '@emotion/core';
|
|
3
|
+
import { CONTENT } from '../../common/constants';
|
|
4
|
+
const contentStyles = css({
|
|
5
|
+
display: 'flex',
|
|
6
|
+
height: '100%',
|
|
7
|
+
position: 'relative',
|
|
8
|
+
gridArea: CONTENT
|
|
9
|
+
});
|
|
4
10
|
|
|
5
11
|
const Content = props => {
|
|
6
12
|
const {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import { css, jsx } from '@emotion/core';
|
|
3
|
+
import { easeOut, prefersReducedMotion } from '@atlaskit/motion';
|
|
4
|
+
import { BANNER_HEIGHT, LEFT_PANEL_WIDTH, LEFT_SIDEBAR_FLYOUT_WIDTH, LEFT_SIDEBAR_WIDTH, TOP_NAVIGATION_HEIGHT, TRANSITION_DURATION } from '../../../common/constants';
|
|
5
|
+
import { useIsSidebarDragging } from '../../../common/hooks';
|
|
6
|
+
// eslint-disable-next-line @repo/internal/react/consistent-css-prop-usage
|
|
7
|
+
const prefersReducedMotionStyles = css(prefersReducedMotion());
|
|
8
|
+
/**
|
|
9
|
+
* This inner wrapper is required to allow the sidebar to be `position: fixed`.
|
|
10
|
+
*
|
|
11
|
+
* If we were to apply `position: fixed` to the outer wrapper, it will be popped
|
|
12
|
+
* out of its flex container and Main would stretch to occupy all the space.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fixedInnerStyles = css({
|
|
16
|
+
width: `${LEFT_SIDEBAR_WIDTH}`,
|
|
17
|
+
position: 'fixed',
|
|
18
|
+
top: `calc(${BANNER_HEIGHT} + ${TOP_NAVIGATION_HEIGHT})`,
|
|
19
|
+
bottom: 0,
|
|
20
|
+
left: `${LEFT_PANEL_WIDTH}`,
|
|
21
|
+
transition: `width ${TRANSITION_DURATION}ms ${easeOut} 0s`
|
|
22
|
+
});
|
|
23
|
+
const fixedInnerFlyoutStyles = css({
|
|
24
|
+
width: LEFT_SIDEBAR_FLYOUT_WIDTH
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Static in the sense of `position: static`.
|
|
28
|
+
*
|
|
29
|
+
* It will expand the page height to fit its content.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const staticInnerStyles = css({
|
|
33
|
+
height: '100%'
|
|
34
|
+
});
|
|
35
|
+
const draggingStyles = css({
|
|
36
|
+
cursor: 'ew-resize',
|
|
37
|
+
// Make sure drag to resize does not animate as the user drags
|
|
38
|
+
transition: 'none'
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const LeftSidebarInner = ({
|
|
42
|
+
children,
|
|
43
|
+
isFixed = false,
|
|
44
|
+
isFlyoutOpen = false
|
|
45
|
+
}) => {
|
|
46
|
+
const isDragging = useIsSidebarDragging();
|
|
47
|
+
return jsx("div", {
|
|
48
|
+
css: [!isFixed && staticInnerStyles, isFixed && fixedInnerStyles, isFixed && isFlyoutOpen && fixedInnerFlyoutStyles, isDragging && draggingStyles, prefersReducedMotionStyles]
|
|
49
|
+
}, children);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default LeftSidebarInner;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
+
|
|
3
|
+
/** @jsx jsx */
|
|
4
|
+
import { forwardRef } from 'react';
|
|
5
|
+
import { css, jsx } from '@emotion/core';
|
|
6
|
+
import { easeOut, prefersReducedMotion } from '@atlaskit/motion';
|
|
7
|
+
import { COLLAPSED_LEFT_SIDEBAR_WIDTH, LEFT_SIDEBAR_FLYOUT_WIDTH, LEFT_SIDEBAR_WIDTH, TRANSITION_DURATION } from '../../../common/constants';
|
|
8
|
+
import { useIsSidebarDragging } from '../../../common/hooks';
|
|
9
|
+
import { getPageLayoutSlotSelector } from '../../../common/utils';
|
|
10
|
+
import SlotFocusRing from './slot-focus-ring';
|
|
11
|
+
// eslint-disable-next-line @repo/internal/react/consistent-css-prop-usage
|
|
12
|
+
const prefersReducedMotionStyles = css(prefersReducedMotion());
|
|
13
|
+
const outerStyles = css({
|
|
14
|
+
width: LEFT_SIDEBAR_WIDTH,
|
|
15
|
+
marginLeft: 0,
|
|
16
|
+
position: 'relative',
|
|
17
|
+
zIndex: 1,
|
|
18
|
+
transition: `width ${TRANSITION_DURATION}ms ${easeOut} 0s`,
|
|
19
|
+
':hover': {
|
|
20
|
+
'--ds--resize-button--opacity': 1
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const draggingStyles = css({
|
|
24
|
+
cursor: 'ew-resize',
|
|
25
|
+
// Make sure drag to resize does not animate as the user drags
|
|
26
|
+
transition: 'none'
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* In fixed mode this element's child is taken out of the document flow.
|
|
30
|
+
* It doesn't take up the width as expected,
|
|
31
|
+
* so the pseudo element forces it to take up the necessary width.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
const fixedStyles = css({
|
|
35
|
+
'::after': {
|
|
36
|
+
display: 'inline-block',
|
|
37
|
+
width: `${LEFT_SIDEBAR_WIDTH}`,
|
|
38
|
+
content: "''"
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const flyoutStyles = css({
|
|
42
|
+
width: LEFT_SIDEBAR_FLYOUT_WIDTH
|
|
43
|
+
});
|
|
44
|
+
const flyoutFixedStyles = css({
|
|
45
|
+
width: COLLAPSED_LEFT_SIDEBAR_WIDTH
|
|
46
|
+
});
|
|
47
|
+
const selector = getPageLayoutSlotSelector('left-sidebar');
|
|
48
|
+
|
|
49
|
+
const LeftSidebarOuter = ({
|
|
50
|
+
children,
|
|
51
|
+
isFixed = false,
|
|
52
|
+
isFlyoutOpen = false,
|
|
53
|
+
testId,
|
|
54
|
+
onMouseLeave,
|
|
55
|
+
onMouseOver,
|
|
56
|
+
id
|
|
57
|
+
}, ref) => {
|
|
58
|
+
const isDragging = useIsSidebarDragging();
|
|
59
|
+
return jsx(SlotFocusRing, {
|
|
60
|
+
isSidebar: true
|
|
61
|
+
}, ({
|
|
62
|
+
className
|
|
63
|
+
}) =>
|
|
64
|
+
/**
|
|
65
|
+
* The mouse handlers control flyout behavior, a mouse-only experience.
|
|
66
|
+
*/
|
|
67
|
+
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
|
|
68
|
+
jsx("div", _extends({
|
|
69
|
+
css: [outerStyles, isFixed && fixedStyles, isFlyoutOpen && flyoutStyles, isFlyoutOpen && isFixed && flyoutFixedStyles, isDragging && draggingStyles, prefersReducedMotionStyles],
|
|
70
|
+
className: className,
|
|
71
|
+
"data-testid": testId,
|
|
72
|
+
id: id,
|
|
73
|
+
onMouseOver: onMouseOver,
|
|
74
|
+
onMouseLeave: onMouseLeave,
|
|
75
|
+
ref: ref
|
|
76
|
+
}, selector), children));
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export default /*#__PURE__*/forwardRef(LeftSidebarOuter);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import { css, jsx } from '@emotion/core';
|
|
3
|
+
import { prefersReducedMotion } from '@atlaskit/motion';
|
|
4
|
+
import { TRANSITION_DURATION } from '../../../common/constants';
|
|
5
|
+
import { useIsSidebarCollapsing } from '../../../common/hooks';
|
|
6
|
+
// eslint-disable-next-line @repo/internal/react/consistent-css-prop-usage
|
|
7
|
+
const prefersReducedMotionStyles = css(prefersReducedMotion());
|
|
8
|
+
/**
|
|
9
|
+
* The transition duration is intentionally set to 0ms.
|
|
10
|
+
*
|
|
11
|
+
* A transition is being used here to delay the setting of
|
|
12
|
+
* opacity and visibility so that it syncs collapsing sidebar.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const hideLeftSidebarContentsStyles = css({
|
|
16
|
+
opacity: 0,
|
|
17
|
+
transition: `opacity 0ms linear, visibility 0ms linear`,
|
|
18
|
+
transitionDelay: `${TRANSITION_DURATION - 100}ms`,
|
|
19
|
+
visibility: 'hidden'
|
|
20
|
+
});
|
|
21
|
+
const resizableChildrenWrapperStyles = css({
|
|
22
|
+
height: '100%',
|
|
23
|
+
opacity: 1,
|
|
24
|
+
overflow: 'hidden auto',
|
|
25
|
+
transition: 'none',
|
|
26
|
+
visibility: 'visible'
|
|
27
|
+
});
|
|
28
|
+
const fixedChildrenWrapperStyles = css({
|
|
29
|
+
minWidth: 240,
|
|
30
|
+
height: '100%'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const ResizableChildrenWrapper = ({
|
|
34
|
+
children,
|
|
35
|
+
isLeftSidebarCollapsed = false,
|
|
36
|
+
hasCollapsedState = false,
|
|
37
|
+
isFlyoutOpen = false
|
|
38
|
+
}) => {
|
|
39
|
+
const isCollapsing = useIsSidebarCollapsing();
|
|
40
|
+
const isCollapsed = isLeftSidebarCollapsed || hasCollapsedState;
|
|
41
|
+
const isHidden = isCollapsing || isCollapsed && !isFlyoutOpen;
|
|
42
|
+
return jsx("div", {
|
|
43
|
+
css: [resizableChildrenWrapperStyles, isHidden && hideLeftSidebarContentsStyles, prefersReducedMotionStyles]
|
|
44
|
+
}, jsx("div", {
|
|
45
|
+
css: fixedChildrenWrapperStyles
|
|
46
|
+
}, children));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default ResizableChildrenWrapper;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import { ClassNames, css, jsx } from '@emotion/core';
|
|
3
|
+
import { B100 } from '@atlaskit/theme/colors';
|
|
4
|
+
const focusStyles = css({
|
|
5
|
+
':focus': {
|
|
6
|
+
outline: 'none',
|
|
7
|
+
// eslint-disable-next-line @repo/internal/styles/no-nested-styles
|
|
8
|
+
'> div': {
|
|
9
|
+
boxShadow: `0px 0px 0px 2px inset ${`var(--ds-border-focused, ${B100})`}`,
|
|
10
|
+
outline: 'none'
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Sidebars have an outer and inner component,
|
|
16
|
+
* so the nested selector needs to target an extra level deeper.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const sidebarFocusStyles = css({
|
|
20
|
+
':focus': {
|
|
21
|
+
outline: 'none',
|
|
22
|
+
// eslint-disable-next-line @repo/internal/styles/no-nested-styles
|
|
23
|
+
'> div > div': {
|
|
24
|
+
boxShadow: `0px 0px 0px 2px inset ${`var(--ds-border-focused, ${B100})`}`,
|
|
25
|
+
outline: 'none'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* We don't use `@atlaskit/focus-ring` here,
|
|
31
|
+
* because we need inset focus styles and:
|
|
32
|
+
*
|
|
33
|
+
* 1. If we set them directly to the layout element,
|
|
34
|
+
* then any child element's background will cover the shadow.
|
|
35
|
+
* 2. We cannot wrap `children` in `FocusRing`,
|
|
36
|
+
* because there's no guarantee the passed child takes `className`.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const SlotFocusRing = ({
|
|
40
|
+
children,
|
|
41
|
+
isSidebar = false
|
|
42
|
+
}) => {
|
|
43
|
+
return jsx(ClassNames, null, ({
|
|
44
|
+
css
|
|
45
|
+
}) => children({
|
|
46
|
+
className: isSidebar ? css(sidebarFocusStyles) : css(focusStyles)
|
|
47
|
+
}));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default SlotFocusRing;
|
|
@@ -2,12 +2,22 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
|
|
3
3
|
/** @jsx jsx */
|
|
4
4
|
import { useEffect } from 'react';
|
|
5
|
-
import { jsx } from '@emotion/core';
|
|
6
|
-
import { DEFAULT_LEFT_PANEL_WIDTH, VAR_LEFT_PANEL_WIDTH } from '../../common/constants';
|
|
5
|
+
import { css, jsx } from '@emotion/core';
|
|
6
|
+
import { DEFAULT_LEFT_PANEL_WIDTH, LEFT_PANEL, LEFT_PANEL_WIDTH, VAR_LEFT_PANEL_WIDTH } from '../../common/constants';
|
|
7
7
|
import { getPageLayoutSlotSelector, resolveDimension } from '../../common/utils';
|
|
8
8
|
import { publishGridState, useSkipLink } from '../../controllers';
|
|
9
|
+
import SlotFocusRing from './internal/slot-focus-ring';
|
|
9
10
|
import SlotDimensions from './slot-dimensions';
|
|
10
|
-
|
|
11
|
+
const leftPanelStyles = css({
|
|
12
|
+
gridArea: LEFT_PANEL
|
|
13
|
+
});
|
|
14
|
+
const leftPanelFixedStyles = css({
|
|
15
|
+
width: LEFT_PANEL_WIDTH,
|
|
16
|
+
position: 'fixed',
|
|
17
|
+
top: 0,
|
|
18
|
+
bottom: 0,
|
|
19
|
+
left: 0
|
|
20
|
+
});
|
|
11
21
|
|
|
12
22
|
const LeftPanel = props => {
|
|
13
23
|
const {
|
|
@@ -28,17 +38,20 @@ const LeftPanel = props => {
|
|
|
28
38
|
publishGridState({
|
|
29
39
|
[VAR_LEFT_PANEL_WIDTH]: 0
|
|
30
40
|
});
|
|
31
|
-
};
|
|
41
|
+
};
|
|
32
42
|
}, [leftPanelWidth]);
|
|
33
43
|
useSkipLink(id, skipLinkTitle);
|
|
34
|
-
return jsx(
|
|
35
|
-
|
|
44
|
+
return jsx(SlotFocusRing, null, ({
|
|
45
|
+
className
|
|
46
|
+
}) => jsx("div", _extends({
|
|
47
|
+
css: [leftPanelStyles, isFixed && leftPanelFixedStyles],
|
|
48
|
+
className: className,
|
|
36
49
|
"data-testid": testId,
|
|
37
50
|
id: id
|
|
38
51
|
}, getPageLayoutSlotSelector('left-panel')), jsx(SlotDimensions, {
|
|
39
52
|
variableName: VAR_LEFT_PANEL_WIDTH,
|
|
40
53
|
value: leftPanelWidth
|
|
41
|
-
}), children);
|
|
54
|
+
}), children));
|
|
42
55
|
};
|
|
43
56
|
|
|
44
57
|
export default LeftPanel;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
|
|
3
1
|
/** @jsx jsx */
|
|
4
2
|
import { useEffect } from 'react';
|
|
5
3
|
import { jsx } from '@emotion/core';
|
|
6
4
|
import { VAR_LEFT_SIDEBAR_WIDTH } from '../../common/constants';
|
|
7
|
-
import {
|
|
5
|
+
import { resolveDimension } from '../../common/utils';
|
|
8
6
|
import { publishGridState, useSkipLink } from '../../controllers';
|
|
9
|
-
import
|
|
7
|
+
import LeftSidebarInner from './internal/left-sidebar-inner';
|
|
8
|
+
import LeftSidebarOuter from './internal/left-sidebar-outer';
|
|
10
9
|
import SlotDimensions from './slot-dimensions';
|
|
11
10
|
|
|
12
11
|
const LeftSidebarWithoutResize = props => {
|
|
@@ -28,18 +27,18 @@ const LeftSidebarWithoutResize = props => {
|
|
|
28
27
|
publishGridState({
|
|
29
28
|
[VAR_LEFT_SIDEBAR_WIDTH]: 0
|
|
30
29
|
});
|
|
31
|
-
};
|
|
30
|
+
};
|
|
32
31
|
}, [leftSidebarWidth]);
|
|
33
32
|
useSkipLink(id, skipLinkTitle);
|
|
34
|
-
return jsx(
|
|
33
|
+
return jsx(LeftSidebarOuter, {
|
|
35
34
|
id: id,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
35
|
+
testId: testId,
|
|
36
|
+
isFixed: isFixed
|
|
37
|
+
}, jsx(SlotDimensions, {
|
|
39
38
|
variableName: VAR_LEFT_SIDEBAR_WIDTH,
|
|
40
39
|
value: leftSidebarWidth
|
|
41
|
-
}), jsx(
|
|
42
|
-
|
|
40
|
+
}), jsx(LeftSidebarInner, {
|
|
41
|
+
isFixed: isFixed
|
|
43
42
|
}, children));
|
|
44
43
|
};
|
|
45
44
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import _extends from "@babel/runtime/helpers/extends";
|
|
2
|
-
|
|
3
1
|
/** @jsx jsx */
|
|
4
2
|
import { useContext, useEffect, useRef } from 'react';
|
|
5
3
|
import { jsx } from '@emotion/core';
|
|
6
4
|
import { COLLAPSED_LEFT_SIDEBAR_WIDTH, DEFAULT_LEFT_SIDEBAR_WIDTH, FLYOUT_DELAY, RESIZE_BUTTON_SELECTOR, VAR_LEFT_SIDEBAR_FLYOUT, VAR_LEFT_SIDEBAR_WIDTH } from '../../common/constants';
|
|
7
|
-
import { getGridStateFromStorage,
|
|
5
|
+
import { getGridStateFromStorage, mergeGridStateIntoStorage, resolveDimension } from '../../common/utils';
|
|
8
6
|
import { publishGridState, SidebarResizeContext, useSkipLink } from '../../controllers';
|
|
9
7
|
import ResizeControl from '../resize-control';
|
|
10
|
-
import
|
|
8
|
+
import LeftSidebarInner from './internal/left-sidebar-inner';
|
|
9
|
+
import LeftSidebarOuter from './internal/left-sidebar-outer';
|
|
10
|
+
import ResizableChildrenWrapper from './internal/resizable-children-wrapper';
|
|
11
11
|
import SlotDimensions from './slot-dimensions';
|
|
12
12
|
|
|
13
13
|
const LeftSidebar = props => {
|
|
@@ -112,7 +112,8 @@ const LeftSidebar = props => {
|
|
|
112
112
|
isLeftSidebarCollapsed: cachedCollapsedState,
|
|
113
113
|
leftSidebarWidth,
|
|
114
114
|
lastLeftSidebarWidth,
|
|
115
|
-
flyoutLockCount: 0
|
|
115
|
+
flyoutLockCount: 0,
|
|
116
|
+
isFixed
|
|
116
117
|
}); // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
117
118
|
}, []); // Every time other than mount,
|
|
118
119
|
// update the local storage and css variables.
|
|
@@ -202,23 +203,25 @@ const LeftSidebar = props => {
|
|
|
202
203
|
};
|
|
203
204
|
|
|
204
205
|
return (// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
|
|
205
|
-
jsx(
|
|
206
|
+
jsx(LeftSidebarOuter, {
|
|
206
207
|
ref: leftSideBarRef,
|
|
207
|
-
|
|
208
|
-
"data-testid": testId,
|
|
208
|
+
testId: testId,
|
|
209
209
|
onMouseOver: onMouseOver,
|
|
210
210
|
onMouseLeave: onMouseLeave,
|
|
211
|
-
id: id
|
|
212
|
-
|
|
211
|
+
id: id,
|
|
212
|
+
isFixed: isFixed,
|
|
213
|
+
isFlyoutOpen: isFlyoutOpen
|
|
214
|
+
}, jsx(SlotDimensions, {
|
|
213
215
|
variableName: VAR_LEFT_SIDEBAR_WIDTH,
|
|
214
216
|
value: notFirstRun.current ? leftSidebarWidth : leftSidebarWidthOnMount
|
|
215
|
-
}), jsx(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
}), jsx(LeftSidebarInner, {
|
|
218
|
+
isFixed: isFixed,
|
|
219
|
+
isFlyoutOpen: isFlyoutOpen
|
|
220
|
+
}, jsx(ResizableChildrenWrapper, {
|
|
221
|
+
isFlyoutOpen: isFlyoutOpen,
|
|
222
|
+
isLeftSidebarCollapsed: isLeftSidebarCollapsed,
|
|
223
|
+
hasCollapsedState: !notFirstRun.current && collapsedState === 'collapsed'
|
|
224
|
+
}, children), jsx(ResizeControl, {
|
|
222
225
|
testId: testId,
|
|
223
226
|
resizeGrabAreaLabel: resizeGrabAreaLabel,
|
|
224
227
|
resizeButtonLabel: resizeButtonLabel,
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/extends";
|
|
2
2
|
|
|
3
3
|
/** @jsx jsx */
|
|
4
|
-
import {
|
|
4
|
+
import { useContext } from 'react';
|
|
5
|
+
import { css, jsx } from '@emotion/core';
|
|
6
|
+
import { prefersReducedMotion } from '@atlaskit/motion/accessibility';
|
|
7
|
+
import { easeOut } from '@atlaskit/motion/curves';
|
|
8
|
+
import { COLLAPSED_LEFT_SIDEBAR_WIDTH, DEFAULT_LEFT_SIDEBAR_FLYOUT_WIDTH, TRANSITION_DURATION, VAR_LEFT_SIDEBAR_FLYOUT } from '../../common/constants';
|
|
9
|
+
import { useIsSidebarDragging } from '../../common/hooks';
|
|
5
10
|
import { getPageLayoutSlotSelector } from '../../common/utils';
|
|
6
|
-
import { useSkipLink } from '../../controllers';
|
|
7
|
-
import
|
|
11
|
+
import { SidebarResizeContext, useSkipLink } from '../../controllers';
|
|
12
|
+
import SlotFocusRing from './internal/slot-focus-ring'; // eslint-disable-next-line @repo/internal/react/consistent-css-prop-usage
|
|
13
|
+
|
|
14
|
+
const prefersReducedMotionStyles = css(prefersReducedMotion());
|
|
15
|
+
const mainStyles = css({
|
|
16
|
+
minWidth: 0,
|
|
17
|
+
marginLeft: 0,
|
|
18
|
+
// Prevent flex container from blowing up when there's super wide content.
|
|
19
|
+
flexGrow: 1,
|
|
20
|
+
// Transition negative margin on main in sync with the increase in width of leftSidebar.
|
|
21
|
+
transition: `margin-left ${TRANSITION_DURATION}ms ${easeOut} 0s`
|
|
22
|
+
});
|
|
23
|
+
const draggingStyles = css({
|
|
24
|
+
cursor: 'ew-resize',
|
|
25
|
+
// Make sure drag to resize remains snappy.
|
|
26
|
+
transition: 'none'
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Adds a negative left margin to main,
|
|
30
|
+
* which transitions at the same speed as the left sidebar's width increase.
|
|
31
|
+
* This give an illusion that the flyout is appearing on top of the main content,
|
|
32
|
+
* while main remains in place.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
const flyoutStyles = css({
|
|
36
|
+
marginLeft: `calc(-1 * var(--${VAR_LEFT_SIDEBAR_FLYOUT}, ${DEFAULT_LEFT_SIDEBAR_FLYOUT_WIDTH}px) + ${COLLAPSED_LEFT_SIDEBAR_WIDTH}px)`
|
|
37
|
+
});
|
|
8
38
|
|
|
9
39
|
const Main = props => {
|
|
10
40
|
const {
|
|
@@ -14,11 +44,21 @@ const Main = props => {
|
|
|
14
44
|
skipLinkTitle
|
|
15
45
|
} = props;
|
|
16
46
|
useSkipLink(id, skipLinkTitle);
|
|
17
|
-
|
|
47
|
+
const isDragging = useIsSidebarDragging();
|
|
48
|
+
const {
|
|
49
|
+
leftSidebarState: {
|
|
50
|
+
isFlyoutOpen,
|
|
51
|
+
isFixed
|
|
52
|
+
}
|
|
53
|
+
} = useContext(SidebarResizeContext);
|
|
54
|
+
return jsx(SlotFocusRing, null, ({
|
|
55
|
+
className
|
|
56
|
+
}) => jsx("div", _extends({
|
|
18
57
|
"data-testid": testId,
|
|
19
|
-
css: mainStyles,
|
|
58
|
+
css: [mainStyles, isDragging && draggingStyles, isFlyoutOpen && !isFixed && flyoutStyles, prefersReducedMotionStyles],
|
|
59
|
+
className: className,
|
|
20
60
|
id: id
|
|
21
|
-
}, getPageLayoutSlotSelector('main')), children);
|
|
61
|
+
}, getPageLayoutSlotSelector('main')), children));
|
|
22
62
|
};
|
|
23
63
|
|
|
24
64
|
export default Main;
|
|
@@ -2,14 +2,26 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
|
|
3
3
|
/** @jsx jsx */
|
|
4
4
|
import { Fragment } from 'react';
|
|
5
|
-
import { jsx } from '@emotion/core';
|
|
6
|
-
import { DEFAULT_I18N_PROPS_SKIP_LINKS, PAGE_LAYOUT_CONTAINER_SELECTOR } from '../../common/constants';
|
|
5
|
+
import { css, jsx } from '@emotion/core';
|
|
6
|
+
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';
|
|
7
7
|
import { SidebarResizeController, SkipLinksController } from '../../controllers';
|
|
8
8
|
import { SkipLinkWrapper } from '../skip-links';
|
|
9
|
-
import { gridStyles } from './styles';
|
|
10
9
|
const pageLayoutSelector = {
|
|
11
10
|
[PAGE_LAYOUT_CONTAINER_SELECTOR]: true
|
|
12
11
|
};
|
|
12
|
+
const gridTemplateAreas = `
|
|
13
|
+
"${LEFT_PANEL} ${BANNER} ${RIGHT_PANEL}"
|
|
14
|
+
"${LEFT_PANEL} ${TOP_NAVIGATION} ${RIGHT_PANEL}"
|
|
15
|
+
"${LEFT_PANEL} ${CONTENT} ${RIGHT_PANEL}"
|
|
16
|
+
`;
|
|
17
|
+
const gridStyles = css({
|
|
18
|
+
display: 'grid',
|
|
19
|
+
height: '100%',
|
|
20
|
+
gridTemplateAreas,
|
|
21
|
+
gridTemplateColumns: `${LEFT_PANEL_WIDTH} minmax(0, 1fr) ${RIGHT_PANEL_WIDTH}`,
|
|
22
|
+
gridTemplateRows: `${BANNER_HEIGHT} ${TOP_NAVIGATION_HEIGHT} auto`,
|
|
23
|
+
outline: 'none'
|
|
24
|
+
});
|
|
13
25
|
|
|
14
26
|
const PageLayout = ({
|
|
15
27
|
skipLinksLabel = DEFAULT_I18N_PROPS_SKIP_LINKS,
|
|
@@ -2,12 +2,22 @@ import _extends from "@babel/runtime/helpers/extends";
|
|
|
2
2
|
|
|
3
3
|
/** @jsx jsx */
|
|
4
4
|
import { useEffect } from 'react';
|
|
5
|
-
import { jsx } from '@emotion/core';
|
|
6
|
-
import { DEFAULT_RIGHT_PANEL_WIDTH, VAR_RIGHT_PANEL_WIDTH } from '../../common/constants';
|
|
5
|
+
import { css, jsx } from '@emotion/core';
|
|
6
|
+
import { DEFAULT_RIGHT_PANEL_WIDTH, RIGHT_PANEL, RIGHT_PANEL_WIDTH, VAR_RIGHT_PANEL_WIDTH } from '../../common/constants';
|
|
7
7
|
import { getPageLayoutSlotSelector, resolveDimension } from '../../common/utils';
|
|
8
8
|
import { publishGridState, useSkipLink } from '../../controllers';
|
|
9
|
+
import SlotFocusRing from './internal/slot-focus-ring';
|
|
9
10
|
import SlotDimensions from './slot-dimensions';
|
|
10
|
-
|
|
11
|
+
const baseStyles = css({
|
|
12
|
+
gridArea: RIGHT_PANEL
|
|
13
|
+
});
|
|
14
|
+
const fixedStyles = css({
|
|
15
|
+
width: RIGHT_PANEL_WIDTH,
|
|
16
|
+
position: 'fixed',
|
|
17
|
+
top: 0,
|
|
18
|
+
right: 0,
|
|
19
|
+
bottom: 0
|
|
20
|
+
});
|
|
11
21
|
|
|
12
22
|
const RightPanel = props => {
|
|
13
23
|
const {
|
|
@@ -28,17 +38,20 @@ const RightPanel = props => {
|
|
|
28
38
|
publishGridState({
|
|
29
39
|
[VAR_RIGHT_PANEL_WIDTH]: 0
|
|
30
40
|
});
|
|
31
|
-
};
|
|
41
|
+
};
|
|
32
42
|
}, [rightPanelWidth]);
|
|
33
43
|
useSkipLink(id, skipLinkTitle);
|
|
34
|
-
return jsx(
|
|
35
|
-
|
|
44
|
+
return jsx(SlotFocusRing, null, ({
|
|
45
|
+
className
|
|
46
|
+
}) => jsx("div", _extends({
|
|
47
|
+
css: [baseStyles, isFixed && fixedStyles],
|
|
48
|
+
className: className,
|
|
36
49
|
"data-testid": testId,
|
|
37
50
|
id: id
|
|
38
51
|
}, getPageLayoutSlotSelector('right-panel')), jsx(SlotDimensions, {
|
|
39
52
|
variableName: VAR_RIGHT_PANEL_WIDTH,
|
|
40
53
|
value: rightPanelWidth
|
|
41
|
-
}), children);
|
|
54
|
+
}), children));
|
|
42
55
|
};
|
|
43
56
|
|
|
44
57
|
export default RightPanel;
|