@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.
Files changed (37) hide show
  1. package/dist-package/src/PageHamburger/PageHamburger.d.ts.map +1 -1
  2. package/dist-package/src/PageHamburger/PageHamburger.js +2 -2
  3. package/dist-package/src/PageHamburger/PageHamburger.js.map +1 -1
  4. package/dist-package/src/PageHamburger/PageHamburgerContext.d.ts +4 -5
  5. package/dist-package/src/PageHamburger/PageHamburgerContext.d.ts.map +1 -1
  6. package/dist-package/src/PageHamburger/PageHamburgerContext.js +9 -25
  7. package/dist-package/src/PageHamburger/PageHamburgerContext.js.map +1 -1
  8. package/dist-package/src/PageHamburger/PageHamburgerPortal.js +2 -2
  9. package/dist-package/src/PageHamburger/PageHamburgerPortal.js.map +1 -1
  10. package/dist-package/src/PageHamburger/index.d.ts +1 -1
  11. package/dist-package/src/PageHamburger/index.d.ts.map +1 -1
  12. package/dist-package/src/PageHamburger/index.js +1 -1
  13. package/dist-package/src/PageHamburger/index.js.map +1 -1
  14. package/dist-package/src/PageSidebar/PageSidebar.d.ts.map +1 -1
  15. package/dist-package/src/PageSidebar/PageSidebar.js +9 -29
  16. package/dist-package/src/PageSidebar/PageSidebar.js.map +1 -1
  17. package/dist-package/src/PageSidebar/PageSidebarDesktop.d.ts +30 -0
  18. package/dist-package/src/PageSidebar/PageSidebarDesktop.d.ts.map +1 -0
  19. package/dist-package/src/PageSidebar/PageSidebarDesktop.js +33 -0
  20. package/dist-package/src/PageSidebar/PageSidebarDesktop.js.map +1 -0
  21. package/dist-package/src/PageTopBar/PageTopBar.d.ts.map +1 -1
  22. package/dist-package/src/PageTopBar/PageTopBar.js +18 -13
  23. package/dist-package/src/PageTopBar/PageTopBar.js.map +1 -1
  24. package/dist-package/src/TopBarMenu/TopBarMenu.d.ts.map +1 -1
  25. package/dist-package/src/TopBarMenu/TopBarMenu.js +0 -2
  26. package/dist-package/src/TopBarMenu/TopBarMenu.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/PageHamburger/PageHamburger.tsx +1 -2
  29. package/src/PageHamburger/PageHamburgerContext.tsx +15 -47
  30. package/src/PageHamburger/PageHamburgerPortal.tsx +2 -2
  31. package/src/PageHamburger/index.ts +0 -1
  32. package/src/PageSidebar/PageSidebar.tsx +24 -65
  33. package/src/PageSidebar/PageSidebarDesktop.tsx +114 -0
  34. package/src/PageTopBar/PageTopBar.tsx +31 -19
  35. package/src/PageTopBar/__snapshots__/test.tsx.snap +122 -194
  36. package/src/PageTopBar/test.tsx +23 -4
  37. 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 { showSidebarMenu, hamburgerRef } = useHamburgerContext()
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 || !showSidebarMenu) {
22
+ if (!container) {
23
23
  return null
24
24
  }
25
25
 
@@ -3,5 +3,4 @@ export { default as PageHamburgerPortal } from './PageHamburgerPortal'
3
3
  export {
4
4
  useHamburgerContext,
5
5
  PageHamburgerContextProvider,
6
- useRegisterMenu,
7
6
  } from './PageHamburgerContext'
@@ -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, twJoin } from '@toptal/picasso-tailwind-merge'
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
- useEffect(() => {
82
- // Clear expanded submenu on sidebar collapse
83
- if (isCollapsed) {
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
- useRegisterMenu()
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
- <PageHamburgerPortal>{children}</PageHamburgerPortal>
138
-
139
- <div
140
- style={{
141
- maxHeight: wrapperMaxHeight,
142
- }}
143
- className={twJoin(
144
- 'h-full',
145
- !disableSticky &&
146
- 'max-h-[calc(100vh-var(--header-height,3.5rem))] sticky top-[var(--header-height,3.5rem)]'
147
- )}
148
- >
149
- <Container
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
- {collapsible && (
156
- <ButtonCircular
157
- className={twMerge(
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 () => setHasTopBar(false)
90
+ return () => {
91
+ setHasTopBar(false)
92
+ }
89
93
  }, [setHasTopBar])
90
94
 
91
- useEffect(() => {
92
- setHasTopBarHamburger(true)
95
+ const { width, fullWidth } = useContext<PageContextProps>(PageContext)
93
96
 
94
- return () => setHasTopBarHamburger(false)
95
- }, [hasTopBar, setHasTopBarHamburger])
97
+ const { hamburgerId, setHasPageHamburger } = useHamburgerContext()
96
98
 
97
- const { width, fullWidth } = useContext<PageContextProps>(PageContext)
98
- const { hamburgerId } = useHamburgerContext()
99
+ const screenSize = useScreenSize()
100
+ const isSmallScreen = screenSize < SMALL_SCREEN_WIDTH
99
101
 
100
- const isDark = ['dark', 'grey'].includes(variant)
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
- <PageHamburger
154
- id={hamburgerId}
155
- data-testid={testIds?.hamburger}
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}>