Skip to content

Commit 5923072

Browse files
authored
refactor(material/button): switch text button to tokens for color and density (#27937)
Switches the color and density styles for the text button to tokens.
1 parent 52c85e5 commit 5923072

File tree

4 files changed

+174
-57
lines changed

4 files changed

+174
-57
lines changed

src/material/button/_button-theme.scss

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,13 @@
1414
@use '../core/typography/typography';
1515
@use '../core/tokens/m2/mdc/filled-button' as tokens-mdc-filled-button;
1616
@use '../core/tokens/m2/mdc/protected-button' as tokens-mdc-protected-button;
17+
@use '../core/tokens/m2/mdc/text-button' as tokens-mdc-text-button;
1718

1819
@function _on-color($theme, $palette) {
1920
$is-dark: inspection.get-theme-type($theme) == dark;
2021
@return if(mdc-helpers.variable-safe-contrast-tone($palette, $is-dark) == 'dark', #000, #fff);
2122
}
2223

23-
@mixin _button-variant($color) {
24-
@include mdc-button-text-theme.theme((
25-
label-text-color: $color,
26-
));
27-
}
28-
2924
@mixin _outlined-button-variant($color) {
3025
@include mdc-button-outlined-theme.theme((
3126
label-text-color: $color,
@@ -40,42 +35,10 @@
4035
@include mdc-helpers.using-mdc-theme($theme) {
4136
$is-dark: inspection.get-theme-type($theme) == dark;
4237
$on-surface: mdc-theme-color.prop-value(on-surface);
43-
$surface: mdc-theme-color.prop-value(surface);
4438
$disabled-ink-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
45-
$disabled-container-color: rgba($on-surface, 0.12);
4639
$primary: mdc-theme-color.prop-value(primary);
47-
$on-primary: mdc-theme-color.prop-value(on-primary);
4840
$secondary: mdc-theme-color.prop-value(secondary);
49-
$on-secondary: mdc-theme-color.prop-value(on-secondary);
5041
$error: mdc-theme-color.prop-value(error);
51-
$on-error: mdc-theme-color.prop-value(on-error);
52-
53-
.mat-mdc-button {
54-
&.mat-unthemed {
55-
@include _button-variant($on-surface);
56-
}
57-
58-
&.mat-primary {
59-
@include _button-variant($primary);
60-
}
61-
62-
&.mat-accent {
63-
@include _button-variant($secondary);
64-
}
65-
66-
&.mat-warn {
67-
@include _button-variant($error);
68-
}
69-
70-
@include button-theme-private.apply-disabled-style() {
71-
@include mdc-button-text-theme.theme((
72-
// We need to pass both the disabled and enabled values, because the enabled
73-
// ones apply to anchors while the disabled ones are for buttons.
74-
disabled-label-text-color: $disabled-ink-color,
75-
label-text-color: $disabled-ink-color
76-
));
77-
}
78-
}
7942

8043
.mat-mdc-outlined-button {
8144
@include mdc-button-outlined-theme.theme((
@@ -130,6 +93,25 @@
13093
$on-accent: _on-color($theme, $accent);
13194
$on-error: _on-color($theme, $error);
13295

96+
.mat-mdc-button {
97+
@include mdc-button-text-theme.theme(tokens-mdc-text-button.get-color-tokens($theme));
98+
99+
&.mat-primary {
100+
@include mdc-button-text-theme.theme(
101+
tokens-mdc-text-button.private-get-color-palette-color-tokens($theme, primary));
102+
}
103+
104+
&.mat-accent {
105+
@include mdc-button-text-theme.theme(
106+
tokens-mdc-text-button.private-get-color-palette-color-tokens($theme, accent));
107+
}
108+
109+
&.mat-warn {
110+
@include mdc-button-text-theme.theme(
111+
tokens-mdc-text-button.private-get-color-palette-color-tokens($theme, warn));
112+
}
113+
}
114+
133115
.mat-mdc-unelevated-button {
134116
$default-color-tokens: tokens-mdc-filled-button.get-color-tokens($theme, $surface, $on-surface);
135117
$primary-color-tokens: tokens-mdc-filled-button.get-color-tokens($theme, $primary, $on-primary);
@@ -201,6 +183,17 @@
201183
$disabled-ink-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
202184
$disabled-container-color: rgba($on-surface, 0.12);
203185

186+
// TODO: these disabled styles are a bit too specific currently.
187+
// Once the buttons are fully tokenized, we should rework how they're applied.
188+
.mat-mdc-button {
189+
@include button-theme-private.apply-disabled-style() {
190+
@include mdc-button-text-theme.theme((
191+
disabled-label-text-color: $disabled-ink-color,
192+
label-text-color: $disabled-ink-color,
193+
));
194+
}
195+
}
196+
204197
.mat-mdc-raised-button {
205198
@include button-theme-private.apply-disabled-style() {
206199
@include mdc-elevation-theme.elevation(0);
@@ -234,6 +227,22 @@
234227
@mixin density($theme) {
235228
$density-scale: theming.clamp-density(inspection.get-theme-density($theme), -3);
236229

230+
.mat-mdc-button {
231+
$density-tokens: tokens-mdc-text-button.get-density-tokens($theme);
232+
@include mdc-button-text-theme.theme($density-tokens);
233+
@include button-theme-private.touch-target-density($density-scale);
234+
235+
// TODO(crisbeto): before the introduction of tokens, MDC's density mixin was adding
236+
// `margin-top: 0` and `margin-bottom: 0` in its `density` mixin which a lot of internal
237+
// clients came to depend upon. Preserve it to make tokens easier to land.
238+
@if ($density-scale < 0) {
239+
&.mat-mdc-button-base {
240+
margin-top: 0;
241+
margin-bottom: 0;
242+
}
243+
}
244+
}
245+
237246
.mat-mdc-raised-button {
238247
$density-tokens: tokens-mdc-protected-button.get-density-tokens($theme);
239248
@include mdc-button-protected-theme.theme($density-tokens);
@@ -246,7 +255,6 @@
246255
@include button-theme-private.touch-target-density($density-scale);
247256
}
248257

249-
.mat-mdc-button,
250258
.mat-mdc-outlined-button {
251259
// Use `mat-mdc-button-base` to increase the specificity over the button's structural styles.
252260
&.mat-mdc-button-base {

src/material/button/button.scss

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,34 @@
1414
@use '../core/focus-indicators/private' as focus-indicators-private;
1515
@use '../core/tokens/m2/mdc/filled-button' as tokens-mdc-filled-button;
1616
@use '../core/tokens/m2/mdc/protected-button' as tokens-mdc-protected-button;
17+
@use '../core/tokens/m2/mdc/text-button' as tokens-mdc-text-button;
1718

1819
@include mdc-helpers.disable-mdc-fallback-declarations {
1920
@include mdc-button.static-styles-without-ripple($query: mdc-helpers.$mdc-base-styles-query);
2021

21-
// Keys to exclude from the MDC theme config, allowing us to drop styles we don't need.
22-
$override-keys: button-base.mat-private-button-remove-ripple((
23-
label-text-font: null,
24-
label-text-size: null,
25-
label-text-tracking: null,
26-
label-text-transform: null,
27-
label-text-weight: null,
28-
with-icon-icon-size: null,
29-
label-text-color: inherit,
30-
));
31-
32-
// Note that we don't include a feature query, because this mixins declare
33-
// all the "slots" for CSS variables that will be defined in the theme.
34-
.mat-mdc-button {
35-
@include mdc-button-text-theme.theme-styles(
36-
map.merge(mdc-button-text-theme.$light-theme, $override-keys));
37-
}
38-
3922
.mat-mdc-outlined-button {
23+
// Keys to exclude from the MDC theme config, allowing us to drop styles we don't need.
24+
$override-keys: button-base.mat-private-button-remove-ripple((
25+
label-text-font: null,
26+
label-text-size: null,
27+
label-text-tracking: null,
28+
label-text-transform: null,
29+
label-text-weight: null,
30+
with-icon-icon-size: null,
31+
label-text-color: inherit,
32+
));
33+
4034
@include mdc-button-outlined-theme.theme-styles(
4135
map.merge(mdc-button-outlined-theme.$light-theme, $override-keys));
4236
}
4337
}
4438

4539
@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
40+
.mat-mdc-button {
41+
@include mdc-button-text-theme.theme-styles(tokens-mdc-text-button.get-token-slots());
42+
@include mdc-button-text-theme.theme(tokens-mdc-text-button.get-unthemable-tokens());
43+
}
44+
4645
// Note that we don't include a feature query, because this mixins declare
4746
// all the "slots" for CSS variables that will be defined in the theme.
4847
.mat-mdc-unelevated-button {
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
@use 'sass:map';
2+
@use '../../token-utils';
3+
@use '../../../style/sass-utils';
4+
@use '../../../theming/inspection';
5+
@use '../../../theming/theming';
6+
7+
// The prefix used to generate the fully qualified name for tokens in this file.
8+
$prefix: (mdc, text-button);
9+
10+
// Tokens that can't be configured through Angular Material's current theming API,
11+
// but may be in a future version of the theming API.
12+
//
13+
// Tokens that are available in MDC, but not used in Angular Material should be mapped to `null`.
14+
// `null` indicates that we are intentionally choosing not to emit a slot or value for the token in
15+
// our CSS.
16+
@function get-unthemable-tokens() {
17+
@return (
18+
container-shape: 4px,
19+
20+
// TODO: `container-height` is also included so it has a default value to
21+
// prevent the buttons from collapsing if a density mixin isn't included.
22+
container-height: 36px,
23+
24+
// TODO: handle these through the typography styles eventually.
25+
label-text-font: null,
26+
label-text-size: null,
27+
label-text-tracking: null,
28+
label-text-transform: null,
29+
label-text-weight: null,
30+
31+
// =============================================================================================
32+
// = TOKENS NOT USED IN ANGULAR MATERIAL =
33+
// =============================================================================================
34+
hover-label-text-color: null,
35+
focus-label-text-color: null,
36+
pressed-label-text-color: null,
37+
focus-state-layer-color: null,
38+
focus-state-layer-opacity: null,
39+
hover-state-layer-color: null,
40+
hover-state-layer-opacity: null,
41+
pressed-state-layer-color: null,
42+
pressed-state-layer-opacity: null,
43+
with-icon-disabled-icon-color: null,
44+
with-icon-focus-icon-color: null,
45+
with-icon-hover-icon-color: null,
46+
with-icon-icon-color: null,
47+
with-icon-icon-size: null,
48+
with-icon-pressed-icon-color: null,
49+
focus-ring-color: null,
50+
focus-ring-offset: null,
51+
keep-touch-target: false,
52+
);
53+
}
54+
55+
// Tokens that can be configured through Angular Material's color theming API.
56+
@function get-color-tokens($theme) {
57+
$is-dark: inspection.get-theme-type($theme) == dark;
58+
$on-surface: if($is-dark, #fff, #000);
59+
60+
@return (
61+
label-text-color: $on-surface,
62+
disabled-label-text-color: rgba($on-surface, if($is-dark, 0.5, 0.38)),
63+
);
64+
}
65+
66+
// Generates the mapping for the properties that change based on the button palette color.
67+
@function private-get-color-palette-color-tokens($theme, $palette-name) {
68+
$palette: map.get($theme, $palette-name);
69+
70+
@return (
71+
label-text-color: inspection.get-theme-color($theme, $palette-name)
72+
);
73+
}
74+
75+
// Tokens that can be configured through Angular Material's typography theming API.
76+
@function get-typography-tokens($theme) {
77+
@return ();
78+
}
79+
80+
// Tokens that can be configured through Angular Material's density theming API.
81+
@function get-density-tokens($theme) {
82+
$scale: theming.clamp-density(inspection.get-theme-density($theme), -3);
83+
84+
@return (
85+
container-height: map.get((
86+
0: 36px,
87+
-1: 32px,
88+
-2: 28px,
89+
-3: 24px,
90+
), $scale),
91+
);
92+
}
93+
94+
// Combines the tokens generated by the above functions into a single map with placeholder values.
95+
// This is used to create token slots.
96+
@function get-token-slots() {
97+
@return sass-utils.deep-merge-all(
98+
get-unthemable-tokens(),
99+
get-color-tokens(token-utils.$placeholder-color-config),
100+
get-typography-tokens(token-utils.$placeholder-typography-config),
101+
get-density-tokens(token-utils.$placeholder-density-config)
102+
);
103+
}

src/material/core/tokens/tests/test-validate-tokens.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
@use '@material/button/button-protected-theme' as mdc-button-protected-theme;
55
@use '@material/button/button-filled-theme' as mdc-button-filled-theme;
6+
@use '@material/button/button-text-theme' as mdc-button-text-theme;
67
@use '@material/card/elevated-card-theme' as mdc-elevated-card-theme;
78
@use '@material/card/outlined-card-theme' as mdc-outlined-card-theme;
89
@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme;
@@ -27,6 +28,7 @@
2728

2829
@use '../m2/mdc/protected-button' as tokens-mdc-protected-button;
2930
@use '../m2/mdc/filled-button' as tokens-mdc-filled-button;
31+
@use '../m2/mdc/text-button' as tokens-mdc-text-button;
3032
@use '../m2/mdc/circular-progress' as tokens-mdc-circular-progress;
3133
@use '../m2/mdc/linear-progress' as tokens-mdc-linear-progress;
3234
@use '../m2/mdc/elevated-card' as tokens-mdc-elevated-card;
@@ -170,3 +172,8 @@
170172
$slots: tokens-mdc-protected-button.get-token-slots(),
171173
$reference: mdc-button-protected-theme.$light-theme
172174
);
175+
@include validate-slots(
176+
$component: 'm2.mdc.text-button',
177+
$slots: tokens-mdc-text-button.get-token-slots(),
178+
$reference: mdc-button-text-theme.$light-theme
179+
);

0 commit comments

Comments
 (0)