@graphcommerce/next-ui 4.0.1 → 4.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Change Log
2
2
 
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1273](https://github.com/ho-nl/m2-pwa/pull/1273)
8
+ [`8c4e4f7cd`](https://github.com/ho-nl/m2-pwa/commit/8c4e4f7cdd2fa4252788fbc9889d0803bba20eef)
9
+ Thanks [@paales](https://github.com/paales)! - Added darkmode support! ☀️🌑, adds a toggle to the
10
+ hamburger menu.
11
+
12
+ ### Patch Changes
13
+
14
+ - [#1271](https://github.com/ho-nl/m2-pwa/pull/1271)
15
+ [`e0008d60d`](https://github.com/ho-nl/m2-pwa/commit/e0008d60d712603219129dd411d1985bf1ebbed1)
16
+ Thanks [@paales](https://github.com/paales)! - make sure the CartFab and MenuFab are stylable with
17
+ sx
18
+
19
+ * [#1271](https://github.com/ho-nl/m2-pwa/pull/1271)
20
+ [`5d9f8320f`](https://github.com/ho-nl/m2-pwa/commit/5d9f8320ff9621d7357fbe01319ab0cafdf9095d)
21
+ Thanks [@paales](https://github.com/paales)! - prevent layout from breaking when url has params
22
+
23
+ - [#1271](https://github.com/ho-nl/m2-pwa/pull/1271)
24
+ [`5082b8c81`](https://github.com/ho-nl/m2-pwa/commit/5082b8c8191cc3e0b4627678bf837af093513d57)
25
+ Thanks [@paales](https://github.com/paales)! - Prevent showing back button on homepage when query
26
+ parameter is present
27
+
3
28
  ## 4.0.1
4
29
 
5
30
  ### Patch Changes
@@ -1,5 +1,4 @@
1
1
  import { useUp, usePrevUp, usePageContext } from '@graphcommerce/framer-next-pages'
2
- import { usePrevPageRouter } from '@graphcommerce/framer-next-pages/hooks/usePrevPageRouter'
3
2
  import { t } from '@lingui/macro'
4
3
  import PageLink from 'next/link'
5
4
  import { useRouter } from 'next/router'
@@ -10,31 +9,31 @@ import { iconChevronLeft } from '../../icons'
10
9
  export type BackProps = Omit<LinkOrButtonProps, 'onClick' | 'children'>
11
10
 
12
11
  export function useShowBack() {
13
- const router = useRouter()
12
+ const path = useRouter().asPath.split('?')[0]
14
13
  const up = useUp()
15
14
  const prevUp = usePrevUp()
16
15
  const { backSteps } = usePageContext()
17
16
 
18
- const canClickBack = backSteps > 0 && router.asPath !== prevUp?.href
17
+ const canClickBack = backSteps > 0 && path !== prevUp?.href
19
18
 
20
19
  if (canClickBack) return true
21
- if (up?.href && up.href !== router.asPath) return true
20
+ if (up?.href && up.href !== path) return true
22
21
  return false
23
22
  }
24
23
 
25
24
  export default function LayoutHeaderBack(props: BackProps) {
26
25
  const router = useRouter()
26
+ const path = router.asPath.split('?')[0]
27
27
  const up = useUp()
28
- const prevRouter = usePrevPageRouter()
29
28
  const prevUp = usePrevUp()
30
29
  const { backSteps } = usePageContext()
31
30
 
32
31
  const backIcon = <SvgIcon src={iconChevronLeft} size='medium' />
33
- const canClickBack = backSteps > 0 && router.asPath !== prevUp?.href
32
+ const canClickBack = backSteps > 0 && path !== prevUp?.href
34
33
 
35
34
  let label = t`Back`
36
- if (up?.href === prevRouter?.asPath && up?.title) label = up.title
37
- if (prevUp?.href === prevRouter?.asPath && prevUp?.title) label = prevUp.title
35
+ if (up?.href === path && up?.title) label = up.title
36
+ if (prevUp?.href === path && prevUp?.title) label = prevUp.title
38
37
 
39
38
  if (canClickBack) {
40
39
  return (
@@ -51,7 +50,7 @@ export default function LayoutHeaderBack(props: BackProps) {
51
50
  )
52
51
  }
53
52
 
54
- if (up?.href && up.href !== router.asPath)
53
+ if (up?.href && up.href !== path)
55
54
  return (
56
55
  <PageLink href={up.href} passHref>
57
56
  <LinkOrButton
@@ -63,7 +63,7 @@ export const Logo = forwardRef<HTMLDivElement, LogoProps>((props, ref) => {
63
63
  />
64
64
  )
65
65
 
66
- return router.asPath === '/' ? (
66
+ return router.asPath.split('?')[0] === '/' ? (
67
67
  <LogoContainer ref={ref} sx={sx} className={classes.parent}>
68
68
  {img}
69
69
  </LogoContainer>
@@ -1,4 +1,4 @@
1
- import { Divider, Fab, ListItem, Menu, styled, Box } from '@mui/material'
1
+ import { Divider, Fab, ListItem, Menu, styled, Box, SxProps, Theme } from '@mui/material'
2
2
  import { m } from 'framer-motion'
3
3
  import { useRouter } from 'next/router'
4
4
  import React, { useEffect } from 'react'
@@ -16,10 +16,11 @@ export type MenuFabProps = {
16
16
  search?: React.ReactNode
17
17
  menuIcon?: React.ReactNode
18
18
  closeIcon?: React.ReactNode
19
+ sx?: SxProps<Theme>
19
20
  }
20
21
 
21
22
  const { classes, selectors } = extendableComponent('MenuFab', [
22
- 'root',
23
+ 'wrapper',
23
24
  'fab',
24
25
  'shadow',
25
26
  'menu',
@@ -28,7 +29,7 @@ const { classes, selectors } = extendableComponent('MenuFab', [
28
29
  const fabIconSize = responsiveVal(42, 56) // @todo generalize this
29
30
 
30
31
  export function MenuFab(props: MenuFabProps) {
31
- const { children, secondary, search, menuIcon, closeIcon } = props
32
+ const { children, secondary, search, menuIcon, closeIcon, sx = [] } = props
32
33
  const router = useRouter()
33
34
  const [openEl, setOpenEl] = React.useState<null | HTMLElement>(null)
34
35
 
@@ -41,9 +42,9 @@ export function MenuFab(props: MenuFabProps) {
41
42
  }, [router])
42
43
 
43
44
  return (
44
- <Box sx={{ width: fabIconSize, height: fabIconSize }}>
45
+ <Box sx={[{ width: fabIconSize, height: fabIconSize }, ...(Array.isArray(sx) ? sx : [sx])]}>
45
46
  <MotionDiv
46
- className={classes.root}
47
+ className={classes.wrapper}
47
48
  sx={(theme) => ({
48
49
  [theme.breakpoints.down('md')]: {
49
50
  opacity: '1 !important',
@@ -8,8 +8,8 @@ export type MenuFabItemProps = Omit<ListItemButtonProps<'a'>, 'href' | 'button'>
8
8
  export function MenuFabItem(props: MenuFabItemProps) {
9
9
  const { href, children, sx = [], ...listItemProps } = props
10
10
  const hrefString = href.toString()
11
- const { asPath } = useRouter()
12
- const active = hrefString === '/' ? asPath === hrefString : asPath.startsWith(hrefString)
11
+ const path = useRouter().asPath.split('?')[0]
12
+ const active = hrefString === '/' ? path === hrefString : path.startsWith(hrefString)
13
13
 
14
14
  return (
15
15
  <PageLink key={href.toString()} href={href} passHref>
@@ -0,0 +1,119 @@
1
+ import { Trans } from '@lingui/macro'
2
+ import {
3
+ Theme,
4
+ ThemeProvider,
5
+ useMediaQuery,
6
+ Fab,
7
+ FabProps,
8
+ ListItemButton,
9
+ ListItemIcon,
10
+ ListItemText,
11
+ ListItemButtonProps,
12
+ } from '@mui/material'
13
+ import { useRouter } from 'next/router'
14
+ import { createContext, useContext, useEffect, useMemo, useState } from 'react'
15
+ import { SvgIcon } from '../SvgIcon/SvgIcon'
16
+ import { iconMoon, iconSun } from '../icons'
17
+
18
+ type Mode = 'dark' | 'light'
19
+ type UserMode = 'auto' | Mode
20
+
21
+ type ColorModeContext = {
22
+ userMode: UserMode
23
+ browserMode: Mode
24
+ currentMode: Mode
25
+ toggle: () => void
26
+ }
27
+
28
+ export const colorModeContext = createContext(undefined as unknown as ColorModeContext)
29
+ colorModeContext.displayName = 'ColorModeContext'
30
+
31
+ type ThemeProviderProps = {
32
+ // eslint-disable-next-line react/no-unused-prop-types
33
+ light: Theme
34
+ // eslint-disable-next-line react/no-unused-prop-types
35
+ dark: Theme
36
+
37
+ children: React.ReactNode
38
+ }
39
+
40
+ /**
41
+ * Wrapper around `import { ThemeProvider } from '@mui/material'`
42
+ *
43
+ * The multi DarkLightModeThemeProvider allows switching between light and dark mode based on URL
44
+ * and on user input.
45
+ *
46
+ * If you *just* wan't a single theme, use the import { ThemeProvider } from '@mui/material' instead.
47
+ */
48
+ export function DarkLightModeThemeProvider(props: ThemeProviderProps) {
49
+ const { children, light, dark } = props
50
+
51
+ // todo: Save this in local storage
52
+ const [userMode, setUserMode] = useState<UserMode>('auto')
53
+ const browserMode: Mode = useMediaQuery('(prefers-color-scheme: dark)') ? 'dark' : 'light'
54
+
55
+ // If the user has set a mode, use that. Otherwise, use the browser mode.
56
+ const currentMode = userMode === 'auto' ? browserMode : userMode
57
+ const theme = currentMode === 'light' ? light : dark
58
+
59
+ // If a URL parameter is present, switch from auto to light or dark mode
60
+ const { asPath } = useRouter()
61
+ useEffect(() => {
62
+ if (asPath.includes('darkmode')) setUserMode('dark')
63
+ }, [asPath])
64
+
65
+ // Create the context
66
+ const colorContext: ColorModeContext = useMemo(
67
+ () => ({
68
+ browserMode,
69
+ userMode,
70
+ currentMode,
71
+ toggle: () => setUserMode(currentMode === 'light' ? 'dark' : 'light'),
72
+ }),
73
+ [browserMode, currentMode, userMode],
74
+ )
75
+
76
+ return (
77
+ <colorModeContext.Provider value={colorContext}>
78
+ <ThemeProvider theme={theme}>{children}</ThemeProvider>
79
+ </colorModeContext.Provider>
80
+ )
81
+ }
82
+
83
+ export function useColorMode() {
84
+ return useContext(colorModeContext)
85
+ }
86
+
87
+ export function DarkLightModeToggleFab(props: Omit<FabProps, 'onClick'>) {
88
+ const { currentMode, toggle } = useColorMode()
89
+ return (
90
+ <Fab size='large' color='inherit' onClick={toggle} {...props}>
91
+ <SvgIcon src={currentMode === 'light' ? iconMoon : iconSun} size='large' />
92
+ </Fab>
93
+ )
94
+ }
95
+
96
+ /**
97
+ * A button that switches between light and dark mode
98
+ *
99
+ * To disable this functionality
100
+ */
101
+ export function DarkLightModeMenuSecondaryItem(props: ListItemButtonProps) {
102
+ const { sx = [] } = props
103
+ const { currentMode, toggle } = useColorMode()
104
+
105
+ return (
106
+ <ListItemButton {...props} sx={[{}, ...(Array.isArray(sx) ? sx : [sx])]} dense onClick={toggle}>
107
+ <ListItemIcon sx={{ minWidth: 'unset', paddingRight: '8px' }}>
108
+ <SvgIcon src={currentMode === 'light' ? iconMoon : iconSun} size='medium' />
109
+ </ListItemIcon>
110
+ <ListItemText>
111
+ {currentMode === 'light' ? (
112
+ <Trans>Switch to Dark Mode</Trans>
113
+ ) : (
114
+ <Trans>Switch to Light Mode</Trans>
115
+ )}
116
+ </ListItemText>
117
+ </ListItemButton>
118
+ )
119
+ }
package/Theme/index.ts CHANGED
@@ -2,3 +2,4 @@ export * from './MuiSlider'
2
2
  export * from './MuiButton'
3
3
  export * from './MuiSnackbar'
4
4
  export * from './themeDefaults'
5
+ export * from './DarkLightModeThemeProvider'
package/icons/index.tsx CHANGED
@@ -36,3 +36,5 @@ export { default as iconParty } from './happy-face.svg'
36
36
  export { default as iconStar } from './star.svg'
37
37
  export { default as iconEmailOutline } from './envelope-alt.svg'
38
38
  export { default as icon404 } from './explore.svg'
39
+ export { default as iconSun } from './sun.svg'
40
+ export { default as iconMoon } from './moon.svg'
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": "4.0.1",
5
+ "version": "4.1.0",
6
6
  "author": "",
7
7
  "license": "MIT",
8
8
  "scripts": {