@graphcommerce/next-ui 4.20.0 → 4.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.
Files changed (41) hide show
  1. package/ActionCard/ActionCard.tsx +46 -12
  2. package/ActionCard/ActionCardList.tsx +17 -15
  3. package/ActionCard/ActionCardListForm.tsx +1 -2
  4. package/AnimatedRow/AnimatedRow.tsx +1 -0
  5. package/Blog/BlogHeader/BlogHeader.tsx +7 -1
  6. package/Blog/BlogListItem/BlogListItem.tsx +5 -1
  7. package/Blog/BlogTags/BlogTag.tsx +2 -3
  8. package/CHANGELOG.md +57 -0
  9. package/Footer/Footer.tsx +3 -2
  10. package/Form/Form.tsx +7 -1
  11. package/Form/FormActions.tsx +1 -1
  12. package/FramerScroller/SidebarGallery.tsx +1 -5
  13. package/IconSvg/IconSvg.tsx +4 -4
  14. package/Layout/components/LayoutHeaderClose.tsx +2 -0
  15. package/Layout/components/LayoutHeaderContent.tsx +3 -1
  16. package/LayoutDefault/components/LayoutDefault.tsx +3 -3
  17. package/LayoutOverlay/components/LayoutOverlay.tsx +2 -1
  18. package/LayoutParts/DesktopHeaderBadge.tsx +3 -3
  19. package/Navigation/components/NavigationItem.tsx +32 -18
  20. package/Navigation/components/NavigationList.tsx +21 -15
  21. package/Navigation/components/NavigationOverlay.tsx +65 -37
  22. package/Navigation/components/NavigationProvider.tsx +12 -30
  23. package/Navigation/hooks/useNavigation.ts +33 -6
  24. package/Overlay/components/Overlay.tsx +1 -2
  25. package/Overlay/components/OverlayBase.tsx +19 -19
  26. package/Overlay/hooks/useOverlayPosition.ts +6 -1
  27. package/Row/HeroBanner/HeroBanner.tsx +7 -2
  28. package/Row/ImageText/ImageText.tsx +10 -3
  29. package/Row/ImageTextBoxed/ImageTextBoxed.tsx +7 -1
  30. package/Row/ParagraphWithSidebarSlide/ParagraphWithSidebarSlide.tsx +4 -2
  31. package/Row/SpecialBanner/SpecialBanner.tsx +10 -2
  32. package/Snackbar/MessageSnackbarImpl.tsx +9 -5
  33. package/Stepper/Stepper.tsx +1 -1
  34. package/Styles/breakpointVal.tsx +1 -1
  35. package/TextInputNumber/TextInputNumber.tsx +5 -4
  36. package/Theme/MuiButton.ts +12 -3
  37. package/Theme/MuiFab.ts +2 -2
  38. package/ToggleButton/ToggleButton.tsx +15 -5
  39. package/hooks/index.ts +1 -0
  40. package/hooks/useMemoDeep.ts +15 -0
  41. package/package.json +6 -6
@@ -1,6 +1,7 @@
1
- import { SxProps, ButtonBase, Box, Theme } from '@mui/material'
1
+ import { SxProps, ButtonBase, Box, Theme, alpha } from '@mui/material'
2
2
  import React, { FormEvent } from 'react'
3
3
  import { extendableComponent } from '../Styles'
4
+ import { breakpointVal } from '../Styles/breakpointVal'
4
5
 
5
6
  export type ActionCardProps = {
6
7
  sx?: SxProps<Theme>
@@ -94,12 +95,32 @@ export function ActionCard(props: ActionCardProps) {
94
95
  border: `1px solid ${theme.palette.divider}`,
95
96
  borderBottomColor: `transparent`,
96
97
  '&:first-of-type': {
97
- borderTopLeftRadius: theme.shape.borderRadius,
98
- borderTopRightRadius: theme.shape.borderRadius,
98
+ ...breakpointVal(
99
+ 'borderTopLeftRadius',
100
+ theme.shape.borderRadius * 3,
101
+ theme.shape.borderRadius * 4,
102
+ theme.breakpoints.values,
103
+ ),
104
+ ...breakpointVal(
105
+ 'borderTopRightRadius',
106
+ theme.shape.borderRadius * 3,
107
+ theme.shape.borderRadius * 4,
108
+ theme.breakpoints.values,
109
+ ),
99
110
  },
100
111
  '&:last-of-type': {
101
- borderBottomLeftRadius: theme.shape.borderRadius,
102
- borderBottomRightRadius: theme.shape.borderRadius,
112
+ ...breakpointVal(
113
+ 'borderBottomLeftRadius',
114
+ theme.shape.borderRadius * 3,
115
+ theme.shape.borderRadius * 4,
116
+ theme.breakpoints.values,
117
+ ),
118
+ ...breakpointVal(
119
+ 'borderBottomRightRadius',
120
+ theme.shape.borderRadius * 3,
121
+ theme.shape.borderRadius * 4,
122
+ theme.breakpoints.values,
123
+ ),
103
124
  borderBottom: `1px solid ${theme.palette.divider}`,
104
125
  },
105
126
  }),
@@ -118,15 +139,27 @@ export function ActionCard(props: ActionCardProps) {
118
139
  selected &&
119
140
  ((theme) => ({
120
141
  border: `2px solid ${theme.palette.secondary.main} !important`,
121
- borderTopLeftRadius: theme.shape.borderRadius,
122
- borderTopRightRadius: theme.shape.borderRadius,
123
- borderBottomLeftRadius: theme.shape.borderRadius,
124
- borderBottomRightRadius: theme.shape.borderRadius,
142
+ boxShadow: `0 0 0 4px ${alpha(
143
+ theme.palette.secondary.main,
144
+ theme.palette.action.hoverOpacity,
145
+ )} !important`,
146
+ ...breakpointVal(
147
+ 'borderRadius',
148
+ theme.shape.borderRadius * 3,
149
+ theme.shape.borderRadius * 4,
150
+ theme.breakpoints.values,
151
+ ),
125
152
  padding: `${theme.spacings.xxs} ${theme.spacings.xs}`,
126
153
  })),
127
154
  disabled &&
128
155
  ((theme) => ({
129
- background: theme.palette.background.default,
156
+ '& *': {
157
+ opacity: theme.palette.action.disabledOpacity,
158
+ },
159
+ background: alpha(
160
+ theme.palette.action.disabledBackground,
161
+ theme.palette.action.disabledOpacity / 10,
162
+ ),
130
163
  })),
131
164
 
132
165
  ...(Array.isArray(sx) ? sx : [sx]),
@@ -156,10 +189,11 @@ export function ActionCard(props: ActionCardProps) {
156
189
  {details && (
157
190
  <Box
158
191
  className={classes.details}
159
- sx={{
192
+ sx={(theme) => ({
193
+ typography: 'body2',
160
194
  gridArea: 'details',
161
195
  color: 'text.secondary',
162
- }}
196
+ })}
163
197
  >
164
198
  {details}
165
199
  </Box>
@@ -1,8 +1,6 @@
1
- import { Alert, Box, FormHelperText } from '@mui/material'
2
- import { AnimatePresence } from 'framer-motion'
1
+ import { Alert, Box } from '@mui/material'
3
2
  import React from 'react'
4
3
  import { isFragment } from 'react-is'
5
- import { AnimatedRow } from '../AnimatedRow/AnimatedRow'
6
4
  import { ActionCardProps } from './ActionCard'
7
5
 
8
6
  type MultiSelect = {
@@ -67,7 +65,7 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
67
65
  }
68
66
 
69
67
  type ActionCardLike = React.ReactElement<
70
- Pick<ActionCardProps, 'value' | 'selected' | 'disabled' | 'onClick'>
68
+ Pick<ActionCardProps, 'value' | 'selected' | 'disabled' | 'onClick' | 'hidden'>
71
69
  >
72
70
  function isActionCardLike(el: React.ReactElement): el is ActionCardLike {
73
71
  const hasValue = (el as ActionCardLike).props.value
@@ -113,18 +111,14 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
113
111
  borderRight: 2,
114
112
  borderLeftColor: 'error.main',
115
113
  borderRightColor: 'error.main',
116
- paddingLeft: theme.spacings.xs,
117
- paddingRight: theme.spacings.xs,
118
114
  },
119
115
  '& > div:first-of-type.ActionCard-root': {
120
116
  borderTop: 2,
121
117
  borderTopColor: 'error.main',
122
- paddingTop: theme.spacings.xxs,
123
118
  },
124
119
  '& > div:last-of-type.ActionCard-root': {
125
120
  borderBottom: 2,
126
121
  borderBottomColor: 'error.main',
127
- paddingBottom: theme.spacings.xxs,
128
122
  },
129
123
  })),
130
124
  ]}
@@ -132,6 +126,7 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
132
126
  {childReactNodes.map((child) =>
133
127
  React.cloneElement(child, {
134
128
  onClick: handleChange,
129
+ hidden: !!value && value !== child.props.value,
135
130
  selected:
136
131
  child.props.selected === undefined
137
132
  ? isValueSelected(child.props.value, value)
@@ -139,13 +134,20 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
139
134
  }),
140
135
  )}
141
136
  {error && (
142
- <Alert
143
- severity='error'
144
- variant='filled'
145
- sx={{ borderStartStartRadius: 0, borderStartEndRadius: 0 }}
146
- >
147
- {errorMessage}
148
- </Alert>
137
+ <Box component='span'>
138
+ <Alert
139
+ severity='error'
140
+ variant='standard'
141
+ sx={(theme) => ({
142
+ marginTop: 0.5,
143
+ borderStartStartRadius: 0,
144
+ borderStartEndRadius: 0,
145
+ borderRadius: theme.shape.borderRadius * 1,
146
+ })}
147
+ >
148
+ {errorMessage}
149
+ </Alert>
150
+ </Box>
149
151
  )}
150
152
  </Box>
151
153
  )
@@ -34,7 +34,7 @@ export function ActionCardListForm<T extends ActionCardItemBase>(
34
34
  control={control}
35
35
  name={name}
36
36
  rules={{ required, ...rules, validate: (v) => (v ? true : errorMessage) }}
37
- render={({ field: { onChange, value, onBlur, ref }, fieldState, formState }) => (
37
+ render={({ field: { onChange, value, ref }, fieldState, formState }) => (
38
38
  <ActionCardList
39
39
  required
40
40
  value={value}
@@ -49,7 +49,6 @@ export function ActionCardListForm<T extends ActionCardItemBase>(
49
49
  key={item.value}
50
50
  value={item.value}
51
51
  selected={value === item.value}
52
- hidden={!!value && value !== item.value}
53
52
  onReset={(e) => {
54
53
  e.preventDefault()
55
54
  onChange(null)
@@ -9,6 +9,7 @@ export type AnimatedRowProps = Omit<
9
9
 
10
10
  const StyledDiv = styled(m.div)({})
11
11
 
12
+ /** @deprecated Should be replaced with Box component */
12
13
  export function AnimatedRow(props: AnimatedRowProps) {
13
14
  return (
14
15
  <StyledDiv
@@ -1,6 +1,7 @@
1
1
  import { Box, SxProps, Theme } from '@mui/material'
2
2
  import React from 'react'
3
3
  import { extendableComponent } from '../../Styles'
4
+ import { breakpointVal } from '../../Styles/breakpointVal'
4
5
  import { responsiveVal } from '../../Styles/responsiveVal'
5
6
 
6
7
  export type BlogHeaderProps = {
@@ -24,7 +25,12 @@ export function BlogHeader(props: BlogHeaderProps) {
24
25
  margin: `0 auto`,
25
26
  marginBottom: theme.spacings.md,
26
27
  '& img': {
27
- borderRadius: responsiveVal(theme.shape.borderRadius * 2, theme.shape.borderRadius * 3),
28
+ ...breakpointVal(
29
+ 'borderRadius',
30
+ theme.shape.borderRadius * 2,
31
+ theme.shape.borderRadius * 3,
32
+ theme.breakpoints.values,
33
+ ),
28
34
  },
29
35
  }),
30
36
  ...(Array.isArray(sx) ? sx : [sx]),
@@ -2,6 +2,7 @@ import { Box, Link, SxProps, Theme, Typography } from '@mui/material'
2
2
  import PageLink from 'next/link'
3
3
  import React from 'react'
4
4
  import { extendableComponent } from '../../Styles'
5
+ import { breakpointVal } from '../../Styles/breakpointVal'
5
6
  import { responsiveVal } from '../../Styles/responsiveVal'
6
7
  import { useDateTimeFormat } from '../../hooks'
7
8
 
@@ -43,12 +44,15 @@ export function BlogListItem(props: BlogListItemProps) {
43
44
  className={classes.asset}
44
45
  sx={(theme) => ({
45
46
  display: 'grid',
47
+ alignContent: 'center',
46
48
  overflow: 'hidden',
47
49
  height: '100%',
48
50
  width: '100%',
49
- borderRadius: responsiveVal(
51
+ ...breakpointVal(
52
+ 'borderRadius',
50
53
  theme.shape.borderRadius * 2,
51
54
  theme.shape.borderRadius * 3,
55
+ theme.breakpoints.values,
52
56
  ),
53
57
  '& img': {
54
58
  height: '100% !important',
@@ -15,9 +15,8 @@ export function BlogTag(props: BlogTagsProps) {
15
15
  label={title}
16
16
  sx={[
17
17
  {
18
- marginRight: '8px',
19
- borderRadius: '4px',
20
- fontSize: '14px',
18
+ marginRight: 3,
19
+ borderRadius: 2,
21
20
  },
22
21
  ...(Array.isArray(sx) ? sx : [sx]),
23
22
  ]}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.23.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1620](https://github.com/graphcommerce-org/graphcommerce/pull/1620) [`755d2cf83`](https://github.com/graphcommerce-org/graphcommerce/commit/755d2cf83343a5ad3d61063eff595d821de360aa) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Add spacing feature to navItems
8
+
9
+ * [#1618](https://github.com/graphcommerce-org/graphcommerce/pull/1618) [`dc7f2dda4`](https://github.com/graphcommerce-org/graphcommerce/commit/dc7f2dda40ff8572fc11161de6eb62ca13e720dd) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Remove prefetch from navigation links
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies []:
14
+ - @graphcommerce/framer-scroller@2.1.34
15
+
16
+ ## 4.22.0
17
+
18
+ ### Minor Changes
19
+
20
+ - [#1610](https://github.com/graphcommerce-org/graphcommerce/pull/1610) [`bb94e7045`](https://github.com/graphcommerce-org/graphcommerce/commit/bb94e7045460cb671c45d612a0833731d7c20c30) Thanks [@mikekeehnen](https://github.com/mikekeehnen)! - Previously when the persisted selected value didn't exist in the list of ActionCard items, all items would be hidden. In this fix we set the hidden prop in the ActionCardList component, where we check if the value exists, if not, we display all items
21
+
22
+ * [#1602](https://github.com/graphcommerce-org/graphcommerce/pull/1602) [`5f781a217`](https://github.com/graphcommerce-org/graphcommerce/commit/5f781a217ce63ed56bc1a9983487b04400a8a315) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Default styles and layout fixes
23
+
24
+ - Scaled icons and fonts down. Size in typography is now more gradual: https://graphcommerce.vercel.app/test/typography
25
+ - Multiple accessibility fixes. Missing button/input labels, and fixed spacing issues resulting in high % appropriately sized tap targets
26
+ - Replaced responsiveVal usage with better performaning breakpointVal where possible
27
+ - All buttons are now Pill by default.
28
+ - Cleaned up checkout styles
29
+
30
+ ### Patch Changes
31
+
32
+ - [#1601](https://github.com/graphcommerce-org/graphcommerce/pull/1601) [`04708dacc`](https://github.com/graphcommerce-org/graphcommerce/commit/04708daccc213c6ea927bc67fa3bd0d5b1fad619) Thanks [@paales](https://github.com/paales)! - Navigation now uses a single `const selection = useNavigationSelection()` motionValue to control the state of the menu, to prevent excessive rerenders.
33
+
34
+ * [#1611](https://github.com/graphcommerce-org/graphcommerce/pull/1611) [`b0dc4e2e1`](https://github.com/graphcommerce-org/graphcommerce/commit/b0dc4e2e1982d502d38dd50a0f493396360a7a15) Thanks [@FrankHarland](https://github.com/FrankHarland)! - Fix overlay doule click
35
+
36
+ - [#1609](https://github.com/graphcommerce-org/graphcommerce/pull/1609) [`4a5286dfe`](https://github.com/graphcommerce-org/graphcommerce/commit/4a5286dfeaa1719e594a0078f274fbab53969c4e) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Solve issue where navigation back would happen twice when closing an overlay
37
+
38
+ * [#1601](https://github.com/graphcommerce-org/graphcommerce/pull/1601) [`d46d5ed0c`](https://github.com/graphcommerce-org/graphcommerce/commit/d46d5ed0cc5794391b7527fc17bbb68ec2212e33) Thanks [@paales](https://github.com/paales)! - Move to newer useScroll hook to watch body scroll, prevents deprecation warnings.
39
+
40
+ * Updated dependencies [[`5f781a217`](https://github.com/graphcommerce-org/graphcommerce/commit/5f781a217ce63ed56bc1a9983487b04400a8a315), [`01372b918`](https://github.com/graphcommerce-org/graphcommerce/commit/01372b918a291e01cbf5db40edcb40fb1c2af313)]:
41
+ - @graphcommerce/framer-next-pages@3.3.0
42
+ - @graphcommerce/framer-utils@3.2.0
43
+ - @graphcommerce/framer-scroller@2.1.33
44
+ - @graphcommerce/image@3.1.9
45
+
46
+ ## 4.21.0
47
+
48
+ ### Minor Changes
49
+
50
+ - [#1597](https://github.com/graphcommerce-org/graphcommerce/pull/1597) [`1f7ee6f6c`](https://github.com/graphcommerce-org/graphcommerce/commit/1f7ee6f6cfb28544439ed36e10929ac530d1b2b7) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Fix safari nav bug
51
+
52
+ ### Patch Changes
53
+
54
+ - Updated dependencies [[`707dbc73d`](https://github.com/graphcommerce-org/graphcommerce/commit/707dbc73d181204d88fdbbd2e09340e25b2b5f7b), [`5c5645e6e`](https://github.com/graphcommerce-org/graphcommerce/commit/5c5645e6eaf5314c063f05547707fcd4b34a8717)]:
55
+ - @graphcommerce/framer-utils@3.1.5
56
+ - @graphcommerce/framer-scroller@2.1.32
57
+ - @graphcommerce/framer-next-pages@3.2.5
58
+ - @graphcommerce/image@3.1.8
59
+
3
60
  ## 4.20.0
4
61
 
5
62
  ### Minor Changes
package/Footer/Footer.tsx CHANGED
@@ -43,10 +43,11 @@ export function Footer(props: FooterProps) {
43
43
  'social social'
44
44
  'links links'
45
45
  `,
46
- gap: theme.spacings.sm,
46
+ gap: theme.spacings.md,
47
47
  '& > *': { maxWidth: 'max-content' },
48
48
 
49
49
  [theme.breakpoints.up('sm')]: {
50
+ gap: theme.spacings.sm,
50
51
  gridTemplateAreas: `
51
52
  'social switcher'
52
53
  'links support'
@@ -70,7 +71,7 @@ export function Footer(props: FooterProps) {
70
71
  justifyContent: 'start',
71
72
  gridAutoFlow: 'column',
72
73
  gridArea: 'social',
73
- gap: { xs: `0 ${theme.spacings.xs}`, md: `0 ${theme.spacings.sm}` },
74
+ gap: { xs: `0 ${theme.spacings.xs}`, md: `0 ${theme.spacings.xs}` },
74
75
  '& > *': {
75
76
  minWidth: 'min-content',
76
77
  },
package/Form/Form.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import { darken, lighten, styled, Theme } from '@mui/material'
2
+ import { breakpointVal } from '../Styles/breakpointVal'
2
3
  import { responsiveVal } from '../Styles/responsiveVal'
3
4
  import { sx } from '../Theme/themeDefaults'
4
5
 
@@ -27,7 +28,12 @@ const styles = ({ theme, contained = false, background }: { theme: Theme } & For
27
28
  padding: `${theme.spacings.xxs} ${theme.spacings.sm}`,
28
29
  // paddingTop: theme.spacings.md,
29
30
  overflow: 'hidden',
30
- borderRadius: responsiveVal(theme.shape.borderRadius * 3, theme.shape.borderRadius * 4),
31
+ ...breakpointVal(
32
+ 'borderRadius',
33
+ theme.shape.borderRadius * 3,
34
+ theme.shape.borderRadius * 4,
35
+ theme.breakpoints.values,
36
+ ),
31
37
  },
32
38
  ])
33
39
 
@@ -6,5 +6,5 @@ export const FormActions = styled('div', { name: 'FormActions' })(({ theme }) =>
6
6
  justifyContent: 'center',
7
7
  display: 'grid',
8
8
  gridAutoFlow: 'column',
9
- gap: `calc(${theme.spacings.xxs} * 2)`,
9
+ gap: theme.spacings.sm,
10
10
  }))
@@ -292,11 +292,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
292
292
  },
293
293
  }}
294
294
  >
295
- <ScrollerDots
296
- layout='position'
297
- layoutDependency={zoomed}
298
- sx={{ backgroundColor: 'background.paper', boxShadow: 6 }}
299
- />
295
+ <ScrollerDots layout='position' layoutDependency={zoomed} />
300
296
  </Box>
301
297
  </MotionBox>
302
298
 
@@ -41,10 +41,10 @@ export type IconSvgProps = StyleProps &
41
41
  Pick<ComponentProps<'svg'>, 'className' | 'style'> & { sx?: SxProps<Theme> }
42
42
 
43
43
  export const sizes = {
44
- xs: rv(11, 13),
45
- small: rv(12, 16),
46
- medium: rv(22, 24),
47
- large: rv(24, 28),
44
+ xs: rv(11, 12),
45
+ small: rv(12, 15),
46
+ medium: rv(22, 23),
47
+ large: rv(24, 26),
48
48
  xl: rv(38, 62),
49
49
  xxl: rv(96, 148),
50
50
  } as const
@@ -1,4 +1,5 @@
1
1
  import { useGo, usePageContext } from '@graphcommerce/framer-next-pages'
2
+ import { i18n } from '@lingui/core'
2
3
  import { Fab } from '@mui/material'
3
4
  import { useState } from 'react'
4
5
  import { IconSvg, useIconSvgSize } from '../../IconSvg'
@@ -32,6 +33,7 @@ export function LayoutHeaderClose() {
32
33
  }}
33
34
  size='responsive'
34
35
  disabled={disabled}
36
+ aria-label={i18n._(/* i18n */ 'Close')}
35
37
  >
36
38
  <IconSvg src={iconClose} size='large' />
37
39
  </Fab>
@@ -144,7 +144,9 @@ export function LayoutHeaderContent(props: LayoutHeaderContentProps) {
144
144
  justifyContent: 'start',
145
145
  })}
146
146
  >
147
- <MotionDiv layout={layout}>{left}</MotionDiv>
147
+ <MotionDiv layout={layout} sx={{ display: 'grid' }}>
148
+ {left}
149
+ </MotionDiv>
148
150
  </Box>
149
151
  )}
150
152
  <Box
@@ -1,6 +1,6 @@
1
1
  import { useScrollOffset } from '@graphcommerce/framer-next-pages'
2
2
  import { Box, SxProps, Theme } from '@mui/material'
3
- import { useTransform, useViewportScroll } from 'framer-motion'
3
+ import { useTransform, useScroll } from 'framer-motion'
4
4
  import { LayoutProvider } from '../../Layout/components/LayoutProvider'
5
5
  import { extendableComponent } from '../../Styles'
6
6
  import { useFabSize } from '../../Theme'
@@ -40,7 +40,7 @@ export function LayoutDefault(props: LayoutDefaultProps) {
40
40
  } = props
41
41
 
42
42
  const scrollWithOffset = useTransform(
43
- [useViewportScroll().scrollY, useScrollOffset()],
43
+ [useScroll().scrollY, useScrollOffset()],
44
44
  ([y, offset]: number[]) => y + offset,
45
45
  )
46
46
 
@@ -110,7 +110,7 @@ export function LayoutDefault(props: LayoutDefaultProps) {
110
110
  [theme.breakpoints.up('sm')]: {
111
111
  padding: `0 ${theme.page.horizontal}`,
112
112
  position: 'sticky',
113
- marginTop: `calc(${theme.appShell.headerHeightMd} * -1 + calc(${fabIconSize} / 2))`,
113
+ marginTop: `calc(${theme.appShell.headerHeightMd} * -1 - calc(${fabIconSize} / 2))`,
114
114
  top: `calc(${theme.appShell.headerHeightMd} / 2 - (${fabIconSize} / 2))`,
115
115
  },
116
116
  [theme.breakpoints.down('md')]: {
@@ -1,6 +1,7 @@
1
1
  import { usePageContext, useGo, useScrollOffset } from '@graphcommerce/framer-next-pages'
2
2
  import { ScrollerProvider, ScrollSnapType } from '@graphcommerce/framer-scroller'
3
3
  import { useMotionValueValue } from '@graphcommerce/framer-utils'
4
+ import { useEventCallback } from '@mui/material'
4
5
  import { usePresence } from 'framer-motion'
5
6
  import type { SetOptional } from 'type-fest'
6
7
  import { OverlayBase, LayoutOverlayBaseProps } from '../../Overlay/components/OverlayBase'
@@ -28,7 +29,7 @@ export function LayoutOverlay(props: LayoutOverlayProps) {
28
29
  <OverlayBase
29
30
  active={active}
30
31
  direction={direction}
31
- onClosed={onCloseHandler}
32
+ onClosed={useEventCallback(() => isPresent && onCloseHandler())}
32
33
  offsetPageY={offsetPageY}
33
34
  variantMd={variantMd}
34
35
  variantSm={variantSm}
@@ -13,13 +13,13 @@ export function DesktopHeaderBadge(props: BadgeProps) {
13
13
  bgcolor: 'text.disabled',
14
14
  },
15
15
  '& .MuiBadge-anchorOriginTopRightCircular': {
16
- right: { xs: '3px', md: '8px' },
17
- top: { xs: '3px', md: '8px' },
16
+ right: { xs: '3px', md: '5px' },
17
+ top: { xs: '3px', md: '5px' },
18
18
  },
19
19
  '& .MuiBadge-badge': {
20
20
  typography: 'caption',
21
21
  borderRadius: '100%',
22
- padding: { xs: '3px', md: '6px' },
22
+ padding: { xs: '3px', md: '5px' },
23
23
  },
24
24
  },
25
25
  ...(Array.isArray(sx) ? sx : [sx]),
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
+ import { useMotionValueValue } from '@graphcommerce/framer-utils'
2
3
  import { Box, ListItemButton, styled, Theme, useEventCallback, useMediaQuery } from '@mui/material'
3
4
  import PageLink from 'next/link'
4
- import { useEffect } from 'react'
5
+ import React from 'react'
5
6
  import { IconSvg } from '../../IconSvg'
6
7
  import { extendableComponent } from '../../Styles/extendableComponent'
7
8
  import { iconChevronRight } from '../../icons'
@@ -10,7 +11,6 @@ import {
10
11
  isNavigationComponent,
11
12
  isNavigationHref,
12
13
  NavigationNode,
13
- NavigationPath,
14
14
  useNavigation,
15
15
  } from '../hooks/useNavigation'
16
16
  import type { NavigationList } from './NavigationList'
@@ -24,7 +24,7 @@ type OwnerState = {
24
24
  }
25
25
 
26
26
  type NavigationItemProps = NavigationNode & {
27
- parentPath: NavigationPath
27
+ parentPath: string
28
28
  idx: number
29
29
  NavigationList: typeof NavigationList
30
30
  } & OwnerState &
@@ -44,16 +44,27 @@ const { withState } = extendableComponent<OwnerState, typeof componentName, type
44
44
 
45
45
  const NavigationLI = styled('li')({ display: 'contents' })
46
46
 
47
- export function NavigationItem(props: NavigationItemProps) {
47
+ export const NavigationItem = React.memo<NavigationItemProps>((props) => {
48
48
  const { id, parentPath, idx, first, last, NavigationList, mouseEvent } = props
49
49
 
50
50
  const row = idx + 1
51
- const { selected, select, hideRootOnNavigate, onClose, animating } = useNavigation()
51
+ const { selection, hideRootOnNavigate, closing, animating } = useNavigation()
52
52
 
53
- const itemPath = [...parentPath, id]
54
- const isSelected = selected.slice(0, itemPath.length).join('/') === itemPath.join('/')
53
+ const itemPath = [...(parentPath ? parentPath.split(',') : []), id]
54
+
55
+ const isSelected = useMotionValueValue(
56
+ selection,
57
+ (s) => s !== false && s.slice(0, itemPath.length).join('/') === itemPath.join('/'),
58
+ )
59
+ const hidingRoot = useMotionValueValue(
60
+ selection,
61
+ (s) => s === false || (hideRootOnNavigate && s.length > 0),
62
+ )
63
+
64
+ const tabIndex = useMotionValueValue(selection, (s) =>
65
+ s !== false && s.join(',').includes(parentPath) ? undefined : -1,
66
+ )
55
67
 
56
- const hidingRoot = hideRootOnNavigate && selected.length > 0
57
68
  const hideItem = hidingRoot && itemPath.length === 1
58
69
 
59
70
  const column = hidingRoot ? itemPath.length - 1 : itemPath.length
@@ -61,8 +72,7 @@ export function NavigationItem(props: NavigationItemProps) {
61
72
 
62
73
  const onCloseHandler: React.MouseEventHandler<HTMLAnchorElement> = useEventCallback((e) => {
63
74
  if (!isNavigationHref(props)) return
64
- const { href } = props
65
- onClose?.(e, href)
75
+ closing.set(true)
66
76
  })
67
77
 
68
78
  const isDesktop = useMediaQuery<Theme>((theme) => theme.breakpoints.up('md'))
@@ -95,19 +105,19 @@ export function NavigationItem(props: NavigationItemProps) {
95
105
  : {},
96
106
  ]}
97
107
  disabled={isSelected}
98
- tabIndex={selected.join(',').includes(parentPath.join(',')) ? undefined : -1}
108
+ tabIndex={tabIndex}
99
109
  onClick={(e) => {
100
110
  e.preventDefault()
101
- if (!isSelected && animating.current === false) {
102
- select(itemPath)
111
+ if (!isSelected && animating.get() === false) {
112
+ selection.set(itemPath)
103
113
  }
104
114
  }}
105
115
  onMouseMove={
106
116
  itemPath.length > 1 && mouseEvent === 'hover'
107
117
  ? (e) => {
108
- if (isDesktop && animating.current === false && !isSelected) {
118
+ if (isDesktop && animating.get() === false && !isSelected) {
109
119
  e.preventDefault()
110
- setTimeout(() => select(itemPath), 0)
120
+ setTimeout(() => selection.set(itemPath), 0)
111
121
  }
112
122
  }
113
123
  : undefined
@@ -130,7 +140,7 @@ export function NavigationItem(props: NavigationItemProps) {
130
140
  <NavigationList
131
141
  items={childItems}
132
142
  selected={isSelected}
133
- parentPath={itemPath}
143
+ parentPath={itemPath.join(',')}
134
144
  mouseEvent={mouseEvent}
135
145
  />
136
146
  </NavigationLI>
@@ -141,7 +151,7 @@ export function NavigationItem(props: NavigationItemProps) {
141
151
  const { name, href } = props
142
152
  return (
143
153
  <NavigationLI sx={[hideItem && { display: 'none' }]} className={classes.li}>
144
- <PageLink href={href} passHref>
154
+ <PageLink href={href} passHref prefetch={false}>
145
155
  <ListItemButton
146
156
  className={classes.item}
147
157
  component='a'
@@ -150,7 +160,7 @@ export function NavigationItem(props: NavigationItemProps) {
150
160
  gridColumnStart: column,
151
161
  gap: theme.spacings.xxs,
152
162
  })}
153
- tabIndex={selected.join(',').includes(parentPath.join(',')) ? undefined : -1}
163
+ tabIndex={tabIndex}
154
164
  onClick={onCloseHandler}
155
165
  >
156
166
  <Box
@@ -183,4 +193,8 @@ export function NavigationItem(props: NavigationItemProps) {
183
193
  if (process.env.NODE_ENV !== 'production') throw Error('NavigationItem: unknown type')
184
194
 
185
195
  return null
196
+ })
197
+
198
+ if (process.env.NODE_ENV !== 'production') {
199
+ NavigationItem.displayName = 'NavigationItem'
186
200
  }