Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(material/button): handle disabled state of icon buttons through tokens #27990

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/dev-app/button/button-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,25 @@ <h4 class="demo-section-header"> Icon Buttons [mat-icon-button]</h4>
</button>
</section>

<h4 class="demo-section-header"> Icon Button Anchors [mat-icon-button]</h4>
<section>
<a href="#" mat-icon-button>
<mat-icon>cached</mat-icon>
</a>
<a href="#" mat-icon-button color="primary">
<mat-icon>cached</mat-icon>
</a>
<a href="#" mat-icon-button color="accent">
<mat-icon>backup</mat-icon>
</a>
<a href="#" mat-icon-button color="warn">
<mat-icon>trending_up</mat-icon>
</a>
<a href="#" mat-icon-button disabled>
<mat-icon>visibility</mat-icon>
</a>
</section>

<h4 class="demo-section-header">Fab Buttons [mat-fab]</h4>
<section>
<button mat-fab>
Expand Down
43 changes: 12 additions & 31 deletions src/material/button/_icon-button-theme.scss
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
@use 'sass:math';
@use '@material/density/functions' as mdc-density-functions;
@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme;
@use '@material/theme/theme-color' as mdc-theme-color;
@use '../core/tokens/m2/mdc/icon-button' as tokens-mdc-icon-button;

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

$_icon-size: 24px;

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

@function _variable-safe-contrast-tone($value, $is-dark) {
@if ($value == 'dark' or $value == 'light' or type-of($value) == 'color') {
@return mdc-theme-color.contrast-tone($value);
}

@return if($is-dark, 'light', 'dark');
}

@mixin base($theme) {
// TODO(mmalerba): Move icon button base tokens here
}

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

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

&.mat-primary {
$color: inspection.get-theme-color($theme, primary);
@include mdc-icon-button-theme.theme((icon-color: $color));
@include _ripple-color($color);
@include _ripple-color(inspection.get-theme-color($theme, primary));
@include mdc-icon-button-theme.theme(
tokens-mdc-icon-button.private-get-color-palette-color-tokens($theme, primary));
}

&.mat-accent {
$color: inspection.get-theme-color($theme, accent);
@include mdc-icon-button-theme.theme((icon-color: $color));
@include _ripple-color($color);
@include _ripple-color(inspection.get-theme-color($theme, accent));
@include mdc-icon-button-theme.theme(
tokens-mdc-icon-button.private-get-color-palette-color-tokens($theme, accent));
}

&.mat-warn {
$color: inspection.get-theme-color($theme, warn);
@include mdc-icon-button-theme.theme((icon-color: $color));
@include _ripple-color($color);
}

@include button-theme-private.apply-disabled-style() {
$disabled-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
@include mdc-icon-button-theme.theme((
icon-color: $disabled-color,
disabled-icon-color: $disabled-color,
));
@include _ripple-color(inspection.get-theme-color($theme, warn));
@include mdc-icon-button-theme.theme(
tokens-mdc-icon-button.private-get-color-palette-color-tokens($theme, warn));
}
}
}

@mixin typography($theme) {
}
@mixin typography($theme) {}

@mixin density($theme) {
$density-scale: inspection.get-theme-density($theme);
Expand Down
28 changes: 16 additions & 12 deletions src/material/button/icon-button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme;
@use '@material/theme/custom-properties' as mdc-custom-properties;

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

@use './button-base';
@use '../core/style/private';
@use '../core/tokens/token-utils';

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

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

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

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

// Icon size used to be placed on the host element. Now, in `theme-styles` it is placed on
// the unused `.mdc-button__icon` class. Explicitly set the font-size here.
font-size: var(--mdc-icon-button-icon-size);

// Border radius is inherited by ripple to know its shape. Set to 50% so the ripple is round.
border-radius: 50%;

Expand All @@ -45,11 +42,18 @@
vertical-align: baseline;
}

@include button-base.mat-private-button-disabled() {
// The color is already dimmed when the button is disabled. Restore the opacity both to
// help with the color contrast and to align with what we had before switching to the new API.
opacity: 1;
};
@include token-utils.use-tokens(
tokens-mdc-icon-button.$prefix, tokens-mdc-icon-button.get-token-slots()) {
// Icon size used to be placed on the host element. Now, in `theme-styles` it is placed on
// the unused `.mdc-button__icon` class. Explicitly set the font-size here.
@include token-utils.create-token-slot(font-size, icon-size);

@include button-base.mat-private-button-disabled {
// MDC's disabled styles target the `:disabled` selector which doesn't work on links.
// We re-apply the disabled icon color here since we support Material buttons on links too.
@include token-utils.create-token-slot(color, disabled-icon-color);
};
}

@include button-base.mat-private-button-interactive();
@include button-base.mat-private-button-touch-target(true);
Expand Down
25 changes: 19 additions & 6 deletions src/material/core/tokens/m2/mdc/_icon-button.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@use 'sass:map';
@use '../../../style/sass-utils';
@use '../../../theming/inspection';
@use '../../token-utils';

// The prefix used to generate the fully qualified name for tokens in this file.
Expand All @@ -20,12 +22,7 @@ $prefix: (mdc, icon-button);
state-layer-size: 48px,
// MDC's icon size applied to svg and img elements inside the component
icon-size: 24px,
// Only applies to :disabled icons, but Angular Components uses [disabled] since :disabled
// wouldn't work on <a> tags.
disabled-icon-color: black,
// Angular version applies an opacity 1 with a color change, and this only applies with
// :disabled anyways.
disabled-icon-opacity: 0.38,

// =============================================================================================
// = TOKENS NOT USED IN ANGULAR MATERIAL =
// =============================================================================================
Expand All @@ -41,13 +38,29 @@ $prefix: (mdc, icon-button);
pressed-state-layer-opacity: null,
focus-ring-color: null,
focus-ring-offset: null,

// We use a color with an opacity to show the disabled state,
// instead of applying it to the entire button.
disabled-icon-opacity: null,
);
}

// Tokens that can be configured through Angular Material's color theming API.
@function get-color-tokens($theme) {
$is-dark: inspection.get-theme-type($theme) == dark;

@return (
icon-color: inherit,
disabled-icon-color: if($is-dark, rgba(#fff, 0.5), rgba(#000, 0.38)),
);
}

// Generates the mapping for the properties that change based on the button palette color.
@function private-get-color-palette-color-tokens($theme, $palette-name) {
$palette: map.get($theme, $palette-name);

@return (
icon-color: inspection.get-theme-color($theme, $palette-name)
);
}

Expand Down
Loading