@toptal/picasso-page 5.1.19 → 5.1.20
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/dist-package/src/PageHamburger/PageHamburger.d.ts.map +1 -1
- package/dist-package/src/PageHamburger/PageHamburger.js +2 -2
- package/dist-package/src/PageHamburger/PageHamburger.js.map +1 -1
- package/dist-package/src/PageHamburger/PageHamburgerContext.d.ts +4 -5
- package/dist-package/src/PageHamburger/PageHamburgerContext.d.ts.map +1 -1
- package/dist-package/src/PageHamburger/PageHamburgerContext.js +9 -25
- package/dist-package/src/PageHamburger/PageHamburgerContext.js.map +1 -1
- package/dist-package/src/PageHamburger/PageHamburgerPortal.js +2 -2
- package/dist-package/src/PageHamburger/PageHamburgerPortal.js.map +1 -1
- package/dist-package/src/PageHamburger/index.d.ts +1 -1
- package/dist-package/src/PageHamburger/index.d.ts.map +1 -1
- package/dist-package/src/PageHamburger/index.js +1 -1
- package/dist-package/src/PageHamburger/index.js.map +1 -1
- package/dist-package/src/PageSidebar/PageSidebar.d.ts.map +1 -1
- package/dist-package/src/PageSidebar/PageSidebar.js +9 -29
- package/dist-package/src/PageSidebar/PageSidebar.js.map +1 -1
- package/dist-package/src/PageSidebar/PageSidebarDesktop.d.ts +30 -0
- package/dist-package/src/PageSidebar/PageSidebarDesktop.d.ts.map +1 -0
- package/dist-package/src/PageSidebar/PageSidebarDesktop.js +33 -0
- package/dist-package/src/PageSidebar/PageSidebarDesktop.js.map +1 -0
- package/dist-package/src/PageTopBar/PageTopBar.d.ts.map +1 -1
- package/dist-package/src/PageTopBar/PageTopBar.js +18 -13
- package/dist-package/src/PageTopBar/PageTopBar.js.map +1 -1
- package/dist-package/src/TopBarMenu/TopBarMenu.d.ts.map +1 -1
- package/dist-package/src/TopBarMenu/TopBarMenu.js +0 -2
- package/dist-package/src/TopBarMenu/TopBarMenu.js.map +1 -1
- package/package.json +1 -1
- package/src/PageHamburger/PageHamburger.tsx +1 -2
- package/src/PageHamburger/PageHamburgerContext.tsx +15 -47
- package/src/PageHamburger/PageHamburgerPortal.tsx +2 -2
- package/src/PageHamburger/index.ts +0 -1
- package/src/PageSidebar/PageSidebar.tsx +24 -65
- package/src/PageSidebar/PageSidebarDesktop.tsx +114 -0
- package/src/PageTopBar/PageTopBar.tsx +31 -19
- package/src/PageTopBar/__snapshots__/test.tsx.snap +122 -194
- package/src/PageTopBar/test.tsx +23 -4
- package/src/TopBarMenu/TopBarMenu.tsx +0 -4
|
@@ -8,7 +8,7 @@ interface Props {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const PageHamburgerPortal = ({ children }: Props) => {
|
|
11
|
-
const {
|
|
11
|
+
const { hamburgerRef } = useHamburgerContext()
|
|
12
12
|
const [container, setContainer] = React.useState<HTMLElement | null>(null)
|
|
13
13
|
const [isMounted, setIsMounted] = React.useState<boolean>(false)
|
|
14
14
|
|
|
@@ -19,7 +19,7 @@ const PageHamburgerPortal = ({ children }: Props) => {
|
|
|
19
19
|
}
|
|
20
20
|
}, [hamburgerRef, isMounted])
|
|
21
21
|
|
|
22
|
-
if (!container
|
|
22
|
+
if (!container) {
|
|
23
23
|
return null
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
import { useSidebar } from '@toptal/picasso-provider'
|
|
1
|
+
import { useSidebar, usePageTopBar } from '@toptal/picasso-provider'
|
|
2
2
|
import type { BaseProps, SizeType } from '@toptal/picasso-shared'
|
|
3
|
-
import { twMerge
|
|
3
|
+
import { twMerge } from '@toptal/picasso-tailwind-merge'
|
|
4
4
|
import type { ReactNode } from 'react'
|
|
5
5
|
import React, { forwardRef, useCallback, useEffect, useState } from 'react'
|
|
6
|
-
import { ButtonCircular } from '@toptal/picasso-button'
|
|
7
6
|
import { Container } from '@toptal/picasso-container'
|
|
8
|
-
import { BackMinor16, ChevronRight16 } from '@toptal/picasso-icons'
|
|
9
7
|
import { noop } from '@toptal/picasso-utils'
|
|
10
8
|
|
|
11
|
-
import {
|
|
12
|
-
PageHamburgerPortal,
|
|
13
|
-
useHamburgerContext,
|
|
14
|
-
useRegisterMenu,
|
|
15
|
-
} from '../PageHamburger'
|
|
9
|
+
import { PageHamburgerPortal, useHamburgerContext } from '../PageHamburger'
|
|
16
10
|
import { SidebarItem } from '../SidebarItem'
|
|
17
11
|
import { SidebarLogo } from '../SidebarLogo'
|
|
18
12
|
import { SidebarMenu } from '../SidebarMenu'
|
|
19
|
-
import { SidebarContextProvider } from './SidebarContextProvider'
|
|
20
13
|
import type { VariantType } from './types'
|
|
14
|
+
import PageSidebarDesktop from './PageSidebarDesktop'
|
|
21
15
|
|
|
22
16
|
export interface Props extends BaseProps {
|
|
23
17
|
/** Style variant of Sidebar and subcomponents */
|
|
@@ -72,18 +66,12 @@ export const PageSidebar = forwardRef<HTMLDivElement, Props>(function Sidebar(
|
|
|
72
66
|
onCollapse = noop,
|
|
73
67
|
} = props
|
|
74
68
|
|
|
75
|
-
const { setHasSidebar } = useSidebar()
|
|
76
69
|
const [isCollapsed, setIsCollapsed] = useState(!!defaultCollapsed)
|
|
77
70
|
const [isHovered, setIsHovered] = useState(false)
|
|
78
|
-
const [expandedItemKey, setExpandedItemKey] = useState<number | null>(null)
|
|
79
|
-
const { hasTopBar } = useHamburgerContext()
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
setExpandedItemKey(null)
|
|
85
|
-
}
|
|
86
|
-
}, [isCollapsed])
|
|
72
|
+
const { setHasSidebar } = useSidebar()
|
|
73
|
+
const { hasPageHamburger } = useHamburgerContext()
|
|
74
|
+
const { hasTopBar } = usePageTopBar()
|
|
87
75
|
|
|
88
76
|
useEffect(() => {
|
|
89
77
|
setHasSidebar(true)
|
|
@@ -93,9 +81,7 @@ export const PageSidebar = forwardRef<HTMLDivElement, Props>(function Sidebar(
|
|
|
93
81
|
}
|
|
94
82
|
}, [setHasSidebar])
|
|
95
83
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const handleCollapseButtonClick = useCallback(() => {
|
|
84
|
+
const handleCollapse = useCallback(() => {
|
|
99
85
|
setIsCollapsed(previousState => !previousState)
|
|
100
86
|
onCollapse()
|
|
101
87
|
}, [setIsCollapsed, onCollapse])
|
|
@@ -134,50 +120,23 @@ export const PageSidebar = forwardRef<HTMLDivElement, Props>(function Sidebar(
|
|
|
134
120
|
onMouseEnter={collapsible ? () => setIsHovered(true) : noop}
|
|
135
121
|
onMouseLeave={collapsible ? () => setIsHovered(false) : noop}
|
|
136
122
|
>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
flex
|
|
151
|
-
direction='column'
|
|
152
|
-
className='scrollable-content h-full overflow-y-auto pt-4 pb-2 px-0'
|
|
153
|
-
data-testid={testIds?.scrollableContainer}
|
|
123
|
+
{hasPageHamburger ? (
|
|
124
|
+
<PageHamburgerPortal>{children}</PageHamburgerPortal>
|
|
125
|
+
) : (
|
|
126
|
+
<PageSidebarDesktop
|
|
127
|
+
testIds={testIds}
|
|
128
|
+
variant={variant}
|
|
129
|
+
wrapperMaxHeight={wrapperMaxHeight}
|
|
130
|
+
disableSticky={disableSticky}
|
|
131
|
+
collapsible={collapsible}
|
|
132
|
+
defaultCollapsed={defaultCollapsed}
|
|
133
|
+
isCollapsed={isCollapsed}
|
|
134
|
+
isHovered={isHovered}
|
|
135
|
+
onCollapse={handleCollapse}
|
|
154
136
|
>
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
// TODO: [FX-XXXX] technical debt: button color/background/radius/shadow shouldn't be overwritten
|
|
159
|
-
'absolute -right-3 top-3 invisible text-graphite-700 bg-white rounded-full shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_0_8px_0_rgba(0,0,0,0.16)] z-[100] hover:text-white hover:bg-blue-500',
|
|
160
|
-
isHovered && 'visible'
|
|
161
|
-
)}
|
|
162
|
-
onClick={handleCollapseButtonClick}
|
|
163
|
-
icon={isCollapsed ? <ChevronRight16 /> : <BackMinor16 />}
|
|
164
|
-
aria-label='collapse sidebar'
|
|
165
|
-
variant='primary'
|
|
166
|
-
data-testid={testIds?.collapseButton}
|
|
167
|
-
/>
|
|
168
|
-
)}
|
|
169
|
-
<div className='order-[50] flex-1 h-full' />
|
|
170
|
-
<SidebarContextProvider
|
|
171
|
-
isCollapsed={isCollapsed}
|
|
172
|
-
isHovered={isHovered}
|
|
173
|
-
variant={variant}
|
|
174
|
-
expandedItemKey={expandedItemKey}
|
|
175
|
-
setExpandedItemKey={setExpandedItemKey}
|
|
176
|
-
>
|
|
177
|
-
{children}
|
|
178
|
-
</SidebarContextProvider>
|
|
179
|
-
</Container>
|
|
180
|
-
</div>
|
|
137
|
+
{children}
|
|
138
|
+
</PageSidebarDesktop>
|
|
139
|
+
)}
|
|
181
140
|
</Container>
|
|
182
141
|
)
|
|
183
142
|
})
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { BaseProps } from '@toptal/picasso-shared'
|
|
2
|
+
import { twMerge, twJoin } from '@toptal/picasso-tailwind-merge'
|
|
3
|
+
import type { ReactNode } from 'react'
|
|
4
|
+
import React, { forwardRef, useState, useEffect } from 'react'
|
|
5
|
+
import { ButtonCircular } from '@toptal/picasso-button'
|
|
6
|
+
import { Container } from '@toptal/picasso-container'
|
|
7
|
+
import { BackMinor16, ChevronRight16 } from '@toptal/picasso-icons'
|
|
8
|
+
import { noop } from '@toptal/picasso-utils'
|
|
9
|
+
|
|
10
|
+
import { SidebarContextProvider } from './SidebarContextProvider'
|
|
11
|
+
import type { VariantType } from './types'
|
|
12
|
+
|
|
13
|
+
export interface Props extends BaseProps {
|
|
14
|
+
/** Style variant of Sidebar and subcomponents */
|
|
15
|
+
variant?: VariantType
|
|
16
|
+
/** Content */
|
|
17
|
+
children?: ReactNode
|
|
18
|
+
/** Indicates Sidebar is collapsible */
|
|
19
|
+
collapsible?: boolean
|
|
20
|
+
/** Indicates Sidebar is collapsed as default */
|
|
21
|
+
defaultCollapsed?: boolean
|
|
22
|
+
/** Callback to notify when sidebar is having collapsed or default state */
|
|
23
|
+
testIds?: {
|
|
24
|
+
collapseButton?: string
|
|
25
|
+
container?: string
|
|
26
|
+
scrollableContainer?: string
|
|
27
|
+
}
|
|
28
|
+
/** Make sidebar scroll with the content */
|
|
29
|
+
disableSticky?: boolean
|
|
30
|
+
wrapperMaxHeight?: string | number
|
|
31
|
+
isHovered: boolean
|
|
32
|
+
isCollapsed: boolean
|
|
33
|
+
/** Callback when sidebar is collapsed */
|
|
34
|
+
onCollapse?: () => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const PageSidebarDesktop = forwardRef<HTMLDivElement, Props>(
|
|
38
|
+
function PageSidebarDesktop(props, ref) {
|
|
39
|
+
const {
|
|
40
|
+
children,
|
|
41
|
+
variant = 'light',
|
|
42
|
+
collapsible,
|
|
43
|
+
testIds,
|
|
44
|
+
wrapperMaxHeight,
|
|
45
|
+
disableSticky,
|
|
46
|
+
isHovered,
|
|
47
|
+
isCollapsed,
|
|
48
|
+
onCollapse = noop,
|
|
49
|
+
} = props
|
|
50
|
+
|
|
51
|
+
const [expandedItemKey, setExpandedItemKey] = useState<number | null>(null)
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
// Clear expanded submenu on sidebar collapse
|
|
55
|
+
if (isCollapsed) {
|
|
56
|
+
setExpandedItemKey(null)
|
|
57
|
+
}
|
|
58
|
+
}, [isCollapsed])
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
style={{
|
|
63
|
+
maxHeight: wrapperMaxHeight,
|
|
64
|
+
}}
|
|
65
|
+
className={twJoin(
|
|
66
|
+
'h-full',
|
|
67
|
+
!disableSticky &&
|
|
68
|
+
'max-h-[calc(100vh-var(--header-height,3.5rem))] sticky top-[var(--header-height,3.5rem)]'
|
|
69
|
+
)}
|
|
70
|
+
>
|
|
71
|
+
<Container
|
|
72
|
+
flex
|
|
73
|
+
direction='column'
|
|
74
|
+
className='scrollable-content h-full overflow-y-auto pt-4 pb-2 px-0'
|
|
75
|
+
data-testid={testIds?.scrollableContainer}
|
|
76
|
+
ref={ref}
|
|
77
|
+
>
|
|
78
|
+
{collapsible && (
|
|
79
|
+
<ButtonCircular
|
|
80
|
+
className={twMerge(
|
|
81
|
+
// TODO: [FX-XXXX] technical debt: button color/background/radius/shadow shouldn't be overwritten
|
|
82
|
+
'absolute -right-3 top-3 invisible text-graphite-700 bg-white rounded-full shadow-[0_0_0_1px_rgba(0,0,0,0.04),0_0_8px_0_rgba(0,0,0,0.16)] z-[100] hover:text-white hover:bg-blue-500',
|
|
83
|
+
isHovered && 'visible'
|
|
84
|
+
)}
|
|
85
|
+
onClick={onCollapse}
|
|
86
|
+
icon={isCollapsed ? <ChevronRight16 /> : <BackMinor16 />}
|
|
87
|
+
aria-label='collapse sidebar'
|
|
88
|
+
variant='primary'
|
|
89
|
+
data-testid={testIds?.collapseButton}
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
92
|
+
<div className='order-[50] flex-1 h-full' />
|
|
93
|
+
<SidebarContextProvider
|
|
94
|
+
isCollapsed={isCollapsed}
|
|
95
|
+
isHovered={isHovered}
|
|
96
|
+
variant={variant}
|
|
97
|
+
expandedItemKey={expandedItemKey}
|
|
98
|
+
setExpandedItemKey={setExpandedItemKey}
|
|
99
|
+
>
|
|
100
|
+
{children}
|
|
101
|
+
</SidebarContextProvider>
|
|
102
|
+
</Container>
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
PageSidebarDesktop.defaultProps = {
|
|
109
|
+
variant: 'light',
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
PageSidebarDesktop.displayName = 'PageSidebarDesktop'
|
|
113
|
+
|
|
114
|
+
export default PageSidebarDesktop
|
|
@@ -5,7 +5,9 @@ import cx from 'classnames'
|
|
|
5
5
|
import type { BaseProps } from '@toptal/picasso-shared'
|
|
6
6
|
import {
|
|
7
7
|
usePageTopBar,
|
|
8
|
+
useSidebar,
|
|
8
9
|
usePreventPageWidthChangeOnScrollbar,
|
|
10
|
+
useScreenSize,
|
|
9
11
|
} from '@toptal/picasso-provider'
|
|
10
12
|
import type { Theme } from '@material-ui/core/styles'
|
|
11
13
|
import { makeStyles } from '@material-ui/core/styles'
|
|
@@ -23,6 +25,8 @@ import {
|
|
|
23
25
|
} from '../PageHamburger'
|
|
24
26
|
import styles from './styles'
|
|
25
27
|
|
|
28
|
+
const SMALL_SCREEN_WIDTH = 1280
|
|
29
|
+
|
|
26
30
|
type VariantType = 'dark' | 'light' | 'grey'
|
|
27
31
|
|
|
28
32
|
export interface Props extends BaseProps, HTMLAttributes<HTMLElement> {
|
|
@@ -79,26 +83,33 @@ export const PageTopBar = forwardRef<HTMLElement, Props>(function PageTopBar(
|
|
|
79
83
|
const { setHasTopBar } = usePageTopBar()
|
|
80
84
|
const { preventPageWidthChangeOnScrollbar } =
|
|
81
85
|
usePreventPageWidthChangeOnScrollbar()
|
|
82
|
-
const { setHasTopBar: setHasTopBarHamburger, hasTopBar } =
|
|
83
|
-
useHamburgerContext()
|
|
84
86
|
|
|
85
87
|
useIsomorphicLayoutEffect(() => {
|
|
86
88
|
setHasTopBar(true)
|
|
87
89
|
|
|
88
|
-
return () =>
|
|
90
|
+
return () => {
|
|
91
|
+
setHasTopBar(false)
|
|
92
|
+
}
|
|
89
93
|
}, [setHasTopBar])
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
setHasTopBarHamburger(true)
|
|
95
|
+
const { width, fullWidth } = useContext<PageContextProps>(PageContext)
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
}, [hasTopBar, setHasTopBarHamburger])
|
|
97
|
+
const { hamburgerId, setHasPageHamburger } = useHamburgerContext()
|
|
96
98
|
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
+
const screenSize = useScreenSize()
|
|
100
|
+
const isSmallScreen = screenSize < SMALL_SCREEN_WIDTH
|
|
99
101
|
|
|
100
|
-
const
|
|
102
|
+
const { hasSidebar } = useSidebar()
|
|
103
|
+
|
|
104
|
+
const showHamburger = isSmallScreen && (hasSidebar || !!centerContent)
|
|
101
105
|
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
setHasPageHamburger(showHamburger)
|
|
108
|
+
|
|
109
|
+
return () => setHasPageHamburger(false)
|
|
110
|
+
}, [setHasPageHamburger, showHamburger])
|
|
111
|
+
|
|
112
|
+
const isDark = ['dark', 'grey'].includes(variant)
|
|
102
113
|
const logoVariant = isDark ? 'white' : 'default'
|
|
103
114
|
const logoDefault = (
|
|
104
115
|
<>
|
|
@@ -150,10 +161,12 @@ export const PageTopBar = forwardRef<HTMLElement, Props>(function PageTopBar(
|
|
|
150
161
|
{/* Left part: Hamburger, Logo, Tagline, Search bar */}
|
|
151
162
|
<div className={classes.left}>
|
|
152
163
|
<Container flex alignItems='center' gap='small'>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
{showHamburger && (
|
|
165
|
+
<PageHamburger
|
|
166
|
+
id={hamburgerId}
|
|
167
|
+
data-testid={testIds?.hamburger}
|
|
168
|
+
/>
|
|
169
|
+
)}
|
|
157
170
|
{logoLink
|
|
158
171
|
? React.cloneElement(logoLink, {}, logoComponent)
|
|
159
172
|
: logoComponent}
|
|
@@ -163,19 +176,18 @@ export const PageTopBar = forwardRef<HTMLElement, Props>(function PageTopBar(
|
|
|
163
176
|
</div>
|
|
164
177
|
|
|
165
178
|
{/* Center part: inline menu */}
|
|
166
|
-
{centerContent &&
|
|
167
|
-
|
|
179
|
+
{centerContent &&
|
|
180
|
+
(isSmallScreen ? (
|
|
168
181
|
<PageHamburgerPortal>
|
|
169
182
|
<div className={classes.centerContentPortal}>
|
|
170
183
|
{centerContent}
|
|
171
184
|
</div>
|
|
172
185
|
</PageHamburgerPortal>
|
|
186
|
+
) : (
|
|
173
187
|
<Container className={classes.centerContent}>
|
|
174
188
|
{centerContent}
|
|
175
189
|
</Container>
|
|
176
|
-
|
|
177
|
-
)}
|
|
178
|
-
|
|
190
|
+
))}
|
|
179
191
|
{/* Right part: Action items, User menu, Notifications */}
|
|
180
192
|
|
|
181
193
|
<div className={classes.right}>
|