diff --git a/src/material-experimental/mdc-button/_button-base.scss b/src/material-experimental/mdc-button/_button-base.scss index 7c5cbfa28515..f0b0f8ee88ef 100644 --- a/src/material-experimental/mdc-button/_button-base.scss +++ b/src/material-experimental/mdc-button/_button-base.scss @@ -1,3 +1,4 @@ +@use 'sass:map'; @use '@material/touch-target' as mdc-touch-target; @use '../mdc-helpers/mdc-helpers'; @use '../../material/core/style/layout-common'; @@ -8,22 +9,10 @@ // ripple and state container so that they fill the button, match the border radius, and avoid // pointer events. @mixin mat-private-button-interactive() { - .mdc-button__ripple::before, .mdc-button__ripple::after, - .mdc-fab__ripple::before, .mdc-fab__ripple::after { - content: ''; - pointer-events: none; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - opacity: 0; - border-radius: inherit; - @content; - } - // The ripple container should match the bounds of the entire button. - .mat-mdc-button-ripple, .mdc-button__ripple, .mdc-fab__ripple { + .mat-mdc-button-ripple, + .mat-mdc-button-persistent-ripple, + .mat-mdc-button-persistent-ripple::before { @include layout-common.fill; // Disable pointer events for the ripple container and state overlay because the container @@ -38,6 +27,17 @@ border-radius: inherit; } + // We use ::before so that we can reuse some of MDC's theming. + .mat-mdc-button-persistent-ripple::before { + content: ''; + opacity: 0; + background-color: var(--mat-mdc-button-persistent-ripple-color); + } + + .mat-ripple-element { + background-color: var(--mat-mdc-button-ripple-color); + } + // The content should appear over the state and ripple layers, otherwise they may adversely affect // the accessibility of the text content. .mdc-button__label { @@ -59,6 +59,7 @@ &[disabled] { cursor: default; pointer-events: none; + @content; } } @@ -75,3 +76,15 @@ $query: mdc-helpers.$mat-base-styles-query); } } + +// Changes a button theme to exclude the ripple styles. +@function mat-private-button-remove-ripple($theme) { + @return map.merge($theme, ( + 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, + )); +} diff --git a/src/material-experimental/mdc-button/_button-theme-private.scss b/src/material-experimental/mdc-button/_button-theme-private.scss index 46b97177d996..742438150fd8 100644 --- a/src/material-experimental/mdc-button/_button-theme-private.scss +++ b/src/material-experimental/mdc-button/_button-theme-private.scss @@ -1,28 +1,43 @@ +@use 'sass:map'; +@use '@material/ripple/ripple-theme' as mdc-ripple-theme; @use '@material/theme/theme-color' as mdc-theme-color; -@use '@material/theme/theme' as mdc-theme; @use '../../material/core/ripple/ripple-theme'; -// Selector for the element that has a background color and opacity applied to its ::before and -// ::after for state interactions (hover, active, focus). Their API calls this their -// "ripple target", but we do not use it as our ripple, just state color. -$button-state-target: '.mdc-button__ripple'; -$fab-state-target: '.mdc-fab__ripple'; - -// The MDC button's ripple ink color is based on the theme color, not on the foreground base -// which is what the ripple mixin uses. This creates a new theme that sets the color to the -// foreground base to appropriately color the ink. -@mixin ripple-ink-color($mdc-color) { - @include ripple-theme.color(( - foreground: ( - base: mdc-theme-color.prop-value($mdc-color) - ), - )); +@mixin _ripple-color($color) { + --mat-mdc-button-persistent-ripple-color: #{$color}; + --mat-mdc-button-ripple-color: #{rgba($color, 0.1)}; } -// Applies the disabled theme color to the text color. -@mixin apply-disabled-color() { - @include mdc-theme.prop(color, - mdc-theme-color.ink-color-for-fill_(disabled, mdc-theme-color.$background)); +@mixin ripple-theme-styles($config, $is-filled) { + $opacities: if(map.get($config, is-dark), + mdc-ripple-theme.$light-ink-opacities, mdc-ripple-theme.$dark-ink-opacities); + + // Ideally these styles would be structural, but MDC bases some of the opacities on the theme. + &:hover .mat-mdc-button-persistent-ripple::before { + opacity: map.get($opacities, hover); + } + + &:focus .mat-mdc-button-persistent-ripple::before { + opacity: map.get($opacities, focus); + } + + &:active .mat-mdc-button-persistent-ripple::before { + opacity: map.get($opacities, press); + } + + @include _ripple-color(mdc-theme-color.prop-value(on-surface)); + + &.mat-primary { + @include _ripple-color(mdc-theme-color.prop-value(if($is-filled, on-primary, primary))); + } + + &.mat-accent { + @include _ripple-color(mdc-theme-color.prop-value(if($is-filled, on-secondary, secondary))); + } + + &.mat-warn { + @include _ripple-color(mdc-theme-color.prop-value(if($is-filled, on-error, error))); + } } // Wraps the content style in a selector for the disabled state. @@ -37,14 +52,6 @@ $fab-state-target: '.mdc-fab__ripple'; } } -// Applies the disabled theme background color for raised buttons. Value is taken from -// mixin `mdc-button--filled`. -// TODO(andrewseguin): Discuss with the MDC team about providing a variable for the 0.12 value -// or otherwise have a mixin we can call to apply this style for both button and anchors. -@mixin apply-disabled-background() { - @include mdc-theme.prop(background-color, rgba(mdc-theme-color.prop-value(on-surface), 0.12)); -} - // Hides the touch target on lower densities. @mixin touch-target-density($scale) { @if ($scale == -2 or $scale == 'minimum') { diff --git a/src/material-experimental/mdc-button/_button-theme.scss b/src/material-experimental/mdc-button/_button-theme.scss index 4f0df23e0872..9f4225d128ff 100644 --- a/src/material-experimental/mdc-button/_button-theme.scss +++ b/src/material-experimental/mdc-button/_button-theme.scss @@ -1,146 +1,181 @@ +@use 'sass:map'; @use '@material/button/button' as mdc-button; @use '@material/button/button-theme' as mdc-button-theme; -@use '@material/ripple/ripple-theme' as mdc-ripple-theme; +@use '@material/button/button-text-theme' as mdc-button-text-theme; +@use '@material/button/button-filled-theme' as mdc-button-filled-theme; +@use '@material/button/button-protected-theme' as mdc-button-protected-theme; +@use '@material/button/button-outlined-theme' as mdc-button-outlined-theme; @use '@material/theme/theme-color' as mdc-theme-color; -@use '@material/theme/theme' as mdc-theme; -@use '@material/elevation/elevation-theme' as mdc-elevation-theme; -@use '../../material/core/ripple/ripple-theme'; @use '../../material/core/typography/typography'; @use '../mdc-helpers/mdc-helpers'; @use '../../material/core/theming/theming'; @use './button-theme-private'; +@mixin _button-variant($color) { + @include mdc-button-text-theme.theme(( + label-text-color: $color, + )); +} + +@mixin _unelevated-button-variant($foreground, $background) { + @include mdc-button-filled-theme.theme(( + container-color: $background, + label-text-color: $foreground, + )); +} + +@mixin _raised-button-variant($foreground, $background) { + @include mdc-button-protected-theme.theme(( + container-color: $background, + label-text-color: $foreground, + )); +} + +@mixin _outlined-button-variant($color) { + @include mdc-button-outlined-theme.theme(( + label-text-color: $color, + outline-color: $color, + )); +} + @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); @include mdc-helpers.mat-using-mdc-theme($config) { - // Add state interactions for hover, focus, press, active. Colors are changed based on - // the mixin mdc-states-base-color - .mat-mdc-button, .mat-mdc-raised-button, .mat-mdc-unelevated-button, .mat-mdc-outlined-button { - @include mdc-ripple-theme.states( - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - } - - .mat-mdc-button, .mat-mdc-outlined-button { + $is-dark: map.get($config, is-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 mdc-button-theme.ink-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query); + @include _button-variant($on-surface); } &.mat-primary { - @include mdc-button-theme.ink-color(primary, $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(primary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include button-theme-private.ripple-ink-color(primary); + @include _button-variant($primary); } &.mat-accent { - @include mdc-button-theme.ink-color(secondary, $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(secondary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include button-theme-private.ripple-ink-color(secondary); + @include _button-variant($secondary); } &.mat-warn { - @include mdc-button-theme.ink-color(error, $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(error, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include button-theme-private.ripple-ink-color(error); + @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-raised-button, .mat-mdc-unelevated-button { &.mat-unthemed { - @include mdc-button-theme.container-fill-color(mdc-theme-color.$surface, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-button-theme.ink-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); + @include _unelevated-button-variant($on-surface, $surface); } &.mat-primary { - @include mdc-button-theme.container-fill-color(primary, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-button-theme.ink-color(on-primary, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(on-primary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include button-theme-private.ripple-ink-color(on-primary); + @include _unelevated-button-variant($on-primary, $primary); } &.mat-accent { - @include mdc-button-theme.container-fill-color(secondary, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-button-theme.ink-color(on-secondary, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(on-secondary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include button-theme-private.ripple-ink-color(on-secondary); + @include _unelevated-button-variant($on-secondary, $secondary); } &.mat-warn { - @include mdc-button-theme.container-fill-color(error, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-button-theme.ink-color(on-error, $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-ripple-theme.states-base-color(on-error, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include button-theme-private.ripple-ink-color(on-error); + @include _unelevated-button-variant($on-error, $error); } @include button-theme-private.apply-disabled-style() { - @include button-theme-private.apply-disabled-background(); + @include mdc-button-filled-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-container-color: $disabled-container-color, + disabled-label-text-color: $disabled-ink-color, + container-color: $disabled-container-color, + label-text-color: $disabled-ink-color, + )); } } - .mat-mdc-outlined-button { + .mat-mdc-raised-button { &.mat-unthemed { - @include mdc-button-theme.outline-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query); + @include _raised-button-variant($on-surface, $surface); } &.mat-primary { - @include mdc-button-theme.outline-color(primary, - $query: mdc-helpers.$mat-theme-styles-query); + @include _raised-button-variant($on-primary, $primary); } &.mat-accent { - @include mdc-button-theme.outline-color(secondary, - $query: mdc-helpers.$mat-theme-styles-query); + @include _raised-button-variant($on-secondary, $secondary); } &.mat-warn { - @include mdc-button-theme.outline-color(error, - $query: mdc-helpers.$mat-theme-styles-query); + @include _raised-button-variant($on-error, $error); } @include button-theme-private.apply-disabled-style() { - @include mdc-theme.prop(border-color, - mdc-theme-color.ink-color-for-fill_(disabled, mdc-theme-color.$background)); + @include mdc-button-protected-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-container-color: $disabled-container-color, + disabled-label-text-color: $disabled-ink-color, + container-color: $disabled-container-color, + label-text-color: $disabled-ink-color, + container-elevation: 0, + )); } } - .mat-mdc-raised-button { - @include button-theme-private.apply-disabled-style() { - @include mdc-elevation-theme.elevation(0, $query: mdc-helpers.$mat-theme-styles-query); + .mat-mdc-outlined-button { + &.mat-unthemed { + @include _outlined-button-variant($on-surface); + } + + &.mat-primary { + @include _outlined-button-variant($primary); + } + + &.mat-accent { + @include _outlined-button-variant($secondary); + } + + &.mat-warn { + @include _outlined-button-variant($error); } - } - .mat-mdc-button, .mat-mdc-raised-button, .mat-mdc-unelevated-button, .mat-mdc-outlined-button { @include button-theme-private.apply-disabled-style() { - @include button-theme-private.apply-disabled-color(); + @include mdc-button-outlined-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. + label-text-color: $disabled-ink-color, + outline-color: $disabled-ink-color, + disabled-label-text-color: $disabled-ink-color, + disabled-outline-color: $disabled-ink-color, + )); } } - @include mdc-button.without-ripple($query: mdc-helpers.$mat-theme-styles-query); + // Ripple colors + .mat-mdc-button, .mat-mdc-outlined-button { + @include button-theme-private.ripple-theme-styles($config, false); + } + + .mat-mdc-raised-button, .mat-mdc-unelevated-button { + @include button-theme-private.ripple-theme-styles($config, true); + } } } diff --git a/src/material-experimental/mdc-button/_fab-theme.scss b/src/material-experimental/mdc-button/_fab-theme.scss index 676fa8340ce3..68075b26bb35 100644 --- a/src/material-experimental/mdc-button/_fab-theme.scss +++ b/src/material-experimental/mdc-button/_fab-theme.scss @@ -1,68 +1,62 @@ +@use 'sass:map'; @use '@material/fab/fab' as mdc-fab; @use '@material/fab/fab-theme' as mdc-fab-theme; -@use '@material/ripple/ripple-theme' as mdc-ripple-theme; -@use '@material/elevation/elevation-theme' as mdc-elevation-theme; @use '@material/theme/theme-color' as mdc-theme-color; @use '../mdc-helpers/mdc-helpers'; @use '../../material/core/theming/theming'; @use '../../material/core/typography/typography'; @use './button-theme-private'; +@mixin _fab-variant($foreground, $background) { + @include mdc-fab-theme.theme(( + container-color: $background, + icon-color: $foreground, + )); + + --mat-mdc-fab-color: #{$foreground}; +} + @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); @include mdc-helpers.mat-using-mdc-theme($config) { + $on-surface: mdc-theme-color.prop-value(on-surface); + $is-dark: map.get($config, is-dark); + .mat-mdc-fab, .mat-mdc-mini-fab { - @include mdc-ripple-theme.states( - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$fab-state-target); + @include button-theme-private.ripple-theme-styles($config, true); &.mat-unthemed { - @include mdc-ripple-theme.states-base-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$fab-state-target); - @include mdc-fab-theme.container-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-fab-theme.ink-color(mdc-theme-color.$on-surface, - $query: mdc-helpers.$mat-theme-styles-query); + @include _fab-variant($on-surface, mdc-theme-color.prop-value(surface)); } &.mat-primary { - @include mdc-ripple-theme.states-base-color(on-primary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$fab-state-target); - @include mdc-fab-theme.container-color(primary, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-fab-theme.ink-color(on-primary, $query: mdc-helpers.$mat-theme-styles-query); - @include button-theme-private.ripple-ink-color(on-primary); + @include _fab-variant( + mdc-theme-color.prop-value(on-primary), + mdc-theme-color.prop-value(primary) + ); } &.mat-accent { - @include mdc-ripple-theme.states-base-color(on-secondary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$fab-state-target); - @include mdc-fab-theme.container-color(secondary, - $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-fab-theme.ink-color(on-secondary, $query: mdc-helpers.$mat-theme-styles-query); - @include button-theme-private.ripple-ink-color(on-secondary); + @include _fab-variant( + mdc-theme-color.prop-value(on-secondary), + mdc-theme-color.prop-value(secondary) + ); } &.mat-warn { - @include mdc-ripple-theme.states-base-color(on-error, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$fab-state-target); - @include mdc-fab-theme.container-color(error, $query: mdc-helpers.$mat-theme-styles-query); - @include mdc-fab-theme.ink-color(on-error, $query: mdc-helpers.$mat-theme-styles-query); - @include button-theme-private.ripple-ink-color(on-error); + @include _fab-variant( + mdc-theme-color.prop-value(on-error), + mdc-theme-color.prop-value(error) + ); } @include button-theme-private.apply-disabled-style() { - @include button-theme-private.apply-disabled-color(); - @include button-theme-private.apply-disabled-background(); - @include mdc-elevation-theme.elevation(0, $query: mdc-helpers.$mat-theme-styles-query); + @include _fab-variant( + rgba($on-surface, if(map.get($config, is-dark), 0.5, 0.38)), + rgba($on-surface, 0.12) + ); } } - - @include mdc-fab.without-ripple($query: mdc-helpers.$mat-theme-styles-query); } } diff --git a/src/material-experimental/mdc-button/_icon-button-theme.scss b/src/material-experimental/mdc-button/_icon-button-theme.scss index 16196ca888db..e69cb94f0dad 100644 --- a/src/material-experimental/mdc-button/_icon-button-theme.scss +++ b/src/material-experimental/mdc-button/_icon-button-theme.scss @@ -1,5 +1,7 @@ +@use 'sass:map'; @use '@material/icon-button/mixins' as mdc-icon-button; -@use '@material/ripple/ripple-theme' as mdc-ripple-theme; +@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme; +@use '@material/theme/theme-color' as mdc-theme-color; @use '../mdc-helpers/mdc-helpers'; @use '../../material/core/theming/theming'; @use '../../material/core/typography/typography'; @@ -8,41 +10,32 @@ @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); @include mdc-helpers.mat-using-mdc-theme($config) { + $is-dark: map.get($config, is-dark); + $on-surface: mdc-theme-color.prop-value(on-surface); + $disabled-color: rgba($on-surface, if($is-dark, 0.5, 0.38)); + .mat-mdc-icon-button { - @include mdc-ripple-theme.states( - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); + @include button-theme-private.ripple-theme-styles($config, false); &.mat-primary { - @include mdc-ripple-theme.states-base-color(primary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include mdc-icon-button.ink-color(primary, $query: mdc-helpers.$mat-theme-styles-query); - @include button-theme-private.ripple-ink-color(primary); + @include mdc-icon-button-theme.theme((icon-color: mdc-theme-color.prop-value(primary))); } &.mat-accent { - @include mdc-ripple-theme.states-base-color(secondary, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include mdc-icon-button.ink-color(secondary, $query: mdc-helpers.$mat-theme-styles-query); - @include button-theme-private.ripple-ink-color(secondary); + @include mdc-icon-button-theme.theme((icon-color: mdc-theme-color.prop-value(secondary))); } &.mat-warn { - @include mdc-ripple-theme.states-base-color(error, - $query: mdc-helpers.$mat-theme-styles-query, - $ripple-target: button-theme-private.$button-state-target); - @include mdc-icon-button.ink-color(error, $query: mdc-helpers.$mat-theme-styles-query); - @include button-theme-private.ripple-ink-color(error); + @include mdc-icon-button-theme.theme((icon-color: (mdc-theme-color.prop-value(error)))); } @include button-theme-private.apply-disabled-style() { - @include button-theme-private.apply-disabled-color(); + @include mdc-icon-button-theme.theme(( + icon-color: $disabled-color, + disabled-icon-color: $disabled-color, + )); } } - - @include mdc-icon-button.without-ripple($query: mdc-helpers.$mat-theme-styles-query); } } diff --git a/src/material-experimental/mdc-button/button-base.ts b/src/material-experimental/mdc-button/button-base.ts index a288955246f1..9d6806a1de71 100644 --- a/src/material-experimental/mdc-button/button-base.ts +++ b/src/material-experimental/mdc-button/button-base.ts @@ -85,12 +85,12 @@ export class MatButtonBase extends _MatButtonMixin implements CanDisable, CanColor, CanDisableRipple { - /** Whether the ripple is centered on the button. */ - _isRippleCentered = false; - /** Whether this button is a FAB. Used to apply the correct class on the ripple. */ _isFab = false; + /** Whether this button is an icon button. Used to apply the correct class on the ripple. */ + _isIconButton = false; + /** Reference to the MatRipple instance of the button. */ @ViewChild(MatRipple) ripple: MatRipple; diff --git a/src/material-experimental/mdc-button/button.html b/src/material-experimental/mdc-button/button.html index acca8bffd4c9..d8644898e680 100644 --- a/src/material-experimental/mdc-button/button.html +++ b/src/material-experimental/mdc-button/button.html @@ -1,6 +1,8 @@ + class="mat-mdc-button-persistent-ripple" + [class.mdc-button__ripple]="!_isFab && !_isIconButton" + [class.mdc-fab__ripple]="_isFab" + [class.mdc-icon-button__ripple]="_isIconButton"> @@ -18,7 +20,7 @@ diff --git a/src/material-experimental/mdc-button/button.scss b/src/material-experimental/mdc-button/button.scss index 72c072e85aa0..04972576ee79 100644 --- a/src/material-experimental/mdc-button/button.scss +++ b/src/material-experimental/mdc-button/button.scss @@ -1,10 +1,55 @@ +@use 'sass:map'; @use '@material/button/button' as mdc-button; +@use '@material/button/button-base' as mdc-button-base; @use '@material/button/variables' as mdc-button-variables; +@use '@material/button/button-text-theme' as mdc-button-text-theme; +@use '@material/button/button-filled-theme' as mdc-button-filled-theme; +@use '@material/button/button-protected-theme' as mdc-button-protected-theme; +@use '@material/button/button-outlined-theme' as mdc-button-outlined-theme; @use '../../material/core/style/private'; @use '../mdc-helpers/mdc-helpers'; @use 'button-base'; -@include mdc-button.without-ripple($query: mdc-helpers.$mat-base-styles-query); +@include mdc-helpers.disable-fallback-declarations { + @include mdc-button.static-styles-without-ripple($query: mdc-helpers.$mat-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-unelevated-button { + @include mdc-button-filled-theme.theme-styles( + map.merge(map.merge(mdc-button-filled-theme.$light-theme, $override-keys), ( + container-color: transparent, + ))); + } + + .mat-mdc-raised-button { + @include mdc-button-protected-theme.theme-styles( + map.merge(map.merge(mdc-button-protected-theme.$light-theme, $override-keys), ( + container-color: transparent, + ))); + } + + .mat-mdc-outlined-button { + @include mdc-button-outlined-theme.theme-styles( + map.merge(mdc-button-outlined-theme.$light-theme, $override-keys)); + } +} .mat-mdc-button, .mat-mdc-unelevated-button, @@ -24,10 +69,10 @@ // mixins will style the icons appropriately. .mat-mdc-button { .mat-icon { - @include mdc-button.icon(); + @include mdc-button-base.icon(); } .mdc-button__label + .mat-icon { - @include mdc-button.icon-trailing(); + @include mdc-button-base.icon-trailing(); } } @@ -36,12 +81,12 @@ .mat-mdc-outlined-button { // Icons inside contained buttons have different styles due to increased button padding .mat-icon { - @include mdc-button.icon(); - @include mdc-button.icon-contained(); + @include mdc-button-base.icon(); + @include mdc-button-base.icon-contained(); } .mdc-button__label + .mat-icon { - @include mdc-button.icon-contained-trailing(); + @include mdc-button-base.icon-contained-trailing(); } } diff --git a/src/material-experimental/mdc-button/fab.scss b/src/material-experimental/mdc-button/fab.scss index b93fe1dbcdf5..cba815029ef9 100644 --- a/src/material-experimental/mdc-button/fab.scss +++ b/src/material-experimental/mdc-button/fab.scss @@ -1,16 +1,49 @@ @use '@material/fab' as mdc-fab; +@use '@material/elevation/elevation-theme' as mdc-elevation-theme; @use '../../material/core/style/private'; @use '../mdc-helpers/mdc-helpers'; -@use 'button-base'; +@use './button-base'; -@include mdc-fab.without-ripple($query: mdc-helpers.$mat-base-styles-query); +@include mdc-helpers.disable-fallback-declarations { + @include mdc-fab.without-ripple($query: mdc-helpers.$mat-base-styles-query); +} .mat-mdc-fab, .mat-mdc-mini-fab { @include button-base.mat-private-button-interactive(); - @include button-base.mat-private-button-disabled(); @include button-base.mat-private-button-touch-target(true); @include private.private-animation-noop(); + @include mdc-helpers.disable-fallback-declarations { + // Theme configuration is copied over from MDC, because it isn't exported + @include mdc-fab.theme-styles(button-base.mat-private-button-remove-ripple(( + container-color: transparent, + container-shape: mdc-fab.$shape-radius, + icon-color: inherit, + ))); + + // TODO(crisbeto): the elevation can be controlled using `container-elevation` in `theme-styles` + // however when it is passed in, MDC throws an error that `container-shadow-color` isn't + // passed in. When `container-shadow-color` is passed in, MDC throws another error, because + // the produced value isn't valid CSS. Eventually we should switch to it once it's fixed. + @include mdc-elevation-theme.elevation(6); + + &:hover, &:focus { + @include mdc-elevation-theme.elevation(8); + } + + &:active, &:focus:active { + @include mdc-elevation-theme.elevation(12); + } + + @include button-base.mat-private-button-disabled { + @include mdc-elevation-theme.elevation(0); + } + } + + // TODO(crisbeto): `theme-styles` doesn't allow for the color to be controlled. Define a custom + // variable for now so we have something to target. + color: var(--mat-mdc-fab-color, inherit); + // Prevent the button from shrinking since it's always supposed to be a circle. flex-shrink: 0; diff --git a/src/material-experimental/mdc-button/icon-button.scss b/src/material-experimental/mdc-button/icon-button.scss index 379c22de9356..e94bffff67c7 100644 --- a/src/material-experimental/mdc-button/icon-button.scss +++ b/src/material-experimental/mdc-button/icon-button.scss @@ -1,15 +1,27 @@ +@use 'sass:map'; @use '@material/icon-button/icon-button' as mdc-icon-button; +@use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme; @use '../../material/core/style/private'; @use '../mdc-helpers/mdc-helpers'; @use 'button-base'; -@include mdc-icon-button.without-ripple( - $query: mdc-helpers.$mat-base-styles-query -); +@include mdc-helpers.disable-fallback-declarations { + @include mdc-icon-button.without-ripple($query: mdc-helpers.$mat-base-styles-query); +} .mat-mdc-icon-button { - @include button-base.mat-private-button-interactive() { - border-radius: 50%; + @include mdc-helpers.disable-fallback-declarations { + $theme-overrides: button-base.mat-private-button-remove-ripple(( + icon-color: inherit, + // We don't change the color on focus/hover so exclude + // these styles both to reduce bundle size and specificity. + focus-icon-color: null, + hover-icon-color: null, + pressed-icon-color: null, + )); + + @include mdc-icon-button-theme.theme-styles( + map.merge(mdc-icon-button-theme.$light-theme, $theme-overrides)); } // Border radius is inherited by ripple to know its shape. Set to 50% so the ripple is round. @@ -18,10 +30,20 @@ // Prevent the button from shrinking since it's always supposed to be a circle. flex-shrink: 0; - @include button-base.mat-private-button-disabled(); + @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 button-base.mat-private-button-interactive(); @include button-base.mat-private-button-touch-target(true); @include private.private-animation-noop(); + .mat-mdc-button-persistent-ripple { + border-radius: 50%; + } + // MDC adds some styles to icon buttons that conflict with some of our focus indicator styles // and don't actually do anything. This undoes those conflicting styles. &.mat-unthemed, diff --git a/src/material-experimental/mdc-button/icon-button.ts b/src/material-experimental/mdc-button/icon-button.ts index d9bf4e8aae6e..548875a196b8 100644 --- a/src/material-experimental/mdc-button/icon-button.ts +++ b/src/material-experimental/mdc-button/icon-button.ts @@ -43,8 +43,7 @@ import { changeDetection: ChangeDetectionStrategy.OnPush, }) export class MatIconButton extends MatButtonBase { - // Set the ripple to be centered for icon buttons - override _isRippleCentered = true; + override _isIconButton = true; constructor( elementRef: ElementRef, @@ -72,8 +71,7 @@ export class MatIconButton extends MatButtonBase { changeDetection: ChangeDetectionStrategy.OnPush, }) export class MatIconAnchor extends MatAnchorBase { - // Set the ripple to be centered for icon buttons - override _isRippleCentered = true; + override _isIconButton = true; constructor( elementRef: ElementRef,