// // Copyright 2020 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. // @use 'sass:map'; @use 'sass:meta'; @use './css'; @use './gss'; /// Returns true if the parameter is a custom property Map. /// /// @param {*} $value - the value to test. /// @return true if the value is a custom property Map, or false if not. @function is-custom-prop($value) { @return meta.type-of($value) == 'map' and map.has-key($value, 'varname'); } /// Returns true if $prop1's varname and fallback values are deeply equal to /// $prop2's varname and fallback values. /// /// @param {Map} $prop1 - the first value to test. /// @param {Map} $prop2 - the second value to test. /// @return true if both properties are deeply equal @function are-equal($prop1, $prop2) { @return create-var($prop1) == create-var($prop2); } /// Creates a custom property Map. /// /// @param {String} $varname - the custom property name. /// @param {String | Number | Map} - the fallback value (may be another custom /// property Map). May be null. /// @return a custom property Map. @function create($varname, $fallback: null) { @return (varname: $varname, fallback: $fallback); } /// Returns the custom property variable name of a custom property Map. /// /// @param {Map} $custom-prop - a custom property Map. /// @return the custom property variable name defined by the Map. @function get-varname($custom-prop) { @return map.get($custom-prop, 'varname'); } /// Returns the fallback value of a custom property Map. May be null if the /// custom property does not have a fallback. /// /// @param {Map} $custom-prop - a custom property Map. /// @param {Bool} $shallow - if true, return the first fallback value, which /// may be another custom property Map. Defaults to false, which will return /// the deep final fallback value. /// @return the fallback value of a custom property Map. May be null. @function get-fallback($custom-prop, $shallow: false) { $fallback: map.get($custom-prop, 'fallback'); @if is-custom-prop($fallback) and not $shallow { @return get-fallback($fallback); } @return $fallback; } /// Creates a new custom property Map and returns it with the specified new /// fallback value. /// /// @param {Map} $custom-prop - the custom property Map to copy. /// @param {String | Number | Map} $new-fallback - the new fallback value of the /// custom property Map. May be null. /// @param {Bool} $shallow - if true, set the first fallback value. Defaults to /// false, which will set the deep final fallback value. /// @return a new custom property Map with the new fallback value. @function set-fallback($custom-prop, $new-fallback, $shallow: false) { $varname: get-varname($custom-prop); $first-fallback: get-fallback($custom-prop, $shallow: true); @if is-custom-prop($first-fallback) and not $shallow { // The first fallback is a custom property and $shallow is false. Deeply // set the fallback value of the custom property and get the new custom // property Map returned. $new-fallback: set-fallback($first-fallback, $new-fallback); } @return create($varname, $new-fallback); } /// Creates and returns a `var()` function declaration represented by the /// provided custom property Map. /// /// @param {Map} $custom-prop - a custom property Map. /// @return a `var()` function declaration using the custom property Map's /// varname and fallback value. @function create-var($custom-prop) { $varname: get-varname($custom-prop); $fallback: get-fallback($custom-prop, $shallow: true); @if is-custom-prop($fallback) { @return var($varname, create-var($fallback)); } @else if $fallback != null { @return var($varname, $fallback); } @else { @return var($varname); } } /// Applies a custom property value to the specified property. /// /// @param {String} $property - the name of the CSS property. /// @param {Map} $custom-prop - a custom property Map for the property's value. /// @param {Map} $gss - optional Map of GSS annotations to set. /// @param {Bool} $important - set to true to add an `!important` rule. Defaults /// to false. @mixin apply($property, $custom-prop, $gss: (), $important: false) { @if not is-custom-prop($custom-prop) { @error "mdc-theme: Invalid custom property: #{$custom-prop}. Must be a Map with 'varname' and 'fallback'."; } @include css.declaration( $property, $value: create-var($custom-prop), $fallback-value: get-fallback($custom-prop), $gss: $gss, $important: $important ); }