Skip to content

Commit 01a9501

Browse files
committed
refactor(material/button): handle disabled states through tokens
MDC applies disabled styles through the `:disabled` selector which forced us to work around it by using a selector like `.mat-mdc-button[disabled][disabled]` and setting both the disabled and enabled button tokens. This is problematic, because it increases the specificity too much and it introduces space for mistakes, because we have to duplicate the tokens values. These changes resolve the issue by re-applying the token slots to disabled buttons with the correct selector so that they can reuse the same tokens as the `button` nodes.
1 parent 69d5ebd commit 01a9501

File tree

5 files changed

+61
-107
lines changed

5 files changed

+61
-107
lines changed

src/material/button/_button-base.scss

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@use 'sass:map';
21
@use '@material/touch-target' as mdc-touch-target;
32

43
@use '../core/style/layout-common';
@@ -89,15 +88,3 @@
8988
$query: mdc-helpers.$mdc-base-styles-query);
9089
}
9190
}
92-
93-
// Changes a button token set to exclude the ripple styles.
94-
@function mat-private-button-remove-ripple($tokens) {
95-
@return map.merge($tokens, (
96-
focus-state-layer-color: null,
97-
focus-state-layer-opacity: null,
98-
hover-state-layer-color: null,
99-
hover-state-layer-opacity: null,
100-
pressed-state-layer-color: null,
101-
pressed-state-layer-opacity: null,
102-
));
103-
}

src/material/button/_button-theme-private.scss

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,6 @@
4545
}
4646
}
4747

48-
// Wraps the content style in a selector for the disabled state.
49-
// MDC adds theme color by using :not(:disabled), so just using [disabled] once will not
50-
// override this, neither will it apply to anchor tags. This needs to override the
51-
// previously set theme color, so it must be ordered after the theme styles.
52-
// TODO(andrewseguin): Discuss with the MDC team to see if we can avoid the :not(:disabled) by
53-
// manually styling disabled buttons with a [disabled] selector.
54-
@mixin apply-disabled-style() {
55-
&[disabled][disabled] {
56-
@content;
57-
}
58-
}
59-
6048
// Hides the touch target on lower densities.
6149
@mixin touch-target-density($scale) {
6250
@include mdc-helpers.if-touch-targets-unsupported($scale) {

src/material/button/_button-theme.scss

Lines changed: 11 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
@use '@material/button/button-filled-theme' as mdc-button-filled-theme;
44
@use '@material/button/button-protected-theme' as mdc-button-protected-theme;
55
@use '@material/button/button-outlined-theme' as mdc-button-outlined-theme;
6-
@use '@material/theme/theme-color' as mdc-theme-color;
76
@use '@material/elevation/elevation-theme' as mdc-elevation-theme;
87

98
@use './button-theme-private';
@@ -21,25 +20,23 @@
2120
@return if(mdc-helpers.variable-safe-contrast-tone($palette, $is-dark) == 'dark', #000, #fff);
2221
}
2322

24-
@mixin _outlined-button-variant($color) {
25-
@include mdc-button-outlined-theme.theme((
26-
label-text-color: $color,
27-
));
28-
}
29-
3023
@mixin base($theme) {
3124
// TODO(mmalerba): Move button base tokens here
3225
}
3326

3427
@mixin color($theme) {
35-
@include mdc-helpers.using-mdc-theme($theme) {
36-
$is-dark: inspection.get-theme-type($theme) == dark;
37-
$on-surface: mdc-theme-color.prop-value(on-surface);
38-
$disabled-ink-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
39-
$primary: mdc-theme-color.prop-value(primary);
40-
$secondary: mdc-theme-color.prop-value(secondary);
41-
$error: mdc-theme-color.prop-value(error);
28+
$surface: inspection.get-theme-color($theme, background, card);
29+
$primary: inspection.get-theme-color($theme, primary);
30+
$accent: inspection.get-theme-color($theme, accent);
31+
$error: inspection.get-theme-color($theme, warn);
4232

33+
$on-surface: _on-color($theme, $surface);
34+
$on-primary: _on-color($theme, $primary);
35+
$on-accent: _on-color($theme, $accent);
36+
$on-error: _on-color($theme, $error);
37+
38+
// TODO: remove these when tokenizing the ripples.
39+
@include mdc-helpers.using-mdc-theme($theme) {
4340
// Ripple colors
4441
.mat-mdc-button, .mat-mdc-outlined-button {
4542
@include button-theme-private.ripple-theme-styles($theme, false);
@@ -50,16 +47,6 @@
5047
}
5148
}
5249

53-
$surface: inspection.get-theme-color($theme, background, card);
54-
$primary: inspection.get-theme-color($theme, primary);
55-
$accent: inspection.get-theme-color($theme, accent);
56-
$error: inspection.get-theme-color($theme, warn);
57-
58-
$on-surface: _on-color($theme, $surface);
59-
$on-primary: _on-color($theme, $primary);
60-
$on-accent: _on-color($theme, $accent);
61-
$on-error: _on-color($theme, $error);
62-
6350
.mat-mdc-button {
6451
@include mdc-button-text-theme.theme(tokens-mdc-text-button.get-color-tokens($theme));
6552

@@ -176,55 +163,6 @@
176163
@include mdc-button-outlined-theme.theme($warn-color-tokens);
177164
}
178165
}
179-
180-
$is-dark: inspection.get-theme-type($theme) == dark;
181-
$disabled-ink-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
182-
$disabled-container-color: rgba($on-surface, 0.12);
183-
184-
// TODO: these disabled styles are a bit too specific currently.
185-
// Once the buttons are fully tokenized, we should rework how they're applied.
186-
.mat-mdc-button {
187-
@include button-theme-private.apply-disabled-style() {
188-
@include mdc-button-text-theme.theme((
189-
disabled-label-text-color: $disabled-ink-color,
190-
label-text-color: $disabled-ink-color,
191-
));
192-
}
193-
}
194-
195-
.mat-mdc-raised-button {
196-
@include button-theme-private.apply-disabled-style() {
197-
@include mdc-elevation-theme.elevation(0);
198-
@include mdc-button-protected-theme.theme((
199-
disabled-container-color: $disabled-container-color,
200-
disabled-label-text-color: $disabled-ink-color,
201-
container-color: $disabled-container-color,
202-
label-text-color: $disabled-ink-color,
203-
));
204-
}
205-
}
206-
207-
.mat-mdc-outlined-button {
208-
@include button-theme-private.apply-disabled-style() {
209-
@include mdc-button-outlined-theme.theme((
210-
label-text-color: $disabled-ink-color,
211-
disabled-label-text-color: $disabled-ink-color,
212-
disabled-outline-color: rgba($on-surface, 0.12),
213-
outline-color: rgba($on-surface, 0.12),
214-
));
215-
}
216-
}
217-
218-
.mat-mdc-unelevated-button {
219-
@include button-theme-private.apply-disabled-style() {
220-
@include mdc-button-filled-theme.theme((
221-
disabled-container-color: $disabled-container-color,
222-
disabled-label-text-color: $disabled-ink-color,
223-
container-color: $disabled-container-color,
224-
label-text-color: $disabled-ink-color,
225-
));
226-
}
227-
}
228166
}
229167

230168
@mixin typography($theme) {

src/material/button/button.scss

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
@use './button-base';
1111
@use '../core/mdc-helpers/mdc-helpers';
1212
@use '../core/style/private' as style-private;
13+
@use '../core/tokens/token-utils';
1314
@use '../core/focus-indicators/private' as focus-indicators-private;
1415
@use '../core/tokens/m2/mdc/filled-button' as tokens-mdc-filled-button;
1516
@use '../core/tokens/m2/mdc/outlined-button' as tokens-mdc-outlined-button;
@@ -22,12 +23,20 @@
2223

2324
@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
2425
.mat-mdc-button {
25-
@include mdc-button-text-theme.theme-styles(tokens-mdc-text-button.get-token-slots());
26+
$mdc-text-button-slots: tokens-mdc-text-button.get-token-slots();
27+
28+
@include mdc-button-text-theme.theme-styles($mdc-text-button-slots);
2629
@include mdc-button-text-theme.theme(tokens-mdc-text-button.get-unthemable-tokens());
30+
31+
@include token-utils.use-tokens(tokens-mdc-text-button.$prefix, $mdc-text-button-slots) {
32+
// We need to re-apply the disabled tokens since MDC uses
33+
// `:disabled` which doesn't apply to anchors.
34+
@include button-base.mat-private-button-disabled {
35+
@include token-utils.create-token-slot(color, disabled-label-text-color);
36+
}
37+
}
2738
}
2839

29-
// Note that we don't include a feature query, because this mixins declare
30-
// all the "slots" for CSS variables that will be defined in the theme.
3140
.mat-mdc-unelevated-button {
3241
$mdc-filled-button-slots: tokens-mdc-filled-button.get-token-slots();
3342

@@ -36,10 +45,17 @@
3645

3746
// Add default values for MDC text button tokens that aren't outputted by the theming API.
3847
@include mdc-button-filled-theme.theme(tokens-mdc-filled-button.get-unthemable-tokens());
48+
49+
@include token-utils.use-tokens(tokens-mdc-filled-button.$prefix, $mdc-filled-button-slots) {
50+
// We need to re-apply the disabled tokens since MDC uses
51+
// `:disabled` which doesn't apply to anchors.
52+
@include button-base.mat-private-button-disabled {
53+
@include token-utils.create-token-slot(color, disabled-label-text-color);
54+
@include token-utils.create-token-slot(background-color, disabled-container-color);
55+
}
56+
}
3957
}
4058

41-
// Note that we don't include a feature query, because this mixins declare
42-
// all the "slots" for CSS variables that will be defined in the theme.
4359
.mat-mdc-raised-button {
4460
$mdc-button-protected-slots: tokens-mdc-protected-button.get-token-slots();
4561

@@ -48,10 +64,24 @@
4864

4965
// Add default values for MDC text button tokens that aren't outputted by the theming API.
5066
@include mdc-button-protected-theme.theme(tokens-mdc-protected-button.get-unthemable-tokens());
67+
68+
@include token-utils.use-tokens(
69+
tokens-mdc-protected-button.$prefix,
70+
$mdc-button-protected-slots) {
71+
// We need to re-apply the disabled tokens since MDC uses
72+
// `:disabled` which doesn't apply to anchors.
73+
@include button-base.mat-private-button-disabled {
74+
@include token-utils.create-token-slot(color, disabled-label-text-color);
75+
@include token-utils.create-token-slot(background-color, disabled-container-color);
76+
77+
// Since we're still doing elevation through the theme, we need additional specificity here.
78+
&[disabled] {
79+
box-shadow: none;
80+
}
81+
}
82+
}
5183
}
5284

53-
// Note that we don't include a feature query, because this mixins declare
54-
// all the "slots" for CSS variables that will be defined in the theme.
5585
.mat-mdc-outlined-button {
5686
$mdc-outlined-button-slots: tokens-mdc-outlined-button.get-token-slots();
5787

@@ -60,6 +90,17 @@
6090

6191
// Add default values for MDC text button tokens that aren't outputted by the theming API.
6292
@include mdc-button-outlined-theme.theme(tokens-mdc-outlined-button.get-unthemable-tokens());
93+
94+
@include token-utils.use-tokens(
95+
tokens-mdc-outlined-button.$prefix,
96+
$mdc-outlined-button-slots) {
97+
// We need to re-apply the disabled tokens since MDC uses
98+
// `:disabled` which doesn't apply to anchors.
99+
@include button-base.mat-private-button-disabled {
100+
@include token-utils.create-token-slot(color, disabled-label-text-color);
101+
@include token-utils.create-token-slot(border-color, disabled-outline-color);
102+
}
103+
}
63104
}
64105
}
65106

@@ -68,7 +109,6 @@
68109
.mat-mdc-raised-button,
69110
.mat-mdc-outlined-button {
70111
@include button-base.mat-private-button-interactive();
71-
@include button-base.mat-private-button-disabled();
72112
@include button-base.mat-private-button-touch-target(false);
73113
@include style-private.private-animation-noop();
74114
}

src/material/core/tokens/m2/mdc/_outlined-button.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,13 @@ $prefix: (mdc, outlined-button);
6464

6565
// Tokens that can be configured through Angular Material's color theming API.
6666
@function get-color-tokens($theme, $color: null, $on-color: null) {
67+
$is-dark: inspection.get-theme-type($theme) == dark;
6768
$surface: inspection.get-theme-color($theme, background, card);
6869
$on-surface: _on-color($theme, $surface);
6970

7071
@return (
7172
disabled-outline-color: rgba($on-surface, 0.12),
72-
disabled-label-text-color: rgba($on-surface, 0.38),
73+
disabled-label-text-color: rgba($on-surface, if($is-dark, 0.5, 0.38)),
7374
label-text-color: if($color, $color, inherit),
7475
outline-color: rgba($on-surface, 0.12)
7576
);

0 commit comments

Comments
 (0)