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

[mui-6] CssVarsProvider createTheme palette.mode ignores existing colorSchemes #43996

Open
ggascoigne opened this issue Oct 4, 2024 · 2 comments
Assignees
Labels
customization: theme Centered around the theming features status: waiting for maintainer These issues haven't been looked at yet by a maintainer

Comments

@ggascoigne
Copy link

ggascoigne commented Oct 4, 2024

Summary

I would like createTheme to use existing colorScheme definitions when initialized with a mode and simply apply them to the theme, as opposed to generating a default and applying it to the theme. I'd like this to only generate a default is a suitable colorScheme had not already been provided.

Examples

My Theme looks something like this:

{
  "name": "Theme Example",
  "colorSchemes": {
    "light": {
      "palette": {
        "primary": {
          "light": "var(--ns-palette-light-primary-light)",
          "main": "var(--ns-palette-light-primary-main)",
          "dark": "var(--ns-palette-light-primary-dark)",
          "lightChannel": "var(--ns-palette-light-primary-light-channel)",
          "mainChannel": "var(--ns-palette-light-primary-main-channel)",
          "darkChannel": "var(--ns-palette-light-primary-dark-channel)",
          "contrastText": "var(--ns-palette-light-primary-contrast-text)"
        },
...
      }
    },
    "dark": {
      "palette": {
        "primary": {
          "light": "var(--ns-palette-dark-primary-light)",
          "main": "var(--ns-palette-dark-primary-main)",
          "dark": "var(--ns-palette-dark-primary-dark)",
          "lightChannel": "var(--ns-palette-dark-primary-light-channel)",
          "mainChannel": "var(--ns-palette-dark-primary-main-channel)",
          "darkChannel": "var(--ns-palette-dark-primary-dark-channel)",
          "contrastText": "var(--ns-palette-dark-primary-contrast-text)"
        },
...
    }
  },
...
  "cssVariables": {
    "colorSchemeSelector": "class"
  },
  "palette": {}
}

This is heavily trimmed, but it should give the context. And yes, the theme itself pulls in css variables for the underlying primitives from our design system, and whilst it gets somewhat indirect, it actually works very nicely.

Then I change color scheme to dark, the main theme (the one attached to the ThemeProvider), becomes:

{
  "defaultColorScheme": "light",
  "name": "Dynamic Theme",
  "colorSchemeSelector": "class",
  "rootSelector": ":root",
  "vars": {
    "palette": {
      "primary": {
        "light": "var(--mui-palette-primary-light)",
        "main": "var(--mui-palette-primary-main)",
        "dark": "var(--mui-palette-primary-dark)",
        "lightChannel": "var(--mui-palette-primary-lightChannel)",
        "mainChannel": "var(--mui-palette-primary-mainChannel)",
        "darkChannel": "var(--mui-palette-primary-darkChannel)",
        "contrastText": "var(--mui-palette-primary-contrastText)",
        "contrastTextChannel": "var(--mui-palette-primary-contrastTextChannel)"
      },
...
    },
...
  },
  "palette": {
    "mode": "dark",
    "primary": {
      "light": "var(--ns-palette-dark-primary-light)",
      "main": "var(--ns-palette-dark-primary-main)",
      "dark": "var(--ns-palette-dark-primary-dark)",
      "lightChannel": "var(--ns-palette-dark-primary-light-channel)",
      "mainChannel": "var(--ns-palette-dark-primary-main-channel)",
      "darkChannel": "var(--ns-palette-dark-primary-dark-channel)",
      "contrastText": "var(--ns-palette-dark-primary-contrast-text)",
      "contrastTextChannel": "var(--ns-palette-dark-primary-contrast-text)"
    },
...
  "colorSchemes": {
    "light": {
      "palette": {
        "mode": "light",
        "primary": {
          "light": "var(--ns-palette-light-primary-light)",
          "main": "var(--ns-palette-light-primary-main)",
          "dark": "var(--ns-palette-light-primary-dark)",
          "lightChannel": "var(--ns-palette-light-primary-light-channel)",
          "mainChannel": "var(--ns-palette-light-primary-main-channel)",
          "darkChannel": "var(--ns-palette-light-primary-dark-channel)",
          "contrastText": "var(--ns-palette-light-primary-contrast-text)",
          "contrastTextChannel": "var(--ns-palette-light-primary-contrast-text)"
        },
...
    },
    "dark": {
      "palette": {
        "mode": "dark",
        "primary": {
          "light": "var(--ns-palette-dark-primary-light)",
          "main": "var(--ns-palette-dark-primary-main)",
          "dark": "var(--ns-palette-dark-primary-dark)",
          "lightChannel": "var(--ns-palette-dark-primary-light-channel)",
          "mainChannel": "var(--ns-palette-dark-primary-main-channel)",
          "darkChannel": "var(--ns-palette-dark-primary-dark-channel)",
          "contrastText": "var(--ns-palette-dark-primary-contrast-text)",
          "contrastTextChannel": "var(--ns-palette-dark-primary-contrast-text)"
        },
...
  },
  "cssVarPrefix": "mui"
}

With palette switching to dark as desired and referencing the underlying colorScheme.

If I just pass in mode = 'dark' to create them, I get this instead:

{
  "defaultColorScheme": "dark",
  "name": "Theme Example",
  "colorSchemeSelector": "class",
  "rootSelector": ":root",
  "vars": {
    "palette": {
      "primary": {
        "light": "var(--mui-palette-primary-light, #e3f2fd)",
        "main": "var(--mui-palette-primary-main, #90caf9)",
        "dark": "var(--mui-palette-primary-dark, #42a5f5)",
        "lightChannel": "var(--mui-palette-primary-lightChannel, 227 242 253)",
        "mainChannel": "var(--mui-palette-primary-mainChannel, 144 202 249)",
        "darkChannel": "var(--mui-palette-primary-darkChannel, 66 165 245)",
        "contrastText": "var(--mui-palette-primary-contrastText, rgba(0, 0, 0, 0.87))",
        "contrastTextChannel": "var(--mui-palette-primary-contrastTextChannel, 0 0 0)"
      },
...
    },
  },
  "palette": {
    "mode": "dark",
    "primary": {
      "main": "#90caf9",
      "light": "#e3f2fd",
      "dark": "#42a5f5",
      "contrastText": "rgba(0, 0, 0, 0.87)",
      "mainChannel": "144 202 249",
      "lightChannel": "227 242 253",
      "darkChannel": "66 165 245",
      "contrastTextChannel": "0 0 0"
    },
...
  "colorSchemes": {
    "dark": {
      "palette": {
        "mode": "dark",
        "primary": {
          "main": "#90caf9",
          "light": "#e3f2fd",
          "dark": "#42a5f5",
          "contrastText": "rgba(0, 0, 0, 0.87)",
          "mainChannel": "144 202 249",
          "lightChannel": "227 242 253",
          "darkChannel": "66 165 245",
          "contrastTextChannel": "0 0 0"
        },
...
    },
    "light": {
      "palette": {
        "mode": "light",
        "primary": {
          "light": "var(--ns-palette-light-primary-light)",
          "main": "var(--ns-palette-light-primary-main)",
          "dark": "var(--ns-palette-light-primary-dark)",
          "lightChannel": "var(--ns-palette-light-primary-light-channel)",
          "mainChannel": "var(--ns-palette-light-primary-main-channel)",
          "darkChannel": "var(--ns-palette-light-primary-dark-channel)",
          "contrastText": "var(--ns-palette-light-primary-contrast-text)",
          "contrastTextChannel": "var(--ns-palette-light-primary-contrast-text)"
        },
...
  },
  "cssVarPrefix": "mui",
}

Whatever theme I pass in as the mode gets overwritten.

Now, I do understand that this is [probably intentional, but it would be awfully useful if this overwriting of the colorScheme only happened when there wasn't already a colorScheme defined. That would make this much more flexible, and to my mind at least, more consistent

Motivation

I'm trying to display a theme inspector - similar to the mui 6 one, where I create a theme using cssVariables, and I can toggle between light and dark modes of the theme without changing the theme that's applied to the application.

I want some way to create a theme object that can be inspected in both light and dark modes that isn't tied to the DOM, as far as I can tell from digging into useCurrentColorScheme.js, there's no way to get a theme in a specific mode without it trying to edit the DOM. I want to be able to inspect the css variables, not apply them.

The closest is to use createTheme with palette.mode set to either light or dark, however that also initializes a default color scheme for that mode ignoring anything that you might already have set and then applying that scheme to the palette. This works as desired if you are using an autogenerated theme, but if you are trying to migrate from an existing theme and have a rather large set of values that you want to preserve, it ignores and overwrites them.

If I just display the main application theme, I can see it switch between light and dark mode and update the palette and it's working beautifully, I can inspect that value and get exactly the behavior that I'm after, but it's changing the application theme.

I want the same change to a theme but without tying it to a ThemeProvider or having it try and update the DOM.

Search keywords: CssVarProvider

@ggascoigne ggascoigne added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Oct 4, 2024
@zannager zannager added the customization: theme Centered around the theming features label Oct 7, 2024
@siriwatknp
Copy link
Member

siriwatknp commented Oct 14, 2024

@ggascoigne I recommend moving palette: { mode: 'dark', … } over to colorSchemes completely.

The reason we override is to have a smooth migration from v5 to v6.

You no longer need to create a theme with mode = dark because you can provide dark tokens to colorSchemes.dark.palette.* directly. This make the theme creation static without binding to a state.

+ const theme = createTheme({ colorSchemes: { light: { … }, dark: { … } } });

function App() {
-  const appMode = useSomethingToGetTheMode();
-  const theme = createTheme({ palette: { mode: appMode }}}
  
  return <ThemeProvider theme={theme}>…
}

@siriwatknp siriwatknp added support: docs-feedback Feedback from documentation page status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer support: docs-feedback Feedback from documentation page labels Oct 14, 2024
@ggascoigne
Copy link
Author

Honestly I don't really care about the mechanism, and ended out with this because it sort of worked.

I want to create a palette with a specific active colorScheme so that it can be browsed, and do so without it being applied to the dom. Or change an existing palettes color mode, but again, without it applying to the DOM. Oh, and without it updating local storage.

As far as I tell, everything to do with colorSchemes is tightly bound to updating the DOM and updating local storage, and I want a way to avoid both.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Oct 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customization: theme Centered around the theming features status: waiting for maintainer These issues haven't been looked at yet by a maintainer
Projects
Status: Backlog
Development

No branches or pull requests

3 participants