Skip to content

Commit

Permalink
feat(MuiCozyTheme): Introduce type prop in addition to variant
Browse files Browse the repository at this point in the history
To prepare the way to dark mode. `type` is set default to `light`.

BREAKING CHANGE: You can't now longer rely on `theme.palette.type` to determine `normal` or `inverted` theme, you have to use `theme.palette.variant` instead.
  • Loading branch information
JF-Cozy committed Jan 10, 2024
1 parent 53a1b02 commit 1d1f053
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 120 deletions.
7 changes: 5 additions & 2 deletions react/MuiCozyTheme/index.jsx
Expand Up @@ -4,16 +4,19 @@ import PropTypes from 'prop-types'
import { ThemeProvider } from '../styles'
import { getTheme } from './theme'

const MuiCozyTheme = ({ variant, children }) => {
const theme = getTheme(variant)
const MuiCozyTheme = ({ type, variant, children }) => {
const theme = getTheme(type, variant)

return <ThemeProvider theme={theme}>{children}</ThemeProvider>
}

MuiCozyTheme.propTypes = {
type: PropTypes.oneOf(['light', 'dark']),
variant: PropTypes.oneOf(['normal', 'inverted'])
}

MuiCozyTheme.defaultProps = {
type: 'light',
variant: 'normal'
}

Expand Down
212 changes: 117 additions & 95 deletions react/MuiCozyTheme/makePalette.js
Expand Up @@ -4,137 +4,159 @@ import { getCssVariableValue, createNodeWithThemeCssVars } from '../utils/color'

const opacityByTheme = {
light: {
action: {
hoverOpacity: 0.04,
selectedOpacity: 0.08,
disabledOpacity: 0.32,
focusOpacity: 0.12,
activatedOpacity: 0.12,
ghostOpacity: 0.08,
hoverGhostOpacity: 0.16
},
border: {
opacity: 0.16,
ghostOpacity: 0.48
},
background: {
contrastOpacity: 0.12
}
},
dark: {
action: {
hoverOpacity: 0.08,
selectedOpacity: 0.16,
disabledOpacity: 0.32,
focusOpacity: 0.25,
activatedOpacity: 0.24,
ghostOpacity: 0.08,
hoverGhostOpacity: 0.16
},
border: {
opacity: 0.24,
ghostOpacity: 0.48
normal: {
action: {
hoverOpacity: 0.04,
selectedOpacity: 0.08,
disabledOpacity: 0.32,
focusOpacity: 0.12,
activatedOpacity: 0.12,
ghostOpacity: 0.08,
hoverGhostOpacity: 0.16
},
border: {
opacity: 0.16,
ghostOpacity: 0.48
},
background: {
contrastOpacity: 0.12
}
},
background: {
contrastOpacity: 0.24
inverted: {
action: {
hoverOpacity: 0.08,
selectedOpacity: 0.16,
disabledOpacity: 0.32,
focusOpacity: 0.25,
activatedOpacity: 0.24,
ghostOpacity: 0.08,
hoverGhostOpacity: 0.16
},
border: {
opacity: 0.24,
ghostOpacity: 0.48
},
background: {
contrastOpacity: 0.24
}
}
}
}

export const makePalette = type => {
const variant = type === 'dark' ? 'inverted' : 'normal'

export const makePalette = (type, variant) => {
// to hold the values of css variables, recoverable by getCssVariableValue()
createNodeWithThemeCssVars(variant)
createNodeWithThemeCssVars(type, variant)

const paletteByTheme = {
type,
variant: variant,
primary: {
light: getCssVariableValue('primaryColorLight', variant),
main: getCssVariableValue('primaryColor', variant),
dark: getCssVariableValue('primaryColorDark', variant),
contrastText: getCssVariableValue('primaryContrastTextColor', variant)
light: getCssVariableValue('primaryColorLight', type, variant),
main: getCssVariableValue('primaryColor', type, variant),
dark: getCssVariableValue('primaryColorDark', type, variant),
contrastText: getCssVariableValue(
'primaryContrastTextColor',
type,
variant
)
},
secondary: {
light: getCssVariableValue('secondaryColorLight', variant),
main: getCssVariableValue('secondaryColor', variant),
dark: getCssVariableValue('secondaryColorDark', variant),
contrastText: getCssVariableValue('secondaryContrastTextColor', variant)
light: getCssVariableValue('secondaryColorLight', type, variant),
main: getCssVariableValue('secondaryColor', type, variant),
dark: getCssVariableValue('secondaryColorDark', type, variant),
contrastText: getCssVariableValue(
'secondaryContrastTextColor',
type,
variant
)
},
error: {
light: getCssVariableValue('errorColorLight', variant),
main: getCssVariableValue('errorColor', variant),
dark: getCssVariableValue('errorColorDark', variant),
contrastText: getCssVariableValue('errorColorContrastText', variant)
light: getCssVariableValue('errorColorLight', type, variant),
main: getCssVariableValue('errorColor', type, variant),
dark: getCssVariableValue('errorColorDark', type, variant),
contrastText: getCssVariableValue('errorColorContrastText', type, variant)
},
warning: {
light: getCssVariableValue('warningColorLight', variant),
main: getCssVariableValue('warningColor', variant),
dark: getCssVariableValue('warningColorDark', variant),
contrastText: getCssVariableValue('warningColorContrastText', variant)
light: getCssVariableValue('warningColorLight', type, variant),
main: getCssVariableValue('warningColor', type, variant),
dark: getCssVariableValue('warningColorDark', type, variant),
contrastText: getCssVariableValue(
'warningColorContrastText',
type,
variant
)
},
success: {
light: getCssVariableValue('successColorLight', variant),
main: getCssVariableValue('successColor', variant),
dark: getCssVariableValue('successColorDark', variant),
contrastText: getCssVariableValue('successColorContrastText', variant)
light: getCssVariableValue('successColorLight', type, variant),
main: getCssVariableValue('successColor', type, variant),
dark: getCssVariableValue('successColorDark', type, variant),
contrastText: getCssVariableValue(
'successColorContrastText',
type,
variant
)
},
info: {
light: getCssVariableValue('infoColorLight', variant),
main: getCssVariableValue('infoColor', variant),
dark: getCssVariableValue('infoColorDark', variant),
contrastText: getCssVariableValue('infoColorContrastText', variant)
light: getCssVariableValue('infoColorLight', type, variant),
main: getCssVariableValue('infoColor', type, variant),
dark: getCssVariableValue('infoColorDark', type, variant),
contrastText: getCssVariableValue('infoColorContrastText', type, variant)
},
text: {
primary: getCssVariableValue('primaryTextColor', variant),
secondary: getCssVariableValue('secondaryTextColor', variant),
disabled: getCssVariableValue('disabledTextColor', variant),
hint: getCssVariableValue('hintTextColor', variant),
icon: getCssVariableValue('iconTextColor', variant)
primary: getCssVariableValue('primaryTextColor', type, variant),
secondary: getCssVariableValue('secondaryTextColor', type, variant),
disabled: getCssVariableValue('disabledTextColor', type, variant),
hint: getCssVariableValue('hintTextColor', type, variant),
icon: getCssVariableValue('iconTextColor', type, variant)
},
grey: {
50: getCssVariableValue('grey50', variant),
100: getCssVariableValue('grey100', variant),
200: getCssVariableValue('grey200', variant),
300: getCssVariableValue('grey300', variant),
400: getCssVariableValue('grey400', variant),
500: getCssVariableValue('grey500', variant),
600: getCssVariableValue('grey600', variant),
700: getCssVariableValue('grey700', variant),
800: getCssVariableValue('grey800', variant),
900: getCssVariableValue('grey900', variant),
A100: getCssVariableValue('greyA100', variant),
A200: getCssVariableValue('greyA200', variant),
A400: getCssVariableValue('greyA400', variant),
A700: getCssVariableValue('greyA700', variant)
50: getCssVariableValue('grey50', type, variant),
100: getCssVariableValue('grey100', type, variant),
200: getCssVariableValue('grey200', type, variant),
300: getCssVariableValue('grey300', type, variant),
400: getCssVariableValue('grey400', type, variant),
500: getCssVariableValue('grey500', type, variant),
600: getCssVariableValue('grey600', type, variant),
700: getCssVariableValue('grey700', type, variant),
800: getCssVariableValue('grey800', type, variant),
900: getCssVariableValue('grey900', type, variant),
A100: getCssVariableValue('greyA100', type, variant),
A200: getCssVariableValue('greyA200', type, variant),
A400: getCssVariableValue('greyA400', type, variant),
A700: getCssVariableValue('greyA700', type, variant)
},
divider: getCssVariableValue('dividerColor', variant),
divider: getCssVariableValue('dividerColor', type, variant),
action: {
active: getCssVariableValue('actionColorActive', variant),
hover: getCssVariableValue('actionColorHover', variant),
selected: getCssVariableValue('actionColorSelected', variant),
disabled: getCssVariableValue('actionColorDisabled', variant),
active: getCssVariableValue('actionColorActive', type, variant),
hover: getCssVariableValue('actionColorHover', type, variant),
selected: getCssVariableValue('actionColorSelected', type, variant),
disabled: getCssVariableValue('actionColorDisabled', type, variant),
disabledBackground: getCssVariableValue(
'actionColorDisabledBackground',
type,
variant
),
focus: getCssVariableValue('actionColorFocus', variant),
ghost: getCssVariableValue('actionColorGhost', variant),
hoverGhost: getCssVariableValue('actionColorHoverGhost', variant)
focus: getCssVariableValue('actionColorFocus', type, variant),
ghost: getCssVariableValue('actionColorGhost', type, variant),
hoverGhost: getCssVariableValue('actionColorHoverGhost', type, variant)
},
border: {
main: getCssVariableValue('borderMainColor', variant),
disabled: getCssVariableValue('borderDisabledColor', variant),
ghost: getCssVariableValue('borderGhostColor', variant),
ghostDisabled: getCssVariableValue('borderGhostDisabledColor', variant)
main: getCssVariableValue('borderMainColor', type, variant),
disabled: getCssVariableValue('borderDisabledColor', type, variant),
ghost: getCssVariableValue('borderGhostColor', type, variant),
ghostDisabled: getCssVariableValue(
'borderGhostDisabledColor',
type,
variant
)
},
background: {
default: getCssVariableValue('defaultBackgroundColor', variant),
paper: getCssVariableValue('paperBackgroundColor', variant),
contrast: getCssVariableValue('contrastBackgroundColor', variant),
default: getCssVariableValue('defaultBackgroundColor', type, variant),
paper: getCssVariableValue('paperBackgroundColor', type, variant),
contrast: getCssVariableValue('contrastBackgroundColor', type, variant),
selected: '#F5FAFF' // deprecated, should be removed. Use action.selected instead
}
}

return merge(paletteByTheme, opacityByTheme[type])
return merge(paletteByTheme, opacityByTheme[type][variant])
}
6 changes: 3 additions & 3 deletions react/MuiCozyTheme/makeTheme.jsx
Expand Up @@ -37,14 +37,14 @@ const themesCommonConfig = {
...(isTesting() && { transitions: { create: () => 'none' } })
}

export const makeTheme = type => {
const palette = makePalette(type)
export const makeTheme = (type, variant) => {
const palette = makePalette(type, variant)
const theme = createTheme({
...themesCommonConfig,
typography: makeTypography(palette),
palette
})
const overrides = makeOverridesByTheme(theme)['light'][type]
const overrides = makeOverridesByTheme(theme)[type][variant]

return {
...theme,
Expand Down
14 changes: 8 additions & 6 deletions react/MuiCozyTheme/theme.jsx
@@ -1,15 +1,17 @@
import { makeTheme } from './makeTheme'

export const normalTheme = makeTheme('light')
export const invertedTheme = makeTheme('dark')
export const normalTheme = makeTheme('light', 'normal')
export const invertedTheme = makeTheme('light', 'inverted')

const themes = {
normal: normalTheme,
inverted: invertedTheme
light: {
normal: normalTheme,
inverted: invertedTheme
}
}

export const getTheme = variant => {
const theme = themes[variant]
export const getTheme = (type, variant) => {
const theme = themes[type]?.[variant]

if (!theme) {
const possibleThemes = Object.keys(themes).join(', ')
Expand Down
6 changes: 3 additions & 3 deletions react/PieChart/index.jsx
Expand Up @@ -31,11 +31,11 @@ const useStyles = makeStyles(theme => ({
borderRadius: '100%',
zIndex: -1,
backgroundColor: ({ single }) =>
!single && theme.palette.type === 'dark'
!single && theme.palette.variant === 'inverted'
? theme.palette.primary.main
: 'none',
boxShadow: ({ single }) =>
!single && theme.palette.type === 'dark'
!single && theme.palette.variant === 'inverted'
? `0 0 0 2px ${theme.palette.primary.main}`
: 'none'
},
Expand All @@ -55,7 +55,7 @@ const useStyles = makeStyles(theme => ({
},
typography: {
color: ({ single }) =>
!single && theme.palette.type === 'dark'
!single && theme.palette.variant === 'inverted'
? theme.palette.primary.contrastText
: theme.palette.text.primary
}
Expand Down
22 changes: 11 additions & 11 deletions react/utils/color.js
@@ -1,30 +1,30 @@
const getThemeNodeClassName = variant => `CozyTheme--light-${variant}`
const getThemeNodeClassName = (type, variant) => `CozyTheme--${type}-${variant}`

const getNodeWithThemeCssVars = variant => {
const className = getThemeNodeClassName(variant)
const getNodeWithThemeCssVars = (type, variant) => {
const className = getThemeNodeClassName(type, variant)

return document.getElementsByClassName(className)[0]
}

export const createNodeWithThemeCssVars = variant => {
if (!getNodeWithThemeCssVars(variant)) {
export const createNodeWithThemeCssVars = (type, variant) => {
if (!getNodeWithThemeCssVars(type, variant)) {
const node = document.createElement('div')
node.className = getThemeNodeClassName(variant)
node.className = getThemeNodeClassName(type, variant)
node.style.display = 'none'
document.body.prepend(node)
}
}

const realGetCssVariableValue = (varName, variant) => {
const node = getNodeWithThemeCssVars(variant)
const realGetCssVariableValue = (varName, type, variant) => {
const node = getNodeWithThemeCssVars(type, variant)

return window
.getComputedStyle(node)
.getPropertyValue(`--${varName}`)
.trim()
}

export const getCssVariableValue = (varName, variant) =>
export const getCssVariableValue = (varName, type, variant) =>
process.env.NODE_ENV === 'test'
? () => () => '#fff'
: realGetCssVariableValue(varName, variant)
? '#fff'
: realGetCssVariableValue(varName, type, variant)

0 comments on commit 1d1f053

Please sign in to comment.