Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[system] Fix color-scheme implementation #34639

Merged
merged 33 commits into from Oct 11, 2022

Conversation

siriwatknp
Copy link
Member

@siriwatknp siriwatknp commented Oct 6, 2022

https://deploy-preview-34639--material-ui.netlify.app/

Breaking changes

The enableColorScheme prop has been removed from CssVarsProvider and getInitColorScheme (both Material UI and Joy UI). Migration:

  • Material UI: you can enable the CSS color scheme via <CssBaseline enableColorScheme />.
 import { Experimental_CssVarsProvider as CssVarsProvider } from '@mui/material/styles';

 function App() {
   return (
-    <CssVarsProvider enableColorScheme>
+    <CssVarsProvider>
-      <CssBaseline />
+      <CssBaseline enableColorScheme />
     </CssVarsProvider>
   );
 }
  • Joy UI: it is enabled automatically if you use <CssBaseline />, see the docs.

Preview:

Docs:

Motivation

From @oliviertassinari's comment, applying inline color-scheme: light | dark to the html tag creates a global effect for complex application (our website is one of the examples where some pages use CssVarsProvider but some are not).

With the current implementation (inline style), the homepage improvement requires several workarounds to override the inline color-scheme.

To fix this, the color-scheme should be moved to CssBaseline so that

Changes

  • Delegate the enableColorScheme flag to CssBaseline.
  • Add CssBaseline and ScopedCssBaseline to Joy UI because the enableColorScheme is removed from the CssVarsProvider.

⚠️ Note: This is considered a BREAKING CHANGE for the experimental CssVarsProvider

How it works

The logic lives in CssBaseline which generates style sheets for each color scheme (to prevent flashing) when enabled:

// CssBaseline.tsx
  const colorSchemeStyles = {};
  if (enableColorScheme && theme.colorSchemes) {
    Object.entries(theme.colorSchemes).forEach(([key, scheme]) => {
      colorSchemeStyles[theme.getColorSchemeSelector(key).replace(/\s*&/, '')] = {
        colorScheme: scheme.palette?.mode, // each palette must contain the `mode`
      };
    });
  }

For example, if the theme has three color schemes: light, dark, and orange(custom). Each color scheme must contain the mode to be used (either light or dark). Material UI already contains the mode in the default light and dark palette, so this PR does the same for Joy UI.

Developers can configure the mode like this:

extendTheme({
  colorSchemes: {
    light: {
      palette: {
        mode: 'light', // this is `light` by default
      }
    },
    dark: {
      palette: {
        mode: 'dark', // this is `dark` by default
      }
    },
    orange: {
      palette: {
        mode: 'dark', // it could be `light` if the palette has high contrast.
      }
    },
  }
})

Benefits

  • Works perfectly with the current Material UI CssBaseline. The existing projects will automatically get the benefits of this.
  • Also works with Material UI ScopedCssBaseline.
  • More dynamic because the color-scheme is not attached as an inline style anymore, it is in the stylesheet. This work with any element that data-color-scheme="..."
    <div data-joy-color-scheme="dark"> /* the scrollbar color-scheme is dark */
  • Reduce the complexity of CssVarsProvider and getInitColorSchemeScript.

Tested that it works well in #33545

Test

Added visual regression to make sure that CssBaseline works for both Material UI and Joy UI. https://app.argos-ci.com/mui/material-ui/builds/5852

Screen Shot 2565-10-07 at 13 20 57


@siriwatknp siriwatknp added package: system Specific to @mui/system package: material-ui Specific to @mui/material package: joy-ui Specific to @mui/joy labels Oct 6, 2022
@mui-bot
Copy link

mui-bot commented Oct 6, 2022

Details of bundle changes

@material-ui/system: parsed: -0.54% 😍, gzip: -0.47% 😍
@mui/material-next: parsed: -0.12% 😍, gzip: -0.14% 😍
@mui/joy: parsed: +0.61% , gzip: +0.55%

Generated by 🚫 dangerJS against 1bfdb50

@siriwatknp siriwatknp marked this pull request as ready for review October 7, 2022 07:15
Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for the isolation of different React trees that this change brings. From what I understand, we can now natively nest light and dark themes inside the same React tree with Joy UI, as we can with Material UI. I can't think of a better alternative, for example, if we had CssVarsProviders create a div to host the style, then it wouldn't work with the portaled components.

test/regressions/fixtures/CssBaseline/JoyCssBaseline.js Outdated Show resolved Hide resolved
@oliviertassinari oliviertassinari added component: CssBaseline The React component bug 🐛 Something doesn't work labels Oct 8, 2022
Signed-off-by: Siriwat K <siriwatkunaporn@gmail.com>
Copy link
Member

@mnajdova mnajdova left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, I left few small comments. I was missing something like this in my preview for MD3 to be able to see at the same time light & dark mode :)


## Global reset

You might be familiar with [normalize.css](https://github.com/necolas/normalize.css), a collection of HTML element and attribute style-normalizations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably should specify that it is used, this is why we are mentioning it :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is mentioned to give the reader a clue that it is a similar purpose. I checked normalize.css and we are not using the same global reset.

docs/data/joy/components/css-baseline/css-baseline.md Outdated Show resolved Hide resolved
(
Object.entries(theme.colorSchemes) as Array<[DefaultColorScheme, ColorSystem]>
).forEach(([key, scheme]) => {
colorSchemeStyles[theme.getColorSchemeSelector(key).replace(/\s*&/, '')] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify what is this doing?

theme.getColorSchemeSelector(key).replace(/\s*&/, '')

We have it in many places, maybe we should extract the logic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

theme.getColorSchemeSelector(key) returns a string, [data-joy-color-scheme="$key"] &, with an & at the end so that developers can use it to write custom styles in styled or sx like this:

styled('div')(({ theme }) => ({
  [theme.getColorSchemeSelector('dark')]: { ... }
  // easier than writing
  // [`${theme.getColorSchemeSelector('dark')} &`]: { ... }
}))

However, the CssBaseline define the selector as global so the .replace(/\s*&/, '') is required to remove & at the end:

theme.getColorSchemeSelector(key).replace(/\s*&/, '') // '[data-joy-color-scheme="dark"]'

I think this case would be rare but I could provide the attribute from the theme to be used like:

[`[${theme.attribute}="dark"]`]: { ... }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking again, I rather go with theme.getColorSchemeSelector(key).replace(/\s*&/, '') for now because I don't want to add a new property to the theme. Let's wait to see how the community would like to use the API.

@siriwatknp siriwatknp merged commit 0c4b1f5 into mui:master Oct 11, 2022
alexfauquette pushed a commit to alexfauquette/material-ui that referenced this pull request Oct 14, 2022
daniel-rabe pushed a commit to daniel-rabe/material-ui that referenced this pull request Nov 29, 2022
feliperli pushed a commit to jesrodri/material-ui that referenced this pull request Dec 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: CssBaseline The React component package: joy-ui Specific to @mui/joy package: material-ui Specific to @mui/material package: system Specific to @mui/system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants