diff --git a/src/material/button/_fab-theme.scss b/src/material/button/_fab-theme.scss index 6857feda06b6..112998e4a3fc 100644 --- a/src/material/button/_fab-theme.scss +++ b/src/material/button/_fab-theme.scss @@ -1,75 +1,96 @@ @use 'sass:map'; -@use '@material/fab/fab' as mdc-fab; @use '@material/fab/fab-theme' as mdc-fab-theme; -@use '@material/theme/theme-color' as mdc-theme-color; +@use '@material/fab/extended-fab-theme' as mdc-extended-fab-theme; @use './button-theme-private'; @use '../core/mdc-helpers/mdc-helpers'; @use '../core/theming/theming'; +@use '../core/tokens/m2/mdc/fab' as tokens-mdc-fab; +@use '../core/tokens/m2/mdc/extended-fab' as tokens-mdc-extended-fab; @use '../core/typography/typography'; -@mixin _fab-variant($foreground, $background) { - @include mdc-fab-theme.theme(( - container-color: $background, - icon-color: $foreground, - )); +@mixin _fab-variant($config, $foreground, $background) { + $color-config: map.merge( + $config, + ( + primary: ( + default: $background, + default-contrast: $foreground, + ), + ) + ); + $color-tokens: tokens-mdc-fab.get-color-tokens($color-config); + @include mdc-fab-theme.theme($color-tokens); --mat-mdc-fab-color: #{$foreground}; } +@function white-or-black($color, $is-dark) { + @return if(mdc-helpers.variable-safe-contrast-tone($color, $is-dark) == 'dark', #000, #fff); +} + @mixin color($config-or-theme) { $config: theming.get-color-config($config-or-theme); - @include mdc-helpers.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 { + $is-dark: map.get($config, is-dark); + $background: map.get($config, background); + + $surface: theming.get-color-from-palette($background, card); + $primary: theming.get-color-from-palette(map.get($config, primary)); + $accent: theming.get-color-from-palette(map.get($config, accent)); + $warn: theming.get-color-from-palette(map.get($config, 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(map.get($config, is-dark), 0.5, 0.38)); + + .mat-mdc-fab, + .mat-mdc-mini-fab { + // 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. + @include mdc-helpers.using-mdc-theme($config) { @include button-theme-private.ripple-theme-styles($config, true); + } + + @include button-theme-private.apply-disabled-style() { + @include _fab-variant($config, $on-disabled, $disabled); + } + + &.mat-unthemed { + @include _fab-variant($config, $on-surface, $surface); + } + + &.mat-primary { + @include _fab-variant($config, $on-primary, $primary); + } + + &.mat-accent { + @include _fab-variant($config, $on-accent, $accent); + } - &.mat-unthemed { - @include _fab-variant($on-surface, mdc-theme-color.prop-value(surface)); - } - - &.mat-primary { - @include _fab-variant( - mdc-theme-color.prop-value(on-primary), - mdc-theme-color.prop-value(primary) - ); - } - - &.mat-accent { - @include _fab-variant( - mdc-theme-color.prop-value(on-secondary), - mdc-theme-color.prop-value(secondary) - ); - } - - &.mat-warn { - @include _fab-variant( - mdc-theme-color.prop-value(on-error), - mdc-theme-color.prop-value(error) - ); - } - - @include button-theme-private.apply-disabled-style() { - @include _fab-variant( - rgba($on-surface, if(map.get($config, is-dark), 0.5, 0.38)), - rgba($on-surface, 0.12) - ); - } + &.mat-warn { + @include _fab-variant($config, $on-warn, $warn); } } } @mixin typography($config-or-theme) { $config: typography.private-typography-to-2018-config( - theming.get-typography-config($config-or-theme)); - @include mdc-helpers.using-mdc-typography($config) { - @include mdc-fab.without-ripple($query: mdc-helpers.$mdc-typography-styles-query); + theming.get-typography-config($config-or-theme) + ); + $typography-tokens: tokens-mdc-extended-fab.get-typography-tokens($config); + .mat-mdc-extended-fab { + @include mdc-extended-fab-theme.theme($typography-tokens); } } -@mixin density($config-or-theme) {} +@mixin density($config-or-theme) { +} @mixin theme($theme-or-color-config) { $theme: theming.private-legacy-get-theme($theme-or-color-config); diff --git a/src/material/button/fab.scss b/src/material/button/fab.scss index b36c3e508e1f..2e279323991f 100644 --- a/src/material/button/fab.scss +++ b/src/material/button/fab.scss @@ -1,13 +1,39 @@ @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/mdc-helpers/mdc-helpers'; @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; -@include mdc-helpers.disable-mdc-fallback-declarations { - @include mdc-fab.without-ripple($query: mdc-helpers.$mdc-base-styles-query); +@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(); + + // Add the MDC fab static styles. + @include mdc-fab.static-styles(); + + // Add default values for tokens that aren't outputted by the theming API. + .mat-mdc-fab, .mat-mdc-mini-fab { + // Add the official slots for the MDC fab. + @include mdc-fab-theme.theme-styles($mdc-fab-token-slots); + + // Add default values for tokens that aren't outputted by the theming API. + @include mdc-fab-theme.theme(m2-mdc-fab.get-unthemable-tokens()); + } + + .mat-mdc-extended-fab { + // Add the official slots for the MDC fab. + @include mdc-extended-fab-theme.theme-styles($mdc-extended-fab-token-slots); + + // Add default values for tokens that aren't outputted by the theming API. + @include mdc-extended-fab-theme.theme(m2-mdc-extended-fab.get-unthemable-tokens()); + } } .mat-mdc-fab, .mat-mdc-mini-fab { @@ -16,13 +42,6 @@ @include style-private.private-animation-noop(); @include mdc-helpers.disable-mdc-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 @@ -76,8 +95,6 @@ } .mat-mdc-extended-fab { - @include mdc-fab.extended_($query: mdc-helpers.$mdc-base-styles-query); - & > .mat-icon, & > .material-icons { // stylelint-disable-line selector-class-pattern @include mdc-fab.extended-icon-padding( diff --git a/src/material/core/tokens/m2/mdc/_extended-fab.scss b/src/material/core/tokens/m2/mdc/_extended-fab.scss new file mode 100644 index 000000000000..b2cfe8eb641a --- /dev/null +++ b/src/material/core/tokens/m2/mdc/_extended-fab.scss @@ -0,0 +1,88 @@ +@use '../../../mdc-helpers/mdc-helpers'; +@use '../../token-utils'; +@use '../../../typography/typography-utils'; + +@use 'sass:map'; + +// The prefix used to generate the fully qualified name for tokens in this file. +$prefix: (mdc, extended-fab); + +@function get-unthemable-tokens() { + @return ( + container-color: null, + container-elevation: null, + container-height: null, + container-shadow-color: null, + container-shape: null, + container-surface-tint-layer-color: null, + focus-container-elevation: null, + focus-icon-color: null, + focus-label-text-color: null, + focus-outline-color: null, + focus-outline-width: null, + focus-state-layer-color: null, + focus-state-layer-opacity: null, + hover-container-elevation: null, + hover-icon-color: null, + hover-label-text-color: null, + hover-state-layer-color: null, + hover-state-layer-opacity: null, + icon-color: null, + icon-size: null, + label-text-color: null, + lowered-container-elevation: null, + lowered-focus-container-elevation: null, + lowered-hover-container-elevation: null, + lowered-pressed-container-elevation: null, + pressed-container-elevation: null, + pressed-icon-color: null, + pressed-label-text-color: null, + pressed-ripple-color: null, + pressed-ripple-opacity: null, + pressed-state-layer-color: null, + pressed-state-layer-opacity: null + ); +} + +// Tokens that can be configured through Angular Material's color theming API. +@function get-color-tokens($config) { + @return (); +} + +// Tokens that can be configured through Angular Material's typography theming API. +@function get-typography-tokens($config) { + // TODO(wagnermaciel): The earlier implementation of the snack bar used MDC's APIs to create the + // typography tokens. As a result, we unintentionally allowed `null` typography configs to be + // passed in. Since there a lot of apps that now depend on this pattern, we need this temporary + // fallback. + @if ($config == null) { + $config: mdc-helpers.private-fallback-typography-from-mdc(); + } + @return ( + label-text-font: typography-utils.font-family($config, button) or + typography-utils.font-family($config), + label-text-size: typography-utils.font-size($config, button), + label-text-tracking: typography-utils.letter-spacing($config, button), + label-text-weight: typography-utils.font-weight($config, button) + ); +} + +// Tokens that can be configured through Angular Material's density theming API. +@function get-density-tokens($config) { + @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 map.merge( + get-unthemable-tokens(), + map.merge( + get-color-tokens(token-utils.$placeholder-color-config), + map.merge( + 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 new file mode 100644 index 000000000000..7bad5c91d02a --- /dev/null +++ b/src/material/core/tokens/m2/mdc/_fab.scss @@ -0,0 +1,89 @@ +@use '../../../theming/theming'; +@use '../../token-utils'; + +@use 'sass:map'; + +// The prefix used to generate the fully qualified name for tokens in this file. +$prefix: (mdc, 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. +// +// 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. +$height: 56px; +$mini-height: 40px; +$shape-radius: 50%; +$ripple-target: '.mdc-fab__ripple'; + +@function get-unthemable-tokens() { + @return ( + container-shape: 50%, + icon-size: 24px, + + container-elevation: null, + container-height: null, + container-shadow-color: null, + container-surface-tint-layer-color: null, + container-width: null, + + focus-container-elevation: null, + focus-icon-color: null, + focus-outline-color: null, + focus-outline-width: null, + focus-state-layer-color: null, + focus-state-layer-opacity: null, + + hover-container-elevation: null, + hover-icon-color: null, + hover-state-layer-color: null, + hover-state-layer-opacity: null, + + lowered-container-elevation: null, + lowered-focus-container-elevation: null, + lowered-hover-container-elevation: null, + lowered-pressed-container-elevation: null, + + pressed-container-elevation: null, + pressed-icon-color: null, + pressed-ripple-color: null, + pressed-ripple-opacity: null, + pressed-state-layer-color: null, + pressed-state-layer-opacity: null + ); +} + +// Tokens that can be configured through Angular Material's color theming API. +@function get-color-tokens($config) { + $primary: map.get($config, primary); + $surface: theming.get-color-from-palette($primary, default); + $on-surface: theming.get-color-from-palette($primary, default-contrast); + + @return (container-color: $surface, icon-color: $on-surface); +} + +// Tokens that can be configured through Angular Material's typography theming API. +@function get-typography-tokens($config) { + @return (); +} + +// Tokens that can be configured through Angular Material's density theming API. +@function get-density-tokens($config) { + @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 map.merge( + get-unthemable-tokens(), + map.merge( + get-color-tokens(token-utils.$placeholder-color-config), + map.merge( + get-typography-tokens(token-utils.$placeholder-typography-config), + get-density-tokens(token-utils.$placeholder-density-config) + ) + ) + ); +} diff --git a/src/material/core/tokens/tests/test-validate-tokens.scss b/src/material/core/tokens/tests/test-validate-tokens.scss index 56c5040fbfe5..c8b54bde1d5c 100644 --- a/src/material/core/tokens/tests/test-validate-tokens.scss +++ b/src/material/core/tokens/tests/test-validate-tokens.scss @@ -5,6 +5,8 @@ @use '@material/card/outlined-card-theme' as mdc-outlined-card-theme; @use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme; @use '@material/circular-progress/circular-progress-theme' as mdc-circular-progress-theme; +@use '@material/fab/extended-fab-theme' as mdc-extended-fab-theme; +@use '@material/fab/fab-theme' as mdc-fab-theme; @use '@material/linear-progress/linear-progress-theme' as mdc-linear-progress-theme; @use '@material/icon-button/icon-button-theme' as mdc-icon-button-theme; @use '@material/list/list-theme' as mdc-list-theme; @@ -21,6 +23,8 @@ @use '../m2/mdc/elevated-card' as tokens-mdc-elevated-card; @use '../m2/mdc/icon-button' as tokens-mdc-icon-button; @use '../m2/mdc/checkbox' as tokens-mdc-checkbox; +@use '../m2/mdc/extended-fab' as tokens-mdc-extended-fab; +@use '../m2/mdc/fab' as tokens-mdc-fab; @use '../m2/mdc/list' as tokens-mdc-list; @use '../m2/mdc/outlined-card' as tokens-mdc-outlined-card; @use '../m2/mdc/plain-tooltip' as tokens-mdc-plain-tooltip; @@ -107,3 +111,13 @@ $slots: tokens-mdc-chip.get-token-slots(), $reference: mdc-chips-theme.$light-theme ); +@include validate-slots( + $component: 'm2.mdc.fab', + $slots: tokens-mdc-fab.get-token-slots(), + $reference: mdc-fab-theme.$light-theme +); +@include validate-slots( + $component: 'm2.mdc.extended-fab', + $slots: tokens-mdc-extended-fab.get-token-slots(), + $reference: mdc-extended-fab-theme.$extended-light-theme +);