diff --git a/src/material/button/_fab-theme.scss b/src/material/button/_fab-theme.scss index 8583d1822f37..3f667eaf0fd3 100644 --- a/src/material/button/_fab-theme.scss +++ b/src/material/button/_fab-theme.scss @@ -9,6 +9,8 @@ @use '../core/theming/inspection'; @use '../core/tokens/m2/mdc/fab' as tokens-mdc-fab; @use '../core/tokens/m2/mdc/extended-fab' as tokens-mdc-extended-fab; +@use '../core/tokens/m2/mat/fab' as tokens-mat-fab; +@use '../core/tokens/token-utils'; @use '../core/typography/typography'; @mixin base($theme) { @@ -21,37 +23,25 @@ } } -@mixin _fab-variant($foreground, $background) { - $color-tokens: ( - container-color: $background, - icon-color: $foreground +@mixin _fab-variant($theme, $palette) { + $mdc-tokens: if($palette, + tokens-mdc-fab.private-get-color-palette-color-tokens($theme, $palette), + tokens-mdc-fab.get-color-tokens($theme) ); - @include mdc-fab-theme.theme($color-tokens); - --mat-mdc-fab-color: #{$foreground}; -} + $mat-tokens: if($palette, + tokens-mat-fab.private-get-color-palette-color-tokens($theme, $palette), + tokens-mat-fab.get-color-tokens($theme) + ); -@function white-or-black($color, $is-dark) { - @return if(mdc-helpers.variable-safe-contrast-tone($color, $is-dark) == 'dark', #000, #fff); + @include mdc-fab-theme.theme($mdc-tokens); + @include token-utils.create-token-values(tokens-mat-fab.$prefix, $mat-tokens); } @mixin color($theme) { - $is-dark: inspection.get-theme-type($theme) == dark; - - $surface: inspection.get-theme-color($theme, background, card); - $primary: inspection.get-theme-color($theme, primary); - $accent: inspection.get-theme-color($theme, accent); - $warn: inspection.get-theme-color($theme, warn); - - $on-surface: white-or-black($surface, $is-dark); - $on-primary: white-or-black($primary, $is-dark); - $on-accent: white-or-black($accent, $is-dark); - $on-warn: white-or-black($warn, $is-dark); - - $disabled: rgba($on-surface, 0.12); - $on-disabled: rgba($on-surface, if($is-dark, 0.5, 0.38)); - @include sass-utils.current-selector-or-root() { + @include _fab-variant($theme, null); + // TODO(wagnermaciel): The ripple-theme-styles mixin depends heavily on // being wrapped by using-mdc-theme. This workaround needs to be // revisited w/ a more holistic solution. @@ -60,28 +50,18 @@ @include mdc-helpers.using-mdc-theme($theme) { @include button-theme-private.ripple-theme-styles($theme, true); } - } - :disabled, a[disabled='true'] { - @include button-theme-private.apply-disabled-style() { - @include _fab-variant($on-disabled, $disabled); + &.mat-primary { + @include _fab-variant($theme, primary); } - } - - .mat-unthemed { - @include _fab-variant($on-surface, $surface); - } - - .mat-primary { - @include _fab-variant($on-primary, $primary); - } - .mat-accent { - @include _fab-variant($on-accent, $accent); - } + &.mat-accent { + @include _fab-variant($theme, accent); + } - .mat-warn { - @include _fab-variant($on-warn, $warn); + &.mat-warn { + @include _fab-variant($theme, warn); + } } } } diff --git a/src/material/button/fab.scss b/src/material/button/fab.scss index 581cb7bcb32e..3902c2b50304 100644 --- a/src/material/button/fab.scss +++ b/src/material/button/fab.scss @@ -1,19 +1,21 @@ @use '@material/fab' as mdc-fab; @use '@material/fab/extended-fab-theme' as mdc-extended-fab-theme; @use '@material/fab/fab-theme' as mdc-fab-theme; -@use '@material/elevation/elevation-theme' as mdc-elevation-theme; @use '@material/theme/custom-properties' as mdc-custom-properties; @use './button-base'; +@use '../core/style/elevation'; @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/extended-fab' as m2-mdc-extended-fab; -@use '../core/tokens/m2/mdc/fab' as m2-mdc-fab; +@use '../core/tokens/m2/mdc/extended-fab' as tokens-mdc-extended-fab; +@use '../core/tokens/m2/mdc/fab' as tokens-mdc-fab; +@use '../core/tokens/m2/mat/fab' as tokens-mat-fab; @include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) { - $mdc-fab-token-slots: m2-mdc-fab.get-token-slots(); - $mdc-extended-fab-token-slots: m2-mdc-extended-fab.get-token-slots(); + $mdc-fab-token-slots: tokens-mdc-fab.get-token-slots(); + $mdc-extended-fab-token-slots: tokens-mdc-extended-fab.get-token-slots(); // Add the MDC fab static styles. @include mdc-fab.static-styles(); @@ -34,33 +36,31 @@ @include button-base.mat-private-button-interactive(); @include button-base.mat-private-button-touch-target(true); @include style-private.private-animation-noop(); + @include elevation.elevation(6); + flex-shrink: 0; // Prevent the button from shrinking since it's always supposed to be a circle. @include mdc-helpers.disable-mdc-fallback-declarations { - // 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); + @include token-utils.use-tokens(tokens-mat-fab.$prefix, tokens-mat-fab.get-token-slots()) { + @include token-utils.create-token-slot(color, foreground-color, inherit); } + } - &:active, &:focus:active { - @include mdc-elevation-theme.elevation(12); - } + &:hover, &:focus { + @include elevation.elevation(8); + } - @include button-base.mat-private-button-disabled { - @include mdc-elevation-theme.elevation(0); - } + &:active, &:focus:active { + @include elevation.elevation(12); } - // 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); + @include button-base.mat-private-button-disabled { + @include elevation.elevation(0); - // Prevent the button from shrinking since it's always supposed to be a circle. - flex-shrink: 0; + @include token-utils.use-tokens(tokens-mat-fab.$prefix, tokens-mat-fab.get-token-slots()) { + @include token-utils.create-token-slot(color, disabled-state-foreground-color); + @include token-utils.create-token-slot(background-color, disabled-state-container-color); + } + } // MDC adds some styles to fab and mini-fab that conflict with some of our focus indicator // styles and don't actually do anything. This undoes those conflicting styles. diff --git a/src/material/core/tokens/m2/mat/_fab.scss b/src/material/core/tokens/m2/mat/_fab.scss new file mode 100644 index 000000000000..1fa4a4b2ccc0 --- /dev/null +++ b/src/material/core/tokens/m2/mat/_fab.scss @@ -0,0 +1,57 @@ +@use '../../token-utils'; +@use '../../../theming/inspection'; +@use '../../../style/sass-utils'; + +// The prefix used to generate the fully qualified name for tokens in this file. +$prefix: (mat, fab); + +// Tokens that can't be configured through Angular Material's current theming API, +// but may be in a future version of the theming API. +@function get-unthemable-tokens() { + @return (); +} + +// 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; + $surface: if($is-dark, #fff, #000); + + @return ( + // Color of icons and text projected into a FAB. + foreground-color: inspection.get-theme-color($theme, foreground, base), + + // MDC doesn't have tokens for disabled FABs so we need to implemented them ourselves. + // Background color of the container when the FAB is disabled. + disabled-state-container-color: rgba($surface, 0.12), + // Color of the icons and projected text when the FAB is disabled. + disabled-state-foreground-color: rgba($surface, if($is-dark, 0.5, 0.38)), + ); +} + +// Generates the mapping for the properties that change based on the FAB palette color. +@function private-get-color-palette-color-tokens($theme, $palette-name) { + @return ( + foreground-color: inspection.get-theme-color($theme, $palette-name, default-contrast), + ); +} + +// 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) { + @return (); +} + +// 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) + ); +} diff --git a/src/material/core/tokens/m2/mdc/_fab.scss b/src/material/core/tokens/m2/mdc/_fab.scss index d108f56ea574..b74094cea9d4 100644 --- a/src/material/core/tokens/m2/mdc/_fab.scss +++ b/src/material/core/tokens/m2/mdc/_fab.scss @@ -22,6 +22,10 @@ $ripple-target: '.mdc-fab__ripple'; container-shape: 50%, icon-size: 24px, + // We don't use this token, because it doesn't set the color of any text inside the FAB. + // We create a custom token for it instead. + icon-color: null, + container-elevation: null, container-height: null, container-shadow-color: null, @@ -56,10 +60,17 @@ $ripple-target: '.mdc-fab__ripple'; // Tokens that can be configured through Angular Material's color theming API. @function get-color-tokens($theme) { - $surface: inspection.get-theme-color($theme, primary, default); - $on-surface: inspection.get-theme-color($theme, primary, default-contrast); + @return ( + // Background color of the FAB. + container-color: inspection.get-theme-color($theme, background, card), + ); +} - @return (container-color: $surface, icon-color: $on-surface); +// Generates the mapping for the properties that change based on the FAB palette color. +@function private-get-color-palette-color-tokens($theme, $palette-name) { + @return ( + container-color: inspection.get-theme-color($theme, $palette-name, default), + ); } // Tokens that can be configured through Angular Material's typography theming API.