@graphcommerce/next-ui 4.12.0 → 4.14.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 +2 -2
- package/ActionCard/ActionCardList.tsx +107 -76
- package/ActionCard/ActionCardListForm.tsx +2 -1
- package/Blog/BlogListItem/BlogListItem.tsx +1 -1
- package/CHANGELOG.md +44 -0
- package/FramerScroller/SidebarGallery.tsx +12 -1
- package/Layout/components/LayoutHeader.tsx +1 -1
- package/Layout/components/LayoutHeaderContent.tsx +9 -4
- package/LayoutDefault/components/LayoutDefault.tsx +5 -3
- package/LayoutOverlay/components/LayoutOverlay.tsx +25 -6
- package/LayoutParts/DesktopNavBar.tsx +1 -1
- package/LayoutParts/DesktopNavBarItem.tsx +38 -4
- package/LayoutParts/MenuFabSecondaryItem.tsx +2 -1
- package/Navigation/components/NavigationFab.tsx +106 -0
- package/Navigation/components/NavigationItem.tsx +147 -0
- package/Navigation/components/NavigationList.tsx +50 -0
- package/Navigation/components/NavigationOverlay.tsx +237 -0
- package/Navigation/components/NavigationProvider.tsx +66 -0
- package/Navigation/hooks/useNavigation.ts +58 -0
- package/Navigation/index.ts +4 -0
- package/Overlay/components/Overlay.tsx +61 -0
- package/{LayoutOverlay/components/LayoutOverlayBase.tsx → Overlay/components/OverlayBase.tsx} +29 -15
- package/Overlay/components/index.ts +2 -0
- package/{LayoutOverlay → Overlay}/hooks/useOverlayPosition.ts +0 -0
- package/Overlay/index.ts +1 -0
- package/PageMeta/PageMeta.tsx +4 -6
- package/Theme/DarkLightModeThemeProvider.tsx +1 -5
- package/index.ts +7 -3
- package/package.json +12 -10
- package/utils/cookie.ts +33 -0
|
@@ -11,7 +11,7 @@ export type ActionCardProps = {
|
|
|
11
11
|
price?: React.ReactNode
|
|
12
12
|
after?: React.ReactNode
|
|
13
13
|
secondaryAction?: React.ReactNode
|
|
14
|
-
onClick?: (
|
|
14
|
+
onClick?: (event: React.MouseEvent<HTMLElement>, value: string | number) => void
|
|
15
15
|
selected?: boolean
|
|
16
16
|
hidden?: boolean
|
|
17
17
|
value: string | number
|
|
@@ -66,7 +66,7 @@ export function ActionCard(props: ActionCardProps) {
|
|
|
66
66
|
|
|
67
67
|
const classes = withState({ hidden, disabled, selected, image: Boolean(image) })
|
|
68
68
|
|
|
69
|
-
const handleClick = (event:
|
|
69
|
+
const handleClick = (event: React.MouseEvent<HTMLElement>) => onClick?.(event, value)
|
|
70
70
|
|
|
71
71
|
return (
|
|
72
72
|
<ButtonBase
|
|
@@ -3,19 +3,20 @@ import { AnimatePresence } from 'framer-motion'
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { isFragment } from 'react-is'
|
|
5
5
|
import { AnimatedRow } from '../AnimatedRow/AnimatedRow'
|
|
6
|
+
import { ActionCardProps } from './ActionCard'
|
|
6
7
|
|
|
7
8
|
type MultiSelect = {
|
|
8
9
|
multiple: true
|
|
9
|
-
value: string[]
|
|
10
|
+
value: (string | number)[]
|
|
10
11
|
|
|
11
|
-
onChange?: (event: React.MouseEvent<HTMLElement>, value:
|
|
12
|
+
onChange?: (event: React.MouseEvent<HTMLElement>, value: MultiSelect['value']) => void
|
|
12
13
|
}
|
|
13
14
|
type Select = {
|
|
14
15
|
multiple?: false
|
|
15
|
-
value: string
|
|
16
|
+
value: string | number
|
|
16
17
|
|
|
17
18
|
/** Value is null when deselected when not required */
|
|
18
|
-
onChange?: (event: React.MouseEvent<HTMLElement>, value:
|
|
19
|
+
onChange?: (event: React.MouseEvent<HTMLElement>, value: Select['value'] | null) => void
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export type ActionCardListProps<SelectOrMulti = MultiSelect | Select> = {
|
|
@@ -29,94 +30,124 @@ function isMulti(props: ActionCardListProps): props is ActionCardListProps<Multi
|
|
|
29
30
|
return props.multiple === true
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
function isValueSelected(
|
|
33
|
-
|
|
33
|
+
function isValueSelected(
|
|
34
|
+
value: ActionCardProps['value'],
|
|
35
|
+
candidate?: Select['value'] | MultiSelect['value'],
|
|
36
|
+
) {
|
|
37
|
+
if (candidate === undefined) return false
|
|
34
38
|
if (Array.isArray(candidate)) return candidate.indexOf(value) >= 0
|
|
35
39
|
return value === candidate
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
export
|
|
39
|
-
|
|
42
|
+
export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListProps>(
|
|
43
|
+
(props, ref) => {
|
|
44
|
+
const { children, required, error = false, errorMessage } = props
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
const handleChange: ActionCardProps['onClick'] = isMulti(props)
|
|
47
|
+
? (event, v) => {
|
|
48
|
+
const { onChange, value } = props
|
|
49
|
+
const index = Boolean(value) && value?.indexOf(v)
|
|
50
|
+
let newValue: typeof value
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
if (value.length && index && index >= 0) {
|
|
53
|
+
newValue = value.slice()
|
|
54
|
+
newValue.splice(index, 1)
|
|
55
|
+
} else {
|
|
56
|
+
newValue = value ? [...value, v] : [v]
|
|
57
|
+
}
|
|
58
|
+
onChange?.(event, newValue)
|
|
52
59
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
: (event: React.MouseEvent<HTMLElement, MouseEvent>, buttonValue: string) => {
|
|
56
|
-
const { onChange } = props
|
|
60
|
+
: (event, v) => {
|
|
61
|
+
const { onChange, value } = props
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
if (value !== v) {
|
|
64
|
+
if (required) onChange?.(event, v)
|
|
65
|
+
else onChange?.(event, value === v ? null : v)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sx={[
|
|
66
|
-
error &&
|
|
67
|
-
((theme) => ({
|
|
68
|
-
'& .ActionCard-root': {
|
|
69
|
-
borderLeft: 2,
|
|
70
|
-
borderRight: 2,
|
|
71
|
-
borderLeftColor: 'error.main',
|
|
72
|
-
borderRightColor: 'error.main',
|
|
73
|
-
paddingLeft: theme.spacings.xs,
|
|
74
|
-
paddingRight: theme.spacings.xs,
|
|
75
|
-
},
|
|
76
|
-
'& > div:first-of-type.ActionCard-root': {
|
|
77
|
-
borderTop: 2,
|
|
78
|
-
borderTopColor: 'error.main',
|
|
79
|
-
paddingTop: theme.spacings.xxs,
|
|
80
|
-
},
|
|
81
|
-
'& > div:last-of-type.ActionCard-root': {
|
|
82
|
-
borderBottom: 2,
|
|
83
|
-
borderBottomColor: 'error.main',
|
|
84
|
-
paddingBottom: theme.spacings.xxs,
|
|
85
|
-
},
|
|
86
|
-
})),
|
|
87
|
-
]}
|
|
69
|
+
type ActionCardLike = React.ReactElement<
|
|
70
|
+
Pick<ActionCardProps, 'value' | 'selected' | 'disabled' | 'onClick'>
|
|
88
71
|
>
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
function isActionCardLike(el: React.ReactElement): el is ActionCardLike {
|
|
73
|
+
const hasValue = (el as ActionCardLike).props.value
|
|
91
74
|
|
|
75
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
76
|
+
if (!hasValue) console.error(el, `must be an instance of ActionCard`)
|
|
77
|
+
}
|
|
78
|
+
return (el as ActionCardLike).props.value !== undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Make sure the children are cardlike
|
|
82
|
+
const childReactNodes = React.Children.toArray(children)
|
|
83
|
+
.filter(React.isValidElement)
|
|
84
|
+
.filter(isActionCardLike)
|
|
85
|
+
.filter((child) => {
|
|
92
86
|
if (process.env.NODE_ENV !== 'production') {
|
|
93
|
-
if (isFragment(child))
|
|
87
|
+
if (isFragment(child))
|
|
94
88
|
console.error(
|
|
95
89
|
[
|
|
96
90
|
"@graphcommerce/next-ui: The ActionCardList component doesn't accept a Fragment as a child.",
|
|
97
|
-
'Consider providing an array instead
|
|
91
|
+
'Consider providing an array instead',
|
|
98
92
|
].join('\n'),
|
|
99
93
|
)
|
|
100
|
-
}
|
|
101
94
|
}
|
|
102
95
|
|
|
103
|
-
return
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
96
|
+
return !isFragment(child)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// Make sure the selected values is in the list of all possible values
|
|
100
|
+
const value = childReactNodes.find(
|
|
101
|
+
// eslint-disable-next-line react/destructuring-assignment
|
|
102
|
+
(child) => child.props.value === props.value && child.props.disabled !== true,
|
|
103
|
+
)?.props.value
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Box
|
|
107
|
+
ref={ref}
|
|
108
|
+
sx={[
|
|
109
|
+
error &&
|
|
110
|
+
((theme) => ({
|
|
111
|
+
'& .ActionCard-root': {
|
|
112
|
+
borderLeft: 2,
|
|
113
|
+
borderRight: 2,
|
|
114
|
+
borderLeftColor: 'error.main',
|
|
115
|
+
borderRightColor: 'error.main',
|
|
116
|
+
paddingLeft: theme.spacings.xs,
|
|
117
|
+
paddingRight: theme.spacings.xs,
|
|
118
|
+
},
|
|
119
|
+
'& > div:first-of-type.ActionCard-root': {
|
|
120
|
+
borderTop: 2,
|
|
121
|
+
borderTopColor: 'error.main',
|
|
122
|
+
paddingTop: theme.spacings.xxs,
|
|
123
|
+
},
|
|
124
|
+
'& > div:last-of-type.ActionCard-root': {
|
|
125
|
+
borderBottom: 2,
|
|
126
|
+
borderBottomColor: 'error.main',
|
|
127
|
+
paddingBottom: theme.spacings.xxs,
|
|
128
|
+
},
|
|
129
|
+
})),
|
|
130
|
+
]}
|
|
131
|
+
>
|
|
132
|
+
{childReactNodes.map((child) =>
|
|
133
|
+
React.cloneElement(child, {
|
|
134
|
+
onClick: handleChange,
|
|
135
|
+
selected:
|
|
136
|
+
child.props.selected === undefined
|
|
137
|
+
? isValueSelected(child.props.value, value)
|
|
138
|
+
: child.props.selected,
|
|
139
|
+
}),
|
|
140
|
+
)}
|
|
141
|
+
{error && (
|
|
142
|
+
<Alert
|
|
143
|
+
severity='error'
|
|
144
|
+
variant='filled'
|
|
145
|
+
sx={{ borderStartStartRadius: 0, borderStartEndRadius: 0 }}
|
|
146
|
+
>
|
|
147
|
+
{errorMessage}
|
|
148
|
+
</Alert>
|
|
149
|
+
)}
|
|
150
|
+
</Box>
|
|
151
|
+
)
|
|
152
|
+
},
|
|
153
|
+
)
|
|
@@ -34,10 +34,11 @@ 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 }, fieldState, formState }) => (
|
|
37
|
+
render={({ field: { onChange, value, onBlur, ref }, fieldState, formState }) => (
|
|
38
38
|
<ActionCardList
|
|
39
39
|
required
|
|
40
40
|
value={value}
|
|
41
|
+
ref={ref}
|
|
41
42
|
onChange={(_, incomming) => onChange(incomming)}
|
|
42
43
|
error={formState.isSubmitted && !!fieldState.error}
|
|
43
44
|
errorMessage={fieldState.error?.message}
|
|
@@ -20,7 +20,7 @@ const { classes } = extendableComponent(name, parts)
|
|
|
20
20
|
export function BlogListItem(props: BlogListItemProps) {
|
|
21
21
|
const { asset, url, date, title, sx = [] } = props
|
|
22
22
|
|
|
23
|
-
const formatter = useDateTimeFormat({
|
|
23
|
+
const formatter = useDateTimeFormat({ dateStyle: 'long' })
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<Box
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1553](https://github.com/graphcommerce-org/graphcommerce/pull/1553) [`323fdee4b`](https://github.com/graphcommerce-org/graphcommerce/commit/323fdee4b15ae23e0e84dd0588cb2c6446dcfd50) Thanks [@NickdeK](https://github.com/NickdeK)! - Added a new cookies utility to load cookies on the frontend
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#1553](https://github.com/graphcommerce-org/graphcommerce/pull/1553) [`afcd8e4bf`](https://github.com/graphcommerce-org/graphcommerce/commit/afcd8e4bfb7010da4d5faeed85b61991ed7975f4) Thanks [@NickdeK](https://github.com/NickdeK)! - ActionCardList will now show all options when the selected value isn't in any of the options
|
|
12
|
+
|
|
13
|
+
* [#1553](https://github.com/graphcommerce-org/graphcommerce/pull/1553) [`02e1988e5`](https://github.com/graphcommerce-org/graphcommerce/commit/02e1988e5f361c6f66ae30d3bbee38ef2ac062df) Thanks [@NickdeK](https://github.com/NickdeK)! - Make sure the useDateTimeFormat isn't giving hydration warnings
|
|
14
|
+
|
|
15
|
+
* Updated dependencies []:
|
|
16
|
+
- @graphcommerce/framer-scroller@2.1.24
|
|
17
|
+
|
|
18
|
+
## 4.13.1
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#1552](https://github.com/graphcommerce-org/graphcommerce/pull/1552) [`18054c441`](https://github.com/graphcommerce-org/graphcommerce/commit/18054c441962ba750bed3acc39ab46c8d3a341ce) Thanks [@paales](https://github.com/paales)! - Updated to Next.js v12.2.2 and other packages and made compatible
|
|
23
|
+
|
|
24
|
+
* [#1552](https://github.com/graphcommerce-org/graphcommerce/pull/1552) [`c5c539c44`](https://github.com/graphcommerce-org/graphcommerce/commit/c5c539c44eeac524cd62ce649e132d2e00333794) Thanks [@paales](https://github.com/paales)! - Make sure the gallery doesn't scroll when overlays are opened
|
|
25
|
+
|
|
26
|
+
- [#1552](https://github.com/graphcommerce-org/graphcommerce/pull/1552) [`6f69bc54c`](https://github.com/graphcommerce-org/graphcommerce/commit/6f69bc54c6e0224452817c532ae58d9c332b61ea) Thanks [@paales](https://github.com/paales)! - Prevent back button scrolling when navigating between overlays
|
|
27
|
+
|
|
28
|
+
* [#1552](https://github.com/graphcommerce-org/graphcommerce/pull/1552) [`21886d6fa`](https://github.com/graphcommerce-org/graphcommerce/commit/21886d6fa64a48d9e932bfaf8d138c9b13c36e43) Thanks [@paales](https://github.com/paales)! - Fix page stacking and scroll restoration when navigating
|
|
29
|
+
|
|
30
|
+
* Updated dependencies [[`18054c441`](https://github.com/graphcommerce-org/graphcommerce/commit/18054c441962ba750bed3acc39ab46c8d3a341ce), [`21886d6fa`](https://github.com/graphcommerce-org/graphcommerce/commit/21886d6fa64a48d9e932bfaf8d138c9b13c36e43), [`b4936e961`](https://github.com/graphcommerce-org/graphcommerce/commit/b4936e96175fe80717895822e245274db05638bd)]:
|
|
31
|
+
- @graphcommerce/framer-next-pages@3.2.4
|
|
32
|
+
- @graphcommerce/framer-scroller@2.1.23
|
|
33
|
+
|
|
34
|
+
## 4.13.0
|
|
35
|
+
|
|
36
|
+
### Minor Changes
|
|
37
|
+
|
|
38
|
+
- [#1522](https://github.com/graphcommerce-org/graphcommerce/pull/1522) [`8d8fda262`](https://github.com/graphcommerce-org/graphcommerce/commit/8d8fda2623e561cb43441110c67ffa34b692668a) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Introducing a new Navigation component that builds on the existing navigation component and tries to address the 'mega menu' question where there are tons of categories that need to be navigated quickly.
|
|
39
|
+
|
|
40
|
+
* [#1522](https://github.com/graphcommerce-org/graphcommerce/pull/1522) [`cefa7b365`](https://github.com/graphcommerce-org/graphcommerce/commit/cefa7b3652b55108d2178927e3c5d98a111cf373) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Introducting a new Overlay component with is the generic part of LayoutOverlay into OverlayBase. The new Overlay is used to render the new Navigation component.
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- Updated dependencies [[`584b683a2`](https://github.com/graphcommerce-org/graphcommerce/commit/584b683a2aedcdf5067644c8dcc0e63a5b9e894c)]:
|
|
45
|
+
- @graphcommerce/framer-scroller@2.1.22
|
|
46
|
+
|
|
3
47
|
## 4.12.0
|
|
4
48
|
|
|
5
49
|
### Minor Changes
|
|
@@ -119,6 +119,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
119
119
|
<Row maxWidth={false} disableGutters className={classes.row} sx={sx}>
|
|
120
120
|
<MotionBox
|
|
121
121
|
layout
|
|
122
|
+
layoutDependency={zoomed}
|
|
122
123
|
className={classes.root}
|
|
123
124
|
sx={[
|
|
124
125
|
{
|
|
@@ -146,6 +147,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
146
147
|
>
|
|
147
148
|
<MotionBox
|
|
148
149
|
layout
|
|
150
|
+
layoutDependency={zoomed}
|
|
149
151
|
className={classes.scrollerContainer}
|
|
150
152
|
sx={[
|
|
151
153
|
{
|
|
@@ -193,6 +195,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
193
195
|
<MotionImageAspect
|
|
194
196
|
key={typeof image.src === 'string' ? image.src : idx}
|
|
195
197
|
layout
|
|
198
|
+
layoutDependency={zoomed}
|
|
196
199
|
src={image.src}
|
|
197
200
|
width={image.width}
|
|
198
201
|
height={image.height}
|
|
@@ -209,6 +212,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
209
212
|
</Scroller>
|
|
210
213
|
<MotionBox
|
|
211
214
|
layout
|
|
215
|
+
layoutDependency={zoomed}
|
|
212
216
|
className={classes.topRight}
|
|
213
217
|
sx={{
|
|
214
218
|
display: 'grid',
|
|
@@ -243,6 +247,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
243
247
|
>
|
|
244
248
|
<ScrollerButton
|
|
245
249
|
layout
|
|
250
|
+
layoutDependency={zoomed}
|
|
246
251
|
direction='left'
|
|
247
252
|
size='small'
|
|
248
253
|
className={classes.sliderButtons}
|
|
@@ -262,6 +267,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
262
267
|
>
|
|
263
268
|
<ScrollerButton
|
|
264
269
|
layout
|
|
270
|
+
layoutDependency={zoomed}
|
|
265
271
|
direction='right'
|
|
266
272
|
size='small'
|
|
267
273
|
className={classes.sliderButtons}
|
|
@@ -286,7 +292,11 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
286
292
|
},
|
|
287
293
|
}}
|
|
288
294
|
>
|
|
289
|
-
<ScrollerDots
|
|
295
|
+
<ScrollerDots
|
|
296
|
+
layout
|
|
297
|
+
layoutDependency={zoomed}
|
|
298
|
+
sx={{ backgroundColor: 'background.paper', boxShadow: 6 }}
|
|
299
|
+
/>
|
|
290
300
|
</Box>
|
|
291
301
|
</MotionBox>
|
|
292
302
|
|
|
@@ -319,6 +329,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
319
329
|
>
|
|
320
330
|
<MotionBox
|
|
321
331
|
layout
|
|
332
|
+
layoutDependency={zoomed}
|
|
322
333
|
className={classes.sidebar}
|
|
323
334
|
sx={{
|
|
324
335
|
boxSizing: 'border-box',
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { useMotionValueValue } from '@graphcommerce/framer-utils'
|
|
2
|
-
import { Box, SxProps, Theme } from '@mui/material'
|
|
2
|
+
import { Box, styled, SxProps, Theme } from '@mui/material'
|
|
3
|
+
import { LayoutProps, m } from 'framer-motion'
|
|
3
4
|
import React, { useRef } from 'react'
|
|
4
5
|
import { extendableComponent } from '../../Styles'
|
|
5
6
|
import { useScrollY } from '../hooks/useScrollY'
|
|
6
7
|
import { FloatingProps } from './LayoutHeadertypes'
|
|
7
8
|
|
|
9
|
+
const MotionDiv = styled(m.div)({})
|
|
10
|
+
|
|
8
11
|
export type LayoutHeaderContentProps = FloatingProps & {
|
|
9
12
|
children?: React.ReactNode
|
|
10
13
|
left?: React.ReactNode
|
|
@@ -13,6 +16,7 @@ export type LayoutHeaderContentProps = FloatingProps & {
|
|
|
13
16
|
switchPoint?: number
|
|
14
17
|
sx?: SxProps<Theme>
|
|
15
18
|
sxBg?: SxProps<Theme>
|
|
19
|
+
layout?: LayoutProps['layout']
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
type OwnerState = { floatingSm: boolean; floatingMd: boolean; scrolled: boolean; divider: boolean }
|
|
@@ -33,6 +37,7 @@ export function LayoutHeaderContent(props: LayoutHeaderContentProps) {
|
|
|
33
37
|
switchPoint = 50,
|
|
34
38
|
sx = [],
|
|
35
39
|
sxBg = [],
|
|
40
|
+
layout,
|
|
36
41
|
} = props
|
|
37
42
|
|
|
38
43
|
const scroll = useScrollY()
|
|
@@ -139,7 +144,7 @@ export function LayoutHeaderContent(props: LayoutHeaderContentProps) {
|
|
|
139
144
|
justifyContent: 'start',
|
|
140
145
|
})}
|
|
141
146
|
>
|
|
142
|
-
{left}
|
|
147
|
+
<MotionDiv layout={layout}>{left}</MotionDiv>
|
|
143
148
|
</Box>
|
|
144
149
|
)}
|
|
145
150
|
<Box
|
|
@@ -172,7 +177,7 @@ export function LayoutHeaderContent(props: LayoutHeaderContentProps) {
|
|
|
172
177
|
},
|
|
173
178
|
})}
|
|
174
179
|
>
|
|
175
|
-
{children}
|
|
180
|
+
<MotionDiv layout={layout}>{children}</MotionDiv>
|
|
176
181
|
</Box>
|
|
177
182
|
<Box
|
|
178
183
|
className={classes.right}
|
|
@@ -188,7 +193,7 @@ export function LayoutHeaderContent(props: LayoutHeaderContentProps) {
|
|
|
188
193
|
justifyContent: 'end',
|
|
189
194
|
})}
|
|
190
195
|
>
|
|
191
|
-
{right}
|
|
196
|
+
<MotionDiv layout={layout}>{right}</MotionDiv>
|
|
192
197
|
</Box>
|
|
193
198
|
{divider && (
|
|
194
199
|
<Box
|
|
@@ -39,8 +39,10 @@ export function LayoutDefault(props: LayoutDefaultProps) {
|
|
|
39
39
|
sx = [],
|
|
40
40
|
} = props
|
|
41
41
|
|
|
42
|
-
const
|
|
43
|
-
|
|
42
|
+
const scrollWithOffset = useTransform(
|
|
43
|
+
[useViewportScroll().scrollY, useScrollOffset()],
|
|
44
|
+
([y, offset]: number[]) => y + offset,
|
|
45
|
+
)
|
|
44
46
|
|
|
45
47
|
const classes = withState({ noSticky })
|
|
46
48
|
|
|
@@ -104,7 +106,7 @@ export function LayoutDefault(props: LayoutDefaultProps) {
|
|
|
104
106
|
justifyContent: 'space-between',
|
|
105
107
|
width: '100%',
|
|
106
108
|
height: 0,
|
|
107
|
-
zIndex: '
|
|
109
|
+
zIndex: 'speedDial',
|
|
108
110
|
[theme.breakpoints.up('sm')]: {
|
|
109
111
|
padding: `0 ${theme.page.horizontal}`,
|
|
110
112
|
position: 'sticky',
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import { usePageContext, useGo, useScrollOffset } from '@graphcommerce/framer-next-pages'
|
|
1
2
|
import { ScrollerProvider, ScrollSnapType } from '@graphcommerce/framer-scroller'
|
|
3
|
+
import { useMotionValueValue } from '@graphcommerce/framer-utils'
|
|
4
|
+
import { usePresence } from 'framer-motion'
|
|
2
5
|
import type { SetOptional } from 'type-fest'
|
|
3
|
-
import {
|
|
6
|
+
import { OverlayBase, LayoutOverlayBaseProps } from '../../Overlay/components/OverlayBase'
|
|
4
7
|
|
|
5
|
-
export type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
export type LayoutOverlayProps = Omit<
|
|
9
|
+
SetOptional<LayoutOverlayBaseProps, 'variantSm' | 'variantMd'>,
|
|
10
|
+
'active' | 'direction' | 'onClosed' | 'offsetPageY' | 'isPresent' | 'safeToRemove'
|
|
11
|
+
>
|
|
8
12
|
|
|
9
13
|
export function LayoutOverlay(props: LayoutOverlayProps) {
|
|
10
14
|
const { children, variantSm = 'bottom', variantMd = 'right', ...otherProps } = props
|
|
@@ -14,11 +18,26 @@ export function LayoutOverlay(props: LayoutOverlayProps) {
|
|
|
14
18
|
const scrollSnapTypeMd: ScrollSnapType =
|
|
15
19
|
variantMd === 'left' || variantMd === 'right' ? 'inline mandatory' : 'block proximity'
|
|
16
20
|
|
|
21
|
+
const { closeSteps, active, direction } = usePageContext()
|
|
22
|
+
const onCloseHandler = useGo(closeSteps * -1)
|
|
23
|
+
const offsetPageY = useMotionValueValue(useScrollOffset(), (v) => v)
|
|
24
|
+
const [isPresent, safeToRemove] = usePresence()
|
|
25
|
+
|
|
17
26
|
return (
|
|
18
27
|
<ScrollerProvider scrollSnapTypeSm={scrollSnapTypeSm} scrollSnapTypeMd={scrollSnapTypeMd}>
|
|
19
|
-
<
|
|
28
|
+
<OverlayBase
|
|
29
|
+
active={active}
|
|
30
|
+
direction={direction}
|
|
31
|
+
onClosed={onCloseHandler}
|
|
32
|
+
offsetPageY={offsetPageY}
|
|
33
|
+
variantMd={variantMd}
|
|
34
|
+
variantSm={variantSm}
|
|
35
|
+
isPresent={isPresent}
|
|
36
|
+
safeToRemove={safeToRemove}
|
|
37
|
+
{...otherProps}
|
|
38
|
+
>
|
|
20
39
|
{children}
|
|
21
|
-
</
|
|
40
|
+
</OverlayBase>
|
|
22
41
|
</ScrollerProvider>
|
|
23
42
|
)
|
|
24
43
|
}
|
|
@@ -43,7 +43,7 @@ export function DesktopNavBar(props: MenuTabsProps) {
|
|
|
43
43
|
sx={(theme) => ({
|
|
44
44
|
gridArea: `1 / 1 / 1 / 4`,
|
|
45
45
|
columnGap: theme.spacings.md,
|
|
46
|
-
padding: `0 ${theme.spacings.
|
|
46
|
+
padding: `0 ${theme.spacings.md}`,
|
|
47
47
|
gridAutoColumns: 'min-content',
|
|
48
48
|
})}
|
|
49
49
|
className={classes.scroller}
|
|
@@ -5,11 +5,45 @@ import { extendableComponent } from '../Styles/extendableComponent'
|
|
|
5
5
|
|
|
6
6
|
const { classes, selectors } = extendableComponent('DesktopNavItem', ['root', 'line'] as const)
|
|
7
7
|
|
|
8
|
-
export type
|
|
8
|
+
export type DesktopNavItemLinkProps = LinkProps<'a'> & Pick<PageLinkProps, 'href'>
|
|
9
|
+
export type DesktopNavItemButtonProps = LinkProps<'div'> & {
|
|
10
|
+
onClick: LinkProps<'button'>['onClick']
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isLinkProps(
|
|
14
|
+
props: DesktopNavItemLinkProps | DesktopNavItemButtonProps,
|
|
15
|
+
): props is DesktopNavItemLinkProps {
|
|
16
|
+
return 'href' in props
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function DesktopNavItem(props: DesktopNavItemLinkProps | DesktopNavItemButtonProps) {
|
|
20
|
+
const router = useRouter()
|
|
21
|
+
|
|
22
|
+
if (!isLinkProps(props)) {
|
|
23
|
+
const { onClick, children, sx = [], ...linkProps } = props
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Link
|
|
27
|
+
className={classes.root}
|
|
28
|
+
component='div'
|
|
29
|
+
variant='h6'
|
|
30
|
+
color='text.primary'
|
|
31
|
+
underline='none'
|
|
32
|
+
{...linkProps}
|
|
33
|
+
onClick={onClick}
|
|
34
|
+
sx={[
|
|
35
|
+
{ whiteSpace: 'nowrap', paddingTop: '6px', cursor: 'pointer' },
|
|
36
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
37
|
+
]}
|
|
38
|
+
>
|
|
39
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>{children}</Box>
|
|
40
|
+
</Link>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
9
43
|
|
|
10
|
-
export function DesktopNavItem(props: DesktopNavItemProps) {
|
|
11
44
|
const { href, children, sx = [], ...linkProps } = props
|
|
12
|
-
|
|
45
|
+
|
|
46
|
+
const active = router.asPath.startsWith(href.toString())
|
|
13
47
|
|
|
14
48
|
return (
|
|
15
49
|
<PageLink href={href} passHref>
|
|
@@ -21,7 +55,7 @@ export function DesktopNavItem(props: DesktopNavItemProps) {
|
|
|
21
55
|
{...linkProps}
|
|
22
56
|
sx={[{ whiteSpace: 'nowrap', paddingTop: '6px' }, ...(Array.isArray(sx) ? sx : [sx])]}
|
|
23
57
|
>
|
|
24
|
-
{children}
|
|
58
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>{children}</Box>
|
|
25
59
|
<Box
|
|
26
60
|
component='span'
|
|
27
61
|
className={classes.line}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ListItemButton, ListItemIcon, ListItemText, SxProps, Theme } from '@mui/material'
|
|
2
2
|
import PageLink from 'next/link'
|
|
3
|
-
import
|
|
3
|
+
import { useRouter } from 'next/router'
|
|
4
4
|
import React from 'react'
|
|
5
5
|
import { extendableComponent } from '../Styles'
|
|
6
6
|
|
|
@@ -17,6 +17,7 @@ const { classes } = extendableComponent(compName, parts)
|
|
|
17
17
|
|
|
18
18
|
export function MenuFabSecondaryItem(props: FabMenuSecondaryItemProps) {
|
|
19
19
|
const { href, children, icon, sx = [] } = props
|
|
20
|
+
const router = useRouter()
|
|
20
21
|
|
|
21
22
|
return (
|
|
22
23
|
<PageLink href={href} passHref>
|