diff --git a/packages/mdc-ripple/README.md b/packages/mdc-ripple/README.md index 8de95534b5b..da66e3b8e2a 100644 --- a/packages/mdc-ripple/README.md +++ b/packages/mdc-ripple/README.md @@ -62,7 +62,7 @@ General notes: #### Sass API -In order to fully style states as well as the ripple effect for pressed state, both `mdc-ripple` mixins below must be included, as well as either the basic `mdc-states` mixin or all of the advanced `mdc-states-...` mixins documented below. +In order to fully style states as well as the ripple effect for pressed state, both `mdc-ripple` mixins below must be included, as well as either the basic or advanced `mdc-states` mixins documented below. Once these styles are in place for a component, it is feasible to further override only the parts necessary (e.g. `mdc-states` specifically) for specific variants (e.g. for flat vs. raised buttons). @@ -75,14 +75,26 @@ Mixin | Description `mdc-ripple-surface` | Adds base styles for a ripple surface `mdc-ripple-radius($radius)` | Adds styles for the radius of the ripple effect,
for both bounded and unbounded ripples -##### Basic States Mixin +##### Basic States Mixins + +When using the basic states mixins, inclusion of the `mdc-states` mixin is mandatory. +Inclusion of `mdc-states-activated` or `mdc-states-selected` is optional, depending on whether activated or selected +states are applicable to the component in question. Mixin | Description --- | --- -`mdc-states($color, $has-nested-focusable-element)` | Adds state and ripple styles for the indicated color, deciding opacities based on whether the passed color is light or dark. `$has-nested-focusable-element` defaults to `false` but should be set to `true` if the component contains a focusable element (e.g. an input) under the root node. +`mdc-states($color, $has-nested-focusable-element)` | Adds state and ripple styles using the indicated color, deciding opacities based on whether the passed color is light or dark.
`$has-nested-focusable-element` defaults to `false` but should be set to `true` if the component contains a focusable element (e.g. an input) under the root node. +`mdc-states-activated($color, $has-nested-focusable-element)` | Adds state and ripple styles for activated states using the indicated color, deciding opacities based on whether the passed color is light or dark.
`$has-nested-focusable-element` defaults to `false` but should be set to `true` if the component contains a focusable element (e.g. an input) under the root node. +`mdc-states-selected($color, $has-nested-focusable-element)` | Adds state and ripple styles for selected states using the indicated color, deciding opacities based on whether the passed color is light or dark.
`$has-nested-focusable-element` defaults to `false` but should be set to `true` if the component contains a focusable element (e.g. an input) under the root node. ##### Advanced States Mixins +When using the advanced states mixins, every one of the mixins below should be included at least once to establish base +styles for states. + +These mixins can also be used to emit activated or selected styles if applicable, by applying them within a selector for +`&--activated` or `&--selected` modifier classes. + Mixin | Description --- | --- `mdc-states-base-color($color)` | Sets up base state styles using the provided color diff --git a/packages/mdc-ripple/_mixins.scss b/packages/mdc-ripple/_mixins.scss index 197dcb0f49c..e33b84c1835 100644 --- a/packages/mdc-ripple/_mixins.scss +++ b/packages/mdc-ripple/_mixins.scss @@ -61,6 +61,7 @@ $mdc-ripple-common-styles-emitted_: false !default; &::after { position: absolute; border-radius: 50%; + opacity: 0; pointer-events: none; content: ""; will-change: transform, opacity; @@ -104,8 +105,6 @@ $mdc-ripple-common-styles-emitted_: false !default; &::before, &::after { @include mdc-theme-prop(background-color, $color, $edgeOptOut: true); - - opacity: 0; } } @@ -156,19 +155,43 @@ $mdc-ripple-common-styles-emitted_: false !default; } } -// Simple mixin which automatically selects opacity values based on whether the ink color is light or dark. +// Simple mixin for base states which automatically selects opacity values based on whether the ink color is +// light or dark. @mixin mdc-states($color: black, $has-nested-focusable-element: false) { - $color-value: mdc-theme-prop-value($color); - $opacity-map: if( - mdc-theme-tone($color-value) == "light", - $mdc-ripple-light-ink-opacities, - $mdc-ripple-dark-ink-opacities - ); + @include mdc-states-interactions_($color, $has-nested-focusable-element); +} - @include mdc-states-base-color($color); - @include mdc-states-hover-opacity(map-get($opacity-map, "hover")); - @include mdc-states-focus-opacity(map-get($opacity-map, "focus"), $has-nested-focusable-element); - @include mdc-states-press-opacity(map-get($opacity-map, "press")); +// Simple mixin for activated states which automatically selects opacity values based on whether the ink color is +// light or dark. +@mixin mdc-states-activated($color, $has-nested-focusable-element: false) { + $opacity-map: mdc-states-opacities_($color); + $activated-opacity: map-get($opacity-map, "activated"); + + &--activated { + // Stylelint seems to think that '&' qualifies as a type selector here? + // stylelint-disable-next-line selector-max-type + &::before { + opacity: $activated-opacity; + } + + @include mdc-states-interactions_($color, $has-nested-focusable-element, $activated-opacity); + } +} + +// Simple mixin for selected states which automatically selects opacity values based on whether the ink color is +// light or dark. +@mixin mdc-states-selected($color, $has-nested-focusable-element: false) { + $opacity-map: mdc-states-opacities_($color); + $selected-opacity: map-get($opacity-map, "selected"); + + &--selected { + // stylelint-disable-next-line selector-max-type + &::before { + opacity: $selected-opacity; + } + + @include mdc-states-interactions_($color, $has-nested-focusable-element, $selected-opacity); + } } @mixin mdc-ripple-radius($radius: 100%) { @@ -250,6 +273,27 @@ $mdc-ripple-common-styles-emitted_: false !default; // Private // +@function mdc-states-opacities_($color) { + $color-value: mdc-theme-prop-value($color); + $opacity-map: if( + mdc-theme-tone($color-value) == "light", + $mdc-ripple-light-ink-opacities, + $mdc-ripple-dark-ink-opacities + ); + + @return $opacity-map; +} + +@mixin mdc-states-interactions_($color, $has-nested-focusable-element, $opacity-modifier: 0) { + $opacity-map: mdc-states-opacities_($color); + + @include mdc-states-base-color($color); + @include mdc-states-hover-opacity(map-get($opacity-map, "hover") + $opacity-modifier); + @include mdc-states-focus-opacity(map-get($opacity-map, "focus") + $opacity-modifier, $has-nested-focusable-element); + @include mdc-states-press-opacity(map-get($opacity-map, "press") + $opacity-modifier); +} + +// Note: This can be removed when we remove the legacy mdc-ripple-color mixin. @mixin mdc-ripple-color_($color, $opacity) { // stylelint-disable at-rule-empty-line-before, block-closing-brace-newline-after @if type-of($color) == "color" { diff --git a/packages/mdc-ripple/_variables.scss b/packages/mdc-ripple/_variables.scss index 71904ad718d..b5f11ca8e88 100644 --- a/packages/mdc-ripple/_variables.scss +++ b/packages/mdc-ripple/_variables.scss @@ -22,13 +22,17 @@ $mdc-states-wash-duration: 15ms; $mdc-ripple-dark-ink-opacities: ( hover: .04, focus: .12, - press: .16 + press: .16, + selected: .04, + activated: .12 ) !default; $mdc-ripple-light-ink-opacities: ( hover: .08, focus: .24, - press: .32 + press: .32, + selected: .08, + activated: .24 ) !default; // Legacy