diff --git a/src/material/card/_card-theme.scss b/src/material/card/_card-theme.scss index 8b9b320c1b2a..c667b81d881f 100644 --- a/src/material/card/_card-theme.scss +++ b/src/material/card/_card-theme.scss @@ -8,12 +8,16 @@ @use '@material/theme/theme-color' as mdc-theme-color; @use 'sass:color'; @use 'sass:map'; +@use 'sass:meta'; @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); $foreground: map.get($config, foreground); @include mdc-helpers.using-mdc-theme($config) { + $on-surface: mdc-theme-color.prop-value(on-surface); + $surface: mdc-theme-color.prop-value(surface); + .mat-mdc-card { // MDC's theme has `container-elevation` and `container-shadow-color` tokens, but we can't // use them because they output under a `.mdc-card` selector whereas the rest of the theme @@ -21,15 +25,18 @@ // different error. @include private.private-theme-elevation(1, $config); @include mdc-elevated-card-theme.theme(( - container-color: mdc-theme-color.prop-value(surface), + container-color: $surface, )); } .mat-mdc-card-outlined { @include private.private-theme-elevation(0, $config); @include mdc-outlined-card-theme.theme(( - outline-color: color.mix(mdc-theme-color.prop-value(on-surface), - mdc-theme-color.prop-value(surface), 12%) + outline-color: if( + meta.type-of($on-surface) == color and meta.type-of($surface) == color, + color.mix($on-surface, $surface, 12%), + $on-surface + ) )); } diff --git a/src/material/chips/_chips-theme.scss b/src/material/chips/_chips-theme.scss index 65ae18053096..49354e533288 100644 --- a/src/material/chips/_chips-theme.scss +++ b/src/material/chips/_chips-theme.scss @@ -1,5 +1,6 @@ @use 'sass:color'; @use 'sass:map'; +@use 'sass:meta'; @use '@material/chips/chip-theme' as mdc-chip-theme; @use '@material/chips/chip-set' as mdc-chip-set; @use '@material/theme/theme-color' as mdc-theme-color; @@ -42,9 +43,18 @@ $is-dark: map.get($config, is-dark); @include mdc-helpers.using-mdc-theme($config) { + $on-surface: mdc-theme-color.prop-value(on-surface); + $surface: mdc-theme-color.prop-value(surface); + .mat-mdc-standard-chip { + $standard-background: if( + meta.type-of($on-surface) == color and meta.type-of($surface) == color, + color.mix($on-surface, $surface, 12%), + $on-surface + ); + @include _chip-variant( - color.mix(mdc-theme-color.prop-value(on-surface), mdc-theme-color.prop-value(surface), 12%), + $standard-background, if($is-dark, mdc-color-palette.$grey-50, mdc-color-palette.$grey-900) ); diff --git a/src/material/core/mdc-helpers/_mdc-helpers.scss b/src/material/core/mdc-helpers/_mdc-helpers.scss index e6b2320fcc71..eced4eea4d6a 100644 --- a/src/material/core/mdc-helpers/_mdc-helpers.scss +++ b/src/material/core/mdc-helpers/_mdc-helpers.scss @@ -97,6 +97,21 @@ $mat-typography-mdc-level-mappings: ( ); } +// MDC logs a warning if the `contrast-tone` function is called with a CSS variable. +// This function falls back to determining the tone based on whether the theme is light or dark. +@function _variable-safe-contrast-tone($value, $is-dark) { + @if ($value == 'dark' or $value == 'light' or type-of($value) == 'color') { + @return mdc-theme-color.contrast-tone($value); + } + + @return if($is-dark, 'light', 'dark'); +} + +@function _variable-safe-ink-color-for-fill($text-style, $fill-color, $is-dark) { + $contrast-tone: _variable-safe-contrast-tone($fill-color, $is-dark); + @return map.get(map.get(mdc-theme-color.$text-colors, $contrast-tone), $text-style); +} + // Configures MDC's global variables to reflect the given theme, applies the given styles, // then resets the global variables to prevent unintended side effects. @mixin using-mdc-theme($config) { @@ -104,6 +119,7 @@ $mat-typography-mdc-level-mappings: ( $accent: theming.get-color-from-palette(map.get($config, accent)); $warn: theming.get-color-from-palette(map.get($config, warn)); $background-palette: map.get($config, background); + $is-dark: map.get($config, is-dark); // Save the original values. $orig-primary: mdc-theme-color.$primary; @@ -120,17 +136,17 @@ $mat-typography-mdc-level-mappings: ( // Set new values based on the given Angular Material theme. mdc-theme-color.$primary: $primary; mdc-theme-color.$on-primary: - if(mdc-theme-color.contrast-tone(mdc-theme-color.$primary) == 'dark', #000, #fff); + if(_variable-safe-contrast-tone(mdc-theme-color.$primary, $is-dark) == 'dark', #000, #fff); mdc-theme-color.$secondary: $accent; mdc-theme-color.$on-secondary: - if(mdc-theme-color.contrast-tone(mdc-theme-color.$secondary) == 'dark', #000, #fff); + if(_variable-safe-contrast-tone(mdc-theme-color.$secondary, $is-dark) == 'dark', #000, #fff); mdc-theme-color.$background: theming.get-color-from-palette($background-palette, background); mdc-theme-color.$surface: theming.get-color-from-palette($background-palette, card); mdc-theme-color.$on-surface: - if(mdc-theme-color.contrast-tone(mdc-theme-color.$surface) == 'dark', #000, #fff); + if(_variable-safe-contrast-tone(mdc-theme-color.$surface, $is-dark) == 'dark', #000, #fff); mdc-theme-color.$error: $warn; mdc-theme-color.$on-error: - if(mdc-theme-color.contrast-tone(mdc-theme-color.$error) == 'dark', #000, #fff); + if(_variable-safe-contrast-tone(mdc-theme-color.$error, $is-dark) == 'dark', #000, #fff); mdc-theme-color.$property-values: ( // Primary primary: mdc-theme-color.$primary, @@ -148,27 +164,27 @@ $mat-typography-mdc-level-mappings: ( on-error: mdc-theme-color.$on-error, // Text-primary on "background" background text-primary-on-background: - mdc-theme-color.ink-color-for-fill_(primary, mdc-theme-color.$background), + _variable-safe-ink-color-for-fill(primary, mdc-theme-color.$background, $is-dark), text-secondary-on-background: - mdc-theme-color.ink-color-for-fill_(secondary, mdc-theme-color.$background), + _variable-safe-ink-color-for-fill(secondary, mdc-theme-color.$background, $is-dark), text-hint-on-background: - mdc-theme-color.ink-color-for-fill_(hint, mdc-theme-color.$background), + _variable-safe-ink-color-for-fill(hint, mdc-theme-color.$background, $is-dark), text-disabled-on-background: - mdc-theme-color.ink-color-for-fill_(disabled, mdc-theme-color.$background), + _variable-safe-ink-color-for-fill(disabled, mdc-theme-color.$background, $is-dark), text-icon-on-background: - mdc-theme-color.ink-color-for-fill_(icon, mdc-theme-color.$background), + _variable-safe-ink-color-for-fill(icon, mdc-theme-color.$background, $is-dark), // Text-primary on "light" background - text-primary-on-light: mdc-theme-color.ink-color-for-fill_(primary, light), - text-secondary-on-light: mdc-theme-color.ink-color-for-fill_(secondary, light), - text-hint-on-light: mdc-theme-color.ink-color-for-fill_(hint, light), - text-disabled-on-light: mdc-theme-color.ink-color-for-fill_(disabled, light), - text-icon-on-light: mdc-theme-color.ink-color-for-fill_(icon, light), + text-primary-on-light: _variable-safe-ink-color-for-fill(primary, light, $is-dark), + text-secondary-on-light: _variable-safe-ink-color-for-fill(secondary, light, $is-dark), + text-hint-on-light: _variable-safe-ink-color-for-fill(hint, light, $is-dark), + text-disabled-on-light: _variable-safe-ink-color-for-fill(disabled, light, $is-dark), + text-icon-on-light: _variable-safe-ink-color-for-fill(icon, light, $is-dark), // Text-primary on "dark" background - text-primary-on-dark: mdc-theme-color.ink-color-for-fill_(primary, dark), - text-secondary-on-dark: mdc-theme-color.ink-color-for-fill_(secondary, dark), - text-hint-on-dark: mdc-theme-color.ink-color-for-fill_(hint, dark), - text-disabled-on-dark: mdc-theme-color.ink-color-for-fill_(disabled, dark), - text-icon-on-dark: mdc-theme-color.ink-color-for-fill_(icon, dark) + text-primary-on-dark: _variable-safe-ink-color-for-fill(primary, dark, $is-dark), + text-secondary-on-dark: _variable-safe-ink-color-for-fill(secondary, dark, $is-dark), + text-hint-on-dark: _variable-safe-ink-color-for-fill(hint, dark, $is-dark), + text-disabled-on-dark: _variable-safe-ink-color-for-fill(disabled, dark, $is-dark), + text-icon-on-dark: _variable-safe-ink-color-for-fill(icon, dark, $is-dark) ); // Apply given rules. diff --git a/src/material/core/theming/tests/test-css-variables-theme.scss b/src/material/core/theming/tests/test-css-variables-theme.scss index 3598d81dc422..0222b8b55200 100644 --- a/src/material/core/theming/tests/test-css-variables-theme.scss +++ b/src/material/core/theming/tests/test-css-variables-theme.scss @@ -1,17 +1,18 @@ @use 'sass:map'; @use 'sass:meta'; @use '../all-theme'; +@use '../../typography/all-typography'; @use '../palette'; @use '../theming'; @use '../../../legacy-core/theming/all-theme' as legacy-all-theme; // Recursively replaces all of the values inside a Sass map with a different value. -@function replace-all-values($palette, $replacement) { +@function _replace-all-values($palette, $replacement) { $output: (); @each $key, $value in $palette { @if (meta.type-of($value) == 'map') { - $output: map.merge(($key: replace-all-values($value, $replacement)), $output); + $output: map.merge(($key: _replace-all-values($value, $replacement)), $output); } @else { $output: map.merge(($key: $replacement), $output); @@ -29,8 +30,10 @@ primary: $palette, accent: $palette, warn: $palette - ) + ), + typography: all-typography.define-typography-config(), )); - $css-var-theme: replace-all-values($theme, var(--test-var)); + $css-var-theme: _replace-all-values($theme, var(--test-var)); + @include all-theme.all-component-themes($css-var-theme); @include legacy-all-theme.all-legacy-component-themes($css-var-theme); } diff --git a/src/material/form-field/_mdc-text-field-theme-variable-refresh.scss b/src/material/form-field/_mdc-text-field-theme-variable-refresh.scss index bed2445556bf..bb85e7a9a15a 100644 --- a/src/material/form-field/_mdc-text-field-theme-variable-refresh.scss +++ b/src/material/form-field/_mdc-text-field-theme-variable-refresh.scss @@ -1,6 +1,7 @@ @use '@material/textfield' as mdc-textfield; @use '@material/theme/variables' as mdc-theme-variables; @use 'sass:color'; +@use 'sass:meta'; // Mixin that refreshes the MDC text-field theming variables. This mixin should be used when // the base MDC theming variables have been explicitly updated, but the component specific @@ -8,38 +9,48 @@ // restores the previous values for the variables to avoid unexpected global side effects. @mixin private-text-field-refresh-theme-variables() { $_disabled-border: mdc-textfield.$disabled-border; - mdc-textfield.$disabled-border: rgba(mdc-theme-variables.prop-value(on-surface), 0.06); + mdc-textfield.$disabled-border: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.06); $_bottom-line-hover: mdc-textfield.$bottom-line-hover; - mdc-textfield.$bottom-line-hover: rgba(mdc-theme-variables.prop-value(on-surface), 0.87); + mdc-textfield.$bottom-line-hover: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.87); $_bottom-line-idle: mdc-textfield.$bottom-line-idle; - mdc-textfield.$bottom-line-idle: rgba(mdc-theme-variables.prop-value(on-surface), 0.42); + mdc-textfield.$bottom-line-idle: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.42); $_label: mdc-textfield.$label; - mdc-textfield.$label: rgba(mdc-theme-variables.prop-value(on-surface), 0.6); + mdc-textfield.$label: _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.6); $_ink-color: mdc-textfield.$ink-color; - mdc-textfield.$ink-color: rgba(mdc-theme-variables.prop-value(on-surface), 0.87); + mdc-textfield.$ink-color: _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.87); $_focused-label-color: mdc-textfield.$focused-label-color; - mdc-textfield.$focused-label-color: rgba(mdc-theme-variables.prop-value(primary), 0.87); + mdc-textfield.$focused-label-color: + _variable-safe-rgba(mdc-theme-variables.prop-value(primary), 0.87); $_placeholder-ink-color: mdc-textfield.$placeholder-ink-color; - mdc-textfield.$placeholder-ink-color: rgba(mdc-theme-variables.prop-value(on-surface), 0.6); + mdc-textfield.$placeholder-ink-color: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.6); $_disabled-label-color: mdc-textfield.$disabled-label-color; - mdc-textfield.$disabled-label-color: rgba(mdc-theme-variables.prop-value(on-surface), 0.38); + mdc-textfield.$disabled-label-color: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.38); $_disabled-ink-color: mdc-textfield.$disabled-ink-color; - mdc-textfield.$disabled-ink-color: rgba(mdc-theme-variables.prop-value(on-surface), 0.38); + mdc-textfield.$disabled-ink-color: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.38); $_disabled-placeholder-ink-color: mdc-textfield.$disabled-placeholder-ink-color; mdc-textfield.$disabled-placeholder-ink-color: - rgba(mdc-theme-variables.prop-value(on-surface), 0.38); + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.38); $_background: mdc-textfield.$background; - mdc-textfield.$background: color.mix(mdc-theme-variables.prop-value(on-surface), + mdc-textfield.$background: _variable-safe-mix(mdc-theme-variables.prop-value(on-surface), mdc-theme-variables.prop-value(surface), 4%); $_disabled-background: mdc-textfield.$disabled-background; - mdc-textfield.$disabled-background: color.mix(mdc-theme-variables.prop-value(on-surface), + mdc-textfield.$disabled-background: _variable-safe-mix(mdc-theme-variables.prop-value(on-surface), mdc-theme-variables.prop-value(surface), 2%); $_outlined-idle-border: mdc-textfield.$outlined-idle-border; - mdc-textfield.$outlined-idle-border: rgba(mdc-theme-variables.prop-value(on-surface), 0.38); + mdc-textfield.$outlined-idle-border: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.38); $_outlined-disabled-border: mdc-textfield.$outlined-disabled-border; - mdc-textfield.$outlined-disabled-border: rgba(mdc-theme-variables.prop-value(on-surface), 0.06); + mdc-textfield.$outlined-disabled-border: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.06); $_outlined-hover-border: mdc-textfield.$outlined-hover-border; - mdc-textfield.$outlined-hover-border: rgba(mdc-theme-variables.prop-value(on-surface), 0.87); + mdc-textfield.$outlined-hover-border: + _variable-safe-rgba(mdc-theme-variables.prop-value(on-surface), 0.87); // The content will be generated with the refreshed MDC text-field theming variables. @content; @@ -61,3 +72,17 @@ mdc-textfield.$outlined-disabled-border: $_outlined-disabled-border; mdc-textfield.$outlined-hover-border: $_outlined-hover-border; } + +@function _variable-safe-rgba($color, $opacity) { + @if (meta.type-of($color) == color) { + @return rgba($color, $opacity); + } + @return $color; +} + +@function _variable-safe-mix($first-color, $second-color, $amount) { + @if (meta.type-of($first-color) == color and meta.type-of($second-color) == color) { + @return color.mix($first-color, $second-color, $amount); + } + @return $first-color; +} diff --git a/src/material/progress-bar/_progress-bar-theme.scss b/src/material/progress-bar/_progress-bar-theme.scss index abac1a5011bd..6cd97f617199 100644 --- a/src/material/progress-bar/_progress-bar-theme.scss +++ b/src/material/progress-bar/_progress-bar-theme.scss @@ -3,9 +3,12 @@ @use '@material/theme/theme-color' as mdc-theme-color; @use '@material/linear-progress/linear-progress-theme' as mdc-linear-progress-theme; @use 'sass:color'; +@use 'sass:meta'; @mixin _palette-styles($color) { + $color-value: mdc-theme-color.prop-value($color); + // We can't set the `track-color` using `theme`, because it isn't possible for it to use a CSS // variable since MDC's buffer animation works by constructing an SVG string from this color. @include mdc-linear-progress-theme.theme-styles(( @@ -13,11 +16,15 @@ // writing, their buffer color is hardcoded to #e6e6e6 which both doesn't account for theming // and doesn't match the Material design spec. For now we approximate the buffer background by // applying an opacity to the color of the bar. - track-color: color.adjust(mdc-theme-color.prop-value($color), $alpha: -0.75), + track-color: if( + meta.type-of($color-value) == color, + color.adjust($color-value, $alpha: -0.75), + $color-value + ), )); @include mdc-linear-progress-theme.theme(( - active-indicator-color: mdc-theme-color.prop-value($color), + active-indicator-color: $color-value, )); } diff --git a/src/material/snack-bar/_snack-bar-theme.scss b/src/material/snack-bar/_snack-bar-theme.scss index cb0e2e1a37ee..d54e31a122f6 100644 --- a/src/material/snack-bar/_snack-bar-theme.scss +++ b/src/material/snack-bar/_snack-bar-theme.scss @@ -6,6 +6,7 @@ @use '@material/snackbar/snackbar-theme' as mdc-snackbar-theme; @use 'sass:color'; @use 'sass:map'; +@use 'sass:meta'; @mixin color($config-or-theme) { @@ -18,16 +19,19 @@ $button-color: if($is-dark-theme, currentColor, theming.get-color-from-palette($accent, text)); --mat-mdc-snack-bar-button-color: #{$button-color}; + $on-surface: mdc-theme-color.prop-value(on-surface); + $surface: mdc-theme-color.prop-value(surface); @include mdc-snackbar-theme.theme(( - container-color: color.mix( - mdc-theme-color.prop-value(on-surface), - mdc-theme-color.prop-value(surface), - 80% + container-color: if( + meta.type-of($on-surface) == color and meta.type-of($surface) == color, + color.mix($on-surface, $surface, 80%), + $on-surface ), - supporting-text-color: rgba( - mdc-theme-color.prop-value(surface), - mdc-theme-color.text-emphasis(high) + supporting-text-color: if( + meta.type-of($surface) == color, + rgba($surface, mdc-theme-color.text-emphasis(high)), + $surface ) )); }