@graphcommerce/next-ui 5.2.0-canary.2 → 5.2.0-canary.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,4 @@
1
1
  import { Box, Link, SxProps, Theme, Typography } from '@mui/material'
2
- import PageLink from 'next/link'
3
2
  import React from 'react'
4
3
  import { extendableComponent } from '../../Styles'
5
4
  import { breakpointVal } from '../../Styles/breakpointVal'
@@ -38,37 +37,35 @@ export function BlogListItem(props: BlogListItemProps) {
38
37
  ...(Array.isArray(sx) ? sx : [sx]),
39
38
  ]}
40
39
  >
41
- <PageLink href={`/${url}`} passHref>
42
- <Link color='inherit' underline='hover'>
43
- <Box
44
- className={classes.asset}
45
- sx={(theme) => ({
46
- display: 'grid',
47
- alignContent: 'center',
48
- overflow: 'hidden',
49
- height: '100%',
50
- width: '100%',
51
- ...breakpointVal(
52
- 'borderRadius',
53
- theme.shape.borderRadius * 2,
54
- theme.shape.borderRadius * 3,
55
- theme.breakpoints.values,
56
- ),
57
- '& img': {
58
- height: '100% !important',
59
- objectFit: 'cover',
60
- },
61
- '& p': {
62
- alignSelf: 'center',
63
- justifySelf: 'center',
64
- },
65
- background: theme.palette.background.paper,
66
- })}
67
- >
68
- {asset}
69
- </Box>
70
- </Link>
71
- </PageLink>
40
+ <Link href={`/${url}`} color='inherit' underline='hover'>
41
+ <Box
42
+ className={classes.asset}
43
+ sx={(theme) => ({
44
+ display: 'grid',
45
+ alignContent: 'center',
46
+ overflow: 'hidden',
47
+ height: '100%',
48
+ width: '100%',
49
+ ...breakpointVal(
50
+ 'borderRadius',
51
+ theme.shape.borderRadius * 2,
52
+ theme.shape.borderRadius * 3,
53
+ theme.breakpoints.values,
54
+ ),
55
+ '& img': {
56
+ height: '100% !important',
57
+ objectFit: 'cover',
58
+ },
59
+ '& p': {
60
+ alignSelf: 'center',
61
+ justifySelf: 'center',
62
+ },
63
+ background: theme.palette.background.paper,
64
+ })}
65
+ >
66
+ {asset}
67
+ </Box>
68
+ </Link>
72
69
 
73
70
  <Box
74
71
  component='time'
@@ -83,13 +80,11 @@ export function BlogListItem(props: BlogListItemProps) {
83
80
  {formatter.format(new Date(date))}
84
81
  </Box>
85
82
 
86
- <PageLink href={`/${url}`} passHref>
87
- <Link href={`/${url}`} className={classes.title} color='inherit' underline='hover'>
88
- <Typography component='h2' variant='h4'>
89
- {title}
90
- </Typography>
91
- </Link>
92
- </PageLink>
83
+ <Link href={`/${url}`} className={classes.title} color='inherit' underline='hover'>
84
+ <Typography component='h2' variant='h4'>
85
+ {title}
86
+ </Typography>
87
+ </Link>
93
88
  </Box>
94
89
  )
95
90
  }
@@ -1,5 +1,5 @@
1
1
  import { Chip, SxProps, Theme } from '@mui/material'
2
- import PageLink from 'next/link'
2
+ import { NextLink } from '../../Theme'
3
3
 
4
4
  type BlogTagsProps = {
5
5
  url: string
@@ -10,17 +10,11 @@ type BlogTagsProps = {
10
10
  export function BlogTag(props: BlogTagsProps) {
11
11
  const { url, title, sx = [] } = props
12
12
  return (
13
- <PageLink href={`/${url}`} passHref>
14
- <Chip
15
- label={title}
16
- sx={[
17
- {
18
- marginRight: 3,
19
- borderRadius: 2,
20
- },
21
- ...(Array.isArray(sx) ? sx : [sx]),
22
- ]}
23
- />
24
- </PageLink>
13
+ <Chip
14
+ href={`/${url}`}
15
+ component={NextLink}
16
+ label={title}
17
+ sx={[{ marginRight: 3, borderRadius: 2 }, ...(Array.isArray(sx) ? sx : [sx])]}
18
+ />
25
19
  )
26
20
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Change Log
2
2
 
3
+ ## 5.2.0-canary.3
4
+
3
5
  ## 5.2.0-canary.2
4
6
 
5
7
  ### Patch Changes
@@ -1,7 +1,6 @@
1
1
  import { useUp, usePrevUp, usePageContext } from '@graphcommerce/framer-next-pages'
2
2
  import { i18n } from '@lingui/core'
3
3
  import { Box, SxProps, Theme } from '@mui/material'
4
- import PageLink from 'next/link'
5
4
  import { useRouter } from 'next/router'
6
5
  import { LinkOrButton, LinkOrButtonProps } from '../../Button/LinkOrButton'
7
6
  import { IconSvg } from '../../IconSvg'
@@ -69,19 +68,18 @@ export function LayoutHeaderBack(props: BackProps) {
69
68
 
70
69
  if (up?.href && up.href !== path)
71
70
  return (
72
- <PageLink href={up.href} passHref>
73
- <LinkOrButton
74
- button={{ variant: 'pill', sx: buttonSx }}
75
- startIcon={backIcon}
76
- aria-label={up.title}
77
- color='inherit'
78
- {...props}
79
- >
80
- <Box component='span' sx={{ display: { xs: 'none', md: 'inline' } }}>
81
- {up.title}
82
- </Box>
83
- </LinkOrButton>
84
- </PageLink>
71
+ <LinkOrButton
72
+ href={up.href}
73
+ button={{ variant: 'pill', sx: buttonSx }}
74
+ startIcon={backIcon}
75
+ aria-label={up.title}
76
+ color='inherit'
77
+ {...props}
78
+ >
79
+ <Box component='span' sx={{ display: { xs: 'none', md: 'inline' } }}>
80
+ {up.title}
81
+ </Box>
82
+ </LinkOrButton>
85
83
  )
86
84
 
87
85
  return null
@@ -1,11 +1,10 @@
1
1
  import { Box, Link, LinkProps } from '@mui/material'
2
- import PageLink, { LinkProps as PageLinkProps } from 'next/link'
3
2
  import { useRouter } from 'next/router'
4
3
  import { extendableComponent } from '../Styles/extendableComponent'
5
4
 
6
5
  const { classes, selectors } = extendableComponent('DesktopNavItem', ['root', 'line'] as const)
7
6
 
8
- export type DesktopNavItemLinkProps = LinkProps<'a'> & Pick<PageLinkProps, 'href'>
7
+ export type DesktopNavItemLinkProps = LinkProps<'a'>
9
8
  export type DesktopNavItemButtonProps = LinkProps<'div'> & {
10
9
  onClick: LinkProps<'button'>['onClick']
11
10
  }
@@ -43,36 +42,35 @@ export function DesktopNavItem(props: DesktopNavItemLinkProps | DesktopNavItemBu
43
42
 
44
43
  const { href, children, sx = [], ...linkProps } = props
45
44
 
46
- const active = router.asPath.startsWith(href.toString())
45
+ const active = router.asPath.startsWith((href ?? '').toString())
47
46
 
48
47
  return (
49
- <PageLink href={href} passHref>
50
- <Link
51
- className={classes.root}
52
- variant='h6'
53
- color='text.primary'
54
- underline='none'
55
- {...linkProps}
56
- sx={[{ whiteSpace: 'nowrap', paddingTop: '6px' }, ...(Array.isArray(sx) ? sx : [sx])]}
57
- >
58
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>{children}</Box>
59
- <Box
60
- component='span'
61
- className={classes.line}
62
- sx={{
63
- maxWidth: 40,
64
- width: '100%',
65
- display: 'flex',
66
- justifyContent: 'center',
67
- height: 2,
68
- background: (theme) => theme.palette.primary.main,
69
- margin: '0 auto',
70
- marginTop: '6px',
71
- opacity: active ? 1 : 0,
72
- }}
73
- />
74
- </Link>
75
- </PageLink>
48
+ <Link
49
+ href={href}
50
+ className={classes.root}
51
+ variant='h6'
52
+ color='text.primary'
53
+ underline='none'
54
+ {...linkProps}
55
+ sx={[{ whiteSpace: 'nowrap', paddingTop: '6px' }, ...(Array.isArray(sx) ? sx : [sx])]}
56
+ >
57
+ <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>{children}</Box>
58
+ <Box
59
+ component='span'
60
+ className={classes.line}
61
+ sx={{
62
+ maxWidth: 40,
63
+ width: '100%',
64
+ display: 'flex',
65
+ justifyContent: 'center',
66
+ height: 2,
67
+ background: (theme) => theme.palette.primary.main,
68
+ margin: '0 auto',
69
+ marginTop: '6px',
70
+ opacity: active ? 1 : 0,
71
+ }}
72
+ />
73
+ </Link>
76
74
  )
77
75
  }
78
76
  DesktopNavItem.selectors = selectors
@@ -6,9 +6,9 @@ import {
6
6
  Theme,
7
7
  unstable_composeClasses as composeClasses,
8
8
  } from '@mui/material'
9
- import PageLink from 'next/link'
10
9
  import { useRouter } from 'next/router'
11
10
  import { forwardRef } from 'react'
11
+ import { NextLink } from '../Theme'
12
12
 
13
13
  /** We're creating some boilerplate */
14
14
  const name = 'GcLogo'
@@ -23,7 +23,7 @@ const useUtilityClasses = ({ classes }: LogoClassProps) =>
23
23
  composeClasses({ logo: ['logo'], parent: ['parent'] }, getLogoUtilityClass, classes)
24
24
 
25
25
  /** Creating styled components */
26
- const LogoContainer = styled('div', {
26
+ const LogoContainer = styled(NextLink, {
27
27
  name,
28
28
  slot: 'parent',
29
29
  overridesResolver: (_props, styles) => styles.parent,
@@ -48,7 +48,7 @@ export type LogoProps = {
48
48
  sx?: SxProps<Theme>
49
49
  } & LogoClassProps
50
50
 
51
- export const Logo = forwardRef<HTMLDivElement, LogoProps>((props, ref) => {
51
+ export const Logo = forwardRef<HTMLAnchorElement, LogoProps>((props, ref) => {
52
52
  const { href = '/', image, sx } = props
53
53
  const router = useRouter()
54
54
 
@@ -68,10 +68,8 @@ export const Logo = forwardRef<HTMLDivElement, LogoProps>((props, ref) => {
68
68
  {img}
69
69
  </LogoContainer>
70
70
  ) : (
71
- <PageLink href={href} passHref>
72
- <LogoContainer ref={ref} as='a' sx={sx} className={classes.parent}>
73
- {img}
74
- </LogoContainer>
75
- </PageLink>
71
+ <LogoContainer href={href} ref={ref} sx={sx} className={classes.parent}>
72
+ {img}
73
+ </LogoContainer>
76
74
  )
77
75
  })
@@ -1,9 +1,10 @@
1
1
  import { ListItemButton, ListItemButtonProps, ListItemText } from '@mui/material'
2
- import PageLink, { LinkProps as PageLinkProps } from 'next/link'
3
2
  import { useRouter } from 'next/router'
3
+ import { NextLink } from '../Theme'
4
4
 
5
- export type MenuFabItemProps = Omit<ListItemButtonProps<'a'>, 'href' | 'button'> &
6
- Pick<PageLinkProps, 'href'>
5
+ export type MenuFabItemProps = Omit<ListItemButtonProps<'a'>, 'href' | 'button'> & {
6
+ href: NonNullable<ListItemButtonProps<'a'>['href']>
7
+ }
7
8
 
8
9
  export function MenuFabItem(props: MenuFabItemProps) {
9
10
  const { href, children, sx = [], ...listItemProps } = props
@@ -12,14 +13,12 @@ export function MenuFabItem(props: MenuFabItemProps) {
12
13
  const active = hrefString === '/' ? path === hrefString : path.startsWith(hrefString)
13
14
 
14
15
  return (
15
- <PageLink key={href.toString()} href={href} passHref>
16
- <ListItemButton component='a' dense selected={active} {...listItemProps}>
17
- <ListItemText
18
- sx={[{ typography: 'h4', lineHeight: 1.1 }, ...(Array.isArray(sx) ? sx : [sx])]}
19
- disableTypography
20
- primary={children}
21
- />
22
- </ListItemButton>
23
- </PageLink>
16
+ <ListItemButton href={href} component={NextLink} dense selected={active} {...listItemProps}>
17
+ <ListItemText
18
+ sx={[{ typography: 'h4', lineHeight: 1.1 }, ...(Array.isArray(sx) ? sx : [sx])]}
19
+ disableTypography
20
+ primary={children}
21
+ />
22
+ </ListItemButton>
24
23
  )
25
24
  }
@@ -1,5 +1,4 @@
1
1
  import { ListItemButton, ListItemIcon, ListItemText, SxProps, Theme } from '@mui/material'
2
- import PageLink from 'next/link'
3
2
  import { useRouter } from 'next/router'
4
3
  import React from 'react'
5
4
  import { extendableComponent } from '../Styles'
@@ -20,19 +19,18 @@ export function MenuFabSecondaryItem(props: FabMenuSecondaryItemProps) {
20
19
  const router = useRouter()
21
20
 
22
21
  return (
23
- <PageLink href={href} passHref>
24
- <ListItemButton
25
- className={classes.root}
26
- sx={[{}, ...(Array.isArray(sx) ? sx : [sx])]}
27
- component='a'
28
- dense
29
- selected={router.asPath.startsWith(href)}
30
- >
31
- <ListItemIcon className={classes.text} sx={{ paddingRight: '8px', minWidth: 'unset' }}>
32
- {icon}
33
- </ListItemIcon>
34
- <ListItemText className={classes.icon}>{children}</ListItemText>
35
- </ListItemButton>
36
- </PageLink>
22
+ <ListItemButton
23
+ href={href}
24
+ className={classes.root}
25
+ sx={[{}, ...(Array.isArray(sx) ? sx : [sx])]}
26
+ component='a'
27
+ dense
28
+ selected={router.asPath.startsWith(href)}
29
+ >
30
+ <ListItemIcon className={classes.text} sx={{ paddingRight: '8px', minWidth: 'unset' }}>
31
+ {icon}
32
+ </ListItemIcon>
33
+ <ListItemText className={classes.icon}>{children}</ListItemText>
34
+ </ListItemButton>
37
35
  )
38
36
  }
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-use-before-define */
2
2
  import { useMotionValueValue } from '@graphcommerce/framer-utils'
3
3
  import { alpha, Box, ListItemButton, styled, useEventCallback, useTheme } from '@mui/material'
4
- import PageLink from 'next/link'
5
4
  import React from 'react'
6
5
  import { IconSvg } from '../../IconSvg'
7
6
  import { extendableComponent } from '../../Styles/extendableComponent'
@@ -15,6 +14,7 @@ import {
15
14
  useNavigation,
16
15
  } from '../hooks/useNavigation'
17
16
  import type { NavigationList } from './NavigationList'
17
+ import { NextLink } from '../../Theme'
18
18
 
19
19
  type OwnerState = {
20
20
  first?: boolean
@@ -160,30 +160,30 @@ export const NavigationItem = React.memo<NavigationItemProps>((props) => {
160
160
 
161
161
  return (
162
162
  <NavigationLI sx={[hideItem && { display: 'none' }]} className={classes.li}>
163
- <PageLink href={href} passHref prefetch={false}>
164
- <ListItemButton
165
- className={classes.item}
166
- component='a'
167
- sx={(theme) => ({
168
- gridRowStart: row,
169
- gridColumnStart: column,
170
- gap: theme.spacings.xxs,
171
- })}
172
- tabIndex={tabIndex}
173
- onClick={onCloseHandler}
163
+ <ListItemButton
164
+ component={NextLink}
165
+ prefetch={false}
166
+ href={href}
167
+ className={classes.item}
168
+ sx={(theme) => ({
169
+ gridRowStart: row,
170
+ gridColumnStart: column,
171
+ gap: theme.spacings.xxs,
172
+ })}
173
+ tabIndex={tabIndex}
174
+ onClick={onCloseHandler}
175
+ >
176
+ <Box
177
+ component='span'
178
+ sx={{
179
+ whiteSpace: 'nowrap',
180
+ overflowX: 'hidden',
181
+ textOverflow: 'ellipsis',
182
+ }}
174
183
  >
175
- <Box
176
- component='span'
177
- sx={{
178
- whiteSpace: 'nowrap',
179
- overflowX: 'hidden',
180
- textOverflow: 'ellipsis',
181
- }}
182
- >
183
- {name}
184
- </Box>
185
- </ListItemButton>
186
- </PageLink>
184
+ {name}
185
+ </Box>
186
+ </ListItemButton>
187
187
  </NavigationLI>
188
188
  )
189
189
  }
@@ -54,7 +54,7 @@ export function canonicalize(router: PartialNextRouter, incomming?: Canonical) {
54
54
  }
55
55
  }
56
56
 
57
- let [href, as] = resolveHref(router as NextRouter, canonical, true)
57
+ let [href, as = href] = resolveHref(router as NextRouter, canonical, true)
58
58
 
59
59
  const curLocale = router.locale
60
60
 
@@ -1,36 +1,29 @@
1
1
  import { ListItemButtonProps, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
2
- import PageLink from 'next/link'
3
2
  import React from 'react'
4
3
  import { IconSvg } from '../../IconSvg'
4
+ import { NextLink } from '../../Theme'
5
5
  import { iconChevronRight } from '../../icons'
6
6
 
7
7
  export type ButtonLinkListItemProps = {
8
- url: string
9
8
  endIcon?: React.ReactNode
10
- } & ListItemButtonProps
9
+ url: string
10
+ } & Omit<ListItemButtonProps<typeof NextLink>, 'href'>
11
11
 
12
12
  export function ButtonLinkListItem(props: ButtonLinkListItemProps) {
13
- const {
14
- children,
15
- url,
16
- endIcon = <IconSvg src={iconChevronRight} />,
17
- ...ButtonLinkListItemProps
18
- } = props
13
+ const { children, endIcon = <IconSvg src={iconChevronRight} />, ...listItemButtonProps } = props
19
14
 
20
15
  return (
21
- <PageLink href={url} passHref>
22
- <ListItemButton
23
- LinkComponent='a'
24
- sx={(theme) => ({
25
- padding: `${theme.spacings.xxs} 0`,
26
- borderBottom: `1px solid ${theme.palette.divider}`,
27
- justifyContent: 'space-between',
28
- })}
29
- {...ButtonLinkListItemProps}
30
- >
31
- <ListItemText>{children}</ListItemText>
32
- <ListItemIcon>{endIcon}</ListItemIcon>
33
- </ListItemButton>
34
- </PageLink>
16
+ <ListItemButton
17
+ component={NextLink}
18
+ sx={(theme) => ({
19
+ padding: `${theme.spacings.xxs} 0`,
20
+ borderBottom: `1px solid ${theme.palette.divider}`,
21
+ justifyContent: 'space-between',
22
+ })}
23
+ {...listItemButtonProps}
24
+ >
25
+ <ListItemText>{children}</ListItemText>
26
+ <ListItemIcon>{endIcon}</ListItemIcon>
27
+ </ListItemButton>
35
28
  )
36
29
  }
@@ -0,0 +1,41 @@
1
+ import Link, { LinkProps as NextLinkProps } from 'next/link'
2
+ import React, { forwardRef } from 'react'
3
+
4
+ type LinkProps = Omit<NextLinkProps, 'legacyBehavior' | 'passHref' | 'as'>
5
+ type AnchorWithoutLinkProps = Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof LinkProps>
6
+ type LinkProppies = AnchorWithoutLinkProps & Partial<LinkProps> & { relative?: boolean }
7
+
8
+ /**
9
+ * This is a wrapper around the Next.js Link component which can be used with MUI's Link component
10
+ * or any ButtonBase derivative.
11
+ *
12
+ * By default you can use the the props provided by the Link or Button component, but you to pass
13
+ * any next/link specific props like `prefetch`, `replace`, `scroll`, `shallow`
14
+ *
15
+ * ```typescript
16
+ * const button = (
17
+ * <Link href='/cart' component={NextLink} prefetch={false}>
18
+ * Cart
19
+ * </Link>
20
+ * )
21
+ * ```
22
+ */
23
+ export const NextLink = forwardRef<HTMLAnchorElement, LinkProppies>((props, ref) => {
24
+ let { href, target, relative, ...rest } = props
25
+
26
+ // The href is optional in a MUI link, but required in a Next.js link
27
+ // eslint-disable-next-line jsx-a11y/anchor-has-content
28
+ if (!href) return <a {...rest} ref={ref} />
29
+
30
+ const hrefString = href.toString()
31
+ const isExternal = hrefString.includes(':') || hrefString.startsWith('//')
32
+ const isHash = hrefString.startsWith('#')
33
+
34
+ if (isExternal) target = target || '_blank'
35
+ target = typeof target === 'undefined' && isExternal ? '_blank' : target
36
+
37
+ // Relative URL's cause more pain than they're worth
38
+ if (!isExternal && !isHash && !hrefString.startsWith('/') && !relative) href = `/${href}`
39
+
40
+ return <Link href={href} {...rest} target={target} ref={ref} />
41
+ })
package/Theme/index.ts CHANGED
@@ -5,3 +5,4 @@ export * from './MuiFab'
5
5
  export * from './MuiSlider'
6
6
  export * from './MuiSnackbar'
7
7
  export * from './themeDefaults'
8
+ export * from './NextLink'
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/next-ui",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "5.2.0-canary.2",
5
+ "version": "5.2.0-canary.3",
6
6
  "author": "",
7
7
  "license": "MIT",
8
8
  "sideEffects": false,
@@ -18,18 +18,18 @@
18
18
  "@emotion/react": "^11.10.5",
19
19
  "@emotion/server": "^11.4.0",
20
20
  "@emotion/styled": "^11.10.5",
21
- "@graphcommerce/framer-next-pages": "5.2.0-canary.2",
22
- "@graphcommerce/framer-scroller": "5.2.0-canary.2",
23
- "@graphcommerce/framer-utils": "5.2.0-canary.2",
24
- "@graphcommerce/image": "5.2.0-canary.2",
21
+ "@graphcommerce/framer-next-pages": "5.2.0-canary.3",
22
+ "@graphcommerce/framer-scroller": "5.2.0-canary.3",
23
+ "@graphcommerce/framer-utils": "5.2.0-canary.3",
24
+ "@graphcommerce/image": "5.2.0-canary.3",
25
25
  "cookie": "^0.5.0",
26
26
  "react-is": "^18.2.0",
27
27
  "schema-dts": "^1.1.0"
28
28
  },
29
29
  "devDependencies": {
30
- "@graphcommerce/eslint-config-pwa": "5.2.0-canary.2",
31
- "@graphcommerce/prettier-config-pwa": "5.2.0-canary.2",
32
- "@graphcommerce/typescript-config-pwa": "5.2.0-canary.2",
30
+ "@graphcommerce/eslint-config-pwa": "5.2.0-canary.3",
31
+ "@graphcommerce/prettier-config-pwa": "5.2.0-canary.3",
32
+ "@graphcommerce/typescript-config-pwa": "5.2.0-canary.3",
33
33
  "@types/cookie": "^0.5.1",
34
34
  "@types/react-is": "^17.0.3",
35
35
  "typescript": "4.9.4"
@@ -40,7 +40,7 @@
40
40
  "@mui/lab": "^5.0.0-alpha.68",
41
41
  "@mui/material": "^5.10.16",
42
42
  "framer-motion": "^7.0.0",
43
- "next": "^12.1.2",
43
+ "next": "^13.1.1",
44
44
  "react": "^18.2.0",
45
45
  "react-dom": "^18.2.0"
46
46
  }