diff --git a/color/_color.scss b/color/_color.scss new file mode 100644 index 0000000000..1bd5ff52c9 --- /dev/null +++ b/color/_color.scss @@ -0,0 +1,193 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use 'sass:list'; +// go/keep-sorted end +// go/keep-sorted start +@use '../tokens'; +// go/keep-sorted end + +/// `color.light-theme()` emits `--md-sys-color-*` custom properties for a light +/// theme from the given color palette. +/// +/// @example scss +/// @use 'sass:map'; +/// @use '@material/web/color/color'; +/// @use '@material/web/tokens'; +/// +/// // Tip: if only changing part of the palette, merge the default palette +/// // values to inherit other tones (such as neutral and error tones). +/// $my-palette: map.merge( +/// tokens.md-ref-palette-values(), +/// ( +/// 'primary10': /* ... */, +/// 'primary20': /* ... */, +/// 'primary30': /* ... */, +/// 'primary40': /* ... */, +/// 'primary50': /* ... */, +/// 'primary60': /* ... */, +/// 'primary70': /* ... */, +/// 'primary80': /* ... */, +/// 'primary90': /* ... */, +/// 'primary95': /* ... */, +/// 'primary99': /* ... */, +/// // Opt: palette values for: +/// // - secondary +/// // - tertiary +/// // - error +/// // - neutral +/// // - neutral-variant +/// ), +/// ); +/// +/// :root { +/// @include color.light-theme($my-palette); +/// } +/// +/// /* Generated CSS */ +/// :root { +/// --md-sys-color-primary: /* ... */; +/// --md-sys-color-primary-container: /* ... */; +/// --md-sys-color-primary-fixed: /* ... */; +/// --md-sys-color-primary-fixed-dim: /* ... */; +/// /* ... */ +/// } +/// +/// To generate a palette, use the Material Theme Builder Figma plugin. +/// +/// @link https://www.figma.com/community/plugin/1034969338659738588/Material-Theme-Builder +/// +/// @param {Map} $md-ref-palette - A map of Material palette keys and their +/// values. +/// @output Emits `--md-sys-color-*` custom properties for a light theme with +/// the given palette. +@mixin light-theme($md-ref-palette: tokens.md-ref-palette-values()) { + @each $token, $value in $md-ref-palette { + @if list.index(tokens.$md-ref-palette-supported-tokens, $token) == null { + @error 'md-ref-palette `#{$token}` is not a supported token.'; + } + } + + @include theme( + tokens.md-sys-color-values-light( + ( + 'md-ref-palette': $md-ref-palette, + ), + $exclude-custom-properties: true + ) + ); +} + +/// `color.dark-theme()` emits `--md-sys-color-*` custom properties for a dark +/// theme from the given color palette. +/// +/// @example scss +/// @use 'sass:map'; +/// @use '@material/web/color/color'; +/// @use '@material/web/tokens'; +/// +/// // Tip: if only changing part of the palette, merge the default palette +/// // values to inherit other tones (such as neutral and error tones). +/// $my-palette: map.merge( +/// tokens.md-ref-palette-values(), +/// ( +/// 'primary10': /* ... */, +/// 'primary20': /* ... */, +/// 'primary30': /* ... */, +/// 'primary40': /* ... */, +/// 'primary50': /* ... */, +/// 'primary60': /* ... */, +/// 'primary70': /* ... */, +/// 'primary80': /* ... */, +/// 'primary90': /* ... */, +/// 'primary95': /* ... */, +/// 'primary99': /* ... */, +/// // Opt: palette values for: +/// // - secondary +/// // - tertiary +/// // - error +/// // - neutral +/// // - neutral-variant +/// ), +/// ); +/// +/// @media (prefers-color-scheme: dark) { +/// @include color.dark-theme($my-palette); +/// } +/// +/// /* Generated CSS */ +/// @media (prefers-color-scheme: dark) { +/// --md-sys-color-primary: /* ... */; +/// --md-sys-color-primary-container: /* ... */; +/// --md-sys-color-primary-fixed: /* ... */; +/// --md-sys-color-primary-fixed-dim: /* ... */; +/// /* ... */ +/// } +/// +/// To generate a palette, use the Material Theme Builder Figma plugin. +/// +/// @link https://www.figma.com/community/plugin/1034969338659738588/Material-Theme-Builder +/// +/// @param {Map} $md-ref-palette - A map of Material palette keys and their +/// values. +/// @output Emits `--md-sys-color-*` custom properties for a dark theme with +/// the given palette. +@mixin dark-theme($md-ref-palette: tokens.md-ref-palette-values()) { + @each $token, $value in $md-ref-palette { + @if list.index(tokens.$md-ref-palette-supported-tokens, $token) == null { + @error 'md-ref-palette `#{$token}` is not a supported token.'; + } + } + + @include theme( + tokens.md-sys-color-values-dark( + ( + 'md-ref-palette': $md-ref-palette, + ), + $exclude-custom-properties: true + ) + ); +} + +/// `color.theme()` emits `--md-sys-color-*` custom properties for a given color +/// scheme. +/// +/// @example scss +/// @use '@material/web/color/color'; +/// +/// :root { +/// @include color.theme( +/// 'primary': /* ... */, +/// 'primary-container': /* ... */, +/// 'primary-fixed': /* ... */, +/// 'primary-fixed-dim': /* ... */, +/// /* ... */ +/// ); +/// } +/// +/// /* Generated CSS */ +/// :root { +/// --md-sys-color-primary: /* ... */; +/// --md-sys-color-primary-container: /* ... */; +/// --md-sys-color-primary-fixed: /* ... */; +/// --md-sys-color-primary-fixed-dim: /* ... */; +/// /* ... */ +/// } +/// +/// @param {Map} $tokens - A Map with `md-sys-color` token name keys and their +/// corresponding values. +/// @output Emits `--md-sys-color-*` custom properties for a given color scheme. +@mixin theme($tokens) { + @each $token, $value in $tokens { + @if list.index(tokens.$md-sys-color-supported-tokens, $token) == null { + @error 'md-sys-color `#{$token}` is not a supported token.'; + } + + @if $value { + --md-sys-color-#{$token}: #{$value}; + } + } +} diff --git a/testing/table/internal/_test-table.scss b/testing/table/internal/_test-table.scss index 4a2343a8b1..0c2b5e2e05 100644 --- a/testing/table/internal/_test-table.scss +++ b/testing/table/internal/_test-table.scss @@ -10,6 +10,7 @@ @use 'sass:map'; // go/keep-sorted end // go/keep-sorted start +@use '../../../color/color'; @use '../../../tokens'; // go/keep-sorted end @@ -96,12 +97,6 @@ $dark-theme: tokens.md-comp-test-table-values( } :host([dark]) { - $dark: tokens.md-sys-color-values-dark( - $exclude-custom-properties: true, - ); - - @each $token, $value in $dark { - --md-sys-color-#{$token}: #{$value}; - } + @include color.dark-theme; } } diff --git a/tokens/_md-ref-palette.scss b/tokens/_md-ref-palette.scss index 9a9beb54bf..4d3609ec43 100644 --- a/tokens/_md-ref-palette.scss +++ b/tokens/_md-ref-palette.scss @@ -5,8 +5,108 @@ // go/keep-sorted start @use './v0_172/md-ref-palette'; +@use './values'; // go/keep-sorted end +$supported-tokens: ( + // go/keep-sorted start + 'black', + 'error0', + 'error10', + 'error100', + 'error20', + 'error30', + 'error40', + 'error50', + 'error60', + 'error70', + 'error80', + 'error90', + 'error95', + 'error99', + 'neutral-variant0', + 'neutral-variant10', + 'neutral-variant100', + 'neutral-variant20', + 'neutral-variant30', + 'neutral-variant40', + 'neutral-variant50', + 'neutral-variant60', + 'neutral-variant70', + 'neutral-variant80', + 'neutral-variant90', + 'neutral-variant95', + 'neutral-variant99', + 'neutral0', + 'neutral10', + 'neutral100', + 'neutral12', + 'neutral17', + 'neutral20', + 'neutral22', + 'neutral24', + 'neutral30', + 'neutral4', + 'neutral40', + 'neutral50', + 'neutral6', + 'neutral60', + 'neutral70', + 'neutral80', + 'neutral87', + 'neutral90', + 'neutral92', + 'neutral94', + 'neutral95', + 'neutral96', + 'neutral98', + 'neutral99', + 'primary0', + 'primary10', + 'primary100', + 'primary20', + 'primary30', + 'primary40', + 'primary50', + 'primary60', + 'primary70', + 'primary80', + 'primary90', + 'primary95', + 'primary99', + 'secondary0', + 'secondary10', + 'secondary100', + 'secondary20', + 'secondary30', + 'secondary40', + 'secondary50', + 'secondary60', + 'secondary70', + 'secondary80', + 'secondary90', + 'secondary95', + 'secondary99', + 'tertiary0', + 'tertiary10', + 'tertiary100', + 'tertiary20', + 'tertiary30', + 'tertiary40', + 'tertiary50', + 'tertiary60', + 'tertiary70', + 'tertiary80', + 'tertiary90', + 'tertiary95', + 'tertiary99', + 'white', + // go/keep-sorted end +); + @function values($exclude-hardcoded-values: false) { - @return md-ref-palette.values($exclude-hardcoded-values); + @return values.validate( + md-ref-palette.values($exclude-hardcoded-values), + $supported-tokens: $supported-tokens + ); } diff --git a/tokens/_md-sys-color.scss b/tokens/_md-sys-color.scss index 20f40cf01b..6c38fa6e81 100644 --- a/tokens/_md-sys-color.scss +++ b/tokens/_md-sys-color.scss @@ -9,8 +9,63 @@ // go/keep-sorted start @use './md-ref-palette'; @use './v0_172/md-sys-color'; +@use './values'; // go/keep-sorted end +$supported-tokens: ( + // go/keep-sorted start + 'background', + 'error', + 'error-container', + 'inverse-on-surface', + 'inverse-primary', + 'inverse-surface', + 'on-background', + 'on-error', + 'on-error-container', + 'on-primary', + 'on-primary-container', + 'on-primary-fixed', + 'on-primary-fixed-variant', + 'on-secondary', + 'on-secondary-container', + 'on-secondary-fixed', + 'on-secondary-fixed-variant', + 'on-surface', + 'on-surface-variant', + 'on-tertiary', + 'on-tertiary-container', + 'on-tertiary-fixed', + 'on-tertiary-fixed-variant', + 'outline', + 'outline-variant', + 'primary', + 'primary-container', + 'primary-fixed', + 'primary-fixed-dim', + 'scrim', + 'secondary', + 'secondary-container', + 'secondary-fixed', + 'secondary-fixed-dim', + 'shadow', + 'surface', + 'surface-bright', + 'surface-container', + 'surface-container-high', + 'surface-container-highest', + 'surface-container-low', + 'surface-container-lowest', + 'surface-dim', + 'surface-tint', + 'surface-variant', + 'tertiary', + 'tertiary-container', + 'tertiary-fixed', + 'tertiary-fixed-dim', + // go/keep-sorted end +); + $_default-dark: ( 'md-ref-palette': md-ref-palette.values(), ); @@ -29,7 +84,7 @@ $_default-dark: ( } } - @return $tokens; + @return values.validate($tokens, $supported-tokens: $supported-tokens); } $_default-light: ( @@ -50,5 +105,5 @@ $_default-light: ( } } - @return $tokens; + @return values.validate($tokens, $supported-tokens: $supported-tokens); }