@graphcommerce/next-ui 4.21.0 → 4.22.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.
- package/ActionCard/ActionCard.tsx +46 -12
- package/ActionCard/ActionCardList.tsx +17 -15
- package/ActionCard/ActionCardListForm.tsx +1 -2
- package/AnimatedRow/AnimatedRow.tsx +1 -0
- package/Blog/BlogHeader/BlogHeader.tsx +7 -1
- package/Blog/BlogListItem/BlogListItem.tsx +5 -1
- package/Blog/BlogTags/BlogTag.tsx +2 -3
- package/CHANGELOG.md +30 -0
- package/Footer/Footer.tsx +3 -2
- package/Form/Form.tsx +7 -1
- package/Form/FormActions.tsx +1 -1
- package/FramerScroller/SidebarGallery.tsx +1 -5
- package/IconSvg/IconSvg.tsx +4 -4
- package/Layout/components/LayoutHeaderClose.tsx +2 -0
- package/Layout/components/LayoutHeaderContent.tsx +3 -1
- package/LayoutDefault/components/LayoutDefault.tsx +3 -3
- package/LayoutOverlay/components/LayoutOverlay.tsx +2 -1
- package/LayoutParts/DesktopHeaderBadge.tsx +3 -3
- package/Navigation/components/NavigationItem.tsx +31 -17
- package/Navigation/components/NavigationList.tsx +21 -15
- package/Navigation/components/NavigationOverlay.tsx +47 -27
- package/Navigation/components/NavigationProvider.tsx +12 -30
- package/Navigation/hooks/useNavigation.ts +33 -6
- package/Overlay/components/Overlay.tsx +1 -2
- package/Overlay/components/OverlayBase.tsx +19 -19
- package/Overlay/hooks/useOverlayPosition.ts +6 -1
- package/Row/HeroBanner/HeroBanner.tsx +7 -2
- package/Row/ImageText/ImageText.tsx +10 -3
- package/Row/ImageTextBoxed/ImageTextBoxed.tsx +7 -1
- package/Row/ParagraphWithSidebarSlide/ParagraphWithSidebarSlide.tsx +4 -2
- package/Row/SpecialBanner/SpecialBanner.tsx +10 -2
- package/Snackbar/MessageSnackbarImpl.tsx +9 -5
- package/Stepper/Stepper.tsx +1 -1
- package/Styles/breakpointVal.tsx +1 -1
- package/TextInputNumber/TextInputNumber.tsx +5 -4
- package/Theme/MuiButton.ts +12 -3
- package/Theme/MuiFab.ts +2 -2
- package/ToggleButton/ToggleButton.tsx +15 -5
- package/hooks/index.ts +1 -0
- package/hooks/useMemoDeep.ts +15 -0
- package/package.json +5 -5
|
@@ -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
|
-
|
|
98
|
-
|
|
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
|
-
|
|
102
|
-
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
<
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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,
|
|
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)
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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',
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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
|
|
8
|
+
|
|
9
|
+
* [#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
|
|
10
|
+
|
|
11
|
+
- Scaled icons and fonts down. Size in typography is now more gradual: https://graphcommerce.vercel.app/test/typography
|
|
12
|
+
- Multiple accessibility fixes. Missing button/input labels, and fixed spacing issues resulting in high % appropriately sized tap targets
|
|
13
|
+
- Replaced responsiveVal usage with better performaning breakpointVal where possible
|
|
14
|
+
- All buttons are now Pill by default.
|
|
15
|
+
- Cleaned up checkout styles
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- [#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.
|
|
20
|
+
|
|
21
|
+
* [#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
|
|
22
|
+
|
|
23
|
+
- [#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
|
|
24
|
+
|
|
25
|
+
* [#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.
|
|
26
|
+
|
|
27
|
+
* Updated dependencies [[`5f781a217`](https://github.com/graphcommerce-org/graphcommerce/commit/5f781a217ce63ed56bc1a9983487b04400a8a315), [`01372b918`](https://github.com/graphcommerce-org/graphcommerce/commit/01372b918a291e01cbf5db40edcb40fb1c2af313)]:
|
|
28
|
+
- @graphcommerce/framer-next-pages@3.3.0
|
|
29
|
+
- @graphcommerce/framer-utils@3.2.0
|
|
30
|
+
- @graphcommerce/framer-scroller@2.1.33
|
|
31
|
+
- @graphcommerce/image@3.1.9
|
|
32
|
+
|
|
3
33
|
## 4.21.0
|
|
4
34
|
|
|
5
35
|
### 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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
package/Form/FormActions.tsx
CHANGED
|
@@ -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
|
|
package/IconSvg/IconSvg.tsx
CHANGED
|
@@ -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,
|
|
45
|
-
small: rv(12,
|
|
46
|
-
medium: rv(22,
|
|
47
|
-
large: rv(24,
|
|
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}
|
|
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,
|
|
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
|
-
[
|
|
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
|
|
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: '
|
|
17
|
-
top: { xs: '3px', md: '
|
|
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: '
|
|
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
|
|
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:
|
|
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
|
|
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 {
|
|
51
|
+
const { selection, hideRootOnNavigate, closing, animating } = useNavigation()
|
|
52
52
|
|
|
53
|
-
const itemPath = [...parentPath, id]
|
|
54
|
-
|
|
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
|
-
|
|
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={
|
|
108
|
+
tabIndex={tabIndex}
|
|
99
109
|
onClick={(e) => {
|
|
100
110
|
e.preventDefault()
|
|
101
|
-
if (!isSelected && animating.
|
|
102
|
-
|
|
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.
|
|
118
|
+
if (isDesktop && animating.get() === false && !isSelected) {
|
|
109
119
|
e.preventDefault()
|
|
110
|
-
setTimeout(() =>
|
|
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>
|
|
@@ -150,7 +160,7 @@ export function NavigationItem(props: NavigationItemProps) {
|
|
|
150
160
|
gridColumnStart: column,
|
|
151
161
|
gap: theme.spacings.xxs,
|
|
152
162
|
})}
|
|
153
|
-
tabIndex={
|
|
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
|
}
|
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
import { styled } from '@mui/material'
|
|
2
|
+
import React from 'react'
|
|
2
3
|
import { extendableComponent } from '../../Styles/extendableComponent'
|
|
3
|
-
import { NavigationNode
|
|
4
|
+
import { NavigationNode } from '../hooks/useNavigation'
|
|
4
5
|
import { NavigationItem, mouseEventPref } from './NavigationItem'
|
|
5
6
|
|
|
6
|
-
const NavigationUList = styled('ul')({
|
|
7
|
+
const NavigationUList = styled('ul')({
|
|
8
|
+
display: 'block',
|
|
9
|
+
position: 'absolute',
|
|
10
|
+
left: '-10000px',
|
|
11
|
+
top: '-10000px',
|
|
12
|
+
'&.selected': {
|
|
13
|
+
display: 'contents',
|
|
14
|
+
},
|
|
15
|
+
})
|
|
7
16
|
|
|
8
17
|
type NavigationItemsProps = {
|
|
9
|
-
parentPath?:
|
|
18
|
+
parentPath?: string
|
|
10
19
|
items: NavigationNode[]
|
|
11
20
|
selected?: boolean
|
|
12
21
|
} & mouseEventPref
|
|
13
22
|
|
|
14
23
|
type OwnerState = {
|
|
15
24
|
column: number
|
|
25
|
+
selected: boolean
|
|
16
26
|
}
|
|
17
27
|
|
|
18
28
|
const name = 'NavigationList'
|
|
19
29
|
const parts = ['root'] as const
|
|
20
30
|
const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export function NavigationList(props: NavigationItemsProps) {
|
|
26
|
-
const { items, parentPath = [], selected = false, mouseEvent } = props
|
|
32
|
+
export const NavigationList = React.memo<NavigationItemsProps>((props) => {
|
|
33
|
+
const { items, parentPath = '', selected = false, mouseEvent } = props
|
|
27
34
|
|
|
35
|
+
const classes = withState({ column: 0, selected })
|
|
28
36
|
return (
|
|
29
|
-
<NavigationUList
|
|
30
|
-
sx={[
|
|
31
|
-
{ display: 'block', position: 'absolute', left: '-10000px', top: '-10000px' },
|
|
32
|
-
selected && { display: 'contents' },
|
|
33
|
-
]}
|
|
34
|
-
className={withState({ column: 0 }).root}
|
|
35
|
-
>
|
|
37
|
+
<NavigationUList className={classes.root}>
|
|
36
38
|
{items.map((item, idx) => (
|
|
37
39
|
<NavigationItem
|
|
38
40
|
NavigationList={NavigationList}
|
|
@@ -48,4 +50,8 @@ export function NavigationList(props: NavigationItemsProps) {
|
|
|
48
50
|
))}
|
|
49
51
|
</NavigationUList>
|
|
50
52
|
)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
56
|
+
NavigationList.displayName = 'NavigationList'
|
|
51
57
|
}
|