| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- //
- // 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.
- //
- @use 'sass:list';
- @use 'sass:map';
- @use 'sass:meta';
- @use '@material/feature-targeting/feature-targeting';
- @use './css';
- @use './custom-properties';
- @use './gss';
- @use './keys';
- @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 theme-color.get-theme-keys() {
- @include custom-properties.declaration(
- keys.create-custom-property($style)
- );
- }
- }
- }
- @each $style in theme-color.get-theme-keys() {
- @if $style != 'background' and $style != 'surface' {
- .mdc-theme--#{$style} {
- @include feature-targeting.targets($feat-color) {
- @include property(color, $style, $important: true);
- }
- }
- } @else {
- .mdc-theme--#{$style} {
- @include feature-targeting.targets($feat-color) {
- @include property(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 property(background-color, $style, $important: 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(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(foo), bar: 8px)
- /// );
- ///
- /// Note: Material theme key Strings (e.g. `primary`) are not supported as
- /// replacement values.
- ///
- /// A CSS custom property declaration may be emitted by providing a custom
- /// property Map to `$property`. The fallback value (or `$value` if provided)
- /// will be used as the declaration value.
- ///
- /// @example - scss
- /// .foo {
- /// @include theme.property(custom-properties.create(foo, teal));
- /// @include theme.property(custom-properties.create(bar, teal), blue);
- /// }
- ///
- /// @example - css
- /// .foo {
- /// --mdc-foo: teal;
- /// --mdc-bar: blue;
- /// }
- ///
- /// @param {String | Map} $property - The name of the CSS property. May also be
- /// a custom property Map to emit a custom propery declaration.
- /// @param {String | Number | Color | List | Map} $value - The property's value.
- /// This parameter may be omitted if `$property` is a custom property Map.
- /// @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: null,
- $gss: (),
- $replace: null,
- $important: false
- ) {
- @if custom-properties.is-custom-prop($property) {
- // $property is a custom property Map
- // --mdc-foo: value;
- @if $value {
- $property: custom-properties.set-fallback(
- $property,
- $value,
- $shallow: true
- );
- }
- @include custom-properties.declaration(
- $property,
- $gss: $gss,
- $important: $important
- );
- } @else if custom-properties.is-custom-prop($value) {
- // $value is a custom property Map
- // property: var(--mdc-foo, fallback);
- @include custom-properties.declaration(
- $property,
- $value,
- $gss: $gss,
- $important: $important
- );
- } @else if keys.is-key($value) {
- // $value is a key String
- // property: key;
- $custom-prop: keys.create-custom-property($value);
- @if theme-color.is-theme-key($value) {
- // Determine if we need to use a compile-time updated value to support
- // Angular.
- $key: $value;
- // (changed: Bool, value: *)
- $result: theme-color.deprecated-get-global-theme-key-value-if-changed(
- $key
- );
- @if map.get($result, changed) {
- // $mdc-theme-property-values was changed at compile time. Use the
- // global value instead. Otherwise if it was not changed, continue
- // using the key store normally.
- $custom-prop: keys.create-custom-property($key);
- $custom-prop: custom-properties.set-fallback(
- $custom-prop,
- map.get($result, value)
- );
- }
- }
- @include custom-properties.declaration(
- $property,
- $custom-prop,
- $gss: $gss,
- $important: $important
- );
- } @else {
- // $value is a standard CSS value
- // property: value;
- $fallback: null;
- @if $replace {
- // If any replacements are null, treat the entire value as null (do not
- // emit anything).
- @each $name, $replacement in $replace {
- @if $replacement == null {
- $value: null;
- }
- }
- }
- @if $replace and $value {
- @if meta.type-of($replace) != 'map' {
- @error 'mdc-theme: Invalid replacement #{$replace}. Must be a Map.';
- }
- $replace-map-fallback: ();
- $replace-map-value: ();
- $needs-fallback: false;
- @each $name, $replacement in $replace {
- @if custom-properties.is-custom-prop($replacement) {
- $replace-value: custom-properties.get-declaration-value($replacement);
- $replace-fallback: custom-properties.get-declaration-fallback(
- $replacement
- );
- @if $replace-fallback {
- $needs-fallback: true;
- }
- $replace-map-value: map.set(
- $replace-map-value,
- $name,
- $replace-value
- );
- $replace-map-fallback: map.set(
- $replace-map-fallback,
- $name,
- $replace-fallback
- );
- } @else {
- $replace-map-value: map.set($replace-map-value, $name, $replacement);
- $replace-map-fallback: map.set(
- $replace-map-fallback,
- $name,
- $replacement
- );
- }
- }
- @if meta.type-of($value) == 'string' {
- @if $needs-fallback {
- $fallback: replace.replace-string($value, $replace-map-fallback);
- }
- $value: replace.replace-string($value, $replace-map-value);
- } @else if meta.type-of($value) == 'list' {
- @if $needs-fallback {
- $fallback: replace.replace-list($value, $replace-map-fallback);
- }
- $value: replace.replace-list($value, $replace-map-value);
- } @else {
- @error 'mdc-theme: Invalid replacement value #{$value}. $replace may only be used with string or list values.';
- }
- }
- @include css.declaration(
- $property,
- $value,
- $fallback-value: $fallback,
- $gss: $gss,
- $important: $important
- );
- }
- }
- // @deprecated use the `property()` mixin instead
- @mixin prop($property, $style, $important: false) {
- @include property($property, $style, $important: $important);
- }
- /// Validates theme configuration keys by comparing it with original theme
- /// configuration, also validates theme values to see if it has any unsupported
- /// value formats.
- ///
- /// Use this in internal `theme()` mixins to validate library-provided
- /// `$theme` maps and ensure that all tokens are correct and present.
- ///
- /// @example
- /// @mixin theme($theme) {
- /// @include theme.validate-theme($light-theme, $theme);
- /// ...
- /// }
- ///
- /// @see validate-theme-styles to validate only theme keys.
- ///
- /// @param {Map} $origin-theme - Original theme configuration in Sass map format
- /// that has all supported keys.
- /// @param {Map} $custom-theme - Provided theme configuration in Sass map format
- /// that should be validated against `$origin-theme`.
- @mixin validate-theme($origin-theme, $custom-theme, $test-only: false) {
- @include validate-theme-styles(
- $origin-theme,
- $custom-theme,
- $test-only: $test-only
- );
- @include _validate-theme-values($custom-theme, $test-only: $test-only);
- }
- /// Validates theme configuration keys by comparing it with original theme
- /// configuration.
- ///
- /// Use this in internal `theme-styles()` mixins to validate library-provided
- /// `$theme` maps and ensure that all tokens are correct and present.
- ///
- /// @example
- /// @mixin theme-styles($theme) {
- /// @include theme.validate-theme-styles($light-theme, $theme);
- /// ...
- /// }
- ///
- /// @see validate-theme to validate both theme keys and theme values.
- ///
- /// @param {Map} $origin-theme - Original theme configuration in Sass map format
- /// that has all supported keys.
- /// @param {Map} $custom-theme - Provided theme configuration in Sass map format
- /// that should be validated against `$origin-theme`.
- @mixin validate-theme-styles($origin-theme, $custom-theme, $test-only: false) {
- $origin-keys: map.keys($origin-theme);
- $unsupported-keys: ();
- @each $key, $value in $custom-theme {
- @if (not list.index($origin-keys, $key)) {
- $unsupported-keys: list.append(
- $unsupported-keys,
- $key,
- $separator: comma
- );
- }
- }
- @if list.length($unsupported-keys) > 0 {
- $error-message: 'Unsupported keys found: #{$unsupported-keys}. Expected one of: #{$origin-keys}.';
- @if $test-only {
- content: $error-message;
- } @else {
- @error $error-message;
- }
- }
- }
- /// Validates theme configuration values to see if it has any unsupported value
- /// formats.
- /// @see Use `validate-theme()` to validate both theme keys and theme values.
- /// @param {Map} $custom-theme - Provided theme configuration in Sass map format
- /// that needs to be validated.
- @mixin _validate-theme-values($custom-theme, $test-only: false) {
- $unsupported-custom-prop-keys: ();
- @each $key, $value in $custom-theme {
- @if custom-properties.is-custom-prop($value) {
- $unsupported-custom-prop-keys: list.append(
- $unsupported-custom-prop-keys,
- $key,
- $separator: comma
- );
- }
- }
- @if list.length($unsupported-custom-prop-keys) > 0 {
- $error-message: 'Custom properties are not supported for theme map keys: #{$unsupported-custom-prop-keys}';
- @if $test-only {
- content: $error-message;
- } @else {
- @error $error-message;
- }
- }
- }
|