@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.
@@ -11,7 +11,7 @@ export type ActionCardProps = {
11
11
  price?: React.ReactNode
12
12
  after?: React.ReactNode
13
13
  secondaryAction?: React.ReactNode
14
- onClick?: (e: FormEvent<HTMLElement>, v: string | number) => void
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: FormEvent<HTMLElement>) => onClick?.(event, value)
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: string[]) => void
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: string | null) => void
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(value: string, candidate: string | string[]) {
33
- if (candidate === undefined || value === undefined) return false
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 function ActionCardList(props: ActionCardListProps) {
39
- const { children, required, value, error = false, errorMessage } = props
42
+ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListProps>(
43
+ (props, ref) => {
44
+ const { children, required, error = false, errorMessage } = props
40
45
 
41
- const handleChange = isMulti(props)
42
- ? (event: React.MouseEvent<HTMLElement, MouseEvent>, buttonValue: string) => {
43
- const { onChange } = props
44
- const index = Boolean(value) && value?.indexOf(buttonValue)
45
- let newValue: string[]
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
- if (Array.isArray(value) && value.length && index && index >= 0) {
48
- newValue = value.slice()
49
- newValue.splice(index, 1)
50
- } else {
51
- newValue = value ? [...value, buttonValue] : [buttonValue]
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
- onChange?.(event, newValue)
54
- }
55
- : (event: React.MouseEvent<HTMLElement, MouseEvent>, buttonValue: string) => {
56
- const { onChange } = props
60
+ : (event, v) => {
61
+ const { onChange, value } = props
57
62
 
58
- if (value === buttonValue) return
59
- if (required) onChange?.(event, buttonValue)
60
- else onChange?.(event, value === buttonValue ? null : buttonValue)
61
- }
63
+ if (value !== v) {
64
+ if (required) onChange?.(event, v)
65
+ else onChange?.(event, value === v ? null : v)
66
+ }
67
+ }
62
68
 
63
- return (
64
- <Box
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
- {React.Children.map(children, (child) => {
90
- if (!React.isValidElement(child)) return null
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 React.cloneElement(child, {
104
- onClick: handleChange,
105
- selected:
106
- child.props.selected === undefined
107
- ? isValueSelected(child.props.value as string, value)
108
- : child.props.selected,
109
- })
110
- })}
111
- {error && (
112
- <Alert
113
- severity='error'
114
- variant='filled'
115
- sx={{ borderStartStartRadius: 0, borderStartEndRadius: 0 }}
116
- >
117
- {errorMessage}
118
- </Alert>
119
- )}
120
- </Box>
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({ year: 'numeric', month: 'long', day: 'numeric' })
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 layout sx={{ backgroundColor: 'background.paper', boxShadow: 6 }} />
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',
@@ -60,7 +60,7 @@ export function LayoutHeader(props: LayoutHeaderProps) {
60
60
  let left = secondary
61
61
  let right = primary
62
62
 
63
- if (back) left = back
63
+ if (back && !secondary) left = back
64
64
 
65
65
  if (!right) right = close
66
66
  else if (!left) left = close
@@ -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 offset = useScrollOffset().y
43
- const scrollWithOffset = useTransform(useViewportScroll().scrollY, (y) => y + offset)
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: 'drawer',
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 { LayoutOverlayBase, LayoutOverlayBaseProps } from './LayoutOverlayBase'
6
+ import { OverlayBase, LayoutOverlayBaseProps } from '../../Overlay/components/OverlayBase'
4
7
 
5
- export type { LayoutOverlayVariant } from './LayoutOverlayBase'
6
-
7
- export type LayoutOverlayProps = SetOptional<LayoutOverlayBaseProps, 'variantSm' | 'variantMd'>
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
- <LayoutOverlayBase variantMd={variantMd} variantSm={variantSm} {...otherProps}>
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
- </LayoutOverlayBase>
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.sm}`,
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 DesktopNavItemProps = LinkProps & Pick<PageLinkProps, 'href'>
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
- const active = useRouter().asPath.startsWith(href.toString())
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 router from 'next/router'
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>