material-foundation / material-color-utilities

Color libraries for Material You
Apache License 2.0
1.57k stars 134 forks source link

How can I add to the theme generator the secondary color? #55

Open matteogratton opened 1 year ago

matteogratton commented 1 year ago

In the M3 Theme Web Generator, it is possible to set not only the primary color but also secondary, tertiary, and neutral.

How can I set them to generate the theme?

This is the current function: const theme = themeFromSourceColor(argbFromHex(primary), [{},]); How can I add something like: const theme = themeFromSourceColor(argbFromHex(primary), argbFromHex(secondary), argbFromHex(tertiary), argbFromHex(error), argbFromHex(neutral), [{},]); or something similar?

Thanks 🙏

ecoant commented 1 year ago

I have been trying to figure this out for way too long. It seems like the two teams (this library and the stub project for the M3 Web Generator) have not collaborated.

I am trying to build a Material Theme for my React project which uses MUI. Google search guides you to the M3 Theme Builder, which allows selecting primary, secondary, and tertiary colors to create a theme. Awesome! However, the functions that run underneath to transform the 3 values into a unified theme are a black box. I have no idea why, but the repository doesn't contain any code. You can export to css format, which is great if you are manually assigning classes to html elements, and useless if not.

Google search some more and you'll find this library, which has handy functions for building themeFromSourceColor. Perfect, that must correspond to how the M3 Web Generator is building your theme!

...no, it isn't. That function only takes one source color.

The fact that the 2 best ways to generate Material 3 Themes each take a different approach, and do not even acknowledge each other is super confusing.

Digging through the source here, I found the following comment surrounding the main "get a predefined palette from a single color value" function.

/**
 * An intermediate concept between the key color for a UI theme, and a full
 * color scheme. 5 sets of tones are generated, all except one use the same hue
 * as the key color, and all vary in chroma.
 */

...suggesting that the full capability for making a theme just hasn't been implemented yet. I fear it's another case where the marketing Materials are way out ahead of the implementation team.

albi005 commented 1 year ago

I don't think you are supposed to set custom secondary and tertiary colors, but it is totally possible. Just create a CorePalette, override the two tonal palettes and then create a Scheme from it:

let corePalette = CorePalette.of(primarySeed);
corePalette.a2 = TonalPalette.fromInt(secondarySeed);
corePalette.a3 = TonalPalette.fromInt(tertiarySeed);

let lightScheme = Scheme.lightFromCorePalette(corePalette);
let darkScheme = Scheme.darkFromCorePalette(corePalette);

let customSecondary = lightScheme.secondary;

You can also harmonize the secondary/tertiary seeds so they are closer to the primary seed:

let harmonizedSecondarySeed = Blend.harmonize(secondarySeed, primarySeed);
ecoant commented 1 year ago

I don't think you are supposed to set custom secondary and tertiary colors, but it is totally possible. Just create a CorePalette, override the two tonal palettes and then create a Scheme from it:

let corePalette = CorePalette.of(primarySeed);
corePalette.a2 = TonalPalette.fromInt(secondarySeed);
corePalette.a3 = TonalPalette.fromInt(tertiarySeed);

let lightScheme = Scheme.lightFromCorePalette(corePalette);
let darkScheme = Scheme.darkFromCorePalette(corePalette);

let customSecondary = lightScheme.secondary;

You can also harmonize the secondary/tertiary seeds so they are closer to the primary seed:

let harmonizedSecondarySeed = Blend.harmonize(secondarySeed, primarySeed);

Thank you!! We are a tiny team of developers trying to quickly grok the new design scheme and there isn't really a central place for this information yet. This is exactly what I was trying to do.

rodydavis commented 1 year ago

So this is possible, we use it in the https://m3.material.io/theme-builder and you override these values in the Core Palette not the scheme.

You then pass that to the scheme to get the tokens

rodydavis commented 1 year ago

This is what I'm proposing in the CorePalette class:

...
/**
   * Create a [CorePalette] from a set of colors
   */
  static fromColors(colors: CorePaletteColors): CorePalette {
    return CorePalette.createPaletteFromColors(false, colors);
  }

  /**
   * Create a content [CorePalette] from a set of colors
   */
  static contentFromColors(colors: CorePaletteColors): CorePalette {
    return CorePalette.createPaletteFromColors(true, colors);
  }

  private static createPaletteFromColors(
      content: boolean, colors: CorePaletteColors) {
    const palette = new CorePalette(colors.primary, content);
    if (colors.secondary) {
      const p = new CorePalette(colors.secondary, content);
      palette.a2 = p.a1;
    }
    if (colors.tertiary) {
      const p = new CorePalette(colors.tertiary, content);
      palette.a3 = p.a1;
    }
    if (colors.error) {
      const p = new CorePalette(colors.error, content);
      palette.error = p.a1;
    }
    if (colors.neutral) {
      const p = new CorePalette(colors.neutral, content);
      palette.n1 = p.n1;
    }
    if (colors.neutralVariant) {
      const p = new CorePalette(colors.neutralVariant, false);
      palette.n2 = p.n2;
    }
    return palette;
  }
...
rodydavis commented 1 year ago

Landed on typescript: https://github.com/material-foundation/material-color-utilities/blob/bde4d30cad3cb766c45bcd8187da74ac56a3e292/typescript/palettes/core_palette.ts#L64