From e45e210055eff26bd74956560b10f2681d4f2ac6 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 17 Jan 2024 19:45:32 +0000 Subject: [PATCH] fix(material-experimental/theming): Add support for color variants in tabs and slider (#28417) --- src/dev-app/theme-m3.scss | 63 ++++---- .../theming/_custom-tokens.scss | 137 +++++++++++++++--- .../theming/_m3-tokens.scss | 8 +- src/material/slider/_slider-theme.scss | 39 +++-- src/material/tabs/_tabs-theme.scss | 46 ++++-- 5 files changed, 213 insertions(+), 80 deletions(-) diff --git a/src/dev-app/theme-m3.scss b/src/dev-app/theme-m3.scss index 7c96c85e36e0..358d0202a34f 100644 --- a/src/dev-app/theme-m3.scss +++ b/src/dev-app/theme-m3.scss @@ -2,53 +2,48 @@ @use '@angular/material' as mat; @use '@angular/material-experimental' as matx; -// TODO(mmalerba): Consider adding this as a back-compat API for users who want it, rather than just -// a demo thing. -@mixin color-variants-back-compat($theme) { - .mat-primary { - @include mat.option-color($theme, $color-variant: primary); - - &.mat-icon { - @include mat.icon-color($theme, $color-variant: primary); - } - - &.mat-mdc-checkbox { - @include mat.checkbox-color($theme, $color-variant: primary); - } +@mixin color-variant-styles($theme, $color-variant) { + @include mat.option-color($theme, $color-variant: $color-variant); - &.mat-mdc-fab, - &.mat-mdc-mini-fab { - @include mat.fab-color($theme, $color-variant: primary); - } + &.mat-icon { + @include mat.icon-color($theme, $color-variant: $color-variant); } - .mat-accent { - @include mat.option-color($theme, $color-variant: secondary); + &.mat-mdc-checkbox { + @include mat.checkbox-color($theme, $color-variant: $color-variant); + } - &.mat-icon { - @include mat.icon-color($theme, $color-variant: secondary); - } + &.mat-mdc-slider { + @include mat.slider-color($theme, $color-variant: $color-variant); + } - &.mat-mdc-checkbox { - @include mat.checkbox-color($theme, $color-variant: secondary); - } + &.mat-mdc-tab-group, + &.mat-mdc-tab-nav-bar { + @include mat.tabs-color($theme, $color-variant: $color-variant); + } + // M3 dropped support for warn/error color FABs. + @if $color-variant != error { &.mat-mdc-fab, &.mat-mdc-mini-fab { - @include mat.fab-color($theme, $color-variant: secondary); + @include mat.fab-color($theme, $color-variant: $color-variant); } } +} - .mat-warn { - @include mat.option-color($theme, $color-variant: error); +// TODO(mmalerba): Consider adding this as a back-compat API for users who want it, rather than just +// a demo thing. +@mixin color-variants-back-compat($theme) { + .mat-primary { + @include color-variant-styles($theme, primary); + } - &.mat-icon { - @include mat.icon-color($theme, $color-variant: error); - } + .mat-accent { + @include color-variant-styles($theme, secondary); + } - &.mat-mdc-checkbox { - @include mat.checkbox-color($theme, $color-variant: error); - } + .mat-warn { + @include color-variant-styles($theme, error); } } diff --git a/src/material-experimental/theming/_custom-tokens.scss b/src/material-experimental/theming/_custom-tokens.scss index 21c0529e3582..93f6e62a7c1e 100644 --- a/src/material-experimental/theming/_custom-tokens.scss +++ b/src/material-experimental/theming/_custom-tokens.scss @@ -684,14 +684,12 @@ /// @param {Boolean} $exclude-hardcoded Whether to exclude hardcoded token values /// @return {Map} A set of custom tokens for the mat-slider @function slider($systems, $exclude-hardcoded) { - $ripple-color: map.get($systems, md-sys-color, primary); - $hover-ripple-color: mat.private-safe-color-change($ripple-color, $alpha: 0.05); - $focus-ripple-color: mat.private-safe-color-change($ripple-color, $alpha: 0.2); - - @return ( - ripple-color: $ripple-color, - hover-state-layer-color: $hover-ripple-color, - focus-state-layer-color: $focus-ripple-color, + @return (( + ripple-color: map.get($systems, md-sys-color, primary), + hover-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, primary), $alpha: 0.05), + focus-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, primary), $alpha: 0.2), value-indicator-opacity: _hardcode(1, $exclude-hardcoded), value-indicator-padding: _hardcode(0, $exclude-hardcoded), value-indicator-width: _hardcode(28px, $exclude-hardcoded), @@ -701,7 +699,31 @@ value-indicator-text-transform: _hardcode(rotate(45deg), $exclude-hardcoded), value-indicator-container-transform: _hardcode(translateX(-50%) rotate(-45deg), $exclude-hardcoded) - ); + ), ( + // Color variants + primary: (), // Default, no overrides needed + secondary: ( + ripple-color: map.get($systems, md-sys-color, secondary), + hover-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, secondary), $alpha: 0.05), + focus-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, secondary), $alpha: 0.2), + ), + teriatiary: ( + ripple-color: map.get($systems, md-sys-color, tertiary), + hover-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, tertiary), $alpha: 0.05), + focus-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, tertiary), $alpha: 0.2), + ), + error: ( + ripple-color: map.get($systems, md-sys-color, error), + hover-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, error), $alpha: 0.05), + focus-state-layer-color: mat.private-safe-color-change( + map.get($systems, md-sys-color, error), $alpha: 0.2), + ), + )); } /// Generates custom tokens for the mat-snack-bar. @@ -766,7 +788,7 @@ /// @param {Boolean} $exclude-hardcoded Whether to exclude hardcoded token values /// @return {Map} A set of custom tokens for the mat-tab-header @function tab-header($systems, $exclude-hardcoded) { - @return mat.private-merge-all( + @return (mat.private-merge-all( _generate-typography-tokens($systems, label-text, title-small), ( divider-color: map.get($systems, md-sys-color, surface-variant), @@ -784,7 +806,22 @@ active-focus-indicator-color: map.get($systems, md-sys-color, primary), active-hover-indicator-color: map.get($systems, md-sys-color, primary), ), - ); + ), ( + // Color variants + primary: (), // Default, no overrides needed + secondary: ( + active-focus-indicator-color: map.get($systems, md-sys-color, secondary), + active-hover-indicator-color: map.get($systems, md-sys-color, secondary), + ), + tertiary: ( + active-focus-indicator-color: map.get($systems, md-sys-color, tertiary), + active-hover-indicator-color: map.get($systems, md-sys-color, tertiary), + ), + error: ( + active-focus-indicator-color: map.get($systems, md-sys-color, error), + active-hover-indicator-color: map.get($systems, md-sys-color, error), + ) + )); } /// Generates custom tokens for the mdc-tab-indicator. (MDC has a tab-indicator component, but they @@ -794,11 +831,23 @@ /// @param {Boolean} $exclude-hardcoded Whether to exclude hardcoded token values /// @return {Map} A set of custom tokens for the mdc-tab-indicator @function tab-indicator($systems, $exclude-hardcoded) { - @return ( + @return (( active-indicator-height: _hardcode(2px, $exclude-hardcoded), active-indicator-shape: _hardcode(0, $exclude-hardcoded), active-indicator-color: map.get($systems, md-sys-color, primary), - ); + ), ( + // Color variants + primary: (), // Default, no overrides needed + secondary: ( + active-indicator-color: map.get($systems, md-sys-color, secondary), + ), + tertiary: ( + active-indicator-color: map.get($systems, md-sys-color, tertiary), + ), + error: ( + active-indicator-color: map.get($systems, md-sys-color, error), + ) + )); } /// Generates custom tokens for the mat-table. @@ -826,11 +875,11 @@ /// @return {Map} A set of custom tokens for the mat-toolbar @function toolbar($systems, $exclude-hardcoded) { @return mat.private-merge-all( - _generate-typography-tokens($systems, title-text, title-large), - ( - container-background-color: map.get($systems, md-sys-color, surface), - container-text-color: map.get($systems, md-sys-color, on-surface), - ) + _generate-typography-tokens($systems, title-text, title-large), + ( + container-background-color: map.get($systems, md-sys-color, surface), + container-text-color: map.get($systems, md-sys-color, on-surface), + ) ); } @@ -896,3 +945,55 @@ ) ); } + +/// Generates custom token overrides for the mdc-slider color variants. +/// @param {Map} $systems The MDC system tokens +/// @param {Boolean} $exclude-hardcoded Whether to exclude hardcoded token values +/// @return {Map} A set of color variant token overrides for the mdc-slider +@function mdc-slider-color-variants($systems, $exclude-hardcoded) { + @return ( + primary: (), // Default, no overrides needed + secondary: ( + active-track-color: map.get($systems, md-sys-color, secondary), + focus-handle-color: map.get($systems, md-sys-color, secondary), + focus-state-layer-color: map.get($systems, md-sys-color, secondary), + handle-color: map.get($systems, md-sys-color, secondary), + hover-handle-color: map.get($systems, md-sys-color, secondary), + hover-state-layer-color: map.get($systems, md-sys-color, secondary), + label-container-color: map.get($systems, md-sys-color, secondary), + label-label-text-color: map.get($systems, md-sys-color, on-secondary), + pressed-handle-color: map.get($systems, md-sys-color, secondary), + pressed-state-layer-color: map.get($systems, md-sys-color, secondary), + with-overlap-handle-outline-color: map.get($systems, md-sys-color, on-secondary), + with-tick-marks-active-container-color: map.get($systems, md-sys-color, on-secondary), + ), + tertiary: ( + active-track-color: map.get($systems, md-sys-color, tertiary), + focus-handle-color: map.get($systems, md-sys-color, tertiary), + focus-state-layer-color: map.get($systems, md-sys-color, tertiary), + handle-color: map.get($systems, md-sys-color, tertiary), + hover-handle-color: map.get($systems, md-sys-color, tertiary), + hover-state-layer-color: map.get($systems, md-sys-color, tertiary), + label-container-color: map.get($systems, md-sys-color, tertiary), + label-label-text-color: map.get($systems, md-sys-color, on-tertiary), + pressed-handle-color: map.get($systems, md-sys-color, tertiary), + pressed-state-layer-color: map.get($systems, md-sys-color, tertiary), + with-overlap-handle-outline-color: map.get($systems, md-sys-color, on-tertiary), + with-tick-marks-active-container-color: map.get($systems, md-sys-color, on-tertiary), + ), + error: ( + active-track-color: map.get($systems, md-sys-color, error), + focus-handle-color: map.get($systems, md-sys-color, error), + focus-state-layer-color: map.get($systems, md-sys-color, error), + handle-color: map.get($systems, md-sys-color, error), + hover-handle-color: map.get($systems, md-sys-color, error), + hover-state-layer-color: map.get($systems, md-sys-color, error), + label-container-color: map.get($systems, md-sys-color, error), + label-label-text-color: map.get($systems, md-sys-color, on-error), + pressed-handle-color: map.get($systems, md-sys-color, error), + pressed-state-layer-color: map.get($systems, md-sys-color, error), + with-overlap-handle-outline-color: map.get($systems, md-sys-color, on-error), + with-tick-marks-active-container-color: map.get($systems, md-sys-color, on-error), + ), + ); +} diff --git a/src/material-experimental/theming/_m3-tokens.scss b/src/material-experimental/theming/_m3-tokens.scss index 80991713dad9..257148b04d25 100644 --- a/src/material-experimental/theming/_m3-tokens.scss +++ b/src/material-experimental/theming/_m3-tokens.scss @@ -540,8 +540,7 @@ // Color variants primary: (), // Default, no overrides needed. secondary: mdc-tokens.md-comp-extended-fab-secondary-values($systems, $exclude-hardcoded), - tertiary: mdc-tokens.md-comp-extended-fab-tertiary-values($systems, $exclude-hardcoded), - error: () // TODO(mmalerba): Should we add our own error variant? + tertiary: mdc-tokens.md-comp-extended-fab-tertiary-values($systems, $exclude-hardcoded) ), ), $token-slots @@ -649,7 +648,10 @@ ), _namespace-tokens( (mdc, slider), - mdc-tokens.md-comp-slider-values($systems, $exclude-hardcoded), + ( + mdc-tokens.md-comp-slider-values($systems, $exclude-hardcoded), + custom-tokens.mdc-slider-color-variants($systems, $exclude-hardcoded) + ), $token-slots ), _namespace-tokens( diff --git a/src/material/slider/_slider-theme.scss b/src/material/slider/_slider-theme.scss index e0b45a6bffd5..25e5dd449b9c 100644 --- a/src/material/slider/_slider-theme.scss +++ b/src/material/slider/_slider-theme.scss @@ -1,4 +1,3 @@ -@use 'sass:map'; @use '@material/slider/slider-theme' as mdc-slider-theme; @use '../core/theming/theming'; @use '../core/theming/inspection'; @@ -8,6 +7,9 @@ @use '../core/tokens/m2/mat/slider' as tokens-mat-slider; @use '../core/tokens/m2/mdc/slider' as tokens-mdc-slider; +/// Outputs base theme styles (styles not dependent on the color, typography, or density settings) +/// for the mat-slider. +/// @param {Map} $theme The theme to generate base styles for. @mixin base($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, base)); @@ -22,9 +24,14 @@ } } -@mixin color($theme) { +/// Outputs color theme styles for the mat-slider. +/// @param {Map} $theme The theme to generate color styles for. +/// @param {ArgList} Additional optional arguments (only supported for M3 themes): +/// $color-variant: The color variant to use for the slider: primary, secondary, tertiary, +/// or error (If not specified, default primary color will be used). +@mixin color($theme, $options...) { @if inspection.get-theme-version($theme) == 1 { - @include _theme-from-tokens(inspection.get-theme-tokens($theme, color)); + @include _theme-from-tokens(inspection.get-theme-tokens($theme, color), $options...); } @else { $is-dark: inspection.get-theme-type($theme) == dark; @@ -66,6 +73,9 @@ } } + +/// Outputs typography theme styles for the mat-slider. +/// @param {Map} $theme The theme to generate typography styles for. @mixin typography($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, typography)); @@ -78,6 +88,9 @@ } } + +/// Outputs density theme styles for the mat-slider. +/// @param {Map} $theme The theme to generate density styles for. @mixin density($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, density)); @@ -90,10 +103,15 @@ } } -@mixin theme($theme) { +/// Outputs all (base, color, typography, and density) theme styles for the mat-option. +/// @param {Map} $theme The theme to generate styles for. +/// @param {ArgList} Additional optional arguments (only supported for M3 themes): +/// $color-variant: The color variant to use for the slider: primary, secondary, tertiary, +/// or error (If not specified, default primary color will be used). +@mixin theme($theme, $options...) { @include theming.private-check-duplicate-theme-styles($theme, 'mat-slider') { @if inspection.get-theme-version($theme) == 1 { - @include _theme-from-tokens(inspection.get-theme-tokens($theme)); + @include _theme-from-tokens(inspection.get-theme-tokens($theme), $options...); } @else { @include base($theme); @@ -110,10 +128,9 @@ } } -@mixin _theme-from-tokens($tokens) { - @if ($tokens != ()) { - @include mdc-slider-theme.theme(map.get($tokens, tokens-mdc-slider.$prefix)); - @include token-utils.create-token-values( - tokens-mat-slider.$prefix, map.get($tokens, tokens-mat-slider.$prefix)); - } +@mixin _theme-from-tokens($tokens, $options...) { + $mdc-slider-tokens: token-utils.get-tokens-for($tokens, tokens-mdc-slider.$prefix, $options...); + $mat-slider-tokens: token-utils.get-tokens-for($tokens, tokens-mat-slider.$prefix, $options...); + @include mdc-slider-theme.theme($mdc-slider-tokens); + @include token-utils.create-token-values(tokens-mat-slider.$prefix, $mat-slider-tokens); } diff --git a/src/material/tabs/_tabs-theme.scss b/src/material/tabs/_tabs-theme.scss index 0729baf88198..a30a2e50dc52 100644 --- a/src/material/tabs/_tabs-theme.scss +++ b/src/material/tabs/_tabs-theme.scss @@ -1,4 +1,3 @@ -@use 'sass:map'; @use '@material/tab-indicator/tab-indicator-theme' as mdc-tab-indicator-theme; @use '@material/tab/tab-theme' as mdc-tab-theme; @use '../core/style/sass-utils'; @@ -11,6 +10,9 @@ @use '../core/typography/typography'; @use '../core/tokens/token-utils'; +/// Outputs base theme styles (styles not dependent on the color, typography, or density settings) +/// for the mat-tab. +/// @param {Map} $theme The theme to generate base styles for. @mixin base($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, base)); @@ -29,9 +31,14 @@ } } -@mixin color($theme) { +/// Outputs color theme styles for the mat-tab. +/// @param {Map} $theme The theme to generate color styles for. +/// @param {ArgList} Additional optional arguments (only supported for M3 themes): +/// $color-variant: The color variant to use for the tab indicator: primary, secondary, +/// tertiary, or error (If not specified, default primary color will be used). +@mixin color($theme, $options...) { @if inspection.get-theme-version($theme) == 1 { - @include _theme-from-tokens(inspection.get-theme-tokens($theme, color)); + @include _theme-from-tokens(inspection.get-theme-tokens($theme, color), $options...); } @else { .mat-mdc-tab-group, .mat-mdc-tab-nav-bar { @@ -74,6 +81,8 @@ tokens-mat-tab-header.get-color-tokens($theme, $palette-name)); } +/// Outputs typography theme styles for the mat-tab. +/// @param {Map} $theme The theme to generate typography styles for. @mixin typography($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, typography)); @@ -92,6 +101,8 @@ } } +/// Outputs density theme styles for the mat-tab. +/// @param {Map} $theme The theme to generate density styles for. @mixin density($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, density)); @@ -110,10 +121,15 @@ } } -@mixin theme($theme) { +/// Outputs all (base, color, typography, and density) theme styles for the mat-tab. +/// @param {Map} $theme The theme to generate styles for. +/// @param {ArgList} Additional optional arguments (only supported for M3 themes): +/// $color-variant: The color variant to use for the tab indicator: primary, secondary, +/// tertiary, or error (If not specified, default primary color will be used). +@mixin theme($theme, $options...) { @include theming.private-check-duplicate-theme-styles($theme, 'mat-tabs') { @if inspection.get-theme-version($theme) == 1 { - @include _theme-from-tokens(inspection.get-theme-tokens($theme)); + @include _theme-from-tokens(inspection.get-theme-tokens($theme), $options...); } @else { @include base($theme); @@ -130,13 +146,15 @@ } } -@mixin _theme-from-tokens($tokens) { - @if ($tokens != ()) { - @include mdc-tab-theme.secondary-navigation-tab-theme( - map.get($tokens, tokens-mdc-tab.$prefix)); - @include mdc-tab-indicator-theme.theme( - map.get($tokens, tokens-mdc-tab-indicator.$prefix)); - @include token-utils.create-token-values( - tokens-mat-tab-header.$prefix, map.get($tokens, tokens-mat-tab-header.$prefix)); - } +@mixin _theme-from-tokens($tokens, $options...) { + $mdc-tab-indicator-tokens: token-utils.get-tokens-for( + $tokens, tokens-mdc-tab-indicator.$prefix, $options...); + $mat-tab-header-tokens: token-utils.get-tokens-for( + $tokens, tokens-mat-tab-header.$prefix, $options...); + // Don't pass $options here, because the mdc-tab doesn't have color variants, + // only the mdc-tab-indicator and mat-tab-header do. + $mdc-tab-tokens: token-utils.get-tokens-for($tokens, tokens-mdc-tab.$prefix); + @include mdc-tab-theme.secondary-navigation-tab-theme($mdc-tab-tokens); + @include mdc-tab-indicator-theme.theme($mdc-tab-indicator-tokens); + @include token-utils.create-token-values(tokens-mat-tab-header.$prefix, $mat-tab-header-tokens); }