// // Copyright 2017 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. // // Selector '.mdc-*' should only be used in this project. // stylelint-disable selector-class-pattern @use 'sass:list'; @use 'sass:map'; @use 'sass:meta'; @use '@material/feature-targeting/feature-targeting'; @use './css'; @use './custom-properties'; @use './gss'; @use './replace'; @use './theme-color'; @mixin core-styles($query: feature-targeting.all()) { $feat-color: feature-targeting.create-target($query, color); :root { @include feature-targeting.targets($feat-color) { @each $style in map.keys(theme-color.$property-values) { --mdc-theme-#{$style}: #{map.get(theme-color.$property-values, $style)}; } } } @each $style in map.keys(theme-color.$property-values) { @if $style != 'background' and $style != 'surface' { .mdc-theme--#{$style} { @include feature-targeting.targets($feat-color) { @include prop(color, $style, true); } } } @else { .mdc-theme--#{$style} { @include feature-targeting.targets($feat-color) { @include prop(background-color, $style); } } } } // CSS rules for using primary and secondary (plus light/dark variants) as background colors. @each $style in ('primary', 'secondary') { .mdc-theme--#{$style}-bg { @include feature-targeting.targets($feat-color) { @include prop(background-color, $style, true); } } } } /// Applies a dynamic value to the specified property. This mixin should be used /// in theme style mixins when setting properties. /// /// The value may be any of the following: /// - a standard CSS value /// - a custom property Map, e.g. (varname: --mdc-foo, fallback: blue) /// - a Material theme key String, e.g. 'primary', 'on-primary' /// /// @example /// @include theme.property(color, teal); /// @include theme.property(color, custom-properties.create(--mdc-foo, blue)); /// @include theme.property(color, primary); /// /// A `$replace` Map parameter may be provided to replace key/value pairs for /// string values. This can be used to substitute parameters in complex string /// values such as `calc()` with custom properties. /// /// @example /// @include theme.property( /// width, /// calc(foo + bar), /// $replace: (foo: custom-properties.create(--mdc-foo), bar: 8px) /// ); /// /// Note: Material theme key Strings (e.g. `primary`) are not supported as /// replacement values. /// /// @param {String} $property - The name of the CSS property. /// @param {String | Number | Color | List | Map} $value - The property's value. /// @param {Map} $gss - Optional Map of GSS annotations to set. /// @param {Map} $replace - An optional Map of replacement key/value pairs if /// the `$value` is a string. /// @param {Bool} $important - Set to true to add an `!important` rule. Defaults /// to false. @mixin property( $property, $value, $gss: (), $replace: null, $important: false ) { @if custom-properties.is-custom-prop($value) { // $value is a custom property Map @include custom-properties.apply( $property, $value, $gss: $gss, $important: $important ); } @else if map.has-key(theme-color.$property-values, $value) { // $value is a theme property String $fallback: map.get(theme-color.$property-values, $value); $custom-prop: custom-properties.create(--mdc-theme-#{$value}, $fallback); @include custom-properties.apply( $property, $custom-prop, $gss: $gss, $important: $important ); } @else { // $value is a standard CSS value $fallback: null; @if $replace { @if meta.type-of($value) != 'string' { // theme.property() should support non-string replacements in the // future, such as List types // e.g. theme.property(border-radius, 8px foo, $replace: (foo: $foo)); @error 'mdc-theme: Invalid replacement value #{$value}. $replace may only be used with string values.'; } $fallback: replace.replace-string($value, $replace, $fallback: true); $value: replace.replace-string($value, $replace); @if $fallback == $value { // The replacements don't contain custom properties with fallbacks $fallback: null; } } @include css.declaration( $property, $value, $fallback-value: $fallback, $gss: $gss, $important: $important ); } } // Applies the correct theme color style to the specified property. // $property is typically color or background-color, but can be any CSS property that accepts color values. // $style should be one of the map keys in $mdc-theme-property-values (_variables.scss), or a color value. // @deprecated use the `property()` mixin instead @mixin prop($property, $style, $important: false) { @if custom-properties.is-custom-prop($style) { @include custom-properties.apply($property, $style, $important: $important); } @else if theme-color.is-valid-theme-prop-value_($style) { @include css.declaration($property, $style, $important: $important); } @else { @if not map.has-key(theme-color.$property-values, $style) { @error "Invalid style: '#{$style}'. Choose one of: #{map.keys(theme-color.$property-values)}"; } $value: map.get(theme-color.$property-values, $style); @include css.declaration( $property, $value: var(--mdc-theme-#{$style}, $value), $fallback-value: $value, $important: $important ); } } /// Perform a recursive map.get on a nested map structure /// Returns a value, or `null` if `$map` does not contain `$path`. /// /// @example scss /// $color: deep-get((foo: (bar: black)), (foo, bar)); /// $color === black; /// /// @param {Map} $map - Map to recurse down /// @param {List} $path - List of keys to traverse the map /// @return {*} The deep value or `null` @function deep-get($map: (), $keys: ()) { $result: $map; @each $key in $keys { $result: map.get($result, $key); @if $result == null { @return null; } } @return $result; }