@graphcommerce/next-ui 3.25.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/AnimatedRow/index.tsx +6 -3
  2. package/ApolloError/ApolloErrorAlert.tsx +20 -21
  3. package/ApolloError/ApolloErrorFullPage.tsx +3 -4
  4. package/ApolloError/ApolloErrorSnackbar.tsx +3 -3
  5. package/Blog/BlogAuthor/index.tsx +42 -48
  6. package/Blog/BlogContent/index.tsx +6 -23
  7. package/Blog/BlogHeader/index.tsx +26 -23
  8. package/Blog/BlogList/index.tsx +7 -25
  9. package/Blog/BlogListItem/index.tsx +63 -52
  10. package/Blog/BlogTags/BlogTag.tsx +27 -0
  11. package/Blog/BlogTags/index.tsx +7 -32
  12. package/Blog/BlogTitle/index.tsx +7 -21
  13. package/Button/Button.tsx +5 -0
  14. package/Button/LinkOrButton.tsx +80 -0
  15. package/Button/index.tsx +2 -177
  16. package/CHANGELOG.md +490 -651
  17. package/ChipMenu/index.tsx +71 -77
  18. package/ContainerWithHeader/index.tsx +33 -30
  19. package/FlagAvatar/index.tsx +2 -12
  20. package/Footer/Footer.tsx +105 -88
  21. package/Footer/index.ts +0 -1
  22. package/Form/Form.tsx +35 -0
  23. package/Form/FormActions.tsx +9 -14
  24. package/Form/FormDivider.tsx +8 -13
  25. package/Form/FormHeader.tsx +5 -26
  26. package/Form/FormRow.tsx +8 -13
  27. package/Form/InputCheckmark.tsx +9 -22
  28. package/FramerScroller/SidebarGallery.tsx +340 -0
  29. package/FramerScroller/SidebarSlider.tsx +107 -0
  30. package/FramerScroller/index.ts +2 -0
  31. package/FullPageMessage/index.tsx +52 -48
  32. package/Highlight/index.tsx +1 -1
  33. package/IconHeader/index.tsx +63 -58
  34. package/JsonLd/index.tsx +3 -2
  35. package/Layout/components/LayoutHeader.tsx +75 -82
  36. package/Layout/components/LayoutHeaderBack.tsx +21 -12
  37. package/Layout/components/LayoutHeaderClose.tsx +9 -22
  38. package/Layout/components/LayoutHeaderContent.tsx +190 -154
  39. package/Layout/components/LayoutHeadertypes.ts +1 -1
  40. package/Layout/components/LayoutTitle.tsx +60 -55
  41. package/LayoutDefault/components/LayoutDefault.tsx +96 -85
  42. package/LayoutOverlay/components/LayoutOverlay.tsx +2 -8
  43. package/LayoutOverlay/components/LayoutOverlayBase.tsx +233 -239
  44. package/LayoutOverlay/test/LayoutOverlayDemo.tsx +1 -1
  45. package/LayoutParts/DesktopHeaderBadge.tsx +28 -0
  46. package/LayoutParts/DesktopNavActions.tsx +15 -0
  47. package/LayoutParts/DesktopNavBar.tsx +113 -0
  48. package/LayoutParts/DesktopNavBarItem.tsx +44 -0
  49. package/{AppShell → LayoutParts}/GlobalHead.tsx +1 -2
  50. package/LayoutParts/Logo.tsx +77 -0
  51. package/LayoutParts/MenuFab.tsx +131 -0
  52. package/LayoutParts/MenuFabItem.tsx +25 -0
  53. package/LayoutParts/MenuFabSecondaryItem.tsx +37 -0
  54. package/{AppShell/PlaceholderFab/index.tsx → LayoutParts/PlaceholderFab.tsx} +1 -1
  55. package/LayoutParts/StickyBelowHeader.tsx +25 -0
  56. package/LayoutParts/index.ts +12 -0
  57. package/{AppShell → LayoutParts}/useFabAnimation.ts +0 -0
  58. package/Page/CssAndFramerMotionProvider.tsx +21 -0
  59. package/Page/index.ts +2 -0
  60. package/Page/types.ts +2 -8
  61. package/PageLoadIndicator/index.tsx +25 -30
  62. package/PageMeta/index.tsx +1 -1
  63. package/Pagination/index.tsx +37 -54
  64. package/RenderType/index.tsx +1 -1
  65. package/Row/ButtonLinkList/ButtonLinkList.tsx +35 -37
  66. package/Row/ButtonLinkList/ButtonLinkListItem.tsx +16 -33
  67. package/Row/ColumnOne/index.tsx +5 -10
  68. package/Row/ColumnOneBoxed/index.tsx +18 -19
  69. package/Row/ColumnOneCentered/index.tsx +3 -4
  70. package/Row/ColumnThree/index.tsx +62 -57
  71. package/Row/ColumnTwo/index.tsx +37 -32
  72. package/Row/ColumnTwoSpread/index.tsx +28 -37
  73. package/Row/ColumnTwoWithTop/index.tsx +37 -43
  74. package/Row/ContentLinks/index.tsx +24 -25
  75. package/Row/HeroBanner/index.tsx +98 -82
  76. package/Row/IconBlocks/IconBlock/index.tsx +45 -37
  77. package/Row/IconBlocks/index.tsx +29 -44
  78. package/Row/ImageText/index.tsx +71 -67
  79. package/Row/ImageTextBoxed/index.tsx +66 -65
  80. package/Row/ParagraphWithSidebarSlide/index.tsx +80 -76
  81. package/Row/Quote/index.tsx +3 -3
  82. package/Row/SpecialBanner/index.tsx +97 -97
  83. package/Row/index.tsx +4 -9
  84. package/SectionContainer/index.tsx +32 -31
  85. package/SectionHeader/index.tsx +41 -43
  86. package/Separator/index.tsx +19 -18
  87. package/Snackbar/MessageSnackbar.tsx +1 -2
  88. package/Snackbar/MessageSnackbarImpl.tsx +68 -115
  89. package/StarRatingField/index.tsx +24 -25
  90. package/Stepper/Stepper.tsx +34 -32
  91. package/Styles/EmotionProvider.tsx +14 -0
  92. package/Styles/breakpointVal.tsx +16 -10
  93. package/Styles/extendableComponent.ts +70 -0
  94. package/Styles/index.tsx +9 -2
  95. package/Styles/withEmotionCache.tsx +36 -0
  96. package/Styles/withTheme.tsx +15 -24
  97. package/SvgIcon/SvgIcon.tsx +60 -0
  98. package/TextInputNumber/index.tsx +49 -50
  99. package/Theme/MuiButton.ts +128 -0
  100. package/Theme/MuiSlider.ts +28 -0
  101. package/Theme/MuiSnackbar.ts +31 -0
  102. package/Theme/{types.ts → createTheme.ts} +8 -2
  103. package/Theme/index.ts +4 -0
  104. package/Theme/themeDefaults.ts +51 -0
  105. package/TimeAgo/index.tsx +1 -1
  106. package/ToggleButton/index.tsx +43 -49
  107. package/ToggleButtonGroup/index.tsx +39 -39
  108. package/UspList/UspListItem.tsx +56 -46
  109. package/UspList/index.tsx +29 -26
  110. package/docs/building-components.mdx +3 -0
  111. package/docs/components/ComponentBasic.tsx +26 -0
  112. package/docs/components/ComponentChild.tsx +48 -0
  113. package/docs/components/ComponentChildVariant.tsx +54 -0
  114. package/docs/components/ComponentChildVariantExtendable.tsx +62 -0
  115. package/docs/components/ComponentStylable.tsx +32 -0
  116. package/docs/pages/building-components.tsx +62 -0
  117. package/index.ts +27 -81
  118. package/package.json +25 -27
  119. package/types.d.ts +1 -1
  120. package/AppShell/AppShellSticky/index.tsx +0 -38
  121. package/AppShell/DesktopNavActions.tsx +0 -32
  122. package/AppShell/DesktopNavBar.tsx +0 -158
  123. package/AppShell/Logo.tsx +0 -46
  124. package/AppShell/Menu.tsx +0 -7
  125. package/AppShell/MenuFab.tsx +0 -162
  126. package/AppShell/MenuFabSecondaryItem.tsx +0 -32
  127. package/AppShell/index.ts +0 -15
  128. package/AspectRatioContainer/index.tsx +0 -27
  129. package/Footer/SocialIcon.tsx +0 -23
  130. package/Form/index.tsx +0 -67
  131. package/FramerScroller/components/SidebarGallery.tsx +0 -317
  132. package/FramerScroller/components/SidebarSlider.tsx +0 -97
  133. package/Page/App.tsx +0 -17
  134. package/Page/Document.tsx +0 -24
  135. package/StyledBadge/index.tsx +0 -20
  136. package/Styles/classesPicker.ts +0 -41
  137. package/SvgImage/SvgImageSimple.tsx +0 -100
  138. package/SvgImage/index.tsx +0 -74
@@ -0,0 +1,113 @@
1
+ import { Scroller, ScrollerButton, ScrollerProvider } from '@graphcommerce/framer-scroller'
2
+ import { Box, BoxProps } from '@mui/material'
3
+ import React from 'react'
4
+ import { extendableComponent } from '../Styles/extendableComponent'
5
+ import { SvgIcon, SvgIconProps } from '../SvgIcon/SvgIcon'
6
+ import { iconChevronLeft, iconChevronRight } from '../icons'
7
+
8
+ export type MenuTabsProps = {
9
+ children: React.ReactNode
10
+ iconLeft?: SvgIconProps['src']
11
+ iconRight?: SvgIconProps['src']
12
+ } & Pick<BoxProps, 'sx'>
13
+
14
+ const { classes, selectors } = extendableComponent('DesktopNavBar', [
15
+ 'root',
16
+ 'scroller',
17
+ 'leftWrapper',
18
+ 'rightWrapper',
19
+ 'left',
20
+ 'right',
21
+ ] as const)
22
+
23
+ export function DesktopNavBar(props: MenuTabsProps) {
24
+ const { children, iconLeft, iconRight, sx = [] } = props
25
+
26
+ return (
27
+ <ScrollerProvider scrollSnapAlign='none'>
28
+ <Box
29
+ className={classes.root}
30
+ sx={[
31
+ {
32
+ width: '100%',
33
+ display: { xs: 'none', md: 'grid' },
34
+ alignItems: 'center',
35
+ position: 'relative',
36
+ pointerEvents: 'all',
37
+ },
38
+ ...(Array.isArray(sx) ? sx : [sx]),
39
+ ]}
40
+ >
41
+ <Scroller
42
+ hideScrollbar
43
+ sx={(theme) => ({
44
+ gridArea: `1 / 1 / 1 / 4`,
45
+ columnGap: theme.spacings.md,
46
+ padding: `0 ${theme.spacings.sm}`,
47
+ gridAutoColumns: 'min-content',
48
+ })}
49
+ className={classes.scroller}
50
+ >
51
+ {children}
52
+ </Scroller>
53
+
54
+ <Box
55
+ sx={{
56
+ gridArea: `1 / 1 / 1 / 2`,
57
+ pointerEvents: 'none',
58
+ '& > *': { pointerEvents: 'all' },
59
+ }}
60
+ className={classes.leftWrapper}
61
+ >
62
+ <ScrollerButton
63
+ sx={{
64
+ pointerEvents: 'all',
65
+ boxShadow: 'none',
66
+ height: 48,
67
+ borderTopLeftRadius: 0,
68
+ borderBottomLeftRadius: 0,
69
+ backgroundColor: 'transparent',
70
+ backgroundImage: (theme) =>
71
+ `linear-gradient(to left, rgba(255,255,255,0) 0%, ${theme.palette.background.default} 35%)`,
72
+ }}
73
+ direction='left'
74
+ size='small'
75
+ className={classes.left}
76
+ >
77
+ <SvgIcon src={iconLeft ?? iconChevronLeft} />
78
+ </ScrollerButton>
79
+ </Box>
80
+
81
+ <Box
82
+ sx={{
83
+ gridArea: `1 / 3 / 1 / 4`,
84
+ pointerEvents: 'none',
85
+ '& > *': {
86
+ pointerEvents: 'all',
87
+ },
88
+ }}
89
+ className={classes.rightWrapper}
90
+ >
91
+ <ScrollerButton
92
+ sx={{
93
+ pointerEvents: 'all',
94
+ boxShadow: 'none',
95
+ height: 48,
96
+ borderTopRightRadius: 0,
97
+ borderBottomRightRadius: 0,
98
+ backgroundColor: 'transparent',
99
+ backgroundImage: (theme) =>
100
+ `linear-gradient(to right, rgba(255,255,255,0) 0%, ${theme.palette.background.default} 35%)`,
101
+ }}
102
+ direction='right'
103
+ size='small'
104
+ className={classes.right}
105
+ >
106
+ <SvgIcon src={iconRight ?? iconChevronRight} />
107
+ </ScrollerButton>
108
+ </Box>
109
+ </Box>
110
+ </ScrollerProvider>
111
+ )
112
+ }
113
+ DesktopNavBar.selectors = selectors
@@ -0,0 +1,44 @@
1
+ import { Box, Link, LinkProps } from '@mui/material'
2
+ import PageLink, { LinkProps as PageLinkProps } from 'next/link'
3
+ import { useRouter } from 'next/router'
4
+ import { extendableComponent } from '../Styles/extendableComponent'
5
+
6
+ const { classes, selectors } = extendableComponent('DesktopNavItem', ['root', 'line'] as const)
7
+
8
+ export type DesktopNavItemProps = LinkProps & Pick<PageLinkProps, 'href'>
9
+
10
+ export function DesktopNavItem(props: DesktopNavItemProps) {
11
+ const { href, children, sx = [], ...linkProps } = props
12
+ const active = useRouter().asPath.startsWith(href.toString())
13
+
14
+ return (
15
+ <PageLink href={href} passHref>
16
+ <Link
17
+ className={classes.root}
18
+ variant='h6'
19
+ color='text.primary'
20
+ underline='none'
21
+ {...linkProps}
22
+ sx={[{ whiteSpace: 'nowrap', paddingTop: '6px' }, ...(Array.isArray(sx) ? sx : [sx])]}
23
+ >
24
+ {children}
25
+ <Box
26
+ component='span'
27
+ className={classes.line}
28
+ sx={{
29
+ maxWidth: 40,
30
+ width: '100%',
31
+ display: 'flex',
32
+ justifyContent: 'center',
33
+ height: 2,
34
+ background: (theme) => theme.palette.primary.main,
35
+ margin: '0 auto',
36
+ marginTop: '6px',
37
+ opacity: active ? 1 : 0,
38
+ }}
39
+ />
40
+ </Link>
41
+ </PageLink>
42
+ )
43
+ }
44
+ DesktopNavItem.selectors = selectors
@@ -1,6 +1,5 @@
1
- import { useTheme } from '@material-ui/core'
1
+ import { useTheme } from '@mui/material'
2
2
  import Head from 'next/head'
3
- import React from 'react'
4
3
 
5
4
  export type GlobalHeadProps = { name: string }
6
5
 
@@ -0,0 +1,77 @@
1
+ import { Image, ImageProps } from '@graphcommerce/image'
2
+ import {
3
+ generateUtilityClass,
4
+ styled,
5
+ SxProps,
6
+ Theme,
7
+ unstable_composeClasses as composeClasses,
8
+ } from '@mui/material'
9
+ import PageLink from 'next/link'
10
+ import { useRouter } from 'next/router'
11
+ import { forwardRef } from 'react'
12
+
13
+ /** We're creating some boilerplate */
14
+ const name = 'GcLogo'
15
+ type LogoClassKey = 'logo' | 'parent'
16
+
17
+ type LogoClasses = Record<LogoClassKey, string>
18
+ type LogoClassProps = { classes?: Partial<LogoClasses> }
19
+
20
+ const getLogoUtilityClass = (slot: string) => generateUtilityClass(name, slot)
21
+
22
+ const useUtilityClasses = ({ classes }: LogoClassProps) =>
23
+ composeClasses({ logo: ['logo'], parent: ['parent'] }, getLogoUtilityClass, classes)
24
+
25
+ /** Creating styled components */
26
+ const LogoContainer = styled('div', {
27
+ name,
28
+ slot: 'parent',
29
+ overridesResolver: (_props, styles) => styles.parent,
30
+ })(({ theme }) => ({
31
+ height: '100%',
32
+ width: 'max-content',
33
+ display: 'flex',
34
+ alignItems: 'center',
35
+ margin: '0 auto',
36
+ justifyContent: 'center',
37
+ pointerEvents: 'all',
38
+ [theme.breakpoints.up('md')]: {
39
+ display: 'flex',
40
+ margin: 'unset',
41
+ justifyContent: 'left',
42
+ },
43
+ }))
44
+
45
+ export type LogoProps = {
46
+ href?: `/${string}`
47
+ image: ImageProps
48
+ sx?: SxProps<Theme>
49
+ } & LogoClassProps
50
+
51
+ export const Logo = forwardRef<HTMLDivElement, LogoProps>((props, ref) => {
52
+ const { href = '/', image, sx } = props
53
+ const router = useRouter()
54
+
55
+ const classes = useUtilityClasses(props)
56
+
57
+ const img = (
58
+ <Image
59
+ layout='fixed'
60
+ loading='eager'
61
+ {...image}
62
+ className={`${image.className} ${classes?.logo ?? ''}`}
63
+ />
64
+ )
65
+
66
+ return router.asPath === '/' ? (
67
+ <LogoContainer ref={ref} sx={sx} className={classes.parent}>
68
+ {img}
69
+ </LogoContainer>
70
+ ) : (
71
+ <PageLink href={href} passHref>
72
+ <LogoContainer ref={ref} as='a' sx={sx} className={classes.parent}>
73
+ {img}
74
+ </LogoContainer>
75
+ </PageLink>
76
+ )
77
+ })
@@ -0,0 +1,131 @@
1
+ import { Divider, Fab, ListItem, Menu, styled, Box } from '@mui/material'
2
+ import { m } from 'framer-motion'
3
+ import { useRouter } from 'next/router'
4
+ import React, { useEffect } from 'react'
5
+ import { extendableComponent } from '../Styles/extendableComponent'
6
+ import { responsiveVal } from '../Styles/responsiveVal'
7
+ import { SvgIcon } from '../SvgIcon/SvgIcon'
8
+ import { iconMenu, iconClose } from '../icons'
9
+ import { useFabAnimation } from './useFabAnimation'
10
+
11
+ const MotionDiv = styled(m.div)({})
12
+
13
+ export type MenuFabProps = {
14
+ children?: React.ReactNode
15
+ secondary?: React.ReactNode
16
+ search?: React.ReactNode
17
+ menuIcon?: React.ReactNode
18
+ closeIcon?: React.ReactNode
19
+ }
20
+
21
+ const { classes, selectors } = extendableComponent('MenuFab', [
22
+ 'root',
23
+ 'fab',
24
+ 'shadow',
25
+ 'menu',
26
+ ] as const)
27
+
28
+ const fabIconSize = responsiveVal(42, 56) // @todo generalize this
29
+
30
+ export function MenuFab(props: MenuFabProps) {
31
+ const { children, secondary, search, menuIcon, closeIcon } = props
32
+ const router = useRouter()
33
+ const [openEl, setOpenEl] = React.useState<null | HTMLElement>(null)
34
+
35
+ const { opacity, scale, shadowOpacity } = useFabAnimation()
36
+
37
+ useEffect(() => {
38
+ const clear = () => setOpenEl(null)
39
+ router.events.on('routeChangeStart', clear)
40
+ return () => router.events.off('routeChangeStart', clear)
41
+ }, [router])
42
+
43
+ return (
44
+ <Box sx={{ width: fabIconSize, height: fabIconSize }}>
45
+ <MotionDiv
46
+ className={classes.root}
47
+ sx={(theme) => ({
48
+ [theme.breakpoints.down('md')]: {
49
+ opacity: '1 !important',
50
+ transform: 'none !important',
51
+ },
52
+ })}
53
+ style={{ scale, opacity }}
54
+ >
55
+ <Fab
56
+ color='inherit'
57
+ aria-label='Open Menu'
58
+ size='medium'
59
+ onClick={(event) => setOpenEl(event.currentTarget)}
60
+ sx={(theme) => ({
61
+ boxShadow: 'none',
62
+ '&:hover, &:focus': {
63
+ boxShadow: 'none',
64
+ background: theme.palette.text.primary,
65
+ },
66
+ background: theme.palette.text.primary,
67
+ width: fabIconSize,
68
+ height: fabIconSize,
69
+ pointerEvents: 'all',
70
+ color: theme.palette.background.paper,
71
+ })}
72
+ className={classes.fab}
73
+ >
74
+ {closeIcon ?? (
75
+ <SvgIcon src={iconClose} size='medium' sx={{ display: openEl ? 'block' : 'none' }} />
76
+ )}
77
+ {menuIcon ?? (
78
+ <SvgIcon src={iconMenu} size='medium' sx={{ display: openEl ? 'none' : 'block' }} />
79
+ )}
80
+ </Fab>
81
+ <MotionDiv
82
+ sx={(theme) => ({
83
+ pointerEvents: 'none',
84
+ borderRadius: '99em',
85
+ position: 'absolute',
86
+ height: '100%',
87
+ width: '100%',
88
+ boxShadow: theme.shadows[6],
89
+ top: 0,
90
+ [theme.breakpoints.down('md')]: { opacity: '1 !important' },
91
+ })}
92
+ className={classes.shadow}
93
+ style={{ opacity: shadowOpacity }}
94
+ />
95
+
96
+ <Menu
97
+ anchorEl={openEl}
98
+ open={!!openEl}
99
+ onClose={() => setOpenEl(null)}
100
+ disableScrollLock
101
+ transitionDuration={{ appear: 175, enter: 175, exit: 175 }}
102
+ PaperProps={{
103
+ sx: (theme) => ({
104
+ backgroundColor: theme.palette.background.paper,
105
+ color: theme.palette.text.primary,
106
+ minWidth: responsiveVal(200, 280),
107
+ marginTop: '12px',
108
+ [theme.breakpoints.down('md')]: {
109
+ marginTop: `calc((${fabIconSize} + 12px) * -1)`,
110
+ },
111
+ }),
112
+ }}
113
+ className={classes.menu}
114
+ MenuListProps={{ dense: true }}
115
+ >
116
+ {[
117
+ search ? (
118
+ <ListItem key='search' dense sx={{ mb: '6px' }}>
119
+ {search}
120
+ </ListItem>
121
+ ) : null,
122
+ ...React.Children.toArray(children),
123
+ <Divider key='divider' variant='middle' sx={{ my: '6px' }} />,
124
+ ...React.Children.toArray(secondary),
125
+ ]}
126
+ </Menu>
127
+ </MotionDiv>
128
+ </Box>
129
+ )
130
+ }
131
+ MenuFab.selectors = selectors
@@ -0,0 +1,25 @@
1
+ import { ListItemButton, ListItemButtonProps, ListItemText } from '@mui/material'
2
+ import PageLink, { LinkProps as PageLinkProps } from 'next/link'
3
+ import { useRouter } from 'next/router'
4
+
5
+ export type MenuFabItemProps = Omit<ListItemButtonProps<'a'>, 'href' | 'button'> &
6
+ Pick<PageLinkProps, 'href'>
7
+
8
+ export function MenuFabItem(props: MenuFabItemProps) {
9
+ const { href, children, sx = [], ...listItemProps } = props
10
+ const hrefString = href.toString()
11
+ const { asPath } = useRouter()
12
+ const active = hrefString === '/' ? asPath === hrefString : asPath.startsWith(hrefString)
13
+
14
+ 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>
24
+ )
25
+ }
@@ -0,0 +1,37 @@
1
+ import { ListItemButton, ListItemIcon, ListItemText, SxProps, Theme } from '@mui/material'
2
+ import PageLink from 'next/link'
3
+ import router from 'next/router'
4
+ import React from 'react'
5
+ import { extendableComponent } from '../Styles'
6
+
7
+ export type FabMenuSecondaryItemProps = {
8
+ href: string
9
+ children: React.ReactNode
10
+ icon: React.ReactNode
11
+ sx?: SxProps<Theme>
12
+ }
13
+
14
+ const compName = 'MenuFabSecondaryItem' as const
15
+ const parts = ['root', 'icon', 'text'] as const
16
+ const { classes } = extendableComponent(compName, parts)
17
+
18
+ export function MenuFabSecondaryItem(props: FabMenuSecondaryItemProps) {
19
+ const { href, children, icon, sx = [] } = props
20
+
21
+ return (
22
+ <PageLink href={href} passHref>
23
+ <ListItemButton
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>
35
+ </PageLink>
36
+ )
37
+ }
@@ -1,4 +1,4 @@
1
- import { Fab, FabProps, styled } from '@material-ui/core'
1
+ import { Fab, FabProps, styled } from '@mui/material'
2
2
 
3
3
  export const PlaceholderFab = styled((props: Omit<FabProps, 'children'>) => (
4
4
  <Fab {...props}>
@@ -0,0 +1,25 @@
1
+ import { Container } from '@mui/material'
2
+ import React from 'react'
3
+
4
+ export type StickyBelowHeaderProps = {
5
+ children: React.ReactNode
6
+ }
7
+
8
+ /** - Makes the children sticky to the parent container */
9
+ export function StickyBelowHeader(props: StickyBelowHeaderProps) {
10
+ return (
11
+ <Container
12
+ sx={(theme) => ({
13
+ position: 'sticky',
14
+ top: { xs: theme.appShell.headerHeightSm, md: `${theme.page.vertical} !important` },
15
+ zIndex: 96,
16
+ pointerEvents: 'none',
17
+ '& > *': {
18
+ pointerEvents: 'auto',
19
+ },
20
+ })}
21
+ maxWidth={false}
22
+ {...props}
23
+ />
24
+ )
25
+ }
@@ -0,0 +1,12 @@
1
+ export * from './DesktopHeaderBadge'
2
+ export * from './DesktopNavActions'
3
+ export * from './DesktopNavBar'
4
+ export * from './DesktopNavBarItem'
5
+ export * from './GlobalHead'
6
+ export * from './Logo'
7
+ export * from './MenuFab'
8
+ export * from './MenuFabItem'
9
+ export * from './MenuFabSecondaryItem'
10
+ export * from './PlaceholderFab'
11
+ export * from './StickyBelowHeader'
12
+ export * from './useFabAnimation'
File without changes
@@ -0,0 +1,21 @@
1
+ import { LazyMotion } from 'framer-motion'
2
+ import { EmotionProvider } from '../Styles'
3
+
4
+ export type GraphCommerceProviderProps = {
5
+ children: React.ReactNode
6
+ }
7
+
8
+ /**
9
+ * For [@emotion/core](https://emotion.sh/docs/introduction) and
10
+ * [framer-motion](https://www.framer.com/motion/) to work they need to have a provider.
11
+ *
12
+ * - Wrapps the app to lazily load framer-motion.
13
+ * - Wrapps the app to have Emotion CSS styles
14
+ */
15
+ export function CssAndFramerMotionProvider({ children }: GraphCommerceProviderProps) {
16
+ return (
17
+ <LazyMotion features={async () => (await import('./framerFeatures')).default} strict>
18
+ <EmotionProvider>{children}</EmotionProvider>
19
+ </LazyMotion>
20
+ )
21
+ }
package/Page/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './CssAndFramerMotionProvider'
2
+ export * from './types'
package/Page/types.ts CHANGED
@@ -1,20 +1,14 @@
1
1
  import { ParsedUrlQuery } from 'querystring'
2
- import { NormalizedCacheObject } from '@apollo/client'
2
+ import { NormalizedCacheObject } from '@graphcommerce/graphql'
3
3
  import { UpPage } from '@graphcommerce/framer-next-pages/types'
4
4
  import { GetStaticProps as GetStaticPropsNext } from 'next'
5
- import { AppProps as NextAppProps } from 'next/app'
6
5
 
7
6
  type AnyObj = Record<string, unknown>
8
7
 
9
- type ApolloStateProps = { apolloState: NormalizedCacheObject; up?: UpPage | null }
8
+ export type ApolloStateProps = { apolloState: NormalizedCacheObject; up?: UpPage | null }
10
9
 
11
10
  export type GetStaticProps<
12
11
  PL extends AnyObj,
13
12
  P extends AnyObj = AnyObj,
14
13
  Q extends ParsedUrlQuery = ParsedUrlQuery,
15
14
  > = GetStaticPropsNext<P & Omit<PL, 'children'> & ApolloStateProps, Q>
16
-
17
- /** Used by _app */
18
- export type AppProps = Omit<NextAppProps, 'pageProps'> & {
19
- pageProps: ApolloStateProps
20
- }
@@ -1,46 +1,41 @@
1
- import { LinearProgress, makeStyles, Fade } from '@material-ui/core'
2
- import zIndex from '@material-ui/core/styles/zIndex'
1
+ import { LinearProgress, Fade } from '@mui/material'
3
2
  import { useRouter } from 'next/router'
4
- import React, { useEffect, useState } from 'react'
3
+ import { useEffect, useState } from 'react'
5
4
 
6
- const useStyles = makeStyles(
7
- {
8
- progress: {
9
- position: 'fixed',
10
- width: '100%',
11
- top: 0,
12
- height: 3,
13
- marginBottom: -3,
14
- zIndex: zIndex.tooltip,
15
- },
16
- },
17
- { name: 'PageLoadIndicator' },
18
- )
19
-
20
- function PageLoadIndicator() {
21
- const router = useRouter()
22
- const classes = useStyles()
5
+ /**
6
+ * Creates a [LinearProgress](https://mui.com/components/progress/#linear) animation when the route
7
+ * is about to change until it has changed.
8
+ */
9
+ export function PageLoadIndicator() {
10
+ const { events } = useRouter()
23
11
  const [loading, setLoading] = useState<boolean>(false)
24
12
 
25
13
  useEffect(() => {
26
14
  const show = () => setLoading(true)
27
15
  const hide = () => setLoading(false)
28
- router.events.on('routeChangeStart', show)
29
- router.events.on('routeChangeComplete', hide)
30
- router.events.on('routeChangeError', hide)
16
+ events.on('routeChangeStart', show)
17
+ events.on('routeChangeComplete', hide)
18
+ events.on('routeChangeError', hide)
31
19
 
32
20
  return () => {
33
- router.events.off('routeChangeStart', show)
34
- router.events.off('routeChangeComplete', hide)
35
- router.events.off('routeChangeError', hide)
21
+ events.off('routeChangeStart', show)
22
+ events.off('routeChangeComplete', hide)
23
+ events.off('routeChangeError', hide)
36
24
  }
37
- }, [router.events])
25
+ }, [events])
38
26
 
39
27
  return (
40
28
  <Fade in={loading}>
41
- <LinearProgress className={classes.progress} />
29
+ <LinearProgress
30
+ sx={{
31
+ position: 'fixed',
32
+ width: '100%',
33
+ top: 0,
34
+ height: 3,
35
+ marginBottom: '-3px',
36
+ zIndex: 'tooltip',
37
+ }}
38
+ />
42
39
  </Fade>
43
40
  )
44
41
  }
45
-
46
- export default PageLoadIndicator
@@ -22,7 +22,7 @@ export type PageMetaProps = {
22
22
  metaRobots?: MetaRobotsAll | MetaRobots[]
23
23
  }
24
24
 
25
- export default function PageMeta(props: PageMetaProps) {
25
+ export function PageMeta(props: PageMetaProps) {
26
26
  const { active } = usePageContext()
27
27
  const { title, canonical, metaDescription, metaRobots = ['all'] } = props
28
28