| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- //
- // Copyright 2021 Google Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- // stylelint-disable selector-class-pattern --
- // Selector '.mdc-*' should only be used in this project.
- @use 'sass:map';
- @use 'sass:math';
- @use 'sass:meta';
- @use '@material/density/functions' as density-functions;
- @use '@material/density/variables' as density-variables;
- @use '@material/dom/mixins' as dom-mixins;
- @use '@material/elevation/elevation-theme';
- @use '@material/feature-targeting/feature-targeting';
- @use '@material/focus-ring/focus-ring';
- @use '@material/ripple/ripple-theme';
- @use '@material/shape/mixins' as shape-mixins;
- @use '@material/theme/custom-properties';
- @use '@material/theme/state';
- @use '@material/theme/theme';
- @use '@material/theme/theme-color';
- @use '@material/typography/typography';
- @use './button-ripple';
- $height: 36px !default;
- $horizontal-padding: 8px !default;
- $contained-horizontal-padding: 16px !default;
- // For a contained button with an icon, the padding on the side of the
- // button with the icon.
- $contained-horizontal-padding-icon: 12px !default;
- $minimum-height: 24px !default;
- $maximum-height: $height !default;
- $density-scale: density-variables.$default-scale !default;
- $density-config: (
- height: (
- default: $height,
- maximum: $maximum-height,
- minimum: $minimum-height,
- ),
- ) !default;
- $shape-radius: small !default;
- $disabled-ink-color: rgba(theme-color.prop-value(on-surface), 0.38) !default;
- $disabled-container-color: rgba(
- theme-color.prop-value(on-surface),
- 0.12
- ) !default;
- @mixin theme-styles($theme, $resolver, $query: feature-targeting.all()) {
- @include _label-text-typography(
- (
- family: map.get($theme, label-text-font),
- size: map.get($theme, label-text-size),
- tracking: map.get($theme, label-text-tracking),
- weight: map.get($theme, label-text-weight),
- transform: map.get($theme, label-text-transform),
- ),
- $query: $query
- );
- @include container-fill-color(
- (
- default: map.get($theme, container-color),
- disabled: map.get($theme, disabled-container-color),
- ),
- $query: $query
- );
- @include ink-color(
- (
- default: map.get($theme, label-text-color),
- hover: map.get($theme, hover-label-text-color),
- focus: map.get($theme, focus-label-text-color),
- pressed: map.get($theme, pressed-label-text-color),
- disabled: map.get($theme, disabled-label-text-color),
- ),
- $query: $query
- );
- @include icon-color(
- (
- default: map.get($theme, with-icon-icon-color),
- hover: map.get($theme, with-icon-hover-icon-color),
- focus: map.get($theme, with-icon-focus-icon-color),
- pressed: map.get($theme, with-icon-pressed-icon-color),
- disabled: map.get($theme, with-icon-disabled-icon-color),
- ),
- $query: $query
- );
- $icon-size: map.get($theme, with-icon-icon-size);
- @include _icon-size($icon-size, $query: $query);
- @include _states-colors(
- (
- focus: map.get($theme, focus-state-layer-color),
- hover: map.get($theme, hover-state-layer-color),
- pressed: map.get($theme, pressed-state-layer-color),
- ),
- $query: $query
- );
- $hover-state-layer-opacity: map.get($theme, hover-state-layer-opacity);
- $focus-state-layer-opacity: map.get($theme, focus-state-layer-opacity);
- $pressed-state-layer-opacity: map.get($theme, pressed-state-layer-opacity);
- @include ripple-theme.states-opacities(
- $opacity-map: (
- focus: $focus-state-layer-opacity,
- hover: $hover-state-layer-opacity,
- press: $pressed-state-layer-opacity,
- ),
- $ripple-target: button-ripple.$ripple-target,
- $query: $query
- );
- $container-height: map.get($theme, container-height);
- @include height($container-height, $query: $query);
- $container-height-value: if(
- custom-properties.is-custom-prop($container-height),
- custom-properties.get-fallback($container-height),
- $container-height
- );
- /// Token "keep-touch-target":
- /// Prevent the increased touch target from being reseted if the
- /// container-height differs from the default (36px)
- $keep-touch-target: map.get($theme, keep-touch-target);
- @if (not $keep-touch-target) and
- ($container-height-value != null) and
- ($container-height-value != $height)
- {
- @include _touch-target-reset($query: $query);
- }
- $shape: map.get($theme, container-shape);
- @if $shape {
- $container-height: if(
- $container-height != null,
- $container-height,
- $height
- );
- @include _shape-radius-with-height(
- $shape,
- $height: $container-height,
- $query: $query
- );
- }
- @include _elevation(
- $resolver,
- $elevation-map: (
- default: map.get($theme, container-elevation),
- disabled: map.get($theme, disabled-container-elevation),
- focus: map.get($theme, focus-container-elevation),
- hover: map.get($theme, hover-container-elevation),
- pressed: map.get($theme, pressed-container-elevation)
- ),
- $shadow-color: map.get($theme, container-shadow-color),
- $query: $query
- );
- }
- @function resolve-theme-elevation-keys($theme, $resolver) {
- $elevation-resolver: map.get($resolver, elevation);
- $shadow-color: map.get($theme, container-shadow-color);
- @if $elevation-resolver == null or $shadow-color == null {
- @return $theme;
- }
- $elevation-keys: (
- container-elevation,
- hover-container-elevation,
- focus-container-elevation,
- pressed-container-elevation,
- disabled-container-elevation
- );
- @each $key in $elevation-keys {
- $elevation: map.get($theme, $key);
- @if $elevation != null {
- $resolved-value: meta.call(
- $resolver,
- $elevation: $elevation,
- $shadow-color: $shadow-color
- );
- // Update the key with the resolved value.
- $theme: map.set($theme, $key, $resolved-value);
- }
- }
- @return $theme;
- }
- ///
- /// Sets ripple color for button.
- ///
- @mixin ripple-states(
- $color,
- $opacity-map: null,
- $query: feature-targeting.all()
- ) {
- @include ripple-theme.states(
- $color: $color,
- $opacity-map: $opacity-map,
- $query: $query,
- $ripple-target: button-ripple.$ripple-target
- );
- }
- @mixin filled-accessible(
- $container-fill-color,
- $query: feature-targeting.all()
- ) {
- $fill-tone: theme-color.tone($container-fill-color);
- @include container-fill-color($container-fill-color, $query);
- @if ($fill-tone == 'dark') {
- @include ink-color(text-primary-on-dark, $query);
- @include ripple-states($color: text-primary-on-dark, $query: $query);
- } @else {
- @include ink-color(text-primary-on-light, $query);
- @include ripple-states($color: text-primary-on-light, $query: $query);
- }
- }
- ///
- /// Sets the container fill color to the given color for an enabled button.
- /// @param {Color|map} $color-or-map - The desired container fill color,
- /// specified either as a flat value or a map of colors with states
- /// {default, hover, focus, pressed, disabled} as keys.
- ///
- @mixin container-fill-color($color-or-map, $query: feature-targeting.all()) {
- // :not(:disabled) is used to support link styled as button
- // as link does not support :enabled style
- &:not(:disabled) {
- @include _container-fill-color(
- state.get-default-state($color-or-map),
- $query: $query
- );
- &:hover {
- @include _container-fill-color(
- state.get-hover-state($color-or-map),
- $query: $query
- );
- }
- @include ripple-theme.focus() {
- @include _container-fill-color(
- state.get-focus-state($color-or-map),
- $query: $query
- );
- }
- @include ripple-theme.active {
- @include _container-fill-color(
- state.get-pressed-state($color-or-map),
- $query: $query
- );
- }
- }
- &:disabled {
- @include _container-fill-color(
- state.get-disabled-state($color-or-map),
- $query: $query
- );
- }
- }
- ///
- /// Sets the container fill color to the given color for a disabled button.
- /// @param {Color} $color - The desired container fill color.
- /// @deprecated - call `container-fill-color` instead with `disabled` as a map
- /// key.
- ///
- @mixin disabled-container-fill-color($color, $query: feature-targeting.all()) {
- @include container-fill-color(
- (
- disabled: $color,
- ),
- $query: $query
- );
- }
- ///
- /// Sets the icon color to the given color for an enabled button.
- /// @param {Color} $color-or-map - The desired icon color, specified either
- /// as a flat value or a map of colors with states
- /// {default, hover, focus, pressed, disabled} as keys.
- ///
- @mixin icon-color($color-or-map, $query: feature-targeting.all()) {
- &:not(:disabled) {
- @include _icon-color(
- state.get-default-state($color-or-map),
- $query: $query
- );
- &:hover {
- @include _icon-color(
- state.get-hover-state($color-or-map),
- $query: $query
- );
- }
- @include ripple-theme.focus() {
- @include _icon-color(
- state.get-focus-state($color-or-map),
- $query: $query
- );
- }
- @include ripple-theme.active {
- @include _icon-color(
- state.get-pressed-state($color-or-map),
- $query: $query
- );
- }
- }
- &:disabled {
- @include _icon-color(
- state.get-disabled-state($color-or-map),
- $query: $query
- );
- }
- }
- ///
- /// Sets the icon color to the given color for a disabled button.
- /// @param {Color} $color - The desired icon color.
- /// @deprecated - call `icon-color` instead with `disabled` as a map key.
- ///
- @mixin disabled-icon-color($color, $query: feature-targeting.all()) {
- @include icon-color(
- (
- disabled: $color,
- ),
- $query: $query
- );
- }
- ///
- /// Sets the ink color to the given color for an enabled button,
- /// and sets the icon color to the given color unless `mdc-button-icon-color`
- /// is also used.
- /// @param {Color} $color-or-map - The desired ink color, specified either
- /// as a flat value or a map of colors with states
- /// {default, hover, focus, pressed, disabled} as keys.
- ///
- @mixin ink-color($color-or-map, $query: feature-targeting.all()) {
- &:not(:disabled) {
- @include _ink-color(state.get-default-state($color-or-map), $query: $query);
- &:hover {
- @include _ink-color(state.get-hover-state($color-or-map), $query: $query);
- }
- @include ripple-theme.focus() {
- @include _ink-color(state.get-focus-state($color-or-map), $query: $query);
- }
- @include ripple-theme.active {
- @include _ink-color(
- state.get-pressed-state($color-or-map),
- $query: $query
- );
- }
- }
- &:disabled {
- @include _ink-color(
- state.get-disabled-state($color-or-map),
- $query: $query
- );
- }
- }
- ///
- /// Sets the ink color to the given color for a disabled button,
- /// and sets the icon color to the given color unless `mdc-button-icon-color`
- /// is also used.
- /// @param {Color} $color - The desired ink color.
- /// @deprecated - call `ink-color` instead with `disabled` as a map key.
- ///
- @mixin disabled-ink-color($color, $query: feature-targeting.all()) {
- @include ink-color(
- (
- disabled: $color,
- ),
- $query: $query
- );
- }
- ///
- /// Sets density scale for button.
- ///
- /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values `-3`,
- /// `-2`, `-1`, `0`.
- ///
- @mixin density($density-scale, $query: feature-targeting.all()) {
- $height: density-functions.prop-value(
- $density-config: $density-config,
- $density-scale: $density-scale,
- $property-name: height,
- );
- @include height($height, $query: $query);
- @if $density-scale != 0 {
- @include _touch-target-reset($query: $query);
- }
- }
- ///
- /// Resets touch target-related styles. This is called from the density mixin to
- /// automatically remove the increased touch target, since dense components
- /// don't have the same default a11y requirements.
- /// @access private
- ///
- @mixin _touch-target-reset($query: feature-targeting.all()) {
- $feat-structure: feature-targeting.create-target($query, structure);
- @include feature-targeting.targets($feat-structure) {
- margin-top: 0;
- margin-bottom: 0;
- }
- .mdc-button__touch {
- @include feature-targeting.targets($feat-structure) {
- // Do not set display: none in case the touch target is <a> element.
- height: 100%;
- }
- }
- }
- ///
- /// Sets custom height for button.
- /// @param {Number} $height - Height of button in `px`.
- ///
- @mixin height($height, $query: feature-targeting.all()) {
- $feat-structure: feature-targeting.create-target($query, structure);
- @include feature-targeting.targets($feat-structure) {
- @include theme.property(height, $height);
- }
- }
- @mixin shape-radius(
- $radius,
- $rtl-reflexive: false,
- $density-scale: $density-scale,
- $query: feature-targeting.all()
- ) {
- $height: density-functions.prop-value(
- $density-config: $density-config,
- $density-scale: $density-scale,
- $property-name: height,
- );
- @include _shape-radius-with-height($radius, $rtl-reflexive, $height, $query);
- }
- @mixin _shape-radius-with-height(
- $radius,
- $rtl-reflexive: false,
- $height: $height,
- $query: feature-targeting.all()
- ) {
- @include shape-mixins.radius(
- $radius,
- $rtl-reflexive,
- $component-height: $height,
- $query: $query
- );
- #{button-ripple.$ripple-target} {
- @include shape-mixins.radius(
- $radius,
- $rtl-reflexive,
- $component-height: $height,
- $query: $query
- );
- }
- }
- ///
- /// Sets horizontal padding to the given number.
- /// @param {Number} $padding
- /// @param {Number} $padding-icon [null] For buttons with an icon, the
- /// horizontal padding on the side with the icon, if different from
- /// $padding.
- ///
- @mixin horizontal-padding(
- $padding,
- $padding-icon: null,
- $query: feature-targeting.all()
- ) {
- $feat-structure: feature-targeting.create-target($query, structure);
- @include feature-targeting.targets($feat-structure) {
- // $padding should be a single value; enforce it by specifying all 4 sides in the output
- padding: 0 $padding 0 $padding;
- }
- @if $padding-icon != null {
- &.mdc-button--icon-trailing {
- @include feature-targeting.targets($feat-structure) {
- // $padding should be a single value; enforce it by specifying all 4
- // sides in the output.
- padding: 0 $padding-icon 0 $padding;
- }
- }
- &.mdc-button--icon-leading {
- @include feature-targeting.targets($feat-structure) {
- // $padding should be a single value; enforce it by specifying all 4
- // sides in the output.
- padding: 0 $padding 0 $padding-icon;
- }
- }
- }
- }
- ///
- /// Sets the button label to overflow as ellipsis
- ///
- @mixin label-overflow-ellipsis($query: feature-targeting.all()) {
- .mdc-button__label {
- @include typography.overflow-ellipsis($query: $query);
- }
- }
- ///
- /// Add a visible outline to the button in high contrast mode.
- ///
- @mixin outline-hcm-shim($query: feature-targeting.all()) {
- &::before {
- @include dom-mixins.transparent-border($query: $query);
- }
- }
- ///
- /// Includes ad-hoc high contrast mode support.
- /// @deprecated Use `outline-hcm-shim` for the outline button. The focus ring
- /// is provided by default.
- ///
- @mixin high-contrast-mode-shim($query: feature-targeting.all()) {
- @include outline-hcm-shim($query: $query);
- // Link buttons apply focus to the contained link. Focus is indicated via the
- // link since focus-within isn't supported by IE.
- & .mdc-button__link:focus,
- &:focus {
- &::before {
- @include focus-ring.focus-ring($query: $query);
- }
- }
- }
- ///
- /// Sets the container fill color to the given color. This mixin should be
- /// wrapped in a selector that qualifies button state.
- /// @access private
- ///
- @mixin _container-fill-color($color, $query: feature-targeting.all()) {
- $feat-color: feature-targeting.create-target($query, color);
- @if $color {
- @include feature-targeting.targets($feat-color) {
- @include theme.property(background-color, $color);
- }
- }
- }
- ///
- /// Sets the icon color to the given color. This mixin should be
- /// wrapped in a selector that qualifies button state.
- /// @access private
- ///
- @mixin _icon-color($color, $query: feature-targeting.all()) {
- $feat-color: feature-targeting.create-target($query, color);
- @if $color {
- .mdc-button__icon {
- @include feature-targeting.targets($feat-color) {
- @include theme.property(color, $color);
- }
- }
- }
- }
- @mixin _icon-size($size-px, $query: feature-targeting.all()) {
- $feat-structure: feature-targeting.create-target($query, structure);
- @if $size-px != null {
- $size-rem: typography.px-to-rem($size-px);
- .mdc-button__icon {
- @include feature-targeting.targets($feat-structure) {
- @include theme.property(font-size, $size-rem);
- @include theme.property(width, $size-rem);
- @include theme.property(height, $size-rem);
- }
- }
- }
- }
- ///
- /// Sets the ink color to the given color. This mixin should be
- /// wrapped in a selector that qualifies button state.
- /// @access private
- ///
- @mixin _ink-color($color, $query: feature-targeting.all()) {
- $feat-color: feature-targeting.create-target($query, color);
- @if $color {
- @include feature-targeting.targets($feat-color) {
- @include theme.property(color, $color);
- }
- }
- }
- @mixin _states-colors($color-map, $query: feature-targeting.all()) {
- $hover: map.get($color-map, hover);
- $hover-value: if(
- custom-properties.is-custom-prop($hover),
- custom-properties.get-fallback($hover),
- $hover
- );
- // TODO(b/191298796): support focused & pressed key colors.
- @if $hover-value != null {
- @include ripple-theme.states-base-color(
- $color: $hover,
- $ripple-target: button-ripple.$ripple-target,
- $query: $query
- );
- }
- }
- @mixin _label-text-typography(
- $typography-map,
- $query: feature-targeting.all()
- ) {
- $feat-typography: feature-targeting.create-target($query, typography);
- $family: map.get($typography-map, family);
- $size: map.get($typography-map, size);
- $tracking: map.get($typography-map, tracking);
- $weight: map.get($typography-map, weight);
- $transform: map.get($typography-map, transform);
- @include feature-targeting.targets($feat-typography) {
- @include theme.property(font-family, $family);
- @include theme.property(font-size, $size);
- @include theme.property(letter-spacing, $tracking);
- @include theme.property(font-weight, $weight);
- @include theme.property(text-transform, $transform);
- }
- }
- @mixin _elevation(
- $resolver,
- $elevation-map,
- $shadow-color,
- $query: feature-targeting.all()
- ) {
- $elevation-resolver: map.get($resolver, elevation);
- @if $shadow-color {
- $default: state.get-default-state($elevation-map);
- @if $default != null {
- @include elevation-theme.with-resolver(
- $elevation-resolver,
- $elevation: $default,
- $shadow-color: $shadow-color,
- $query: $query
- );
- }
- $focus: state.get-focus-state($elevation-map);
- @if $focus != null {
- @include ripple-theme.focus {
- @include elevation-theme.with-resolver(
- $elevation-resolver,
- $elevation: $focus,
- $shadow-color: $shadow-color,
- $query: $query
- );
- }
- }
- $hover: state.get-hover-state($elevation-map);
- @if $hover != null {
- &:hover {
- @include elevation-theme.with-resolver(
- $elevation-resolver,
- $elevation: $hover,
- $shadow-color: $shadow-color,
- $query: $query
- );
- }
- }
- $pressed: state.get-pressed-state($elevation-map);
- @if $pressed != null {
- @include ripple-theme.active {
- @include elevation-theme.with-resolver(
- $elevation-resolver,
- $elevation: $pressed,
- $shadow-color: $shadow-color,
- $query: $query
- );
- }
- }
- $disabled: state.get-disabled-state($elevation-map);
- @if $disabled != null {
- &:disabled {
- @include elevation-theme.with-resolver(
- $elevation-resolver,
- $elevation: $disabled,
- $shadow-color: $shadow-color,
- $query: $query
- );
- }
- }
- }
- }
|