Skip to content

Commit 34ec567

Browse files
authored
refactor(material/button): handle disabled state of icon buttons through tokens (#27990)
* Fixes that icon buttons weren't using the right token for disabled state. * Fixes that the specificity of the icon button disabled styles was really high. * Moves the logic for generating the palette tokens into the icon button tokens file. * Fixes one place where we were referencing a token directly instead of using the API to generate the name.
1 parent a3f9ca1 commit 34ec567

File tree

4 files changed

+66
-49
lines changed

4 files changed

+66
-49
lines changed

src/dev-app/button/button-demo.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,25 @@ <h4 class="demo-section-header"> Icon Buttons [mat-icon-button]</h4>
150150
</button>
151151
</section>
152152

153+
<h4 class="demo-section-header"> Icon Button Anchors [mat-icon-button]</h4>
154+
<section>
155+
<a href="#" mat-icon-button>
156+
<mat-icon>cached</mat-icon>
157+
</a>
158+
<a href="#" mat-icon-button color="primary">
159+
<mat-icon>cached</mat-icon>
160+
</a>
161+
<a href="#" mat-icon-button color="accent">
162+
<mat-icon>backup</mat-icon>
163+
</a>
164+
<a href="#" mat-icon-button color="warn">
165+
<mat-icon>trending_up</mat-icon>
166+
</a>
167+
<a href="#" mat-icon-button disabled>
168+
<mat-icon>visibility</mat-icon>
169+
</a>
170+
</section>
171+
153172
<h4 class="demo-section-header">Fab Buttons [mat-fab]</h4>
154173
<section>
155174
<button mat-fab>

src/material/button/_icon-button-theme.scss

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
@use 'sass:math';
22
@use '@material/density/functions' as mdc-density-functions;
33
@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme;
4-
@use '@material/theme/theme-color' as mdc-theme-color;
54
@use '../core/tokens/m2/mdc/icon-button' as tokens-mdc-icon-button;
65

76
@use './button-theme-private';
@@ -10,64 +9,46 @@
109

1110
$_icon-size: 24px;
1211

12+
// TODO(crisbeto): move these into tokens
1313
@mixin _ripple-color($color) {
1414
--mat-mdc-button-persistent-ripple-color: #{$color};
1515
--mat-mdc-button-ripple-color: #{rgba($color, 0.1)};
1616
}
1717

18-
@function _variable-safe-contrast-tone($value, $is-dark) {
19-
@if ($value == 'dark' or $value == 'light' or type-of($value) == 'color') {
20-
@return mdc-theme-color.contrast-tone($value);
21-
}
22-
23-
@return if($is-dark, 'light', 'dark');
24-
}
25-
2618
@mixin base($theme) {
2719
// TODO(mmalerba): Move icon button base tokens here
2820
}
2921

3022
@mixin color($theme) {
3123
$color-tokens: tokens-mdc-icon-button.get-color-tokens($theme);
32-
$surface: inspection.get-theme-color($theme, background, card);
3324
$is-dark: inspection.get-theme-type($theme) == dark;
34-
$on-surface: if(_variable-safe-contrast-tone($surface, $is-dark) == 'dark', #000, #fff);
3525

3626
.mat-mdc-icon-button {
3727
@include button-theme-private.ripple-theme-styles($theme, false);
3828
@include mdc-icon-button-theme.theme($color-tokens);
39-
@include _ripple-color($on-surface);
29+
@include _ripple-color(if($is-dark, #fff, #000));
4030

4131
&.mat-primary {
42-
$color: inspection.get-theme-color($theme, primary);
43-
@include mdc-icon-button-theme.theme((icon-color: $color));
44-
@include _ripple-color($color);
32+
@include _ripple-color(inspection.get-theme-color($theme, primary));
33+
@include mdc-icon-button-theme.theme(
34+
tokens-mdc-icon-button.private-get-color-palette-color-tokens($theme, primary));
4535
}
4636

4737
&.mat-accent {
48-
$color: inspection.get-theme-color($theme, accent);
49-
@include mdc-icon-button-theme.theme((icon-color: $color));
50-
@include _ripple-color($color);
38+
@include _ripple-color(inspection.get-theme-color($theme, accent));
39+
@include mdc-icon-button-theme.theme(
40+
tokens-mdc-icon-button.private-get-color-palette-color-tokens($theme, accent));
5141
}
5242

5343
&.mat-warn {
54-
$color: inspection.get-theme-color($theme, warn);
55-
@include mdc-icon-button-theme.theme((icon-color: $color));
56-
@include _ripple-color($color);
57-
}
58-
59-
@include button-theme-private.apply-disabled-style() {
60-
$disabled-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
61-
@include mdc-icon-button-theme.theme((
62-
icon-color: $disabled-color,
63-
disabled-icon-color: $disabled-color,
64-
));
44+
@include _ripple-color(inspection.get-theme-color($theme, warn));
45+
@include mdc-icon-button-theme.theme(
46+
tokens-mdc-icon-button.private-get-color-palette-color-tokens($theme, warn));
6547
}
6648
}
6749
}
6850

69-
@mixin typography($theme) {
70-
}
51+
@mixin typography($theme) {}
7152

7253
@mixin density($theme) {
7354
$density-scale: inspection.get-theme-density($theme);

src/material/button/icon-button.scss

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme;
33
@use '@material/theme/custom-properties' as mdc-custom-properties;
44

5-
@use '../core/tokens/m2/mdc/icon-button' as m2-mdc-icon-button;
5+
@use '../core/tokens/m2/mdc/icon-button' as tokens-mdc-icon-button;
66

77
@use './button-base';
88
@use '../core/style/private';
9+
@use '../core/tokens/token-utils';
910

1011
// The slots for tokens that will be configured in the theme can be emitted with no fallback.
1112
@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
12-
$token-slots: m2-mdc-icon-button.get-token-slots();
13+
$token-slots: tokens-mdc-icon-button.get-token-slots();
1314

1415
// Add the MDC component static styles.
1516
@include mdc-icon-button.static-styles();
@@ -19,7 +20,7 @@
1920
@include mdc-icon-button-theme.theme-styles($token-slots);
2021

2122
// Add default values for tokens that aren't outputted by the theming API.
22-
@include mdc-icon-button-theme.theme(m2-mdc-icon-button.get-unthemable-tokens());
23+
@include mdc-icon-button-theme.theme(tokens-mdc-icon-button.get-unthemable-tokens());
2324
}
2425
}
2526

@@ -28,10 +29,6 @@
2829
// TODO: Determine how to enforce theming exists, otherwise padding will be unset.
2930
padding: 12px;
3031

31-
// Icon size used to be placed on the host element. Now, in `theme-styles` it is placed on
32-
// the unused `.mdc-button__icon` class. Explicitly set the font-size here.
33-
font-size: var(--mdc-icon-button-icon-size);
34-
3532
// Border radius is inherited by ripple to know its shape. Set to 50% so the ripple is round.
3633
border-radius: 50%;
3734

@@ -45,11 +42,18 @@
4542
vertical-align: baseline;
4643
}
4744

48-
@include button-base.mat-private-button-disabled() {
49-
// The color is already dimmed when the button is disabled. Restore the opacity both to
50-
// help with the color contrast and to align with what we had before switching to the new API.
51-
opacity: 1;
52-
};
45+
@include token-utils.use-tokens(
46+
tokens-mdc-icon-button.$prefix, tokens-mdc-icon-button.get-token-slots()) {
47+
// Icon size used to be placed on the host element. Now, in `theme-styles` it is placed on
48+
// the unused `.mdc-button__icon` class. Explicitly set the font-size here.
49+
@include token-utils.create-token-slot(font-size, icon-size);
50+
51+
@include button-base.mat-private-button-disabled {
52+
// MDC's disabled styles target the `:disabled` selector which doesn't work on links.
53+
// We re-apply the disabled icon color here since we support Material buttons on links too.
54+
@include token-utils.create-token-slot(color, disabled-icon-color);
55+
};
56+
}
5357

5458
@include button-base.mat-private-button-interactive();
5559
@include button-base.mat-private-button-touch-target(true);

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
@use 'sass:map';
12
@use '../../../style/sass-utils';
3+
@use '../../../theming/inspection';
24
@use '../../token-utils';
35

46
// The prefix used to generate the fully qualified name for tokens in this file.
@@ -20,12 +22,7 @@ $prefix: (mdc, icon-button);
2022
state-layer-size: 48px,
2123
// MDC's icon size applied to svg and img elements inside the component
2224
icon-size: 24px,
23-
// Only applies to :disabled icons, but Angular Components uses [disabled] since :disabled
24-
// wouldn't work on <a> tags.
25-
disabled-icon-color: black,
26-
// Angular version applies an opacity 1 with a color change, and this only applies with
27-
// :disabled anyways.
28-
disabled-icon-opacity: 0.38,
25+
2926
// =============================================================================================
3027
// = TOKENS NOT USED IN ANGULAR MATERIAL =
3128
// =============================================================================================
@@ -41,13 +38,29 @@ $prefix: (mdc, icon-button);
4138
pressed-state-layer-opacity: null,
4239
focus-ring-color: null,
4340
focus-ring-offset: null,
41+
42+
// We use a color with an opacity to show the disabled state,
43+
// instead of applying it to the entire button.
44+
disabled-icon-opacity: null,
4445
);
4546
}
4647

4748
// Tokens that can be configured through Angular Material's color theming API.
4849
@function get-color-tokens($theme) {
50+
$is-dark: inspection.get-theme-type($theme) == dark;
51+
4952
@return (
5053
icon-color: inherit,
54+
disabled-icon-color: if($is-dark, rgba(#fff, 0.5), rgba(#000, 0.38)),
55+
);
56+
}
57+
58+
// Generates the mapping for the properties that change based on the button palette color.
59+
@function private-get-color-palette-color-tokens($theme, $palette-name) {
60+
$palette: map.get($theme, $palette-name);
61+
62+
@return (
63+
icon-color: inspection.get-theme-color($theme, $palette-name)
5164
);
5265
}
5366

0 commit comments

Comments
 (0)