| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- //
- // Copyright 2019 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 "./variables";
- // ==Terminology==
- // Feature:
- // A simple string (e.g. `color`) representing a cross-cutting feature in
- // Material.
- // Feature query:
- // A structure that represents a query for a feature or combination of features. This may be
- // either a feature or a map containing `op` and `queries` fields. A single feature represents a
- // simple query for just that feature. A map represents a complex query made up of an operator,
- // `op`, applied to a list of sub-queries, `queries`.
- // (e.g. `color`, `(op: any, queries: (color, typography))`).
- // Feature target:
- // A map that contains the feature being targeted as well as the current feature query. This is
- // the structure that is intended to be passed to the `@mdc-feature-targets` mixin.
- // (e.g. `(target: color, query: (op: any, queries: (color, typography))`).
- //
- // Public
- //
- // Creates a feature target from the given feature query and targeted feature.
- @function create-target($feature-query, $targeted-feature) {
- $feature-target: (query: $feature-query, target: $targeted-feature);
- $valid: verify-target_($feature-target);
- @return $feature-target;
- }
- // Parses a list of feature targets to produce a map containing the feature query and list of
- // available features.
- @function parse-targets($feature-targets) {
- $valid: verify-target_($feature-targets...);
- $available-features: ();
- @each $target in $feature-targets {
- $available-features: list.append($available-features, map.get($target, target));
- }
- @return (
- available: $available-features,
- query: map.get(list.nth($feature-targets, 1), query)
- );
- }
- // Creates a feature query that is satisfied iff all of its sub-queries are satisfied.
- @function all($feature-queries...) {
- $valid: verify-query_($feature-queries...);
- @return (
- op: all,
- queries: $feature-queries
- );
- }
- // Creates a feature query that is satisfied iff any of its sub-queries are satisfied.
- @function any($feature-queries...) {
- $valid: verify-query_($feature-queries...);
- @return (
- op: any,
- queries: $feature-queries
- );
- }
- // Creates a feature query that is satisfied iff its sub-query is not satisfied.
- @function without($feature-query) {
- $valid: verify-query_($feature-query);
- @return (
- op: without,
- // NOTE: we need to use `append`, just putting parens around a single value doesn't make it a list in Sass.
- queries: list.append((), $feature-query)
- );
- }
- //
- // Package-internal
- //
- // Verifies that the given feature targets are valid, throws an error otherwise.
- @function verify-target_($feature-targets...) {
- @each $target in $feature-targets {
- @if meta.type-of($target) != map {
- @error "Invalid feature target: '#{$target}'. Must be a map.";
- }
- $targeted-feature: map.get($target, target);
- $feature-query: map.get($target, query);
- $valid: verify-feature_($targeted-feature) and verify-query_($feature-query);
- }
- @return true;
- }
- // Checks whether the given feature query is satisfied by the given list of available features.
- @function is-query-satisfied_($feature-query, $available-features) {
- $valid: verify-query_($feature-query);
- $valid: verify-feature_($available-features...);
- @if meta.type-of($feature-query) == map {
- $op: map.get($feature-query, op);
- $sub-queries: map.get($feature-query, queries);
- @if $op == without {
- @return not is-query-satisfied_(list.nth($sub-queries, 1), $available-features);
- }
- @if $op == any {
- @each $sub-query in $sub-queries {
- @if is-query-satisfied_($sub-query, $available-features) {
- @return true;
- }
- }
- @return false;
- }
- @if $op == all {
- @each $sub-query in $sub-queries {
- @if not is-query-satisfied_($sub-query, $available-features) {
- @return false;
- }
- }
- @return true;
- }
- }
- @return list-contains_($available-features, $feature-query);
- }
- //
- // Private
- //
- // Verifies that the given feature(s) are valid, throws an error otherwise.
- @function verify-feature_($features...) {
- @each $feature in $features {
- @if not list-contains_(variables.$all-features, $feature) {
- @error "Invalid feature: '#{$feature}'. Valid features are: #{variables.$all-features}.";
- }
- }
- @return true;
- }
- // Verifies that the given feature queries are valid, throws an error otherwise.
- @function verify-query_($feature-queries...) {
- @each $query in $feature-queries {
- @if meta.type-of($query) == map {
- $op: map.get($query, op);
- $sub-queries: map.get($query, queries);
- $valid: verify-query_($sub-queries...);
- @if not list-contains_(variables.$all-query-operators, $op) {
- @error "Invalid feature query operator: '#{$op}'. " +
- "Valid operators are: #{variables.$all-query-operators}";
- }
- } @else {
- $valid: verify-feature_($query);
- }
- }
- @return true;
- }
- // Checks whether the given list contains the given item.
- @function list-contains_($list, $item) {
- @return list.index($list, $item) != null;
- }
|