Skip to content

Commit 5f5c516

Browse files
authored
refactor(material-experimental/theming): condense matx.theme and matx.retheme into a single mixin (#27309)
Rather than having a separate mixin for "retheming" we have a single mixin `matx.theme` that can either emit fallback token defaults or not depending on how its configured. Added `matx.token-defaults` which can be used to configure the fallbacks.
1 parent 25adcd2 commit 5f5c516

File tree

6 files changed

+79
-59
lines changed

6 files changed

+79
-59
lines changed

src/dev-app/theme-token-api.scss

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ $theme: mat.define-light-theme((
3737
// on the page will inherit these tokens.
3838
html {
3939
@include matx.theme(
40-
$tokens: mat.m2-tokens-from-theme($theme),
41-
$components: (
42-
matx.card(),
43-
matx.checkbox(),
44-
)
40+
matx.token-defaults(mat.m2-tokens-from-theme($theme)),
41+
matx.card(),
42+
matx.checkbox(),
4543
);
4644
}
4745

@@ -51,11 +49,11 @@ html {
5149
// rather than the ones for light theme tokens set on `body`. Note that we're not setting *all* of
5250
// the tokens, since many (density, typography, etc) are the same between light and dark theme.
5351
.demo-unicorn-dark-theme {
54-
@include matx.retheme((
52+
@include matx.theme(
5553
// TODO(mmalerba): In the future this should be configured through `matx.system-colors()`
5654
matx.checkbox((theme-type: dark)),
5755
matx.card((theme-type: dark)),
58-
));
56+
);
5957
}
6058

6159
// Apply tokens related to the color palette to any element with `.mat-primary`, `.mat-accent`, or
@@ -68,31 +66,31 @@ html {
6866
// take precedence.
6967
// (e.g. <div class="mat-warn><mat-checkbox class="mat-primary">I'm primary</mat-checkbox></div>)
7068
.mat-primary {
71-
@include matx.retheme((
69+
@include matx.theme(
7270
matx.checkbox((
7371
color-palette: map.get($theme, color, primary)
7472
)),
75-
));
73+
);
7674
}
7775
.mat-accent {
78-
@include matx.retheme((
76+
@include matx.theme(
7977
matx.checkbox((
8078
color-palette: map.get($theme, color, accent)
8179
)),
82-
));
80+
);
8381
}
8482
.mat-warn {
85-
@include matx.retheme((
83+
@include matx.theme(
8684
matx.checkbox((
8785
color-palette: map.get($theme, color, warn)
8886
)),
89-
));
87+
);
9088
}
9189

9290
// Apply tokens for a completely custom checkbox that appears as an unfilled red box when unchecked,
9391
// and a filled green box when checked.
9492
.demo-traffic-light-checkbox {
95-
@include matx.retheme((
93+
@include matx.theme(
9694
matx.checkbox((
9795
checkmark-color: transparent,
9896
selected-box-color: green,
@@ -110,5 +108,10 @@ html {
110108
unselected-hover-ring-color: red,
111109
unselected-pressed-ring-color: red,
112110
))
113-
));
111+
);
112+
}
113+
114+
.demo-what-am-i-doing {
115+
// Will not produce any output, should result in a warning.
116+
@include matx.theme(matx.checkbox());
114117
}

src/material-experimental/_index.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
popover-edit-typography, popover-edit-density, popover-edit-theme;
66

77
// Token-based theming API
8-
@forward './theming/theming' show theme, retheme;
8+
@forward './theming/theming' show theme, token-defaults;
99
@forward './theming/checkbox' show checkbox;
1010
@forward './theming/card' show card;
1111

src/material-experimental/theming/README.md

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,34 @@ $my-theme: mat.define-light-theme(...);
2020
$m2-tokens: mat.m2-tokens-from-theme($my-theme);
2121
```
2222
## Component theme configuration functions
23-
- 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
24-
- So far the following component theme configuration functions have been implements:
23+
- These functions are used to specify which tokens should be applied by the `matx.theme` mixin _and_ to customize the tokens used in that component to something other than the value from the token set
24+
- `matx.token-defaults` is a special configuration function used to set the default token values that will be used for any components that are configured as part of the same mixin call, if no `matx.token-defaults` config is specified, only tokens for the explicitly customized properties will be emitted
25+
- So far the following component theme configuration functions have been implemented:
2526
- `matx.checkbox` configures tokens for the mat-checkbox to be applied
2627
- `matx.card` configures tokens for the mat-card to be applied
27-
- The returned configurations from these functions are passed to `matx.theme` or `matx.retheme`
28-
- 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
29-
- The functions can also accept a map of customizations as an argument.
28+
- The returned configurations from these functions are passed to `matx.theme`
29+
- The functions optionally accept a map of customizations as an argument which allows overriding properties tha would otherwise be derived from the default tokens.
3030
- Each function has its own set of supported map keys that can be used to customize the value of the underlying tokens
31-
- 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
31+
- The map keys are a higher level API then the tokens, some the keys may result in a single token being change, but some may change multiple tokens
3232
- For supported map keys (TODO: have docs for these):
3333
- See `$_customization-resolvers` [here](https://github.com/angular/components/blob/main/src/material-experimental/theming/_checkbox.scss) for `matx.checkbox`
3434
- See `$_customization-resolvers` [here](https://github.com/angular/components/blob/main/src/material-experimental/theming/_card.scss) for `matx.card`
3535

3636
## Theming mixins
37-
- There are 2 mixins used for theming apps
38-
- `matx.theme` is intended to apply the full theme for some components, with all tokens they need to function.
39-
- `matx.retheme` is intended to re-apply specific tokens to change the appearance for some components by overriding the tokens applied by `matx.theme`.
40-
- Both mixins emit *only* CSS variables representing design tokens
41-
- Both mixins emit their tokens directly under the user specified selector. This gives the user complete control over the selector specificity.
37+
- There is a single mixin used for theming apps: `matx.theme` applies the theme for some set of components (specified by passing component configs)
38+
- This mixin will always apply theme values for properties explicitly customized in the individual component configs
39+
- This mixin will apply *all* tokens for the configured component if a `matx.token-defaults` config is specified
40+
- This mixin emits *only* CSS variables representing design tokens
41+
- This mixin emits the CSS vars directly under the user specified selector. This gives the user complete control over the selector specificity.
4242
- Using `matx.theme`
4343
- Takes 2 arguments:
4444
- `$tokens` The set of token defaults that will be used for any tokens not explicitly customized by the component theme config
4545
- `$components` List of component theme configs indicating which components to emit tokens for, and optionally, customizations for some token values
46-
- Outputs *all* tokens used by the configured components
47-
- Using `matx.retheme`
48-
- Takes 1 argument:
49-
- `$components` List of component theme configs to emit customized token values for
50-
- Outputs *only* the explicitly customized tokens, not any of the other tokens used by the component
46+
- Outputs CSS variables for the configured components
5147

5248
## Recommended theming structure
53-
- Apply the base token values using `matx.theme` *once*
49+
- Apply the base token values using `matx.theme` together with `matx.token-defaults` *once* (typically to the document root `html { ... }`)
50+
- Apply incremental overrides to the theme by calling `matx.theme` *without* `matx.token-default` to emit only the properties you want to change
5451
- Choose selectors with minimal specificity when applying tokens
5552
- Prefer to rely on CSS inheritance to apply token overrides rather than specificity.
5653
For example if checkbox tokens are set on the root element (`html`) they will be inherited down

src/material-experimental/theming/_theming.scss

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -88,27 +88,43 @@ $_error-on-missing-dep: false;
8888
}
8989
}
9090

91-
/// Takes the full list of tokens and a list of components to configure, and outputs all theme
92-
/// tokens for the configured components.
93-
/// @param {Map} $tokens A map of all tokens for the current design system.
91+
/// Takes a list of components to configure, and outputs theme tokens for the configured components.
9492
/// @param {List} $components The list of component configurations to emit tokens for.
9593
/// @output CSS variables representing the theme tokens for the given component configs.
96-
// TODO(mmalerba): Consider an alternate API where `$tokens` is not a separate argument,
97-
// but one of the configs in the `$components` list
98-
@mixin theme($tokens, $components) {
99-
@include _theme($tokens, _get-transitive-deps(mat.private-coerce-to-list($components)));
94+
@mixin theme($components...) {
95+
$filtered-components: ();
96+
$tokens: null;
97+
@each $component in $components {
98+
@if (map.get($component, id) == 'mat.token-defaults') {
99+
@if $tokens == null {
100+
$tokens: map.get($component, tokens);
101+
}
102+
@else {
103+
@error 'mat.token-defaults specified multiple times in call to mat.theme';
104+
}
105+
}
106+
@else {
107+
$filtered-components: list.append($filtered-components, $component);
108+
}
109+
}
110+
$tokens: $tokens or ();
111+
@if $tokens == () {
112+
@each $component in $filtered-components {
113+
@if (map.get($component, customizations) or ()) == () {
114+
$component-id: map.get($component, id);
115+
@warn 'Call to `#{$component-id}()` will produce no output, this is likely a mistake.' +
116+
' Did you mean to:'+
117+
'\a 1. Provide default token values with `mat.token-defaults`?' +
118+
'\a 2. Specify customizations in the call to `#{$component-id}`?';
119+
}
120+
}
121+
}
122+
@include _theme($tokens, $filtered-components);
100123
}
101124

102-
/// Takes a list of components to configure, and outputs only the theme tokens that are explicitly
103-
/// customized by the configurations.
104-
/// @param {List} $components The list of component configurations to emit tokens for.
105-
/// @output CSS variables representing the theme tokens for the given component configs.
106-
// TODO(mmalerba): What should we call this?
107-
// - update-theme
108-
// - adjust-theme
109-
// - edit-theme
110-
// - override-theme
111-
// - retheme
112-
@mixin retheme($components) {
113-
@include _theme((), mat.private-coerce-to-list($components));
125+
@function token-defaults($tokens) {
126+
@return (
127+
id: 'mat.token-defaults',
128+
tokens: $tokens
129+
);
114130
}

src/material/card/_card-theme.scss

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@
7979
}
8080

8181
@mixin theme-from-tokens($tokens) {
82-
@include mdc-elevated-card-theme.theme(map.get($tokens, tokens-mdc-elevated-card.$prefix));
83-
@include mdc-outlined-card-theme.theme(map.get($tokens, tokens-mdc-outlined-card.$prefix));
84-
@include token-utils.create-token-values(
85-
tokens-mat-card.$prefix, map.get($tokens, tokens-mat-card.$prefix));
82+
@if ($tokens != ()) {
83+
@include mdc-elevated-card-theme.theme(map.get($tokens, tokens-mdc-elevated-card.$prefix));
84+
@include mdc-outlined-card-theme.theme(map.get($tokens, tokens-mdc-outlined-card.$prefix));
85+
@include token-utils.create-token-values(
86+
tokens-mat-card.$prefix, map.get($tokens, tokens-mat-card.$prefix));
87+
}
8688
}

src/material/checkbox/_checkbox-theme.scss

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@
9090
}
9191

9292
@mixin theme-from-tokens($tokens) {
93-
// TODO(mmalerba): Some of the theme styles above are not represented in terms of tokens,
94-
// so this mixin is currently incomplete.
95-
@include mdc-checkbox-theme.theme(map.get($tokens, tokens-mdc-checkbox.$prefix));
93+
@if ($tokens != ()) {
94+
// TODO(mmalerba): Some of the theme styles above are not represented in terms of tokens,
95+
// so this mixin is currently incomplete.
96+
@include mdc-checkbox-theme.theme(map.get($tokens, tokens-mdc-checkbox.$prefix));
97+
}
9698
}

0 commit comments

Comments
 (0)