@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 +25 -0
- package/Layout/components/LayoutHeaderBack.tsx +8 -9
- package/LayoutParts/Logo.tsx +1 -1
- package/LayoutParts/MenuFab.tsx +6 -5
- package/LayoutParts/MenuFabItem.tsx +2 -2
- package/Theme/DarkLightModeThemeProvider.tsx +119 -0
- package/Theme/index.ts +1 -0
- package/icons/index.tsx +2 -0
- package/package.json +1 -1
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
|
|
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 &&
|
|
17
|
+
const canClickBack = backSteps > 0 && path !== prevUp?.href
|
|
19
18
|
|
|
20
19
|
if (canClickBack) return true
|
|
21
|
-
if (up?.href && up.href !==
|
|
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 &&
|
|
32
|
+
const canClickBack = backSteps > 0 && path !== prevUp?.href
|
|
34
33
|
|
|
35
34
|
let label = t`Back`
|
|
36
|
-
if (up?.href ===
|
|
37
|
-
if (prevUp?.href ===
|
|
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 !==
|
|
53
|
+
if (up?.href && up.href !== path)
|
|
55
54
|
return (
|
|
56
55
|
<PageLink href={up.href} passHref>
|
|
57
56
|
<LinkOrButton
|
package/LayoutParts/Logo.tsx
CHANGED
|
@@ -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>
|
package/LayoutParts/MenuFab.tsx
CHANGED
|
@@ -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
|
-
'
|
|
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.
|
|
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
|
|
12
|
-
const active = 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
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'
|