forked from angular/components
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(material-experimental/theming): Introduce a facade layer between…
… user-facing customizable keys and actual MDC token names (angular#27219) * feat(material-experimental/theming): Introduce a facade layer between user-facing customizable keys and actual MDC token names This allows us to expose easier to understand names for users, and decouples us from changes that MDC might make to token names in the future * Demo using the new API to implement dark theme & primary/accent/warn * fixup! Demo using the new API to implement dark theme & primary/accent/warn * Demo completely custom token values * Add some brief bullet point docs of the API
- Loading branch information
Showing
11 changed files
with
449 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
This is an experimental theming API based on [design tokens](https://m3.material.io/foundations/design-tokens/how-to-use-tokens). It is currently in the prototype phase, | ||
and still being evaluated. | ||
|
||
## Design tokens | ||
- Design tokens are a set of variables that determine what components look like. They can affect things like color, typography, desnity, elevation, border radius, and more. | ||
- Angular Material represents design tokens as CSS variables | ||
|
||
## M2 vs M3 tokens | ||
- Angular Material can use tokens corresponding to either the [Material Design 2](https://m2.material.io/) or [Material Design 3](https://m3.material.io/) spec | ||
- Token values for M2 can be obtained by: | ||
1. Generating them from an Angular Material theme object (e.g. one defined with `mat.define-light-theme`). To generate M2 tokens for a theme, pass it to the `mat.m2-tokens-from-theme` function. | ||
- Token values for M3 are not yet available | ||
|
||
Example: | ||
```scss | ||
// Create an Angular Material theme. | ||
$my-theme: mat.define-light-theme(...); | ||
|
||
// Create tokens for M2 from the theme. | ||
$m2-tokens: mat.m2-tokens-from-theme($my-theme); | ||
``` | ||
## Component theme configuration functions | ||
- These functions are used to specify which tokens should be applied by the theming mixins _and_ to customize the tokens used in that component to something other than the value from the token set | ||
- So far the following component theme configuration functions have been implements: | ||
- `matx.checkbox` configures tokens for the mat-checkbox to be applied | ||
- `matx.card` configures tokens for the mat-card to be applied | ||
- The returned configurations from these functions are passed to `matx.theme` or `matx.retheme` | ||
- If no arguments are passed, the configuration instructs the mixin to just output the default value for all of the tokens needed by that component | ||
- The functions can also accept a map of customizations as an argument. | ||
- Each function has its own set of supported map keys that can be used to customize the value of the underlying tokens | ||
- The map keys are a higher level API then the tokens, some of the keys may result in a single token being change, but some may change multiple tokens | ||
- For supported map keys (TODO: have docs for these): | ||
- See `$_customization-resolvers` [here](https://github.com/angular/components/blob/main/src/material-experimental/theming/_checkbox.scss) for `matx.checkbox` | ||
- See `$_customization-resolvers` [here](https://github.com/angular/components/blob/main/src/material-experimental/theming/_card.scss) for `matx.card` | ||
|
||
## Theming mixins | ||
- There are 2 mixins used for theming apps | ||
- `matx.theme` is intended to apply the full theme for some components, with all tokens they need to function. | ||
- `matx.retheme` is intended to re-apply specific tokens to change the appearance for some components by overriding the tokens applied by `matx.theme`. | ||
- Both mixins emit *only* CSS variables representing design tokens | ||
- Both mixins emit their tokens directly under the user specified selector. This gives the user complete control over the selector specificity. | ||
- Using `matx.theme` | ||
- Takes 2 arguments: | ||
- `$tokens` The set of token defaults that will be used for any tokens not explicitly customized by the component theme config | ||
- `$components` List of component theme configs indicating which components to emit tokens for, and optionally, customizations for some token values | ||
- Outputs *all* tokens used by the configured components | ||
- Using `matx.retheme` | ||
- Takes 1 argument: | ||
- `$components` List of component theme configs to emit customized token values for | ||
- Outputs *only* the explicitly customized tokens, not any of the other tokens used by the component | ||
|
||
## Recommended theming structure | ||
- Apply the base token values using `matx.theme` *once* | ||
- Choose selectors with minimal specificity when applying tokens | ||
- Prefer to rely on CSS inheritance to apply token overrides rather than specificity. | ||
For example if checkbox tokens are set on the root element (`html`) they will be inherited down | ||
the DOM and affect any `<mat-checkbox>` within the document. If checkboxes in a specific section | ||
need to appear differently, say within `.dark-sidebar`, set the token overrides on the | ||
`.dark-sidebar` element and they will be inherited down to the checkboxes within, instead of the | ||
values from the root element. | ||
- For a small example, see this [alternate partial theme](https://github.com/angular/components/blob/main/src/dev-app/theme-token-api.scss) for the dev-app |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
@use 'sass:color'; | ||
@use 'sass:meta'; | ||
@use '@angular/material' as mat; | ||
@use './token-resolution'; | ||
|
||
// TODO(mmalerba): This should live under material/card when moving out of experimental. | ||
|
||
/// Gets tokens for setting the card's shape. | ||
/// @param {String} $shape The card's shape. | ||
/// @return {Map} A map of tokens for setting the card's shape. | ||
// Note: we use a function rather than simple rename, because we want to map a single shape value to | ||
// multiple tokens, rather than offer separate shape customizations for elevated and outlined cards. | ||
@function _get-tokens-for-card-shape($shape) { | ||
@return ( | ||
(mdc, elevated-card): (container-shape: $shape), | ||
(mdc, outline-card): (container-shape: $shape), | ||
); | ||
} | ||
|
||
/// Gets tokens for setting the card's color. | ||
/// @param {String} $shape The card's shape. | ||
/// @return {Map} A map of tokens for setting the card's shape. | ||
@function _get-tokens-for-card-color($color) { | ||
@return ( | ||
(mdc, elevated-card): (container-color: $color), | ||
(mdc, outline-card): (container-color: $color), | ||
); | ||
} | ||
|
||
/// Gets a map of card token values that are derived from the theme type. | ||
/// @param {'light' | 'dark'} $theme-type The type of theme. | ||
/// @return {Map} A map of card token values derived from the given theme type. | ||
@function _get-tokens-for-theme-type($theme-type) { | ||
$is-dark: $theme-type == 'dark'; | ||
$foreground: if($is-dark, white, black); | ||
$card-color: if($is-dark, mat.get-color-from-palette(mat.$gray-palette, 800), white); | ||
$outline-color: color.change($foreground, $alpha: 0.12); | ||
$subtitle-color: if($is-dark, rgba(white, 0.7), rgba(black, 0.54)); | ||
|
||
@return ( | ||
(mdc, elevated-card): ( | ||
container-color: $card-color, | ||
), | ||
(mdc, outlined-card): ( | ||
container-color: $card-color, | ||
outline-color: $outline-color, | ||
), | ||
(mat, card): ( | ||
subtitle-text-color: $subtitle-color, | ||
), | ||
); | ||
} | ||
|
||
/// Resolvers for mat-card customizations. | ||
$_customization-resolvers: mat.private-merge-all( | ||
token-resolution.alias(( | ||
elevation: container-elevation, | ||
shadow-color: container-shadow-color, | ||
), (mdc, elevated-card)), | ||
token-resolution.forward(( | ||
outline-width, | ||
outline-color | ||
), (mdc, outlined-card)), | ||
token-resolution.alias(( | ||
title-font: title-text-font, | ||
title-line-height: title-text-line-height, | ||
title-font-size: title-text-size, | ||
title-letter-spacing: title-text-tracking, | ||
title-font-weight: title-text-weight, | ||
subtitle-font: subtitle-text-font, | ||
subtitle-line-height: subtitle-text-line-height, | ||
subtitle-font-size: subtitle-text-size, | ||
subtitle-letter-spacing: subtitle-text-tracking, | ||
subtitle-font-weight: subtitle-text-weight, | ||
subtitle-color: subtitle-text-color | ||
), (mat, card)), | ||
( | ||
background-color: meta.get-function(_get-tokens-for-card-color), | ||
border-radius: meta.get-function(_get-tokens-for-card-shape), | ||
theme-type: meta.get-function(_get-tokens-for-theme-type), | ||
) | ||
); | ||
|
||
/// Configure the mat-card's theme. | ||
/// @param {Map} $customizations [()] A map of custom values to use when theming mat-card. | ||
@function card($customizations: ()) { | ||
@return ( | ||
id: 'mat.card', | ||
customizations: token-resolution.resolve-customized-tokens( | ||
'mat.card', $_customization-resolvers, $customizations), | ||
deps: (), | ||
); | ||
} |
Oops, something went wrong.