Closed Nevro closed 11 months ago
Currently missing link... I'm not sure if this correct approach, but work for me!
import * as m3utils from '@material/material-color-utilities'; /** * All available color tokens */ const tokens = [ 'primary', 'onPrimary', 'primaryContainer', 'onPrimaryContainer', 'inversePrimary', 'inverseOnPrimary', 'primaryFixed', 'primaryFixedDim', 'onPrimaryFixed', 'onPrimaryFixedVariant', 'secondary', 'onSecondary', 'secondaryContainer', 'onSecondaryContainer', 'secondaryFixed', 'secondaryFixedDim', 'onSecondaryFixed', 'onSecondaryFixedVariant', 'tertiary', 'onTertiary', 'tertiaryContainer', 'onTertiaryContainer', 'tertiaryFixed', 'tertiaryFixedDim', 'onTertiaryFixed', 'onTertiaryFixedVariant', 'error', 'onError', 'errorContainer', 'onErrorContainer', 'surfaceDim', 'surface', 'surfaceBright', 'surfaceContainerLowest', 'surfaceContainerLow', 'surfaceContainer', 'surfaceContainerHigh', 'surfaceContainerHighest', 'onSurface', 'onSurfaceVariant', 'outline', 'outlineVariant', 'inverseSurface', 'inverseOnSurface', 'surfaceVariant', 'surfaceTintColor', 'background', 'onBackground', 'shadow', 'scrim', ]; /** * Generate custom color group from source and target color * * @param source Source color * @param color Custom color * @param variant Scheme variant, equal to scheme class name (SchemeMonochrome, SchemeNeutral, SchemeTonalSpot,...) * @param contrastLevel Contrast level between -1.0 and 1.0 * @return Custom color group * * @link https://m3.material.io/styles/color/the-color-system/color-roles */ export function customColor(source, color, variant = 'SchemeTonalSpot', contrastLevel = 0.0) { let value = color.value; const from = value; const to = source; if (color.blend) { value = m3utils.Blend.harmonize(from, to); } const hct = m3utils.Hct.fromInt(value); const scheme = new m3utils[variant](hct, false, contrastLevel); const darkScheme = new m3utils[variant](hct, true, contrastLevel); const getDynamicColor = (token, scheme) => m3utils.MaterialDynamicColors[token].getArgb(scheme); return { color, value, light: { color: getDynamicColor('primary', scheme), onColor: getDynamicColor('onPrimary', scheme), colorContainer: getDynamicColor('primaryContainer', scheme), onColorContainer: getDynamicColor('onPrimaryContainer', scheme), }, dark: { color: getDynamicColor('primary', darkScheme), onColor: getDynamicColor('onPrimary', darkScheme), colorContainer: getDynamicColor('primaryContainer', darkScheme), onColorContainer: getDynamicColor('onPrimaryContainer', darkScheme), }, }; } /** * Generate a theme from a source color * * @param source Source color * @param customColors Array of custom colors * @param variant Scheme variant, equal to scheme class name (SchemeMonochrome, SchemeNeutral, SchemeTonalSpot,...) * @param contrastLevel Contrast level between -1.0 and 1.0 * @return Theme object */ export function themeFromSourceColor(source, variant = 'SchemeTonalSpot', contrastLevel = 0.0, customColors = []) { const hct = m3utils.Hct.fromInt(source); const scheme = new m3utils[variant](hct, false, contrastLevel); const darkScheme = new m3utils[variant](hct, true, contrastLevel); const getDynamicColors = (scheme) => Object.fromEntries(tokens.map(token => [token, m3utils.MaterialDynamicColors[token].getArgb(scheme)])); const theme = { source, schemes: { light: getDynamicColors(scheme), dark: getDynamicColors(darkScheme), }, palettes: { primary: scheme.primaryPalette, secondary: scheme.secondaryPalette, tertiary: scheme.tertiaryPalette, neutral: scheme.neutralPalette, neutralVariant: scheme.neutralVariantPalette, error: scheme.errorPalette, }, customColors: customColors.map((c) => customColor(source, c, variant, contrastLevel)), }; theme.schemes.__proto__.toJSON = function() { return this; } return theme; } /** * Generate a theme from an image source * * @param image Image element * @param variant Scheme variant, equal to scheme class name (SchemeMonochrome, SchemeNeutral, SchemeTonalSpot,...) * @param contrastLevel Contrast level between -1.0 and 1.0 * @param customColors Array of custom colors * @return Theme object */ export async function themeFromImage(image, variant = 'SchemeTonalSpot', contrastLevel = 0.0, customColors = []) { const source = await m3utils.sourceColorFromImage(image); return themeFromSourceColor(source, variant, contrastLevel, customColors); } /** * Sample code */ const source = m3utils.argbFromHex("#4285f4"); // Get the theme from a source color const theme = themeFromSourceColor(source, 'SchemeTonalSpot', 0.0, [ { name: "custom-1", value: m3utils.argbFromHex("#ff0000"), blend: true, } ]); // Print out the theme as JSON console.log(JSON.stringify(theme, null, 2)); // Check if the user has dark mode turned on const systemDark = window.matchMedia("(prefers-color-scheme: dark)").matches; // Apply the theme to the body by updating custom properties for material tokens m3utils.applyTheme(theme, {target: document.body, dark: systemDark});
{ "source": 4282549748, "schemes": { "light": { "primary": 4282343064, "onPrimary": 4294967295, "primaryContainer": 4292403967, "onPrimaryContainer": 4278196801, "inversePrimary": 4289578751, "inverseOnPrimary": 4278464103, "primaryFixed": 4292403967, "primaryFixedDim": 4289578751, "onPrimaryFixed": 4278196801, "onPrimaryFixedVariant": 4280567423, "secondary": 4283915889, "onSecondary": 4294967295, "secondaryContainer": 4292600569, "onSecondaryContainer": 4279507756, "secondaryFixed": 4292600569, "secondaryFixedDim": 4290758364, "onSecondaryFixed": 4279507756, "onSecondaryFixedVariant": 4282337113, "tertiary": 4285617523, "onTertiary": 4294967295, "tertiaryContainer": 4294694908, "onTertiaryContainer": 4280881965, "tertiaryFixed": 4294694908, "tertiaryFixedDim": 4292787423, "onTertiaryFixed": 4280881965, "onTertiaryFixedVariant": 4283973211, "error": 4290386458, "onError": 4294967295, "errorContainer": 4294957782, "onErrorContainer": 4282449922, "surfaceDim": 4292467168, "surface": 4294572543, "surfaceBright": 4294572543, "surfaceContainerLowest": 4294967295, "surfaceContainerLow": 4294177786, "surfaceContainer": 4293783028, "surfaceContainerHigh": 4293453806, "surfaceContainerHighest": 4293059305, "onSurface": 4279900960, "onSurfaceVariant": 4282664783, "outline": 4285691005, "outlineVariant": 4291086032, "inverseSurface": 4281282614, "inverseOnSurface": 4293980407, "surfaceVariant": 4292993772, "surfaceTintColor": 4282343064, "background": 4294572543, "onBackground": 4279900960, "shadow": 4278190080, "scrim": 4278190080 }, "dark": { "primary": 4289578751, "onPrimary": 4278464103, "primaryContainer": 4280567423, "onPrimaryContainer": 4292403967, "inversePrimary": 4282343064, "inverseOnPrimary": 4294967295, "primaryFixed": 4292403967, "primaryFixedDim": 4289578751, "onPrimaryFixed": 4278196801, "onPrimaryFixedVariant": 4280567423, "secondary": 4290758364, "onSecondary": 4280889409, "secondaryContainer": 4282337113, "onSecondaryContainer": 4292600569, "secondaryFixed": 4292600569, "secondaryFixedDim": 4290758364, "onSecondaryFixed": 4279507756, "onSecondaryFixedVariant": 4282337113, "tertiary": 4292787423, "onTertiary": 4282394691, "tertiaryContainer": 4283973211, "onTertiaryContainer": 4294694908, "tertiaryFixed": 4294694908, "tertiaryFixedDim": 4292787423, "onTertiaryFixed": 4280881965, "onTertiaryFixedVariant": 4283973211, "error": 4294948011, "onError": 4285071365, "errorContainer": 4287823882, "onErrorContainer": 4294957782, "surfaceDim": 4279309080, "surface": 4279309080, "surfaceBright": 4281809214, "surfaceContainerLowest": 4278980115, "surfaceContainerLow": 4279900960, "surfaceContainer": 4280164133, "surfaceContainerHigh": 4280822319, "surfaceContainerHighest": 4281546042, "onSurface": 4293059305, "onSurfaceVariant": 4291086032, "outline": 4285691005, "outlineVariant": 4282664783, "inverseSurface": 4293059305, "inverseOnSurface": 4281282614, "surfaceVariant": 4282664783, "surfaceTintColor": 4289578751, "background": 4279309080, "onBackground": 4293059305, "shadow": 4278190080, "scrim": 4278190080 } }, "palettes": { "primary": { "hue": 265.97939535792614, "chroma": 40, "cache": {} }, "secondary": { "hue": 265.97939535792614, "chroma": 16, "cache": {} }, "tertiary": { "hue": 325.97939535792614, "chroma": 24, "cache": {} }, "neutral": { "hue": 265.97939535792614, "chroma": 6, "cache": {} }, "neutralVariant": { "hue": 265.97939535792614, "chroma": 8, "cache": {} }, "error": { "hue": 25, "chroma": 84, "cache": {} } }, "customColors": [ { "color": { "name": "custom-1", "value": 4294901760, "blend": true }, "value": 4294639703, "light": { "color": 4287842128, "onColor": 4294967295, "colorContainer": 4294957788, "onColorContainer": 4282188817 }, "dark": { "color": 4294947513, "onColor": 4284029477, "colorContainer": 4285935674, "onColorContainer": 4294957788 } } ] }
--md-sys-color-primary: #adc6ff --md-sys-color-on-primary: #042e67 --md-sys-color-primary-container: #24467f --md-sys-color-on-primary-container: #d8e2ff --md-sys-color-inverse-primary: #3f5e98 --md-sys-color-inverse-on-primary: #ffffff --md-sys-color-primary-fixed: #d8e2ff --md-sys-color-primary-fixed-dim: #adc6ff --md-sys-color-on-primary-fixed: #001a41 --md-sys-color-on-primary-fixed-variant: #24467f --md-sys-color-secondary: #bfc6dc --md-sys-color-on-secondary: #293041 --md-sys-color-secondary-container: #3f4759 --md-sys-color-on-secondary-container: #dbe2f9 --md-sys-color-secondary-fixed: #dbe2f9 --md-sys-color-secondary-fixed-dim: #bfc6dc --md-sys-color-on-secondary-fixed: #141b2c --md-sys-color-on-secondary-fixed-variant: #3f4759 --md-sys-color-tertiary: #debcdf --md-sys-color-on-tertiary: #402843 --md-sys-color-tertiary-container: #583e5b --md-sys-color-on-tertiary-container: #fbd7fc --md-sys-color-tertiary-fixed: #fbd7fc --md-sys-color-tertiary-fixed-dim: #debcdf --md-sys-color-on-tertiary-fixed: #29132d --md-sys-color-on-tertiary-fixed-variant: #583e5b --md-sys-color-error: #ffb4ab --md-sys-color-on-error: #690005 --md-sys-color-error-container: #93000a --md-sys-color-on-error-container: #ffdad6 --md-sys-color-surface-dim: #111318 --md-sys-color-surface: #111318 --md-sys-color-surface-bright: #37393e --md-sys-color-surface-container-lowest: #0c0e13 --md-sys-color-surface-container-low: #1a1b20 --md-sys-color-surface-container: #1e1f25 --md-sys-color-surface-container-high: #282a2f --md-sys-color-surface-container-highest: #33353a --md-sys-color-on-surface: #e2e2e9 --md-sys-color-on-surface-variant: #c4c6d0 --md-sys-color-outline: #72747d --md-sys-color-outline-variant: #44474f --md-sys-color-inverse-surface: #e2e2e9 --md-sys-color-inverse-on-surface: #2f3036 --md-sys-color-surface-variant: #44474f --md-sys-color-surface-tint-color: #adc6ff --md-sys-color-background: #111318 --md-sys-color-on-background: #e2e2e9 --md-sys-color-shadow: #000000 --md-sys-color-scrim: #000000
Currently missing link... I'm not sure if this correct approach, but work for me!