From aec23ac348f41d288417c1ae7788e0bd7cb8a9a9 Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 31 May 2023 22:40:48 +0000 Subject: [PATCH] feat(material-experimental/theming): add first part of token-based theming API (#27000) * feat(material-experimental/theming): add first part of token-based theming API * Set up a query parameter to use the token-based Sass API in the dev-app * Generate all M2 tokens from a theme object * Add mixins to emit the theme based on tokens * Add the new mat.theme API * fixup! Add the new mat.theme API * tweaks based on recent feedback and discussions * addressed more feedback * fixup! addressed more feedback --- .github/CODEOWNERS | 2 +- .ng-dev/commit-message.mts | 13 +- src/dev-app/BUILD.bazel | 11 + src/dev-app/dev-app.ts | 16 +- src/dev-app/index.html | 2 +- src/dev-app/theme-token-api.scss | 68 ++++++ src/material-experimental/BUILD.bazel | 4 +- src/material-experimental/_index.scss | 3 + src/material-experimental/theming/BUILD.bazel | 9 + .../theming/_theming.scss | 134 ++++++++++++ src/material/BUILD.bazel | 1 + src/material/_index.scss | 3 + src/material/_token-theming.scss | 2 + src/material/button/_icon-button-theme.scss | 1 - src/material/card/_card-theme.import.scss | 2 +- src/material/card/_card-theme.scss | 11 + .../checkbox/_checkbox-theme.import.scss | 2 +- src/material/checkbox/_checkbox-theme.scss | 9 + src/material/core/style/_sass-utils.scss | 34 ++- src/material/core/tokens/_token-utils.scss | 11 +- src/material/core/tokens/m2/_index.scss | 84 ++++++++ src/material/core/tokens/m2/mat/_card.scss | 33 +-- src/material/core/tokens/m2/mat/_radio.scss | 11 +- .../core/tokens/m2/mat/_snack-bar.scss | 11 +- .../m2/mat/_tab-header-with-background.scss | 11 +- .../core/tokens/m2/mat/_tab-header.scss | 3 +- .../core/tokens/m2/mdc/_checkbox.scss | 77 +++---- src/material/core/tokens/m2/mdc/_chip.scss | 4 +- .../tokens/m2/mdc/_circular-progress.scss | 13 +- src/material/core/tokens/m2/mdc/_dialog.scss | 13 +- .../core/tokens/m2/mdc/_elevated-card.scss | 3 +- .../core/tokens/m2/mdc/_icon-button.scss | 18 +- .../core/tokens/m2/mdc/_linear-progress.scss | 19 +- src/material/core/tokens/m2/mdc/_list.scss | 203 +++++++++--------- .../core/tokens/m2/mdc/_outlined-card.scss | 3 +- .../core/tokens/m2/mdc/_plain-tooltip.scss | 15 +- src/material/core/tokens/m2/mdc/_radio.scss | 13 +- .../core/tokens/m2/mdc/_snack-bar.scss | 14 +- .../core/tokens/m2/mdc/_tab-indicator.scss | 12 +- src/material/core/tokens/m2/mdc/_tab.scss | 12 +- .../tokens/tests/test-validate-tokens.scss | 4 +- src/material/legacy-radio/radio.scss | 1 - .../legacy-slide-toggle/slide-toggle.scss | 1 - src/material/slide-toggle/slide-toggle.scss | 2 +- src/material/stepper/stepper.scss | 1 - src/material/tabs/_tabs-theme.scss | 1 - tools/stylelint/no-unused-import.ts | 13 +- 47 files changed, 647 insertions(+), 286 deletions(-) create mode 100644 src/dev-app/theme-token-api.scss create mode 100644 src/material-experimental/theming/BUILD.bazel create mode 100644 src/material-experimental/theming/_theming.scss create mode 100644 src/material/_token-theming.scss create mode 100644 src/material/core/tokens/m2/_index.scss diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 093e4974d285..db0983f2611a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -131,10 +131,10 @@ # Material experimental package /src/material-experimental/* @andrewseguin /src/material-experimental/column-resize/** @andrewseguin -/src/material-experimental/mdc-tooltip/** @crisbeto /src/material-experimental/menubar/** @jelbourn /src/material-experimental/popover-edit/** @andrewseguin /src/material-experimental/selection/** @andrewseguin +/src/material-experimental/theming/** @mmalerba # CDK experimental package /src/cdk-experimental/* @andrewseguin diff --git a/.ng-dev/commit-message.mts b/.ng-dev/commit-message.mts index 1e82ea3e64ac..e1b54802345d 100644 --- a/.ng-dev/commit-message.mts +++ b/.ng-dev/commit-message.mts @@ -40,6 +40,10 @@ export const commitMessage: CommitMessageConfig = { 'cdk/tree', 'google-maps', 'material-experimental/column-resize', + 'material-experimental/theming', + 'material-experimental/menubar', + 'material-experimental/popover-edit', + 'material-experimental/selection', 'material/button', 'material/card', 'material/checkbox', @@ -53,12 +57,6 @@ export const commitMessage: CommitMessageConfig = { 'material/snack-bar', 'material/table', 'material/tabs', - 'material-experimental/menubar', - 'material-experimental/popover-edit', - 'material-experimental/selection', - 'material-moment-adapter', - 'material-date-fns-adapter', - 'material-luxon-adapter', 'material/autocomplete', 'material/legacy-autocomplete', 'material/badge', @@ -110,6 +108,9 @@ export const commitMessage: CommitMessageConfig = { 'material/legacy-tooltip', 'material/tooltip', 'material/tree', + 'material-moment-adapter', + 'material-date-fns-adapter', + 'material-luxon-adapter', 'youtube-player', ], }; diff --git a/src/dev-app/BUILD.bazel b/src/dev-app/BUILD.bazel index 2fdc1132ba58..d6412e1750b9 100644 --- a/src/dev-app/BUILD.bazel +++ b/src/dev-app/BUILD.bazel @@ -137,6 +137,16 @@ sass_binary( ], ) +sass_binary( + name = "theme_token_api", + src = "theme-token-api.scss", + deps = [ + "//src/material:sass_lib", + "//src/material-experimental:sass_lib", + "//src/material/core:theming_scss_lib", + ], +) + # Variables that are going to be inlined into the dev app index.html. filegroup( name = "variables", @@ -154,6 +164,7 @@ filegroup( "favicon.ico", "index.html", ":theme", + ":theme_token_api", ":variables", "//src/dev-app/icon:icon_demo_assets", "@npm//:node_modules/moment/min/moment-with-locales.min.js", diff --git a/src/dev-app/dev-app.ts b/src/dev-app/dev-app.ts index 7d9cc94d644d..70a4cb693ad8 100644 --- a/src/dev-app/dev-app.ts +++ b/src/dev-app/dev-app.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, ViewEncapsulation} from '@angular/core'; -import {RouterModule} from '@angular/router'; +import {Component, inject, ViewEncapsulation} from '@angular/core'; +import {ActivatedRoute, RouterModule} from '@angular/router'; import {DevAppLayout} from './dev-app/dev-app-layout'; /** Root component for the dev-app demos. */ @@ -18,4 +18,14 @@ import {DevAppLayout} from './dev-app/dev-app-layout'; standalone: true, imports: [DevAppLayout, RouterModule], }) -export class DevApp {} +export class DevApp { + route = inject(ActivatedRoute); + + constructor() { + this.route.queryParams.subscribe(q => { + (document.querySelector('#theme-styles') as any).href = q.hasOwnProperty('tokenapi') + ? 'theme-token-api.css' + : 'theme.css'; + }); + } +} diff --git a/src/dev-app/index.html b/src/dev-app/index.html index 67ea3ff04fcc..8bb6fe02053c 100644 --- a/src/dev-app/index.html +++ b/src/dev-app/index.html @@ -10,7 +10,7 @@ - + diff --git a/src/dev-app/theme-token-api.scss b/src/dev-app/theme-token-api.scss new file mode 100644 index 000000000000..284b1312f249 --- /dev/null +++ b/src/dev-app/theme-token-api.scss @@ -0,0 +1,68 @@ +@use '@angular/material' as mat; +@use '@angular/material-experimental' as matx; + +dev-app { + &::before { + content: 'Using experimental theming API'; + display: inline-block; + position: fixed; + z-index: 100; + bottom: 0; + left: 50%; + transform: translateX(-50%); + padding: 8px; + background: red; + color: white; + } +} + +.demo-unicorn-dark-theme { + background: black; + color: white; +} + +@include mat.core(); + +$light-theme: mat.define-light-theme(( + color: ( + primary: mat.define-palette(mat.$indigo-palette), + accent: mat.define-palette(mat.$pink-palette), + ), + typography: mat.define-typography-config(), + density: 0, +)); + +$dark-theme: mat.define-dark-theme(( + color: ( + primary: mat.define-palette(mat.$blue-grey-palette), + accent: mat.define-palette(mat.$amber-palette, A200, A100, A400), + warn: mat.define-palette(mat.$deep-orange-palette), + ), + typography: mat.define-typography-config(), + density: 0, +)); + +// Set up light theme. + +html { + @include matx.theme( + $tokens: mat.m2-tokens-from-theme($light-theme), + $components: ( + matx.card(), + matx.checkbox(), + )); +} + +// Set up dark theme. + +.demo-unicorn-dark-theme { + @include matx.theme( + $tokens: mat.m2-tokens-from-theme($dark-theme), + $components: ( + matx.checkbox(( + (mdc, checkbox): ( + selected-checkmark-color: red, + ) + )), + )); +} diff --git a/src/material-experimental/BUILD.bazel b/src/material-experimental/BUILD.bazel index 6dbd1275218b..187e01847642 100644 --- a/src/material-experimental/BUILD.bazel +++ b/src/material-experimental/BUILD.bazel @@ -19,7 +19,9 @@ ts_library( sass_library( name = "theming_scss_lib", - srcs = MATERIAL_EXPERIMENTAL_SCSS_LIBS, + srcs = MATERIAL_EXPERIMENTAL_SCSS_LIBS + [ + "//src/material-experimental/theming:theming_scss_lib", + ], ) sass_library( diff --git a/src/material-experimental/_index.scss b/src/material-experimental/_index.scss index b862e70da073..fd2a45e8fc61 100644 --- a/src/material-experimental/_index.scss +++ b/src/material-experimental/_index.scss @@ -4,4 +4,7 @@ @forward './popover-edit/popover-edit-theme' as popover-edit-* show popover-edit-color, popover-edit-typography, popover-edit-density, popover-edit-theme; +// Token-based theming API +@forward './theming/theming' show theme, card, checkbox; + // Additional public APIs for individual components diff --git a/src/material-experimental/theming/BUILD.bazel b/src/material-experimental/theming/BUILD.bazel new file mode 100644 index 000000000000..dd86907ef7c4 --- /dev/null +++ b/src/material-experimental/theming/BUILD.bazel @@ -0,0 +1,9 @@ +load("//tools:defaults.bzl", "sass_library") + +package(default_visibility = ["//visibility:public"]) + +sass_library( + name = "theming_scss_lib", + srcs = glob(["**/_*.scss"]), + deps = ["//src/material:sass_lib"], +) diff --git a/src/material-experimental/theming/_theming.scss b/src/material-experimental/theming/_theming.scss new file mode 100644 index 000000000000..9a6b181d8a8a --- /dev/null +++ b/src/material-experimental/theming/_theming.scss @@ -0,0 +1,134 @@ +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use '@angular/material' as mat; + +/// Whether to throw an error when a required dep is not configured. If false, the dep will be +/// automatically configured instead. +$_error-on-missing-dep: false; + +/// Applies the theme for the given component configuration. +/// @param {Map} $tokens A map containing the default values to use for tokens not explicitly +/// customized in the component config object. +/// @param {List} $component The component config object to emit theme tokens for. +/// @output CSS variables representing the theme tokens for this component. +@mixin _apply-theme($tokens, $component) { + $id: map.get($component, id); + $tokens: map.deep-merge($tokens, map.get($component, customizations)); + + // NOTE: for now we use a hardcoded if-chain, but in the future when first-class mixins are + // supported, the configuration data will contain a reference to its own theme mixin. + @if $id == 'mat.card' { + @include mat.private-apply-card-theme-from-tokens($tokens); + } + @else if $id == 'mat.checkbox' { + @include mat.private-apply-checkbox-theme-from-tokens($tokens); + } + @else { + @error 'Unrecognized component theme: #{id}'; + } +} + +/// Gets the transitive closure of the given list of component configuration dependencies. +/// @param {List} $components The list of component config objects to get the transitive deps for. +/// @param {Map} $configured [()] A map of already configured component IDs. Used for recursion, +/// should not be passed when calling. +/// @return {List} The transitive closure of configs for the given $components. +// TODO(mmalerba): Currently we use the deps to determine if additional tokens, other than the +// explicitly requested ones need to be emitted, but the deps do not affect the ordering in which +// the various configs are processed. Before moving out of experimental we should think more about +// the ordering behavior we want. For the most part the order shouldn't matter, unless we have 2 +// configs trying to set the same token. +@function _get-transitive-deps($components, $configured: ()) { + // Mark the given components as configured. + @each $component in $components { + $configured: map.set($configured, map.get($component, id), true); + } + $new-deps: (); + + // Check each of the given components for new deps. + @each $component in $components { + // Note: Deps are specified as getter functions that return a config object rather than a direct + // config object. This allows us to only call the getter if the dep has not yet been configured. + // This can be useful if we have 2 components that want to require each other to be configured. + // Example: form-field and input. If we used direct config objects in this case, it would cause + // infinite co-recursion. + @each $dep-getter in mat.private-coerce-to-list(map.get($component, deps)) { + $dep: meta.call($dep-getter); + $dep-id: map.get($dep, id); + @if not (map.has-key($configured, $dep-id)) { + @if $_error-on-missing-dep { + @error 'Missing theme: `#{map.get($component, id)}` depends on `#{$dep-id}`.' + + ' Please configure the theme for `#{$dep-id}` in your call to `mat.theme`'; + } + @else { + $configured: map.set($configured, $dep-id, true); + $new-deps: list.append($new-deps, $dep); + } + } + } + } + + // Append on the new deps to this list of component configurations and return. + @if list.length($new-deps) > 0 { + $components: list.join($components, _get-transitive-deps($new-deps, $configured)); + } + @return $components; +} + +/// Apply the themes for the given component configs with the given ste of fallback token values. +/// @param {Map} $tokens A map of fallback values to use for tokens that are not explicitly +/// customized by one of the component configs. +/// @param {List} $components The list of component configurations to emit tokens for. +/// @output CSS variables representing the theme tokens for the given component configs. +@mixin _theme($tokens, $components) { + // Call the theme mixin for each configured component. + @each $component in $components { + @include _apply-theme($tokens, $component); + } +} + +/// Takes the full list of tokens and a list of components to configure, and outputs all theme +/// tokens for the configured components. +/// @param {Map} $tokens A map of all tokens for the current design system. +/// @param {List} $components The list of component configurations to emit tokens for. +/// @output CSS variables representing the theme tokens for the given component configs. +// TODO(mmalerba): Consider an alternate API where `$tokens` is not a separate argument, +// but one of the configs in the `$components` list +@mixin theme($tokens, $components) { + @include _theme($tokens, _get-transitive-deps(mat.private-coerce-to-list($components))); +} + +/// Takes a list of components to configure, and outputs only the theme tokens that are explicitly +/// customized by the configurations. +/// @param {List} $components The list of component configurations to emit tokens for. +/// @output CSS variables representing the theme tokens for the given component configs. +// TODO(mmalerba): What should we call this? +// - update-theme +// - adjust-theme +// - edit-theme +// - override-theme +// - retheme +@mixin retheme($components) { + @include _theme((), $components); +} + +/// Configure the mat-card's theme. +/// @param {Map} $customizations [()] A map of custom token values to use when theming mat-card. +@function card($customizations: ()) { + @return ( + id: 'mat.card', + customizations: $customizations, + deps: (), + ); +} + +/// Configure the mat-checkbox's theme. +/// @param {Map} $customizations [()] A map of custom token values to use when theming mat-checkbox. +@function checkbox($customizations: ()) { + @return ( + id: 'mat.checkbox', + customizations: $customizations, + deps: (), + ); +} diff --git a/src/material/BUILD.bazel b/src/material/BUILD.bazel index 26c33fa6d079..f91607ee8367 100644 --- a/src/material/BUILD.bazel +++ b/src/material/BUILD.bazel @@ -24,6 +24,7 @@ sass_library( srcs = [ "_index.scss", "_theming.scss", + "_token-theming.scss", ], deps = [ "//src/material/core:core_scss_lib", diff --git a/src/material/_index.scss b/src/material/_index.scss index 2634a22cc791..53d2b2f165ff 100644 --- a/src/material/_index.scss +++ b/src/material/_index.scss @@ -14,6 +14,7 @@ legacy-typography-hierarchy; @forward './core/typography/typography-utils' show typography-level, font-size, line-height, font-weight, letter-spacing, font-family, font-shorthand; +@forward './core/tokens/m2' show m2-tokens-from-theme; // Private/Internal @forward './core/density/private/all-density' show all-component-densities; @@ -37,6 +38,8 @@ @forward './core/style/button-common' as private-button-common-*; // The form field density mixin needs to be exposed, because the paginator depends on it. @forward './form-field/form-field-theme' as private-form-field-* show private-form-field-density; +@forward './token-theming' as private-apply-*; +@forward './core/style/sass-utils' as private-*; // Structural @forward './core/core' show core; diff --git a/src/material/_token-theming.scss b/src/material/_token-theming.scss new file mode 100644 index 000000000000..0783e8e5bb06 --- /dev/null +++ b/src/material/_token-theming.scss @@ -0,0 +1,2 @@ +@forward './card/card-theme' as card-* show card-theme-from-tokens; +@forward './checkbox/checkbox-theme' as checkbox-* show checkbox-theme-from-tokens; diff --git a/src/material/button/_icon-button-theme.scss b/src/material/button/_icon-button-theme.scss index 8a6e1c41fc3b..9123fff0533f 100644 --- a/src/material/button/_icon-button-theme.scss +++ b/src/material/button/_icon-button-theme.scss @@ -1,7 +1,6 @@ @use 'sass:map'; @use 'sass:math'; @use '@material/density/functions' as mdc-density-functions; -@use '@material/icon-button/mixins' as mdc-icon-button; @use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme; @use '@material/theme/theme-color' as mdc-theme-color; @use '../core/tokens/m2/mdc/icon-button' as tokens-mdc-icon-button; diff --git a/src/material/card/_card-theme.import.scss b/src/material/card/_card-theme.import.scss index f9431af5f9e7..367a7bcad08b 100644 --- a/src/material/card/_card-theme.import.scss +++ b/src/material/card/_card-theme.import.scss @@ -1,3 +1,3 @@ -@forward 'card-theme' hide color, density, theme, typography; +@forward 'card-theme' hide color, density, theme, typography, theme-from-tokens; @forward 'card-theme' as mat-mdc-card-* hide $mat-mdc-card-mdc-card-action-icon-color, $mat-mdc-card-mdc-card-outline-color; diff --git a/src/material/card/_card-theme.scss b/src/material/card/_card-theme.scss index 4d54b95b74f3..2f3eb3cbb71a 100644 --- a/src/material/card/_card-theme.scss +++ b/src/material/card/_card-theme.scss @@ -1,3 +1,4 @@ +@use 'sass:map'; @use '../core/theming/theming'; @use '../core/typography/typography'; @use '../core/tokens/token-utils'; @@ -76,3 +77,13 @@ } } } + +@mixin theme-from-tokens($tokens) { + // Add values for card tokens. + .mat-mdc-card { + @include mdc-elevated-card-theme.theme(map.get($tokens, tokens-mdc-elevated-card.$prefix)); + @include mdc-outlined-card-theme.theme(map.get($tokens, tokens-mdc-outlined-card.$prefix)); + @include token-utils.create-token-values( + tokens-mat-card.$prefix, map.get($tokens, tokens-mat-card.$prefix)); + } +} diff --git a/src/material/checkbox/_checkbox-theme.import.scss b/src/material/checkbox/_checkbox-theme.import.scss index 4b578d213a5e..aea7a1d373fb 100644 --- a/src/material/checkbox/_checkbox-theme.import.scss +++ b/src/material/checkbox/_checkbox-theme.import.scss @@ -1,5 +1,5 @@ @forward 'checkbox-theme' hide color, density, private-checkbox-styles-with-color, theme, -typography; +typography, theme-from-tokens; @forward 'checkbox-theme' as mat-mdc-* hide $mat-mdc-mdc-checkbox-border-color, $mat-mdc-mdc-checkbox-disabled-color, mat-mdc-background-focus-density, mat-mdc-background-focus-indicator-checked-color, mat-mdc-background-focus-indicator-color, diff --git a/src/material/checkbox/_checkbox-theme.scss b/src/material/checkbox/_checkbox-theme.scss index ed076353f62c..b46761feeac5 100644 --- a/src/material/checkbox/_checkbox-theme.scss +++ b/src/material/checkbox/_checkbox-theme.scss @@ -88,3 +88,12 @@ } } } + +@mixin theme-from-tokens($tokens) { + // TODO(mmalerba): Some of the theme styles above are not represented in terms of tokens, + // so this mixin is currently incomplete. + + .mat-mdc-checkbox { + @include mdc-checkbox-theme.theme(map.get($tokens, tokens-mdc-checkbox.$prefix)); + } +} diff --git a/src/material/core/style/_sass-utils.scss b/src/material/core/style/_sass-utils.scss index 19ab313b2f42..af9fb2218cef 100644 --- a/src/material/core/style/_sass-utils.scss +++ b/src/material/core/style/_sass-utils.scss @@ -1,7 +1,37 @@ -// Include content under the current selector (&) or the document root if there is no current -// selector. +@use 'sass:map'; +@use 'sass:meta'; + +/// Include content under the current selector (&) or the document root if there is no current +/// selector. +/// @param {String} $root [html] The default root selector to use when there is no current selector. +/// @output The given content under the current selector, or root selector if there is no current +/// selector. +/// @content Content to output under the current selector, or root selector if there is no current +/// selector. @mixin current-selector-or-root($root: html) { @at-root #{& or $root} { @content; } } + +/// A version of the standard `map.deep-merge` function that takes a variable number of arguments. +/// Each argument is deep-merged into the final result from left to right. +/// @param {List} $maps The maps to combine with map.deep-merge +/// @return {Map} The combined result of successively calling map.deep-merge with each parameter. +@function deep-merge-all($maps...) { + $result: (); + @each $map in $maps { + $result: map.deep-merge($result, $map); + } + @return $result; +} + +/// Coerces the given value to a list, by converting any non-list value into a single-item list. +/// This should be used when dealing with user-passed lists of args to avoid confusing errors, +/// since Sass treats `($x)` as equivalent to `$x`. +/// @param {Any} $value The value to coerce to a list. +/// @return {List} The original $value if it was a list, otherwise a single-item list containing +/// $value. +@function coerce-to-list($value) { + @return if(meta.type-of($value) != 'list', ($value,), $value); +} diff --git a/src/material/core/tokens/_token-utils.scss b/src/material/core/tokens/_token-utils.scss index 03a266f7fbd2..254e0c97e09b 100644 --- a/src/material/core/tokens/_token-utils.scss +++ b/src/material/core/tokens/_token-utils.scss @@ -52,7 +52,7 @@ $_component-prefix: null; $_component-prefix: '' !global; @each $item in $rest { $_component-prefix: - if($_component-prefix == '', $item, '#{$_component-prefix}-#{$item}') !global; + if($_component-prefix == '', $item, '#{$_component-prefix}-#{$item}') !global; } @include mdc-custom-properties.configure($varname-prefix: $first) { @content; @@ -87,15 +87,6 @@ $_component-prefix: null; } } -// Merges together a list of maps into a single map. -@function merge-all($maps...) { - $result: (); - @each $map in $maps { - $result: map.merge($result, $map); - } - @return $result; -} - // MDC doesn't currently handle elevation tokens properly. As a temporary workaround we can combine // the elevation and shadow-color tokens into a full box-shadow and use it as the value for the // elevation token. diff --git a/src/material/core/tokens/m2/_index.scss b/src/material/core/tokens/m2/_index.scss new file mode 100644 index 000000000000..da279eb223b3 --- /dev/null +++ b/src/material/core/tokens/m2/_index.scss @@ -0,0 +1,84 @@ +@use 'sass:map'; +@use 'sass:meta'; +@use '../../style/sass-utils'; + +@use './mat/card' as tokens-mat-card; +@use './mat/radio' as tokens-mat-radio; +@use './mat/snack-bar' as tokens-mat-snack-bar; +@use './mat/tab-header' as tokens-mat-tab-header; +@use './mat/tab-header-with-background' as tokens-mat-tab-header-with-background; +@use './mdc/checkbox' as tokens-mdc-checkbox; +@use './mdc/circular-progress' as tokens-mdc-circular-progress; +@use './mdc/dialog' as tokens-mdc-dialog; +@use './mdc/elevated-card' as tokens-mdc-elevated-card; +@use './mdc/icon-button' as tokens-mdc-icon-button; +@use './mdc/linear-progress' as tokens-mdc-linear-progress; +@use './mdc/list' as tokens-mdc-list; +@use './mdc/outlined-card' as tokens-mdc-outlined-card; +@use './mdc/radio' as tokens-mdc-radio; +@use './mdc/snack-bar' as tokens-mdc-snack-bar; +@use './mdc/tab' as tokens-mdc-tab; +@use './mdc/tab-indicator' as tokens-mdc-tab-indicator; + +/// Gets the tokens for the given theme, m2 tokens module, and theming system. +/// @param {Map} $theme The Angular Material theme object to generate token values from. +/// @param {String} $module The Sass module containing the token getter functions. +/// @param {String} $system The theming system to get tokens for. Valid values are: unthemable, +/// color, typography, density. +/// @return {Map} The token map by calling the token getter for the given system in the given module +/// with the given Angular Material theme. Token names are not fully-qualified. +@function _get-tokens-for-module-and-system($theme, $module, $system) { + @if $system == unthemable { + @return meta.call( + meta.get-function(get-#{$system}-tokens, $module: $module)); + } + @if not map.get($theme, $system) { + @return (); + } + @return meta.call( + meta.get-function(get-#{$system}-tokens, $module: $module), map.get($theme, $system)); +} + +/// Gets the fully qualified tokens map for the given theme and m2 tokens module. +/// @param {Map} $theme The Angular Material theme object to generate token values from. +/// @param {String} $module The Sass module containing the token getter functions. +/// @return {Map} The token map by calling the token getters in the given module with the given +/// Angular Material theme. Token names are fully-qualified. +@function _get-tokens-for-module($theme, $module) { + $tokens: sass-utils.deep-merge-all( + _get-tokens-for-module-and-system($theme, $module, unthemable), + _get-tokens-for-module-and-system($theme, $module, color), + _get-tokens-for-module-and-system($theme, $module, typography), + _get-tokens-for-module-and-system($theme, $module, density)); + @return map.set((), map.get(meta.module-variables($module), prefix), $tokens); +} + +/// Gets the full set of M2 tokens for the given theme object. +/// @param {Map} $theme The Angular Material theme object to generate token values from. +/// @return {Map} The token map for the given Angular Material theme. Returned format: +/// ( +/// (fully, qualified, namespace): ( +/// token: value +/// ) +/// ) +@function m2-tokens-from-theme($theme) { + @return sass-utils.deep-merge-all( + _get-tokens-for-module($theme, tokens-mat-card), + _get-tokens-for-module($theme, tokens-mat-radio), + _get-tokens-for-module($theme, tokens-mat-snack-bar), + _get-tokens-for-module($theme, tokens-mat-tab-header), + _get-tokens-for-module($theme, tokens-mat-tab-header-with-background), + _get-tokens-for-module($theme, tokens-mdc-checkbox), + _get-tokens-for-module($theme, tokens-mdc-circular-progress), + _get-tokens-for-module($theme, tokens-mdc-dialog), + _get-tokens-for-module($theme, tokens-mdc-elevated-card), + _get-tokens-for-module($theme, tokens-mdc-icon-button), + _get-tokens-for-module($theme, tokens-mdc-linear-progress), + _get-tokens-for-module($theme, tokens-mdc-list), + _get-tokens-for-module($theme, tokens-mdc-outlined-card), + _get-tokens-for-module($theme, tokens-mdc-radio), + _get-tokens-for-module($theme, tokens-mdc-snack-bar), + _get-tokens-for-module($theme, tokens-mdc-tab), + _get-tokens-for-module($theme, tokens-mdc-tab-indicator), + ); +} diff --git a/src/material/core/tokens/m2/mat/_card.scss b/src/material/core/tokens/m2/mat/_card.scss index 7f19a99189a5..5b27c9f1d7c7 100644 --- a/src/material/core/tokens/m2/mat/_card.scss +++ b/src/material/core/tokens/m2/mat/_card.scss @@ -2,6 +2,7 @@ @use '../../token-utils'; @use '../../../theming/theming'; @use '../../../typography/typography-utils'; +@use '../../../style/sass-utils'; // The prefix used to generate the fully qualified name for tokens in this file. $prefix: (mat, card); @@ -18,7 +19,7 @@ $prefix: (mat, card); @return ( // Text color of the card's subtitle. - subtitle-text-color: theming.get-color-from-palette($foreground, secondary-text), + subtitle-text-color: theming.get-color-from-palette($foreground, secondary-text), ); } @@ -26,27 +27,27 @@ $prefix: (mat, card); @function get-typography-tokens($config) { @return ( // Font family of the card's title. - title-text-font: typography-utils.font-family($config, headline-6) + title-text-font: typography-utils.font-family($config, headline-6) or typography-utils.font-family($config), // Line height of the card's title. - title-text-line-height: typography-utils.line-height($config, headline-6), + title-text-line-height: typography-utils.line-height($config, headline-6), // Font size of the card's title. - title-text-size: typography-utils.font-size($config, headline-6), + title-text-size: typography-utils.font-size($config, headline-6), // Letter spacing of the card's title. - title-text-tracking: typography-utils.letter-spacing($config, headline-6), + title-text-tracking: typography-utils.letter-spacing($config, headline-6), // Font weight of the card's title. - title-text-weight: typography-utils.font-weight($config, headline-6), + title-text-weight: typography-utils.font-weight($config, headline-6), // Font family of the card's subtitle. - subtitle-text-font: typography-utils.font-family($config, subtitle-2) + subtitle-text-font: typography-utils.font-family($config, subtitle-2) or typography-utils.font-family($config), // Line height of the card's subtitle. - subtitle-text-line-height: typography-utils.line-height($config, subtitle-2), + subtitle-text-line-height: typography-utils.line-height($config, subtitle-2), // Font size of the card's subtitle. - subtitle-text-size: typography-utils.font-size($config, subtitle-2), + subtitle-text-size: typography-utils.font-size($config, subtitle-2), // Letter spacing of the card's subtitle. - subtitle-text-tracking: typography-utils.letter-spacing($config, subtitle-2), + subtitle-text-tracking: typography-utils.letter-spacing($config, subtitle-2), // Font weight of the card's subtitle. - subtitle-text-weight: typography-utils.font-weight($config, subtitle-2), + subtitle-text-weight: typography-utils.font-weight($config, subtitle-2), ); } @@ -58,10 +59,10 @@ $prefix: (mat, card); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mat/_radio.scss b/src/material/core/tokens/m2/mat/_radio.scss index 7555c1c8b00c..eca8bd448037 100644 --- a/src/material/core/tokens/m2/mat/_radio.scss +++ b/src/material/core/tokens/m2/mat/_radio.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../token-utils'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; // The prefix used to generate the fully qualified name for tokens in this file. $prefix: (mat, radio); @@ -37,10 +38,10 @@ $prefix: (mat, radio); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mat/_snack-bar.scss b/src/material/core/tokens/m2/mat/_snack-bar.scss index 10156de32f08..70f704467494 100644 --- a/src/material/core/tokens/m2/mat/_snack-bar.scss +++ b/src/material/core/tokens/m2/mat/_snack-bar.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../token-utils'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; // The prefix used to generate the fully qualified name for tokens in this file. $prefix: (mat, snack-bar); @@ -34,10 +35,10 @@ $prefix: (mat, snack-bar); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mat/_tab-header-with-background.scss b/src/material/core/tokens/m2/mat/_tab-header-with-background.scss index 96db92e5cb76..d332fa7ce7c5 100644 --- a/src/material/core/tokens/m2/mat/_tab-header-with-background.scss +++ b/src/material/core/tokens/m2/mat/_tab-header-with-background.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../token-utils'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; // The prefix used to generate the fully qualified name for tokens in this file. $prefix: (mat, tab-header-with-background); @@ -34,10 +35,10 @@ $prefix: (mat, tab-header-with-background); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mat/_tab-header.scss b/src/material/core/tokens/m2/mat/_tab-header.scss index 4a54c6880cc1..d81f699e7043 100644 --- a/src/material/core/tokens/m2/mat/_tab-header.scss +++ b/src/material/core/tokens/m2/mat/_tab-header.scss @@ -2,6 +2,7 @@ @use '../../token-utils'; @use '../../../theming/theming'; @use '../../../typography/typography-utils'; +@use '../../../style/sass-utils'; // The prefix used to generate the fully qualified name for tokens in this file. $prefix: (mat, tab-header); @@ -62,7 +63,7 @@ $prefix: (mat, tab-header); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( + @return sass-utils.deep-merge-all( get-unthemable-tokens(), get-color-tokens(token-utils.$placeholder-color-config), get-typography-tokens(token-utils.$placeholder-typography-config), diff --git a/src/material/core/tokens/m2/mdc/_checkbox.scss b/src/material/core/tokens/m2/mdc/_checkbox.scss index 6fcde37aaaee..c0e0f9da633a 100644 --- a/src/material/core/tokens/m2/mdc/_checkbox.scss +++ b/src/material/core/tokens/m2/mdc/_checkbox.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../../theming/palette'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; @use '@material/theme/theme-color' as mdc-theme-color; @@ -26,25 +27,25 @@ $prefix: (mdc, checkbox); @function get-unthemable-tokens() { @return ( // The color of the checkmark when the checkbox is selected and disabled. - disabled-selected-checkmark-color: #fff, + disabled-selected-checkmark-color: #fff, // The opacity of the ripple when the checkbox is selected and focused. - selected-focus-state-layer-opacity: 0.16, + selected-focus-state-layer-opacity: 0.16, // The opacity of the ripple when the checkbox is selected and hovered. - selected-hover-state-layer-opacity: 0.04, + selected-hover-state-layer-opacity: 0.04, // The opacity of the ripple when the checkbox is selected and pressed. - selected-pressed-state-layer-opacity: 0.16, + selected-pressed-state-layer-opacity: 0.16, // The opacity of the ripple when the checkbox is unselected and focused. - unselected-focus-state-layer-opacity: 0.16, + unselected-focus-state-layer-opacity: 0.16, // The opacity of the ripple when the checkbox is unselected and hovered. - unselected-hover-state-layer-opacity: 0.04, + unselected-hover-state-layer-opacity: 0.04, // The opacity of the ripple when the checkbox is unselected and pressed. - unselected-pressed-state-layer-opacity: 0.16, + unselected-pressed-state-layer-opacity: 0.16, // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= // MDC currently doesn't output a slot for these tokens. - disabled-selected-icon-opacity: null, - disabled-unselected-icon-opacity: null, + disabled-selected-icon-opacity: null, + disabled-unselected-icon-opacity: null, ); } @@ -59,43 +60,43 @@ $prefix: (mdc, checkbox); $selected-color: theming.get-color-from-palette($accent); $border-color: theming.get-color-from-palette($foreground, base, 0.54); $active-border-color: - theming.get-color-from-palette(palette.$gray-palette, if($is-dark, 200, 900)); + theming.get-color-from-palette(palette.$gray-palette, if($is-dark, 200, 900)); @return ( // The color of the checkbox fill when the checkbox is selected and disabled. - disabled-selected-icon-color: $disabled-color, + disabled-selected-icon-color: $disabled-color, // The color of the checkbox border when the checkbox is unselected and disabled. - disabled-unselected-icon-color: $disabled-color, + disabled-unselected-icon-color: $disabled-color, // The color of the checkmark when the checkbox is selected. - selected-checkmark-color: _contrast-tone($selected-color, $is-dark), + selected-checkmark-color: _contrast-tone($selected-color, $is-dark), // The color of the checkbox fill when the checkbox is selected and focused. - selected-focus-icon-color: $selected-color, + selected-focus-icon-color: $selected-color, // The color of the checkbox fill when the checkbox is selected and hovered. - selected-hover-icon-color: $selected-color, + selected-hover-icon-color: $selected-color, // The color of the checkbox fill when the checkbox is selected. - selected-icon-color: $selected-color, + selected-icon-color: $selected-color, // The color of the checkbox fill when the checkbox is selected an pressed. - selected-pressed-icon-color: $selected-color, + selected-pressed-icon-color: $selected-color, // The color of the checkbox border when the checkbox is unselected and focused. - unselected-focus-icon-color: $active-border-color, + unselected-focus-icon-color: $active-border-color, // The color of the checkbox border when the checkbox is unselected and hovered. - unselected-hover-icon-color: $active-border-color, + unselected-hover-icon-color: $active-border-color, // The color of the checkbox border when the checkbox is unselected. - unselected-icon-color: $border-color, + unselected-icon-color: $border-color, // The color of the checkbox border when the checkbox is unselected and pressed. - unselected-pressed-icon-color: $border-color, + unselected-pressed-icon-color: $border-color, // The color of the ripple when the checkbox is selected and focused. - selected-focus-state-layer-color: $accent-default, + selected-focus-state-layer-color: $accent-default, // The color of the ripple when the checkbox is selected and hovered. - selected-hover-state-layer-color: $accent-default, + selected-hover-state-layer-color: $accent-default, // The color of the ripple when the checkbox is selected and pressed. - selected-pressed-state-layer-color: $accent-default, + selected-pressed-state-layer-color: $accent-default, // The color of the ripple when the checkbox is unselected and focused. - unselected-focus-state-layer-color: $foreground-base, + unselected-focus-state-layer-color: $foreground-base, // The color of the ripple when the checkbox is unselected and hovered. - unselected-hover-state-layer-color: $foreground-base, + unselected-hover-state-layer-color: $foreground-base, // The color of the ripple when the checkbox is unselected and pressed. - unselected-pressed-state-layer-color: $foreground-base, + unselected-pressed-state-layer-color: $foreground-base, ); } @@ -110,22 +111,22 @@ $prefix: (mdc, checkbox); @return ( // The diameter of the checkbox's ripple. - state-layer-size: map.get(( - 0: 40px, - -1: 36px, - -2: 32px, - -3: 28px, - ), $scale) + state-layer-size: map.get(( + 0: 40px, + -1: 36px, + -2: 32px, + -3: 28px, + ), $scale) ); } // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_chip.scss b/src/material/core/tokens/m2/mdc/_chip.scss index e4d006d86469..db18f9fa7acd 100644 --- a/src/material/core/tokens/m2/mdc/_chip.scss +++ b/src/material/core/tokens/m2/mdc/_chip.scss @@ -1,7 +1,7 @@ -@use 'sass:color'; @use 'sass:map'; @use '../../token-utils'; @use '../../../mdc-helpers/mdc-helpers'; +@use '../../../style/sass-utils'; @use '../../../theming/theming'; @use '../../../typography/typography-utils'; @@ -304,7 +304,7 @@ $prefix: (mdc, chip); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( + @return sass-utils.deep-merge-all( get-unthemable-tokens(), get-color-tokens(token-utils.$placeholder-color-config), get-typography-tokens(token-utils.$placeholder-typography-config), diff --git a/src/material/core/tokens/m2/mdc/_circular-progress.scss b/src/material/core/tokens/m2/mdc/_circular-progress.scss index 108542b4c63e..5c8445bfeead 100644 --- a/src/material/core/tokens/m2/mdc/_circular-progress.scss +++ b/src/material/core/tokens/m2/mdc/_circular-progress.scss @@ -1,5 +1,6 @@ @use 'sass:map'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -52,14 +53,10 @@ $prefix: (mdc, circular-progress); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return map.merge( - get-unthemable-tokens(), - map.merge( + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), get-color-tokens(token-utils.$placeholder-color-config), - map.merge( - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) - ) - ) + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_dialog.scss b/src/material/core/tokens/m2/mdc/_dialog.scss index 7dff874feef2..101e344bc8d8 100644 --- a/src/material/core/tokens/m2/mdc/_dialog.scss +++ b/src/material/core/tokens/m2/mdc/_dialog.scss @@ -2,6 +2,7 @@ @use '../../../theming/theming'; @use '../../../typography/typography-utils'; @use '../../../mdc-helpers/mdc-helpers'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -21,7 +22,6 @@ $prefix: (mdc, dialog); container-shadow-color: #000, // Border radius of the container. container-shape: 4px, - // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= @@ -87,7 +87,6 @@ $prefix: (mdc, dialog); subhead-size: typography-utils.font-size($config, headline-6), subhead-weight: typography-utils.font-weight($config, headline-6), subhead-tracking: typography-utils.letter-spacing($config, headline-6), - // Typography of the dialog body text. supporting-text-font: typography-utils.font-family($config, body-1) or typography-utils.font-family($config), @@ -106,10 +105,10 @@ $prefix: (mdc, dialog); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_elevated-card.scss b/src/material/core/tokens/m2/mdc/_elevated-card.scss index ad72d34894cc..cb70896635a0 100644 --- a/src/material/core/tokens/m2/mdc/_elevated-card.scss +++ b/src/material/core/tokens/m2/mdc/_elevated-card.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../../style/elevation'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -74,7 +75,7 @@ $prefix: (mdc, elevated-card); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( + @return sass-utils.deep-merge-all( get-unthemable-tokens(), get-color-tokens(token-utils.$placeholder-color-config), get-typography-tokens(token-utils.$placeholder-typography-config), diff --git a/src/material/core/tokens/m2/mdc/_icon-button.scss b/src/material/core/tokens/m2/mdc/_icon-button.scss index d4ff0261e152..3d7c33de437c 100644 --- a/src/material/core/tokens/m2/mdc/_icon-button.scss +++ b/src/material/core/tokens/m2/mdc/_icon-button.scss @@ -1,4 +1,4 @@ -@use 'sass:map'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -18,18 +18,14 @@ $prefix: (mdc, icon-button); // Determines the size of the icon. Name is inaccurate - applies to the whole component, // not just the state layer. state-layer-size: 48px, - // MDC's icon size applied to svg and img elements inside the component icon-size: 24px, - // Only applies to :disabled icons, but Angular Components uses [disabled] since :disabled // wouldn't work on tags. disabled-icon-color: black, - // Angular version applies an opacity 1 with a color change, and this only applies with // :disabled anyways. disabled-icon-opacity: 0.38, - // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= @@ -66,14 +62,10 @@ $prefix: (mdc, icon-button); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return map.merge( + @return sass-utils.deep-merge-all( get-unthemable-tokens(), - map.merge( - get-color-tokens(token-utils.$placeholder-color-config), - map.merge( - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) - ) - ) + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_linear-progress.scss b/src/material/core/tokens/m2/mdc/_linear-progress.scss index 2d9309da4f3a..f8db382857a0 100644 --- a/src/material/core/tokens/m2/mdc/_linear-progress.scss +++ b/src/material/core/tokens/m2/mdc/_linear-progress.scss @@ -1,4 +1,5 @@ @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; @use 'sass:color'; @use 'sass:map'; @@ -32,9 +33,9 @@ $prefix: (mdc, linear-progress); // The color of the progress bar's active section. active-indicator-color: $primary, track-color: if( - meta.type-of($primary) == color, - color.adjust($primary, $alpha: -0.75), - $primary + meta.type-of($primary) == color, + color.adjust($primary, $alpha: -0.75), + $primary ) ); } @@ -52,14 +53,10 @@ $prefix: (mdc, linear-progress); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return map.merge( - get-unthemable-tokens(), - map.merge( + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), get-color-tokens(token-utils.$placeholder-color-config), - map.merge( - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) - ) - ) + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_list.scss b/src/material/core/tokens/m2/mdc/_list.scss index 79b2cccbad1c..f848f59d8c32 100644 --- a/src/material/core/tokens/m2/mdc/_list.scss +++ b/src/material/core/tokens/m2/mdc/_list.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../../theming/theming'; @use '../../../typography/typography-utils'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -15,69 +16,69 @@ $prefix: (mdc, list); @function get-unthemable-tokens() { @return ( // Border radius of list items. - list-item-container-shape: 0, + list-item-container-shape: 0, // Border radius of the list item's leading avatar. - list-item-leading-avatar-shape: 50%, + list-item-leading-avatar-shape: 50%, // Background color of list items. - list-item-container-color: transparent, + list-item-container-color: transparent, // Background color of list items when selected. - list-item-selected-container-color: transparent, + list-item-selected-container-color: transparent, // Background color of the list item's leading avatar. - list-item-leading-avatar-color: transparent, + list-item-leading-avatar-color: transparent, // Height & width of the list item's leading icon. - list-item-leading-icon-size: 24px, + list-item-leading-icon-size: 24px, // Height & width of the list item's leading avatar. - list-item-leading-avatar-size: 40px, + list-item-leading-avatar-size: 40px, // Height & width of the list item's trailing icon. - list-item-trailing-icon-size: 24px, + list-item-trailing-icon-size: 24px, // Color of the list item's overlay when the item is disabled. - list-item-disabled-state-layer-color: transparent, + list-item-disabled-state-layer-color: transparent, // Opacity of the list item's overlay when the item is disabled. - list-item-disabled-state-layer-opacity: 0, + list-item-disabled-state-layer-opacity: 0, // Opacity of the list item's primary & supporting text when the item is disabled. - list-item-disabled-label-text-opacity: 0.38, + list-item-disabled-label-text-opacity: 0.38, // Opacity of the list item's leading icon when the item is disabled. - list-item-disabled-leading-icon-opacity: 0.38, + list-item-disabled-leading-icon-opacity: 0.38, // Opacity of the list item's trailing icon when the item is disabled. - list-item-disabled-trailing-icon-opacity: 0.38, + list-item-disabled-trailing-icon-opacity: 0.38, // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= // Overline not implemented in Angular Material. // TODO(mmalerba): Consider implementing in the future. - list-item-overline-color: null, - list-item-overline-font: null, - list-item-overline-line-height: null, - list-item-overline-size: null, - list-item-overline-tracking: null, - list-item-overline-weight: null, + list-item-overline-color: null, + list-item-overline-font: null, + list-item-overline-line-height: null, + list-item-overline-size: null, + list-item-overline-tracking: null, + list-item-overline-weight: null, // Leading video not implemented in Angular Material. // TODO(mmalerba): Consider implementing in the future. - list-item-leading-video-shape: null, - list-item-leading-video-width: null, - list-item-leading-video-height: null, + list-item-leading-video-shape: null, + list-item-leading-video-width: null, + list-item-leading-video-height: null, // Leading image not implemented in Angular Material. // TODO(mmalerba): Consider implementing in the future. - list-item-leading-image-width: null, - list-item-leading-image-height: null, - list-item-leading-image-shape: null, + list-item-leading-image-width: null, + list-item-leading-image-height: null, + list-item-leading-image-shape: null, // List divider is not implemented in Angular Material. // TODO(mmalerba): Maybe mat-divider should be based on these tokens? - divider-color: null, - divider-height: null, + divider-color: null, + divider-height: null, // Redundant since it is always overridden by one- two- or three- line tokens, omitted to save // bytes. - list-item-container-height: null, + list-item-container-height: null, // MDC does not seem to emit any CSS variables for these tokens, may be use in the future. // TODO(mmalerba): Discuss with MDC if these should be added. - list-item-container-elevation: null, - list-item-leading-avatar-label-color: null, - list-item-leading-avatar-label-font: null, - list-item-leading-avatar-label-line-height: null, - list-item-leading-avatar-label-size: null, - list-item-leading-avatar-label-tracking: null, - list-item-leading-avatar-label-weight: null, - list-item-unselected-trailing-icon-color: null, + list-item-container-elevation: null, + list-item-leading-avatar-label-color: null, + list-item-leading-avatar-label-font: null, + list-item-leading-avatar-label-line-height: null, + list-item-leading-avatar-label-size: null, + list-item-leading-avatar-label-tracking: null, + list-item-leading-avatar-label-weight: null, + list-item-unselected-trailing-icon-color: null, ); } @@ -87,44 +88,44 @@ $prefix: (mdc, list); $is-dark: map.get($config, is-dark); $foreground-base: theming.get-color-from-palette($foreground, base); $text-icon-on-background: - theming.get-color-from-palette($foreground, base, if($is-dark, 0.5, 0.38)); + theming.get-color-from-palette($foreground, base, if($is-dark, 0.5, 0.38)); @return ( // Text color of the list item primary text. - list-item-label-text-color: theming.get-color-from-palette($foreground, text), + list-item-label-text-color: theming.get-color-from-palette($foreground, text), // Text color of the list item supporting text. - list-item-supporting-text-color: theming.get-color-from-palette($foreground, secondary-text), + list-item-supporting-text-color: theming.get-color-from-palette($foreground, secondary-text), // Color of the list item's leading icon. - list-item-leading-icon-color: $text-icon-on-background, + list-item-leading-icon-color: $text-icon-on-background, // Text color of the list item's trailing text. - list-item-trailing-supporting-text-color: theming.get-color-from-palette( - $foreground, hint-text), + list-item-trailing-supporting-text-color: theming.get-color-from-palette( + $foreground, hint-text), // Color of the list item's trailing icon. - list-item-trailing-icon-color: $text-icon-on-background, + list-item-trailing-icon-color: $text-icon-on-background, // Color of the list item's trailing icon when the item is selected. - list-item-selected-trailing-icon-color: $text-icon-on-background, + list-item-selected-trailing-icon-color: $text-icon-on-background, // Text color of the list item's primary text when the item is disabled. - list-item-disabled-label-text-color: theming.get-color-from-palette($foreground, base), + list-item-disabled-label-text-color: theming.get-color-from-palette($foreground, base), // Color of the list item's leading icon when the item is disabled. - list-item-disabled-leading-icon-color: theming.get-color-from-palette($foreground, base), + list-item-disabled-leading-icon-color: theming.get-color-from-palette($foreground, base), // Color of the list item's trailing icon when the item is disabled. - list-item-disabled-trailing-icon-color: theming.get-color-from-palette($foreground, base), + list-item-disabled-trailing-icon-color: theming.get-color-from-palette($foreground, base), // Color of the list item's primary text when the item is being hovered. - list-item-hover-label-text-color: theming.get-color-from-palette($foreground, text), + list-item-hover-label-text-color: theming.get-color-from-palette($foreground, text), // Color of the list item's leading icon when the item is being hovered. - list-item-hover-leading-icon-color: $text-icon-on-background, + list-item-hover-leading-icon-color: $text-icon-on-background, // Color of the list item's trailing icon when the item is being hovered. - list-item-hover-trailing-icon-color: $text-icon-on-background, + list-item-hover-trailing-icon-color: $text-icon-on-background, // Color of the list item's primary text when the item is focused. - list-item-focus-label-text-color: theming.get-color-from-palette($foreground, text), + list-item-focus-label-text-color: theming.get-color-from-palette($foreground, text), // Color of the list item's overlay when the item is hovered. - list-item-hover-state-layer-color: theming.get-color-from-palette($foreground, base), + list-item-hover-state-layer-color: theming.get-color-from-palette($foreground, base), // Opacity of the list item's overlay when the item is hovered. - list-item-hover-state-layer-opacity: if($is-dark, 0.08, 0.04), + list-item-hover-state-layer-opacity: if($is-dark, 0.08, 0.04), // Color of the list item's overlay when the item is focused. - list-item-focus-state-layer-color: theming.get-color-from-palette($foreground, base), + list-item-focus-state-layer-color: theming.get-color-from-palette($foreground, base), // Opacity of the list item's overlay when the item is focused. - list-item-focus-state-layer-opacity: if($is-dark, 0.24, 0.12), + list-item-focus-state-layer-opacity: if($is-dark, 0.24, 0.12), ); } @@ -132,40 +133,40 @@ $prefix: (mdc, list); @function get-typography-tokens($config) { @return ( // Font family of the list item primary text. - list-item-label-text-font: typography-utils.font-family($config, body-1) + list-item-label-text-font: typography-utils.font-family($config, body-1) or typography-utils.font-family($config), // Line height of the list item primary text. - list-item-label-text-line-height: typography-utils.line-height($config, body-1), + list-item-label-text-line-height: typography-utils.line-height($config, body-1), // Font size of the list item primary text. - list-item-label-text-size: typography-utils.font-size($config, body-1), + list-item-label-text-size: typography-utils.font-size($config, body-1), // Letter spacing of the list item primary text. - list-item-label-text-tracking: typography-utils.letter-spacing($config, body-1), + list-item-label-text-tracking: typography-utils.letter-spacing($config, body-1), // Font weight of the list item primary text. - list-item-label-text-weight: typography-utils.font-weight($config, body-1), + list-item-label-text-weight: typography-utils.font-weight($config, body-1), // Font family of the list item supporting text. - list-item-supporting-text-font: typography-utils.font-family($config, body-2) + list-item-supporting-text-font: typography-utils.font-family($config, body-2) or typography-utils.font-family($config), // Line height of the list item supporting text. - list-item-supporting-text-line-height: typography-utils.line-height($config, body-2), + list-item-supporting-text-line-height: typography-utils.line-height($config, body-2), // Font size of the list item supporting text. - list-item-supporting-text-size: typography-utils.font-size($config, body-2), + list-item-supporting-text-size: typography-utils.font-size($config, body-2), // Letter spacing of the list item supporting text. - list-item-supporting-text-tracking: typography-utils.letter-spacing($config, body-2), + list-item-supporting-text-tracking: typography-utils.letter-spacing($config, body-2), // Font weight of the list item supporting text. - list-item-supporting-text-weight: typography-utils.font-weight($config, body-2), + list-item-supporting-text-weight: typography-utils.font-weight($config, body-2), // Font family of the list item's trailing text. - list-item-trailing-supporting-text-font: typography-utils.font-family($config, caption) + list-item-trailing-supporting-text-font: typography-utils.font-family($config, caption) or typography-utils.font-family($config), // Line height of the list item's trailing text. - list-item-trailing-supporting-text-line-height: typography-utils.line-height( - $config, caption), + list-item-trailing-supporting-text-line-height: typography-utils.line-height( + $config, caption), // Font size of the list item's trailing text. - list-item-trailing-supporting-text-size: typography-utils.font-size($config, caption), + list-item-trailing-supporting-text-size: typography-utils.font-size($config, caption), // Letter spacing color of the list item's trailing text. - list-item-trailing-supporting-text-tracking: typography-utils.letter-spacing( - $config, caption), + list-item-trailing-supporting-text-tracking: typography-utils.letter-spacing( + $config, caption), // Font weight of the list item's trailing text. - list-item-trailing-supporting-text-weight: typography-utils.font-weight($config, caption), + list-item-trailing-supporting-text-weight: typography-utils.font-weight($config, caption), ); } @@ -175,42 +176,42 @@ $prefix: (mdc, list); @return ( // Height of one line list items. - list-item-one-line-container-height: map.get(( - 0: 48px, - -1: 44px, - -2: 40px, - -3: 36px, - -4: 32px, - -5: 24px, - ), $scale), + list-item-one-line-container-height: map.get(( + 0: 48px, + -1: 44px, + -2: 40px, + -3: 36px, + -4: 32px, + -5: 24px, + ), $scale), // Height of two line list items. - list-item-two-line-container-height: map.get(( - 0: 64px, - -1: 60px, - -2: 56px, - -3: 52px, - -4: 48px, - -5: 48px, - ), $scale), + list-item-two-line-container-height: map.get(( + 0: 64px, + -1: 60px, + -2: 56px, + -3: 52px, + -4: 48px, + -5: 48px, + ), $scale), // Height of three line list items. - list-item-three-line-container-height: map.get(( - 0: 88px, - -1: 84px, - -2: 80px, - -3: 76px, - -4: 72px, - -5: 56px, - ), $scale), + list-item-three-line-container-height: map.get(( + 0: 88px, + -1: 84px, + -2: 80px, + -3: 76px, + -4: 72px, + -5: 56px, + ), $scale), ); } // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_outlined-card.scss b/src/material/core/tokens/m2/mdc/_outlined-card.scss index 6efdb969634f..595eece7df7f 100644 --- a/src/material/core/tokens/m2/mdc/_outlined-card.scss +++ b/src/material/core/tokens/m2/mdc/_outlined-card.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../../style/elevation'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -82,7 +83,7 @@ $prefix: (mdc, outlined-card); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( + @return sass-utils.deep-merge-all( get-unthemable-tokens(), get-color-tokens(token-utils.$placeholder-color-config), get-typography-tokens(token-utils.$placeholder-typography-config), diff --git a/src/material/core/tokens/m2/mdc/_plain-tooltip.scss b/src/material/core/tokens/m2/mdc/_plain-tooltip.scss index 1853c15e8f45..3636238f6b82 100644 --- a/src/material/core/tokens/m2/mdc/_plain-tooltip.scss +++ b/src/material/core/tokens/m2/mdc/_plain-tooltip.scss @@ -2,6 +2,7 @@ @use '../../../theming/theming'; @use '../../../typography/typography-utils'; @use '../../../mdc-helpers/mdc-helpers'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -67,14 +68,10 @@ $prefix: (mdc, plain-tooltip); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return map.merge( - get-unthemable-tokens(), - map.merge( - get-color-tokens(token-utils.$placeholder-color-config), - map.merge( - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) - ) - ) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_radio.scss b/src/material/core/tokens/m2/mdc/_radio.scss index 1b9caace43f8..29879d95c986 100644 --- a/src/material/core/tokens/m2/mdc/_radio.scss +++ b/src/material/core/tokens/m2/mdc/_radio.scss @@ -1,6 +1,7 @@ @use 'sass:map'; @use '../../../theming/palette'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -16,12 +17,10 @@ $prefix: (mdc, radio); @return ( disabled-selected-icon-opacity: 0.38, disabled-unselected-icon-opacity: 0.38, - // This is specified both here and in the density tokens, because it // determines the size of the radio button itself and there are internal // tests who don't configure the theme correctly. state-layer-size: 40px, - // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= @@ -85,10 +84,10 @@ $prefix: (mdc, radio); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_snack-bar.scss b/src/material/core/tokens/m2/mdc/_snack-bar.scss index 6853e5ddfe28..cd191a22fa2e 100644 --- a/src/material/core/tokens/m2/mdc/_snack-bar.scss +++ b/src/material/core/tokens/m2/mdc/_snack-bar.scss @@ -5,6 +5,7 @@ @use '../../token-utils'; @use '../../../typography/typography-utils'; @use '../../../mdc-helpers/mdc-helpers'; +@use '../../../style/sass-utils'; // The prefix used to generate the fully qualified name for tokens in this file. $prefix: (mdc, snackbar); @@ -19,18 +20,15 @@ $prefix: (mdc, snackbar); @return ( // Sets the snack bar border radius. container-shape: 4px, - // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= // Removed to match the previous appearance. supporting-text-tracking: null, - // Excluded because they target the wrong DOM node. See the // comments on the elevation of `.mat-mdc-snack-bar-container`. container-elevation: null, container-shadow-color: null, - action-focus-label-text-color: null, action-focus-state-layer-color: null, action-focus-state-layer-opacity: null, @@ -99,10 +97,10 @@ $prefix: (mdc, snackbar); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_tab-indicator.scss b/src/material/core/tokens/m2/mdc/_tab-indicator.scss index 82adb1dbdf89..1b8d0776497e 100644 --- a/src/material/core/tokens/m2/mdc/_tab-indicator.scss +++ b/src/material/core/tokens/m2/mdc/_tab-indicator.scss @@ -1,5 +1,6 @@ @use 'sass:map'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -14,7 +15,6 @@ $prefix: (mdc, tab-indicator); @function get-unthemable-tokens() { @return ( active-indicator-height: 2px, - // Currently set to zero, but used by the gmat styles to make the indicator rounded. active-indicator-shape: 0, ); @@ -42,10 +42,10 @@ $prefix: (mdc, tab-indicator); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/m2/mdc/_tab.scss b/src/material/core/tokens/m2/mdc/_tab.scss index 0c2cb1025d92..3869ef97da2a 100644 --- a/src/material/core/tokens/m2/mdc/_tab.scss +++ b/src/material/core/tokens/m2/mdc/_tab.scss @@ -1,5 +1,6 @@ @use 'sass:map'; @use '../../../theming/theming'; +@use '../../../style/sass-utils'; @use '../../token-utils'; // The prefix used to generate the fully qualified name for tokens in this file. @@ -16,7 +17,6 @@ $prefix: (mdc, tab); // This is specified both here and in the density tokens, because it determines the size of the // tab itself and there are internal tests who don't configure the theme correctly. container-height: 48px, - // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= @@ -77,10 +77,10 @@ $prefix: (mdc, tab); // Combines the tokens generated by the above functions into a single map with placeholder values. // This is used to create token slots. @function get-token-slots() { - @return token-utils.merge-all( - get-unthemable-tokens(), - get-color-tokens(token-utils.$placeholder-color-config), - get-typography-tokens(token-utils.$placeholder-typography-config), - get-density-tokens(token-utils.$placeholder-density-config) + @return sass-utils.deep-merge-all( + get-unthemable-tokens(), + get-color-tokens(token-utils.$placeholder-color-config), + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) ); } diff --git a/src/material/core/tokens/tests/test-validate-tokens.scss b/src/material/core/tokens/tests/test-validate-tokens.scss index af106eb0f0f8..56c5040fbfe5 100644 --- a/src/material/core/tokens/tests/test-validate-tokens.scss +++ b/src/material/core/tokens/tests/test-validate-tokens.scss @@ -5,8 +5,8 @@ @use '@material/card/outlined-card-theme' as mdc-outlined-card-theme; @use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme; @use '@material/circular-progress/circular-progress-theme' as mdc-circular-progress-theme; -@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme; @use '@material/linear-progress/linear-progress-theme' as mdc-linear-progress-theme; +@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme; @use '@material/list/list-theme' as mdc-list-theme; @use '@material/tooltip/plain-tooltip-theme' as mdc-plaintip-tooltip-theme; @use '@material/radio/radio-theme' as mdc-radio-theme; @@ -17,10 +17,10 @@ @use '@material/theme/validate' as mdc-validate; @use '../m2/mdc/circular-progress' as tokens-mdc-circular-progress; +@use '../m2/mdc/linear-progress' as tokens-mdc-linear-progress; @use '../m2/mdc/elevated-card' as tokens-mdc-elevated-card; @use '../m2/mdc/icon-button' as tokens-mdc-icon-button; @use '../m2/mdc/checkbox' as tokens-mdc-checkbox; -@use '../m2/mdc/linear-progress' as tokens-mdc-linear-progress; @use '../m2/mdc/list' as tokens-mdc-list; @use '../m2/mdc/outlined-card' as tokens-mdc-outlined-card; @use '../m2/mdc/plain-tooltip' as tokens-mdc-plain-tooltip; diff --git a/src/material/legacy-radio/radio.scss b/src/material/legacy-radio/radio.scss index 59b8414df1e5..5751e269a599 100644 --- a/src/material/legacy-radio/radio.scss +++ b/src/material/legacy-radio/radio.scss @@ -2,7 +2,6 @@ @use '@angular/cdk'; @use '../core/style/variables'; -@use '../core/ripple/ripple'; @use '../core/style/vendor-prefixes'; diff --git a/src/material/legacy-slide-toggle/slide-toggle.scss b/src/material/legacy-slide-toggle/slide-toggle.scss index e420cb134285..86358134d533 100644 --- a/src/material/legacy-slide-toggle/slide-toggle.scss +++ b/src/material/legacy-slide-toggle/slide-toggle.scss @@ -3,7 +3,6 @@ @use '../core/style/vendor-prefixes'; @use '../core/style/variables'; -@use '../core/ripple/ripple'; @use '../core/style/list-common'; $thumb-size: 20px !default; diff --git a/src/material/slide-toggle/slide-toggle.scss b/src/material/slide-toggle/slide-toggle.scss index 4163fbe3c45e..4296aaa6a79b 100644 --- a/src/material/slide-toggle/slide-toggle.scss +++ b/src/material/slide-toggle/slide-toggle.scss @@ -5,7 +5,7 @@ @use '@material/form-field' as mdc-form-field; @use '@material/ripple' as mdc-ripple; @use '../core/mdc-helpers/mdc-helpers'; -@use '../core/style/_layout-common.scss'; +@use '../core/style/layout-common'; @include mdc-helpers.disable-mdc-fallback-declarations { diff --git a/src/material/stepper/stepper.scss b/src/material/stepper/stepper.scss index 41c756947198..5d2a70d19970 100644 --- a/src/material/stepper/stepper.scss +++ b/src/material/stepper/stepper.scss @@ -1,7 +1,6 @@ @use '@angular/cdk'; @use 'sass:math'; -@use '../core/style/variables'; @use './stepper-variables'; .mat-stepper-vertical, diff --git a/src/material/tabs/_tabs-theme.scss b/src/material/tabs/_tabs-theme.scss index 203be33801ec..d4d85fc32382 100644 --- a/src/material/tabs/_tabs-theme.scss +++ b/src/material/tabs/_tabs-theme.scss @@ -1,6 +1,5 @@ @use 'sass:map'; @use '@material/tab-indicator/tab-indicator-theme' as mdc-tab-indicator-theme; -@use '@material/tab' as mdc-tab; @use '@material/tab/tab-theme' as mdc-tab-theme; @use '../core/tokens/m2/mdc/tab' as tokens-mdc-tab; @use '../core/tokens/m2/mdc/tab-indicator' as tokens-mdc-tab-indicator; diff --git a/tools/stylelint/no-unused-import.ts b/tools/stylelint/no-unused-import.ts index 4a3761f26b1f..2acfa729b405 100644 --- a/tools/stylelint/no-unused-import.ts +++ b/tools/stylelint/no-unused-import.ts @@ -9,6 +9,13 @@ const messages = utils.ruleMessages(ruleName, { `imports Stylelint rule likely needs to be updated.`, }); +function stripCommentsAndAtUse(content: string) { + return content + .replace(/@use.*?;/g, '') + .replace(/\/\/.*?\n/g, '') + .replace(/\/\*.*?\*\//g, ''); +} + /** Stylelint plugin that flags unused `@use` statements. */ const ruleFn: Rule = (isEnabled, _options, context) => { return (root, result) => { @@ -16,7 +23,7 @@ const ruleFn: Rule = (isEnabled, _options, context) => { return; } - const fileContent = root.toString(); + const fileContent = stripCommentsAndAtUse(root.toString()); root.walkAtRules(rule => { if (rule.name === 'use') { @@ -30,7 +37,9 @@ const ruleFn: Rule = (isEnabled, _options, context) => { message: messages.invalid(rule.params), node: rule, }); - } else if (!fileContent.includes(namespace + '.')) { + } else if (!fileContent.match('[^\\w$@-]' + namespace + '[^\\w-]')) { + // We use a broader match than just `${namespace}.`, because this doesn't catch the case + // where we use the module as an argument to something like `meta.get-function`. if (context.fix) { rule.remove(); } else {