@graphcommerce/next-ui 3.21.15 → 3.23.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.
@@ -1,9 +1,9 @@
1
- import { usePageRouter } from '@graphcommerce/framer-next-pages'
2
1
  import { Scroller, ScrollerButton, ScrollerProvider } from '@graphcommerce/framer-scroller'
3
2
  import { Link, LinkProps as MuiLinkProps, makeStyles, Theme } from '@material-ui/core'
4
3
  import clsx from 'clsx'
5
4
  import { m } from 'framer-motion'
6
5
  import PageLink from 'next/link'
6
+ import { useRouter } from 'next/router'
7
7
  import React from 'react'
8
8
  import { UseStyles } from '../Styles'
9
9
  import SvgImageSimple from '../SvgImage/SvgImageSimple'
@@ -92,7 +92,7 @@ export type MenuTabsProps = MenuProps &
92
92
  export default function DesktopNavBar(props: MenuTabsProps) {
93
93
  const { menu, LinkProps, iconScrollerBtnLeft, iconScrollerBtnRight } = props
94
94
  const classes = useStyles(props)
95
- const router = usePageRouter()
95
+ const router = useRouter()
96
96
 
97
97
  return (
98
98
  <ScrollerProvider scrollSnapAlign='none'>
package/AppShell/Logo.tsx CHANGED
@@ -1,7 +1,7 @@
1
- import { usePageRouter } from '@graphcommerce/framer-next-pages'
2
1
  import { Image, ImageProps } from '@graphcommerce/image'
3
2
  import { makeStyles, Theme } from '@material-ui/core'
4
3
  import PageLink from 'next/link'
4
+ import { useRouter } from 'next/router'
5
5
  import React from 'react'
6
6
  import { UseStyles } from '../Styles'
7
7
 
@@ -29,7 +29,7 @@ export type LogoProps = { href?: `/${string}`; image: ImageProps } & UseStyles<t
29
29
 
30
30
  export default function Logo(props: LogoProps) {
31
31
  const { href, image } = props
32
- const router = usePageRouter()
32
+ const router = useRouter()
33
33
  const classes = useStyles(props)
34
34
 
35
35
  return router.asPath === '/' ? (
package/CHANGELOG.md CHANGED
@@ -3,6 +3,65 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.23.0](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/next-ui@3.22.2...@graphcommerce/next-ui@3.23.0) (2022-01-04)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * backbutton wasn't translated ([5f841c0](https://github.com/ho-nl/m2-pwa/commit/5f841c052b454c0d565a68829f78492c5a3b6dab))
12
+
13
+
14
+ ### Features
15
+
16
+ * introduced a withTheme hoc to allow theming per route ([55e3fc1](https://github.com/ho-nl/m2-pwa/commit/55e3fc178b385d0ccdc19a5c09a7887be5db14dc))
17
+
18
+
19
+
20
+
21
+
22
+ ## [3.22.2](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/next-ui@3.22.1...@graphcommerce/next-ui@3.22.2) (2022-01-04)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * broder radius of drawer was too small on desktop ([f8b3962](https://github.com/ho-nl/m2-pwa/commit/f8b3962825972e6bc232387e0a2e801289fcc492))
28
+ * close button of bottom sheet spacing ([be33c20](https://github.com/ho-nl/m2-pwa/commit/be33c20fc8f41ad85d90bff15842738bc370b81e))
29
+ * regression where primary action wasn't visible ([66f8ed2](https://github.com/ho-nl/m2-pwa/commit/66f8ed20ea0728881be81994d49bd6c399f2e914))
30
+
31
+
32
+
33
+
34
+
35
+ ## [3.22.1](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/next-ui@3.22.0...@graphcommerce/next-ui@3.22.1) (2022-01-04)
36
+
37
+
38
+ ### Bug Fixes
39
+
40
+ * overlay would have a height instead of minHeight ([07dba4b](https://github.com/ho-nl/m2-pwa/commit/07dba4b875a37beac2ab6a8afe50e6b7a7ba1bf9))
41
+
42
+
43
+
44
+
45
+
46
+ # [3.22.0](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/next-ui@3.21.15...@graphcommerce/next-ui@3.22.0) (2022-01-03)
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * backbutton had wrong label ([c6d0b27](https://github.com/ho-nl/m2-pwa/commit/c6d0b2738e5de734af40bc632177dcc867e8e556))
52
+ * make sure we're able to close the overlay ([8d19fde](https://github.com/ho-nl/m2-pwa/commit/8d19fde07d51493acfdfaa97a19f61246d04d42a))
53
+
54
+
55
+ ### Features
56
+
57
+ * add support for minimal overlay size ([96e508a](https://github.com/ho-nl/m2-pwa/commit/96e508a94e23fe5b3ec523cddeb19b7b70f50034))
58
+ * added support for more positioning options for the overlay ([79eae9e](https://github.com/ho-nl/m2-pwa/commit/79eae9eb39513f5611103c4c745c3db99b11f15a))
59
+ * **framer-next-pages:** reduce rerenders when navigating to a new page ([5cf3301](https://github.com/ho-nl/m2-pwa/commit/5cf330130bb3527057da015e3c4a6fa295d7262e))
60
+
61
+
62
+
63
+
64
+
6
65
  ## [3.21.15](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/next-ui@3.21.14...@graphcommerce/next-ui@3.21.15) (2021-12-24)
7
66
 
8
67
 
@@ -1,4 +1,3 @@
1
- import { usePageRouter } from '@graphcommerce/framer-next-pages'
2
1
  import { usePrevPageRouter } from '@graphcommerce/framer-next-pages/hooks/usePrevPageRouter'
3
2
  import {
4
3
  MotionImageAspect,
@@ -11,6 +10,7 @@ import {
11
10
  import { clientSize, useMotionValueValue } from '@graphcommerce/framer-utils'
12
11
  import { Fab, makeStyles, Theme, useTheme, alpha } from '@material-ui/core'
13
12
  import { m, useDomEvent, useMotionValue } from 'framer-motion'
13
+ import { useRouter } from 'next/router'
14
14
  import React, { useEffect, useRef } from 'react'
15
15
  import Row from '../../Row'
16
16
  import { UseStyles } from '../../Styles'
@@ -183,7 +183,7 @@ export default function SidebarGallery(props: SidebarGalleryProps) {
183
183
  classes: classesBase,
184
184
  } = props
185
185
 
186
- const router = usePageRouter()
186
+ const router = useRouter()
187
187
  const prevRoute = usePrevPageRouter()
188
188
  const clientHeight = useMotionValueValue(clientSize.y, (y) => y)
189
189
  const classes = useStyles({ clientHeight, aspectRatio, classes: classesBase })
@@ -23,8 +23,6 @@ export type LayoutHeaderProps = FloatingProps &
23
23
  */
24
24
  secondary?: React.ReactNode
25
25
 
26
- additional?: React.ReactNode
27
-
28
26
  noAlign?: boolean
29
27
  }
30
28
 
@@ -97,7 +95,7 @@ const useStyles = makeStyles(
97
95
  )
98
96
 
99
97
  export function LayoutHeader(props: LayoutHeaderProps) {
100
- const { children, additional, divider, primary, secondary, noAlign, switchPoint } = props
98
+ const { children, divider, primary, secondary, noAlign, switchPoint } = props
101
99
  const classes = useStyles(props)
102
100
  const showBack = useShowBack()
103
101
  const showClose = useShowClose()
@@ -118,8 +116,8 @@ export function LayoutHeader(props: LayoutHeaderProps) {
118
116
 
119
117
  if (back) left = back
120
118
 
121
- if (!left) left = close
122
- else if (!right) right = close
119
+ if (!right) right = close
120
+ else if (!left) left = close
123
121
 
124
122
  if (!left && !right && !children) return null
125
123
 
@@ -144,7 +142,6 @@ export function LayoutHeader(props: LayoutHeaderProps) {
144
142
  switchPoint={switchPoint}
145
143
  >
146
144
  {children}
147
- {additional}
148
145
  </LayoutHeaderContent>
149
146
  </div>
150
147
  )
@@ -1,15 +1,17 @@
1
- import { usePageRouter, useUp, usePrevUp, usePageContext } from '@graphcommerce/framer-next-pages'
1
+ import { useUp, usePrevUp, usePageContext } from '@graphcommerce/framer-next-pages'
2
2
  import { t } from '@lingui/macro'
3
3
  import PageLink from 'next/link'
4
+ import { useRouter } from 'next/router'
4
5
  import React from 'react'
5
6
  import Button, { ButtonProps } from '../../Button'
6
7
  import SvgImageSimple from '../../SvgImage/SvgImageSimple'
7
8
  import { iconChevronLeft } from '../../icons'
9
+ import { usePrevPageRouter } from '@graphcommerce/framer-next-pages/hooks/usePrevPageRouter'
8
10
 
9
11
  export type BackProps = Omit<ButtonProps, 'onClick' | 'children'>
10
12
 
11
13
  export function useShowBack() {
12
- const router = usePageRouter()
14
+ const router = useRouter()
13
15
  const up = useUp()
14
16
  const prevUp = usePrevUp()
15
17
  const { backSteps } = usePageContext()
@@ -22,8 +24,9 @@ export function useShowBack() {
22
24
  }
23
25
 
24
26
  export default function LayoutHeaderBack(props: BackProps) {
25
- const router = usePageRouter()
27
+ const router = useRouter()
26
28
  const up = useUp()
29
+ const prevRouter = usePrevPageRouter()
27
30
  const prevUp = usePrevUp()
28
31
  const { backSteps } = usePageContext()
29
32
 
@@ -31,7 +34,7 @@ export default function LayoutHeaderBack(props: BackProps) {
31
34
  const canClickBack = backSteps > 0 && router.asPath !== prevUp?.href
32
35
 
33
36
  if (canClickBack) {
34
- const label = up?.href === router.asPath ? up.title : t`Back`
37
+ const label = up?.href === prevRouter?.asPath ? up?.title : t`Back`
35
38
  return (
36
39
  <Button
37
40
  onClick={() => router.back()}
@@ -1,27 +1,39 @@
1
- import { usePageRouter, usePageContext } from '@graphcommerce/framer-next-pages'
1
+ import { useGo, usePageContext } from '@graphcommerce/framer-next-pages'
2
2
  import React from 'react'
3
3
  import Button from '../../Button'
4
4
  import SvgImageSimple from '../../SvgImage/SvgImageSimple'
5
5
  import { iconClose } from '../../icons'
6
+ import { makeStyles, Theme } from '@material-ui/core'
7
+ import { responsiveVal } from '../../Styles/responsiveVal'
8
+ import { Trans } from '@lingui/macro'
6
9
 
7
10
  export function useShowClose() {
8
11
  const { overlayGroup } = usePageContext()
9
12
  return !!overlayGroup
10
13
  }
11
14
 
15
+ const useStyles = makeStyles((theme: Theme) => ({
16
+ close: {
17
+ marginLeft: `calc(${responsiveVal(12, 22)} * -1)`,
18
+ marginRight: `calc(${responsiveVal(12, 22)} * -1)`,
19
+ },
20
+ }))
21
+
12
22
  export default function LayoutHeaderClose() {
13
- const router = usePageRouter()
14
23
  const { closeSteps } = usePageContext()
24
+ const onClick = useGo(closeSteps * -1)
25
+ const classes = useStyles()
15
26
 
16
27
  return (
17
28
  <Button
18
29
  type='button'
19
- onClick={() => router.go(closeSteps * -1)}
30
+ onClick={onClick}
20
31
  aria-label='Close'
21
- variant='pill-link'
32
+ variant='text'
22
33
  startIcon={<SvgImageSimple src={iconClose} />}
34
+ className={classes.close}
23
35
  >
24
- Close
36
+ <Trans>Close</Trans>
25
37
  </Button>
26
38
  )
27
39
  }
@@ -25,6 +25,8 @@ const useStyles = makeStyles(
25
25
  [theme.breakpoints.up('md')]: {
26
26
  height: theme.appShell.appBarHeightMd,
27
27
  },
28
+ borderTopLeftRadius: theme.shape.borderRadius * 3,
29
+ borderTopRightRadius: theme.shape.borderRadius * 3,
28
30
  },
29
31
  bgDivider: {
30
32
  boxShadow: 'unset',
@@ -50,6 +52,7 @@ const useStyles = makeStyles(
50
52
  gridTemplateAreas: `"left center right"`,
51
53
  gridTemplateColumns: '1fr auto 1fr',
52
54
  alignItems: 'center',
55
+ // columnGap: theme.spacings.xs,
53
56
 
54
57
  height: theme.appShell.headerHeightSm,
55
58
  [theme.breakpoints.up('md')]: {
@@ -104,7 +107,10 @@ const useStyles = makeStyles(
104
107
  },
105
108
  },
106
109
  right: {
107
- '& > *': { pointerEvents: 'all' },
110
+ '& > *': {
111
+ pointerEvents: 'all',
112
+ width: 'min-content',
113
+ },
108
114
  display: 'grid',
109
115
  gridAutoFlow: 'column',
110
116
  gap: theme.spacings.sm,
@@ -168,7 +174,7 @@ export default function LayoutHeaderContent(props: ContentProps) {
168
174
  <>
169
175
  <div {...className('bg')} />
170
176
  <div {...className('content')} ref={ref}>
171
- <div {...className('left')}>{left}</div>
177
+ {left && <div {...className('left')}>{left}</div>}
172
178
  <div {...className('center')}>{children}</div>
173
179
  <div {...className('right')}>{right}</div>
174
180
  {divider && <div {...className('divider')}>{divider}</div>}
@@ -20,11 +20,17 @@ const useStyles = makeStyles(
20
20
  },
21
21
  containerSizeSmall: {
22
22
  flexFlow: 'unset',
23
+ overflow: 'hidden',
23
24
  '& svg': {
24
25
  width: responsiveVal(24, 28),
25
26
  height: responsiveVal(24, 28),
26
27
  strokeWidth: 1.4,
27
28
  },
29
+ '& > *': {
30
+ overflow: 'hidden',
31
+ whiteSpace: 'nowrap',
32
+ textOverflow: 'ellipsis',
33
+ },
28
34
  },
29
35
  containerGutterTop: {
30
36
  marginTop: theme.spacings.xl,
@@ -55,6 +55,7 @@ const useStyles = makeStyles(
55
55
  )
56
56
 
57
57
  export type LayoutDefaultProps = {
58
+ className?: string
58
59
  header: React.ReactNode
59
60
  footer: React.ReactNode
60
61
  menuFab?: React.ReactNode
@@ -64,14 +65,14 @@ export type LayoutDefaultProps = {
64
65
  } & UseStyles<typeof useStyles>
65
66
 
66
67
  export function LayoutDefault(props: LayoutDefaultProps) {
67
- const { children, header, footer, menuFab, cartFab, noSticky } = props
68
+ const { children, header, footer, menuFab, cartFab, noSticky, className } = props
68
69
  const classes = useStyles(props)
69
70
 
70
71
  const offset = useScrollOffset().y
71
72
  const scrollWithOffset = useTransform(useViewportScroll().scrollY, (y) => y + offset)
72
73
 
73
74
  return (
74
- <div className={classes.root}>
75
+ <div className={clsx(classes.root, className)}>
75
76
  <LayoutProvider scroll={scrollWithOffset}>
76
77
  <header className={clsx(classes.header, !noSticky && classes.headerSticky)}>
77
78
  {header}
@@ -8,7 +8,7 @@ export type { LayoutOverlayVariant } from './LayoutOverlayBase'
8
8
  export type LayoutOverlayProps = SetOptional<LayoutOverlayBaseProps, 'variantSm' | 'variantMd'>
9
9
 
10
10
  export function LayoutOverlay(props: LayoutOverlayProps) {
11
- const { children, variantSm = 'bottom', variantMd = 'right', classes } = props
11
+ const { children, variantSm = 'bottom', variantMd = 'right', classes, ...otherProps } = props
12
12
 
13
13
  const scrollSnapTypeSm: ScrollSnapType =
14
14
  variantSm === 'left' || variantSm === 'right' ? 'inline mandatory' : 'block proximity'
@@ -17,7 +17,12 @@ export function LayoutOverlay(props: LayoutOverlayProps) {
17
17
 
18
18
  return (
19
19
  <ScrollerProvider scrollSnapTypeSm={scrollSnapTypeSm} scrollSnapTypeMd={scrollSnapTypeMd}>
20
- <LayoutOverlayBase variantMd={variantMd} variantSm={variantSm} classes={classes}>
20
+ <LayoutOverlayBase
21
+ variantMd={variantMd}
22
+ variantSm={variantSm}
23
+ classes={classes}
24
+ {...otherProps}
25
+ >
21
26
  {children}
22
27
  </LayoutOverlayBase>
23
28
  </ScrollerProvider>
@@ -1,7 +1,7 @@
1
- import { usePageContext, usePageRouter, useScrollOffset } from '@graphcommerce/framer-next-pages'
1
+ import { useGo, usePageContext, useScrollOffset } from '@graphcommerce/framer-next-pages'
2
2
  import { Scroller, useScrollerContext, useScrollTo } from '@graphcommerce/framer-scroller'
3
3
  import { useElementScroll, useIsomorphicLayoutEffect } from '@graphcommerce/framer-utils'
4
- import { makeStyles, Theme, ClickAwayListener } from '@material-ui/core'
4
+ import { makeStyles, Theme, capitalize, styled } from '@material-ui/core'
5
5
  import { m, useDomEvent, useMotionValue, usePresence, useTransform } from 'framer-motion'
6
6
  import React, { useCallback, useEffect, useRef } from 'react'
7
7
  import LayoutProvider from '../../Layout/components/LayoutProvider'
@@ -72,92 +72,43 @@ const useStyles = makeStyles(
72
72
  height: '100vh',
73
73
  },
74
74
  },
75
- beforeOverlay: {
76
- gridArea: 'beforeOverlay',
77
- scrollSnapAlign: 'start',
78
- display: 'grid',
79
- alignContent: 'end',
80
- },
81
- beforeOverlayVariantSmRight: {
82
- [theme.breakpoints.down('sm')]: {
83
- width: '100vw',
84
- },
85
- },
86
- beforeOverlayVariantMdRight: {
87
- [theme.breakpoints.up('md')]: {
88
- width: '100vw',
89
- },
90
- },
91
75
 
92
- beforeOverlayVariantSmLeft: {
93
- [theme.breakpoints.down('sm')]: {
94
- width: '100vw',
95
- },
96
- },
97
- beforeOverlayVariantMdLeft: {
98
- [theme.breakpoints.up('md')]: {
99
- width: '100vw',
100
- },
101
- },
76
+ // Overlay pane styles
77
+ overlayPane: {},
102
78
 
103
- beforeOverlayVariantMdBottom: {
104
- [theme.breakpoints.up('md')]: {
105
- height: '100vh',
106
- },
107
- },
108
- beforeOverlayVariantSmBottom: {
79
+ overlaySizeSmFloating: {
109
80
  [theme.breakpoints.down('sm')]: {
110
- height: '100vh',
111
- '@supports (-webkit-touch-callout: none)': {
112
- height: '-webkit-fill-available',
113
- },
81
+ padding: `${theme.page.vertical} ${theme.page.horizontal}`,
114
82
  },
115
83
  },
116
- overlay: {
117
- pointerEvents: 'none',
118
- gridArea: 'overlay',
119
- scrollSnapAlign: 'start',
120
- minHeight: '100vh',
121
- '@supports (-webkit-touch-callout: none)': {
122
- minHeight: '-webkit-fill-available',
84
+ overlaySizeMdFloating: {
85
+ [theme.breakpoints.up('md')]: {
86
+ padding: `${theme.page.vertical} ${theme.page.horizontal}`,
123
87
  },
124
88
  },
125
- overlayVariantSmBottom: {
89
+ overlayPaneVariantSmBottom: {
126
90
  [theme.breakpoints.down('sm')]: {
127
- marginTop: `calc(${theme.appShell.headerHeightSm} * 0.5 * -1)`,
128
- paddingTop: `calc(${theme.appShell.headerHeightSm} * 0.5)`,
129
- display: 'grid',
91
+ borderTopLeftRadius: theme.shape.borderRadius * 3,
92
+ borderTopRightRadius: theme.shape.borderRadius * 3,
130
93
  },
131
94
  },
132
- overlayVariantMdBottom: {
95
+ overlayPaneVariantMdBottom: {
133
96
  [theme.breakpoints.up('md')]: {
134
- marginTop: `calc(${theme.appShell.headerHeightMd} + (${theme.appShell.appBarHeightMd} - ${theme.appShell.appBarInnerHeightMd}) * 0.5)`,
135
- paddingTop: `calc(${theme.appShell.headerHeightMd} + (${theme.appShell.appBarHeightMd} - ${theme.appShell.appBarInnerHeightMd}) * -0.5)`,
136
- display: 'grid',
97
+ borderTopLeftRadius: theme.shape.borderRadius * 4,
98
+ borderTopRightRadius: theme.shape.borderRadius * 4,
137
99
  },
138
100
  },
139
- overlayPane: {
140
- pointerEvents: 'all',
141
- backgroundColor: theme.palette.background.paper,
142
- boxShadow: theme.shadows[24],
143
- minWidth: 'min(800px, 90vw)',
144
- scrollSnapAlign: 'end',
145
-
146
- paddingBottom: 56,
147
- },
148
- overlayPaneVariantSmBottom: {
101
+ overlayPaneSizeSmFloating: {
149
102
  [theme.breakpoints.down('sm')]: {
150
- borderTopLeftRadius: theme.shape.borderRadius * 3,
151
- borderTopRightRadius: theme.shape.borderRadius * 3,
103
+ borderRadius: theme.shape.borderRadius * 3,
152
104
  },
153
105
  },
154
- overlayPaneVariantMdBottom: {
106
+ overlayPaneSizeMdFloating: {
155
107
  [theme.breakpoints.up('md')]: {
156
- borderTopLeftRadius: theme.shape.borderRadius * 3,
157
- borderTopRightRadius: theme.shape.borderRadius * 3,
108
+ borderRadius: theme.shape.borderRadius * 4,
158
109
  },
159
110
  },
160
- overlayPaneVariantSmLeft: {
111
+ overlayPaneSmVariantSizeLeftFull: {
161
112
  [theme.breakpoints.down('sm')]: {
162
113
  paddingBottom: 1,
163
114
  minHeight: '100vh',
@@ -166,7 +117,7 @@ const useStyles = makeStyles(
166
117
  },
167
118
  },
168
119
  },
169
- overlayPaneVariantMdLeft: {
120
+ overlayPaneMdVariantSizeLeftFull: {
170
121
  [theme.breakpoints.up('md')]: {
171
122
  paddingBottom: 1,
172
123
  minHeight: '100vh',
@@ -175,7 +126,7 @@ const useStyles = makeStyles(
175
126
  },
176
127
  },
177
128
  },
178
- overlayPaneVariantSmRight: {
129
+ overlayPaneSmVariantSizeRightFull: {
179
130
  [theme.breakpoints.down('sm')]: {
180
131
  paddingBottom: 1,
181
132
  minHeight: '100vh',
@@ -184,7 +135,7 @@ const useStyles = makeStyles(
184
135
  },
185
136
  },
186
137
  },
187
- overlayPaneVariantMdRight: {
138
+ overlayPaneMdVariantSizeRightFull: {
188
139
  [theme.breakpoints.up('md')]: {
189
140
  paddingBottom: 1,
190
141
  minHeight: '100vh',
@@ -213,33 +164,63 @@ const useStyles = makeStyles(
213
164
  )
214
165
 
215
166
  export type LayoutOverlayVariant = 'left' | 'bottom' | 'right'
167
+ export type LayoutOverlaySize = 'floating' | 'minimal' | 'full'
168
+ export type LayoutOverlayAlign = 'start' | 'end' | 'center' | 'stretch'
216
169
 
217
- export type LayoutOverlayBaseProps = {
218
- children?: React.ReactNode
170
+ type StyleProps = {
219
171
  variantSm: LayoutOverlayVariant
220
172
  variantMd: LayoutOverlayVariant
221
- } & UseStyles<typeof useStyles>
173
+ sizeSm?: LayoutOverlaySize
174
+ sizeMd?: LayoutOverlaySize
175
+ justifySm?: LayoutOverlayAlign
176
+ justifyMd?: LayoutOverlayAlign
177
+ }
222
178
 
223
- export enum OverlayPosition {
179
+ export type LayoutOverlayBaseProps = {
180
+ children?: React.ReactNode
181
+ className?: string
182
+ } & StyleProps &
183
+ UseStyles<typeof useStyles>
184
+
185
+ enum OverlayPosition {
224
186
  UNOPENED = -1,
225
187
  OPENED = 1,
226
188
  CLOSED = 0,
227
189
  }
228
190
 
229
191
  export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
230
- const { children, variantSm, variantMd } = props
231
- const { scrollerRef } = useScrollerContext()
192
+ const {
193
+ children,
194
+ variantSm,
195
+ variantMd,
196
+ classes: _classes,
197
+ className,
198
+ sizeSm = 'full',
199
+ sizeMd = 'full',
200
+ justifySm = 'stretch',
201
+ justifyMd = 'stretch',
202
+ } = props
203
+
204
+ const { scrollerRef, snap } = useScrollerContext()
232
205
  const positions = useOverlayPosition()
233
206
  const scrollTo = useScrollTo()
234
207
  const [isPresent, safeToRemove] = usePresence()
208
+ const beforeRef = useRef<HTMLDivElement>(null)
235
209
 
236
210
  const { closeSteps, active, direction } = usePageContext()
237
- const pageRouter = usePageRouter()
211
+ const close = useGo(closeSteps * -1)
238
212
 
239
213
  const position = useMotionValue<OverlayPosition>(OverlayPosition.UNOPENED)
240
214
 
241
- const classes = useStyles(props)
242
- const className = classesPicker(classes, { variantSm, variantMd })
215
+ const classes = useStyles({ classes: _classes, sizeSm, sizeMd, justifySm, justifyMd })
216
+ const clsName = classesPicker(classes, {
217
+ variantSm,
218
+ variantMd,
219
+ sizeSm,
220
+ sizeMd,
221
+ smVariantSize: `${variantSm}${capitalize(sizeSm)}`,
222
+ mdVariantSize: `${variantMd}${capitalize(sizeMd)}`,
223
+ })
243
224
 
244
225
  const overlayRef = useRef<HTMLDivElement>(null)
245
226
 
@@ -286,7 +267,6 @@ export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
286
267
  // When the overlay is closed by navigating away, we're closing the overlay.
287
268
  useEffect(() => {
288
269
  if (isPresent) return
289
-
290
270
  position.set(OverlayPosition.CLOSED)
291
271
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
292
272
  scrollTo({
@@ -299,9 +279,8 @@ export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
299
279
  const closeOverlay = useCallback(() => {
300
280
  if (position.get() !== OverlayPosition.OPENED) return
301
281
  position.set(OverlayPosition.CLOSED)
302
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
303
- pageRouter.go(closeSteps * -1)
304
- }, [closeSteps, pageRouter, position])
282
+ close()
283
+ }, [close, position])
305
284
 
306
285
  // Handle escape key
307
286
  const windowRef = useRef(typeof window !== 'undefined' ? window : null)
@@ -331,25 +310,96 @@ export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
331
310
  )
332
311
 
333
312
  const onClickAway = useCallback(
334
- (event: React.MouseEvent<Document>) => {
335
- if (event.target === document.body && event.type === 'click') return
336
- closeOverlay()
313
+ (event: React.MouseEvent<HTMLDivElement>) => {
314
+ const isTarget = event.target === scrollerRef.current || event.target === beforeRef.current
315
+ if (isTarget && snap.get()) closeOverlay()
337
316
  },
338
- [closeOverlay],
317
+ [closeOverlay, scrollerRef, snap],
318
+ )
319
+
320
+ const Overlay = styled('div')(
321
+ ({ theme }) => ({
322
+ display: 'grid',
323
+ pointerEvents: 'none',
324
+ gridArea: 'overlay',
325
+ scrollSnapAlign: 'start',
326
+
327
+ [theme.breakpoints.down('sm')]: {
328
+ justifyContent: justifySm,
329
+ alignItems: justifySm,
330
+
331
+ ...(variantSm === 'bottom' && {
332
+ marginTop: `calc(${theme.appShell.headerHeightSm} * 0.5 * -1)`,
333
+ paddingTop: `calc(${theme.appShell.headerHeightSm} * 0.5)`,
334
+ }),
335
+ },
336
+ [theme.breakpoints.up('md')]: {
337
+ justifyContent: justifyMd,
338
+ alignItems: justifyMd,
339
+
340
+ ...(variantMd === 'bottom' && {
341
+ marginTop: `calc(${theme.appShell.headerHeightMd} + (${theme.appShell.appBarHeightMd} - ${theme.appShell.appBarInnerHeightMd}) * 0.5)`,
342
+ paddingTop: `calc(${theme.appShell.headerHeightMd} + (${theme.appShell.appBarHeightMd} - ${theme.appShell.appBarInnerHeightMd}) * -0.5)`,
343
+ display: 'grid',
344
+ }),
345
+ },
346
+ }),
347
+ { name: 'Overlay' },
348
+ )
349
+
350
+ const OverlayPane = styled('div')(
351
+ ({ theme }) => ({
352
+ pointerEvents: 'all',
353
+ backgroundColor: theme.palette.background.paper,
354
+ boxShadow: theme.shadows[24],
355
+ // scrollSnapAlign: 'end',
356
+ [theme.breakpoints.down('sm')]: {
357
+ minWidth: '80vw',
358
+ ...((sizeSm === 'full' || sizeSm === 'minimal') && { paddingBottom: 56 }),
359
+ ...(variantSm === 'bottom' && sizeSm === 'full' && { minHeight: 'calc(100vh - 56px)' }),
360
+ },
361
+ [theme.breakpoints.up('md')]: {
362
+ ...(variantMd === 'bottom' && sizeMd === 'full' && { minHeight: '100vh' }),
363
+ ...(sizeMd === 'full' && { minWidth: 'max(600px, 50vw)' }),
364
+ },
365
+ }),
366
+ { name: 'OverlayPane' },
367
+ )
368
+
369
+ const BeforeOverlay = styled('div')(
370
+ ({ theme }) => ({
371
+ gridArea: 'beforeOverlay',
372
+ scrollSnapAlign: 'start',
373
+ display: 'grid',
374
+ alignContent: 'end',
375
+
376
+ [theme.breakpoints.down('sm')]: {
377
+ ...((variantSm === 'left' || variantSm === 'right') && { width: '100vw' }),
378
+ ...(variantSm === 'bottom' && {
379
+ height: '100vh',
380
+ '@supports (-webkit-touch-callout: none)': {
381
+ height: '-webkit-fill-available',
382
+ },
383
+ }),
384
+ },
385
+ [theme.breakpoints.up('md')]: {
386
+ ...((variantMd === 'left' || variantMd === 'right') && { width: '100vw' }),
387
+ ...(variantSm === 'bottom' && { height: '100vh' }),
388
+ },
389
+ }),
390
+ { name: 'BeforeOverlay' },
339
391
  )
340
392
 
341
393
  return (
342
394
  <>
343
- <m.div {...className('backdrop')} style={{ opacity: positions.open.visible }} />
344
- <Scroller {...className('root')} grid={false} hideScrollbar>
345
- <div {...className('beforeOverlay')} />
346
- <div {...className('overlay')} ref={overlayRef}>
347
- <ClickAwayListener onClickAway={onClickAway}>
348
- <div {...className('overlayPane')}>
349
- <LayoutProvider scroll={scrollWithoffset}>{children}</LayoutProvider>
350
- </div>
351
- </ClickAwayListener>
352
- </div>
395
+ <m.div {...clsName('backdrop')} style={{ opacity: positions.open.visible }} />
396
+ <Scroller {...clsName('root')} grid={false} hideScrollbar onClick={onClickAway}>
397
+ <BeforeOverlay onClick={onClickAway} ref={beforeRef} />
398
+ <Overlay {...clsName('overlay')} ref={overlayRef}>
399
+ <OverlayPane {...clsName('overlayPane', className)}>
400
+ <LayoutProvider scroll={scrollWithoffset}>{children}</LayoutProvider>
401
+ </OverlayPane>
402
+ </Overlay>
353
403
  </Scroller>
354
404
  </>
355
405
  )
@@ -0,0 +1,41 @@
1
+ import { ParsedUrlQuery } from 'querystring'
2
+ import { useRouter } from 'next/router'
3
+ import { useCallback } from 'react'
4
+ import { LayoutOverlay, LayoutOverlayProps } from '../components/LayoutOverlay'
5
+
6
+ export type LayoutOverlayState = Omit<LayoutOverlayProps, 'children' | 'classes'>
7
+
8
+ function useQueryState<T extends ParsedUrlQuery>(builder: (query: T) => T) {
9
+ const { query, replace } = useRouter()
10
+ const queryState = builder(query as T)
11
+
12
+ const setRouterQuery = (partialQuery: T) => {
13
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
14
+ replace({ query: { ...queryState, ...partialQuery } }, undefined, { shallow: true })
15
+ }
16
+ return [queryState, setRouterQuery] as const
17
+ }
18
+
19
+ export function useLayoutState() {
20
+ const [routerQuery, setRouterQuery] = useQueryState<LayoutOverlayState>(
21
+ useCallback(
22
+ ({ sizeMd, sizeSm, justifyMd, justifySm, variantMd, variantSm }) => ({
23
+ sizeMd,
24
+ sizeSm,
25
+ justifyMd,
26
+ justifySm,
27
+ variantMd,
28
+ variantSm,
29
+ }),
30
+ [],
31
+ ),
32
+ )
33
+
34
+ return [routerQuery, setRouterQuery] as const
35
+ }
36
+
37
+ export function LayoutOverlayDemo({ children }: { children?: React.ReactNode }) {
38
+ const [layout] = useLayoutState()
39
+
40
+ return <LayoutOverlay {...layout}>{children}</LayoutOverlay>
41
+ }
package/Styles/index.tsx CHANGED
@@ -1,3 +1,8 @@
1
1
  export type UseStyles<T extends (...args: never[]) => unknown> = {
2
2
  classes?: Partial<ReturnType<T>>
3
3
  }
4
+
5
+ export * from './breakpointVal'
6
+ export * from './responsiveVal'
7
+ export * from './classesPicker'
8
+ export * from './withTheme'
@@ -0,0 +1,51 @@
1
+ import { makeStyles, Theme, ThemeProvider } from '@material-ui/core'
2
+
3
+ const useStyles = makeStyles(
4
+ {
5
+ // These theme specific styles are copied from
6
+ // https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/CssBaseline/CssBaseline.js#L18-L24
7
+ root: (theme: Theme) => ({
8
+ color: theme.palette.text.primary,
9
+ ...theme.typography.body1,
10
+ backgroundColor: theme.palette.background.default,
11
+ }),
12
+ },
13
+ { name: 'Theme' },
14
+ )
15
+
16
+ /**
17
+ * It will provide a theme for the underlying tree and will set the color/font and backgroundColor
18
+ * for the child.
19
+ *
20
+ * To use it, wrap your component with it.
21
+ *
22
+ * Example:
23
+ *
24
+ * ```tsx
25
+ * const MyPage = () => {
26
+ * return <div>Your regular page content</div>
27
+ * }
28
+ * export default MyPage
29
+ * ```
30
+ *
31
+ * Becomes:
32
+ *
33
+ * ```tsx
34
+ * const MyPage = () => {
35
+ * return <div>Your regular page content, but now in darkMode</div>
36
+ * }
37
+ *
38
+ * export default withTheme(MyPage, darkTheme)
39
+ * ```
40
+ */
41
+ export function withTheme<P extends { className?: string }>(Component: React.FC<P>, theme: Theme) {
42
+ return (props: P) => {
43
+ const classes = useStyles(theme)
44
+
45
+ return (
46
+ <ThemeProvider theme={theme}>
47
+ <Component {...props} className={classes.root} />
48
+ </ThemeProvider>
49
+ )
50
+ }
51
+ }
package/index.ts CHANGED
@@ -106,9 +106,6 @@ export * from './Stepper/Stepper'
106
106
  export { default as Stepper } from './Stepper/Stepper'
107
107
  export { default as StyledBadge } from './StyledBadge'
108
108
  export * from './Styles'
109
- export * from './Styles/breakpointVal'
110
- export * from './Styles/responsiveVal'
111
- export * from './Styles/classesPicker'
112
109
  export * from './SvgImage'
113
110
  export { default as SvgImage } from './SvgImage'
114
111
  export { default as SvgImageSimple } from './SvgImage/SvgImageSimple'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphcommerce/next-ui",
3
- "version": "3.21.15",
3
+ "version": "3.23.0",
4
4
  "author": "",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -10,11 +10,11 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@apollo/client": "^3.5.6",
13
- "@graphcommerce/framer-next-pages": "^2.108.11",
14
- "@graphcommerce/framer-scroller": "^1.1.25",
15
- "@graphcommerce/framer-utils": "^2.103.20",
16
- "@graphcommerce/graphql": "^2.105.12",
17
- "@graphcommerce/image": "^2.105.11",
13
+ "@graphcommerce/framer-next-pages": "^2.109.2",
14
+ "@graphcommerce/framer-scroller": "^1.2.3",
15
+ "@graphcommerce/framer-utils": "^2.103.21",
16
+ "@graphcommerce/graphql": "^2.105.13",
17
+ "@graphcommerce/image": "^2.105.13",
18
18
  "@lingui/macro": "^3.13.0",
19
19
  "@material-ui/core": "^4.12.3",
20
20
  "@material-ui/lab": "^4.0.0-alpha.60",
@@ -25,7 +25,6 @@
25
25
  "next": "^12.0.7",
26
26
  "react": "^17.0.2",
27
27
  "react-dom": "^17.0.2",
28
- "react-focus-lock": "^2.7.1",
29
28
  "react-is": "^17.0.2",
30
29
  "react-schemaorg": "^2.0.0",
31
30
  "schema-dts": "^1.0.0",
@@ -33,7 +32,7 @@
33
32
  },
34
33
  "devDependencies": {
35
34
  "@graphcommerce/browserslist-config-pwa": "^3.0.3",
36
- "@graphcommerce/eslint-config-pwa": "^3.1.9",
35
+ "@graphcommerce/eslint-config-pwa": "^3.1.10",
37
36
  "@graphcommerce/prettier-config-pwa": "^3.0.5",
38
37
  "@graphcommerce/typescript-config-pwa": "^3.1.2",
39
38
  "@playwright/test": "^1.17.1",
@@ -52,5 +51,5 @@
52
51
  "project": "./tsconfig.json"
53
52
  }
54
53
  },
55
- "gitHead": "a9174584cfeb04807a72b6c609175c24e24ac818"
54
+ "gitHead": "dce525a80fd42cebe9af0b207c3bd27f89be9543"
56
55
  }