Skip to content

Commit

Permalink
refactor(material/button): switch text button to tokens for color and…
Browse files Browse the repository at this point in the history
… density

Switches the color and density styles for the text button to tokens.
  • Loading branch information
crisbeto committed Oct 12, 2023
1 parent 702ccbe commit 6f8039b
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 57 deletions.
73 changes: 34 additions & 39 deletions src/material/button/_button-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,13 @@
@use '../core/typography/typography';
@use '../core/tokens/m2/mdc/filled-button' as tokens-mdc-filled-button;
@use '../core/tokens/m2/mdc/protected-button' as tokens-mdc-protected-button;
@use '../core/tokens/m2/mdc/text-button' as tokens-mdc-text-button;

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

@mixin _button-variant($color) {
@include mdc-button-text-theme.theme((
label-text-color: $color,
));
}

@mixin _outlined-button-variant($color) {
@include mdc-button-outlined-theme.theme((
label-text-color: $color,
Expand All @@ -40,42 +35,10 @@
@include mdc-helpers.using-mdc-theme($theme) {
$is-dark: inspection.get-theme-type($theme) == dark;
$on-surface: mdc-theme-color.prop-value(on-surface);
$surface: mdc-theme-color.prop-value(surface);
$disabled-ink-color: rgba($on-surface, if($is-dark, 0.5, 0.38));
$disabled-container-color: rgba($on-surface, 0.12);
$primary: mdc-theme-color.prop-value(primary);
$on-primary: mdc-theme-color.prop-value(on-primary);
$secondary: mdc-theme-color.prop-value(secondary);
$on-secondary: mdc-theme-color.prop-value(on-secondary);
$error: mdc-theme-color.prop-value(error);
$on-error: mdc-theme-color.prop-value(on-error);

.mat-mdc-button {
&.mat-unthemed {
@include _button-variant($on-surface);
}

&.mat-primary {
@include _button-variant($primary);
}

&.mat-accent {
@include _button-variant($secondary);
}

&.mat-warn {
@include _button-variant($error);
}

@include button-theme-private.apply-disabled-style() {
@include mdc-button-text-theme.theme((
// We need to pass both the disabled and enabled values, because the enabled
// ones apply to anchors while the disabled ones are for buttons.
disabled-label-text-color: $disabled-ink-color,
label-text-color: $disabled-ink-color
));
}
}

.mat-mdc-outlined-button {
@include mdc-button-outlined-theme.theme((
Expand Down Expand Up @@ -130,6 +93,25 @@
$on-accent: _on-color($theme, $accent);
$on-error: _on-color($theme, $error);

.mat-mdc-button {
@include mdc-button-text-theme.theme(tokens-mdc-text-button.get-color-tokens($theme));

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

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

&.mat-warn {
@include mdc-button-text-theme.theme(
tokens-mdc-text-button.private-get-color-palette-color-tokens($theme, warn));
}
}

.mat-mdc-unelevated-button {
$default-color-tokens: tokens-mdc-filled-button.get-color-tokens($theme, $surface, $on-surface);
$primary-color-tokens: tokens-mdc-filled-button.get-color-tokens($theme, $primary, $on-primary);
Expand Down Expand Up @@ -234,6 +216,20 @@
@mixin density($theme) {
$density-scale: theming.clamp-density(inspection.get-theme-density($theme), -3);

.mat-mdc-button {
$density-tokens: tokens-mdc-text-button.get-density-tokens($theme);
@include mdc-button-text-theme.theme($density-tokens);
@include button-theme-private.touch-target-density($density-scale);

// TODO(crisbeto): before the introduction of tokens, MDC's density mixin was adding
// `margin-top: 0` and `margin-bottom: 0` in its `density` mixin which a lot of internal
// clients came to depend upon. Preserve it to make tokens easier to land.
@if ($density-scale < 0) {
margin-top: 0;
margin-bottom: 0;
}
}

.mat-mdc-raised-button {
$density-tokens: tokens-mdc-protected-button.get-density-tokens($theme);
@include mdc-button-protected-theme.theme($density-tokens);
Expand All @@ -246,7 +242,6 @@
@include button-theme-private.touch-target-density($density-scale);
}

.mat-mdc-button,
.mat-mdc-outlined-button {
// Use `mat-mdc-button-base` to increase the specificity over the button's structural styles.
&.mat-mdc-button-base {
Expand Down
46 changes: 28 additions & 18 deletions src/material/button/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,39 +10,49 @@

@use './button-base';
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/tokens/token-utils';
@use '../core/style/private' as style-private;
@use '../core/focus-indicators/private' as focus-indicators-private;
@use '../core/tokens/m2/mdc/filled-button' as tokens-mdc-filled-button;
@use '../core/tokens/m2/mdc/protected-button' as tokens-mdc-protected-button;
@use '../core/tokens/m2/mdc/text-button' as tokens-mdc-text-button;

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

// Keys to exclude from the MDC theme config, allowing us to drop styles we don't need.
$override-keys: button-base.mat-private-button-remove-ripple((
label-text-font: null,
label-text-size: null,
label-text-tracking: null,
label-text-transform: null,
label-text-weight: null,
with-icon-icon-size: null,
label-text-color: inherit,
));

// Note that we don't include a feature query, because this mixins declare
// all the "slots" for CSS variables that will be defined in the theme.
.mat-mdc-button {
@include mdc-button-text-theme.theme-styles(
map.merge(mdc-button-text-theme.$light-theme, $override-keys));
}

.mat-mdc-outlined-button {
// Keys to exclude from the MDC theme config, allowing us to drop styles we don't need.
$override-keys: button-base.mat-private-button-remove-ripple((
label-text-font: null,
label-text-size: null,
label-text-tracking: null,
label-text-transform: null,
label-text-weight: null,
with-icon-icon-size: null,
label-text-color: inherit,
));

@include mdc-button-outlined-theme.theme-styles(
map.merge(mdc-button-outlined-theme.$light-theme, $override-keys));
}
}

@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) {
$text-button-slot: tokens-mdc-text-button.get-token-slots();

.mat-mdc-button {
@include mdc-button-text-theme.theme-styles($text-button-slot);
@include mdc-button-text-theme.theme(tokens-mdc-text-button.get-unthemable-tokens());
}

// MDC uses `:disabled` for disabled styling which doesn't work on anchors.
// Override the color to point to the correct disabled color token.
a.mat-mdc-button[disabled] {
@include token-utils.use-tokens(tokens-mdc-text-button.$prefix, $text-button-slot) {
color: var(#{token-utils.get-token-variable(disabled-label-text-color)});
}
}

// Note that we don't include a feature query, because this mixins declare
// all the "slots" for CSS variables that will be defined in the theme.
.mat-mdc-unelevated-button {
Expand Down
99 changes: 99 additions & 0 deletions src/material/core/tokens/m2/mdc/_text-button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
@use 'sass:map';
@use '../../token-utils';
@use '../../../style/sass-utils';
@use '../../../theming/inspection';
@use '../../../theming/theming';

// The prefix used to generate the fully qualified name for tokens in this file.
$prefix: (mdc, text-button);

// Tokens that can't be configured through Angular Material's current theming API,
// but may be in a future version of the theming API.
//
// Tokens that are available in MDC, but not used in Angular Material should be mapped to `null`.
// `null` indicates that we are intentionally choosing not to emit a slot or value for the token in
// our CSS.
@function get-unthemable-tokens() {
@return (
container-shape: 4px,

// TODO: handle these through the typography styles eventually.
label-text-font: null,
label-text-size: null,
label-text-tracking: null,
label-text-transform: null,
label-text-weight: null,

// =============================================================================================
// = TOKENS NOT USED IN ANGULAR MATERIAL =
// =============================================================================================
hover-label-text-color: null,
focus-label-text-color: null,
pressed-label-text-color: null,
focus-state-layer-color: null,
focus-state-layer-opacity: null,
hover-state-layer-color: null,
hover-state-layer-opacity: null,
pressed-state-layer-color: null,
pressed-state-layer-opacity: null,
with-icon-disabled-icon-color: null,
with-icon-focus-icon-color: null,
with-icon-hover-icon-color: null,
with-icon-icon-color: null,
with-icon-icon-size: null,
with-icon-pressed-icon-color: null,
focus-ring-color: null,
focus-ring-offset: null,
keep-touch-target: false,
);
}

// 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;
$on-surface: if($is-dark, #fff, #000);

@return (
label-text-color: $on-surface,
disabled-label-text-color: rgba($on-surface, if($is-dark, 0.5, 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 (
label-text-color: inspection.get-theme-color($theme, $palette-name)
);
}

// Tokens that can be configured through Angular Material's typography theming API.
@function get-typography-tokens($theme) {
@return ();
}

// Tokens that can be configured through Angular Material's density theming API.
@function get-density-tokens($theme) {
$scale: theming.clamp-density(inspection.get-theme-density($theme), -3);

@return (
container-height: map.get((
0: 36px,
-1: 32px,
-2: 28px,
-3: 24px,
), $scale),
);
}

// Combines the tokens generated by the above functions into a single map with placeholder values.
// This is used to create token slots.
@function get-token-slots() {
@return sass-utils.deep-merge-all(
get-unthemable-tokens(),
get-color-tokens(token-utils.$placeholder-color-config),
get-typography-tokens(token-utils.$placeholder-typography-config),
get-density-tokens(token-utils.$placeholder-density-config)
);
}
7 changes: 7 additions & 0 deletions src/material/core/tokens/tests/test-validate-tokens.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

@use '@material/button/button-protected-theme' as mdc-button-protected-theme;
@use '@material/button/button-filled-theme' as mdc-button-filled-theme;
@use '@material/button/button-text-theme' as mdc-button-text-theme;
@use '@material/card/elevated-card-theme' as mdc-elevated-card-theme;
@use '@material/card/outlined-card-theme' as mdc-outlined-card-theme;
@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme;
Expand All @@ -27,6 +28,7 @@

@use '../m2/mdc/protected-button' as tokens-mdc-protected-button;
@use '../m2/mdc/filled-button' as tokens-mdc-filled-button;
@use '../m2/mdc/text-button' as tokens-mdc-text-button;
@use '../m2/mdc/circular-progress' as tokens-mdc-circular-progress;
@use '../m2/mdc/linear-progress' as tokens-mdc-linear-progress;
@use '../m2/mdc/elevated-card' as tokens-mdc-elevated-card;
Expand Down Expand Up @@ -170,3 +172,8 @@
$slots: tokens-mdc-protected-button.get-token-slots(),
$reference: mdc-button-protected-theme.$light-theme
);
@include validate-slots(
$component: 'm2.mdc.text-button',
$slots: tokens-mdc-text-button.get-token-slots(),
$reference: mdc-button-text-theme.$light-theme
);

0 comments on commit 6f8039b

Please sign in to comment.