@graphcommerce/next-ui 3.21.14 → 3.22.2

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,5 +1,4 @@
1
1
  import { Container, makeStyles, Theme } from '@material-ui/core'
2
- import clsx from 'clsx'
3
2
  import React from 'react'
4
3
  import { UseStyles } from '../../Styles'
5
4
 
@@ -7,22 +6,18 @@ const useStyles = makeStyles(
7
6
  (theme: Theme) => ({
8
7
  root: {
9
8
  position: 'sticky',
9
+ top: theme.appShell.headerHeightSm,
10
10
  zIndex: 96,
11
- },
12
- fillMobileOnly: {
13
11
  [theme.breakpoints.up('md')]: {
14
12
  top: `${theme.page.vertical} !important`,
15
13
  },
16
14
  },
17
15
  }),
18
- {
19
- name: 'AppShellSticky',
20
- },
16
+ { name: 'AppShellSticky' },
21
17
  )
22
18
 
23
19
  type AppShellStickyBaseProps = {
24
20
  children: React.ReactNode
25
- headerFill?: 'mobile-only' | 'both'
26
21
  }
27
22
 
28
23
  type AppShellStickyProps = AppShellStickyBaseProps & UseStyles<typeof useStyles>
@@ -32,18 +27,11 @@ type AppShellStickyProps = AppShellStickyBaseProps & UseStyles<typeof useStyles>
32
27
  - determines top offset based on header height dynamically
33
28
  */
34
29
  export default function AppShellSticky(props: AppShellStickyProps) {
35
- const { children, headerFill = 'both' } = props
30
+ const { children } = props
36
31
  const classes = useStyles(props)
37
32
 
38
- // todo
39
- const top = 0
40
-
41
33
  return (
42
- <Container
43
- maxWidth={false}
44
- className={clsx(classes.root, headerFill === 'mobile-only' && classes.fillMobileOnly)}
45
- style={{ top }}
46
- >
34
+ <Container maxWidth={false} className={classes.root}>
47
35
  <>{children}</>
48
36
  </Container>
49
37
  )
@@ -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,60 @@
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.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)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * broder radius of drawer was too small on desktop ([f8b3962](https://github.com/ho-nl/m2-pwa/commit/f8b3962825972e6bc232387e0a2e801289fcc492))
12
+ * close button of bottom sheet spacing ([be33c20](https://github.com/ho-nl/m2-pwa/commit/be33c20fc8f41ad85d90bff15842738bc370b81e))
13
+ * regression where primary action wasn't visible ([66f8ed2](https://github.com/ho-nl/m2-pwa/commit/66f8ed20ea0728881be81994d49bd6c399f2e914))
14
+
15
+
16
+
17
+
18
+
19
+ ## [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)
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * overlay would have a height instead of minHeight ([07dba4b](https://github.com/ho-nl/m2-pwa/commit/07dba4b875a37beac2ab6a8afe50e6b7a7ba1bf9))
25
+
26
+
27
+
28
+
29
+
30
+ # [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)
31
+
32
+
33
+ ### Bug Fixes
34
+
35
+ * backbutton had wrong label ([c6d0b27](https://github.com/ho-nl/m2-pwa/commit/c6d0b2738e5de734af40bc632177dcc867e8e556))
36
+ * make sure we're able to close the overlay ([8d19fde](https://github.com/ho-nl/m2-pwa/commit/8d19fde07d51493acfdfaa97a19f61246d04d42a))
37
+
38
+
39
+ ### Features
40
+
41
+ * add support for minimal overlay size ([96e508a](https://github.com/ho-nl/m2-pwa/commit/96e508a94e23fe5b3ec523cddeb19b7b70f50034))
42
+ * added support for more positioning options for the overlay ([79eae9e](https://github.com/ho-nl/m2-pwa/commit/79eae9eb39513f5611103c4c745c3db99b11f15a))
43
+ * **framer-next-pages:** reduce rerenders when navigating to a new page ([5cf3301](https://github.com/ho-nl/m2-pwa/commit/5cf330130bb3527057da015e3c4a6fa295d7262e))
44
+
45
+
46
+
47
+
48
+
49
+ ## [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)
50
+
51
+
52
+ ### Bug Fixes
53
+
54
+ * make sure the filters are aligned properly on mobile ([4bfe978](https://github.com/ho-nl/m2-pwa/commit/4bfe978f095c1b9867608c138eccf3227b18d4e9))
55
+
56
+
57
+
58
+
59
+
6
60
  ## [3.21.13](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/next-ui@3.21.12...@graphcommerce/next-ui@3.21.13) (2021-12-23)
7
61
 
8
62
 
@@ -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,25 +1,36 @@
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'
6
8
 
7
9
  export function useShowClose() {
8
10
  const { overlayGroup } = usePageContext()
9
11
  return !!overlayGroup
10
12
  }
11
13
 
14
+ const useStyles = makeStyles((theme: Theme) => ({
15
+ close: {
16
+ marginLeft: `calc(${responsiveVal(12, 22)} * -1)`,
17
+ marginRight: `calc(${responsiveVal(12, 22)} * -1)`,
18
+ },
19
+ }))
20
+
12
21
  export default function LayoutHeaderClose() {
13
- const router = usePageRouter()
14
22
  const { closeSteps } = usePageContext()
23
+ const onClick = useGo(closeSteps * -1)
24
+ const classes = useStyles()
15
25
 
16
26
  return (
17
27
  <Button
18
28
  type='button'
19
- onClick={() => router.go(closeSteps * -1)}
29
+ onClick={onClick}
20
30
  aria-label='Close'
21
- variant='pill-link'
31
+ variant='text'
22
32
  startIcon={<SvgImageSimple src={iconClose} />}
33
+ className={classes.close}
23
34
  >
24
35
  Close
25
36
  </Button>
@@ -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,
@@ -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,61 @@ 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
+ } & StyleProps &
182
+ UseStyles<typeof useStyles>
183
+
184
+ enum OverlayPosition {
224
185
  UNOPENED = -1,
225
186
  OPENED = 1,
226
187
  CLOSED = 0,
227
188
  }
228
189
 
229
190
  export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
230
- const { children, variantSm, variantMd } = props
231
- const { scrollerRef } = useScrollerContext()
191
+ const {
192
+ children,
193
+ variantSm,
194
+ variantMd,
195
+ classes: _classes,
196
+ sizeSm = 'full',
197
+ sizeMd = 'full',
198
+ justifySm = 'stretch',
199
+ justifyMd = 'stretch',
200
+ } = props
201
+
202
+ const { scrollerRef, snap } = useScrollerContext()
232
203
  const positions = useOverlayPosition()
233
204
  const scrollTo = useScrollTo()
234
205
  const [isPresent, safeToRemove] = usePresence()
206
+ const beforeRef = useRef<HTMLDivElement>(null)
235
207
 
236
208
  const { closeSteps, active, direction } = usePageContext()
237
- const pageRouter = usePageRouter()
209
+ const close = useGo(closeSteps * -1)
238
210
 
239
211
  const position = useMotionValue<OverlayPosition>(OverlayPosition.UNOPENED)
240
212
 
241
- const classes = useStyles(props)
242
- const className = classesPicker(classes, { variantSm, variantMd })
213
+ const classes = useStyles({ classes: _classes, sizeSm, sizeMd, justifySm, justifyMd })
214
+ const className = classesPicker(classes, {
215
+ variantSm,
216
+ variantMd,
217
+ sizeSm,
218
+ sizeMd,
219
+ smVariantSize: `${variantSm}${capitalize(sizeSm)}`,
220
+ mdVariantSize: `${variantMd}${capitalize(sizeMd)}`,
221
+ })
243
222
 
244
223
  const overlayRef = useRef<HTMLDivElement>(null)
245
224
 
@@ -286,7 +265,6 @@ export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
286
265
  // When the overlay is closed by navigating away, we're closing the overlay.
287
266
  useEffect(() => {
288
267
  if (isPresent) return
289
-
290
268
  position.set(OverlayPosition.CLOSED)
291
269
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
292
270
  scrollTo({
@@ -299,9 +277,8 @@ export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
299
277
  const closeOverlay = useCallback(() => {
300
278
  if (position.get() !== OverlayPosition.OPENED) return
301
279
  position.set(OverlayPosition.CLOSED)
302
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
303
- pageRouter.go(closeSteps * -1)
304
- }, [closeSteps, pageRouter, position])
280
+ close()
281
+ }, [close, position])
305
282
 
306
283
  // Handle escape key
307
284
  const windowRef = useRef(typeof window !== 'undefined' ? window : null)
@@ -331,25 +308,96 @@ export function LayoutOverlayBase(props: LayoutOverlayBaseProps) {
331
308
  )
332
309
 
333
310
  const onClickAway = useCallback(
334
- (event: React.MouseEvent<Document>) => {
335
- if (event.target === document.body && event.type === 'click') return
336
- closeOverlay()
311
+ (event: React.MouseEvent<HTMLDivElement>) => {
312
+ const isTarget = event.target === scrollerRef.current || event.target === beforeRef.current
313
+ if (isTarget && snap.get()) closeOverlay()
337
314
  },
338
- [closeOverlay],
315
+ [closeOverlay, scrollerRef, snap],
316
+ )
317
+
318
+ const Overlay = styled('div')(
319
+ ({ theme }) => ({
320
+ display: 'grid',
321
+ pointerEvents: 'none',
322
+ gridArea: 'overlay',
323
+ scrollSnapAlign: 'start',
324
+
325
+ [theme.breakpoints.down('sm')]: {
326
+ justifyContent: justifySm,
327
+ alignItems: justifySm,
328
+
329
+ ...(variantSm === 'bottom' && {
330
+ marginTop: `calc(${theme.appShell.headerHeightSm} * 0.5 * -1)`,
331
+ paddingTop: `calc(${theme.appShell.headerHeightSm} * 0.5)`,
332
+ }),
333
+ },
334
+ [theme.breakpoints.up('md')]: {
335
+ justifyContent: justifyMd,
336
+ alignItems: justifyMd,
337
+
338
+ ...(variantMd === 'bottom' && {
339
+ marginTop: `calc(${theme.appShell.headerHeightMd} + (${theme.appShell.appBarHeightMd} - ${theme.appShell.appBarInnerHeightMd}) * 0.5)`,
340
+ paddingTop: `calc(${theme.appShell.headerHeightMd} + (${theme.appShell.appBarHeightMd} - ${theme.appShell.appBarInnerHeightMd}) * -0.5)`,
341
+ display: 'grid',
342
+ }),
343
+ },
344
+ }),
345
+ { name: 'Overlay' },
346
+ )
347
+
348
+ const OverlayPane = styled('div')(
349
+ ({ theme }) => ({
350
+ pointerEvents: 'all',
351
+ backgroundColor: theme.palette.background.paper,
352
+ boxShadow: theme.shadows[24],
353
+ // scrollSnapAlign: 'end',
354
+ [theme.breakpoints.down('sm')]: {
355
+ minWidth: '80vw',
356
+ ...((sizeSm === 'full' || sizeSm === 'minimal') && { paddingBottom: 56 }),
357
+ ...(variantSm === 'bottom' && sizeSm === 'full' && { minHeight: 'calc(100vh - 56px)' }),
358
+ },
359
+ [theme.breakpoints.up('md')]: {
360
+ ...(variantMd === 'bottom' && sizeMd === 'full' && { minHeight: '100vh' }),
361
+ ...(sizeMd === 'full' && { minWidth: 'max(600px, 50vw)' }),
362
+ },
363
+ }),
364
+ { name: 'OverlayPane' },
365
+ )
366
+
367
+ const BeforeOverlay = styled('div')(
368
+ ({ theme }) => ({
369
+ gridArea: 'beforeOverlay',
370
+ scrollSnapAlign: 'start',
371
+ display: 'grid',
372
+ alignContent: 'end',
373
+
374
+ [theme.breakpoints.down('sm')]: {
375
+ ...((variantSm === 'left' || variantSm === 'right') && { width: '100vw' }),
376
+ ...(variantSm === 'bottom' && {
377
+ height: '100vh',
378
+ '@supports (-webkit-touch-callout: none)': {
379
+ height: '-webkit-fill-available',
380
+ },
381
+ }),
382
+ },
383
+ [theme.breakpoints.up('md')]: {
384
+ ...((variantMd === 'left' || variantMd === 'right') && { width: '100vw' }),
385
+ ...(variantSm === 'bottom' && { height: '100vh' }),
386
+ },
387
+ }),
388
+ { name: 'BeforeOverlay' },
339
389
  )
340
390
 
341
391
  return (
342
392
  <>
343
393
  <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>
394
+ <Scroller {...className('root')} grid={false} hideScrollbar onClick={onClickAway}>
395
+ <BeforeOverlay onClick={onClickAway} ref={beforeRef} />
396
+ <Overlay {...className('overlay')} ref={overlayRef}>
397
+ <OverlayPane {...className('overlayPane')}>
398
+ <LayoutProvider scroll={scrollWithoffset}>{children}</LayoutProvider>
399
+ </OverlayPane>
400
+ </Overlay>
353
401
  </Scroller>
354
402
  </>
355
403
  )
@@ -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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphcommerce/next-ui",
3
- "version": "3.21.14",
3
+ "version": "3.22.2",
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.10",
14
- "@graphcommerce/framer-scroller": "^1.1.24",
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.2",
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": "ce4499b06791f3b2e54a7e88bfca40abbcd1401c"
54
+ "gitHead": "0553535bc06348d46a64c90e5330f8ff108c0cbc"
56
55
  }