From f0f84513f8efe533b6ee670a6f1a0c074387b2ec Mon Sep 17 00:00:00 2001 From: Volpeon Date: Wed, 13 Aug 2025 12:01:46 +0200 Subject: Make use of SASS modules --- src/_contexts.scss | 231 +++++++------- src/_easing.scss | 206 ++++++------ src/_functions.scss | 356 ++++++++++----------- src/_gradients.scss | 791 +++++++++++++++++++++++------------------------ src/_harmony.scss | 65 ++-- src/_props.scss | 214 ++++++------- src/_responsive.scss | 475 ++++++++++++++-------------- src/bem/_block.scss | 250 +++++++-------- src/bem/_debug.scss | 15 +- src/bem/_element.scss | 565 +++++++++++++++++---------------- src/bem/_functions.scss | 27 +- src/bem/_modifier.scss | 227 +++++++------- src/bem/_multi.scss | 102 +++--- src/bem/_state.scss | 84 ++--- src/bem/_suffix.scss | 95 +++--- src/bem/_theme.scss | 57 ++-- src/bem/_validators.scss | 165 +++++----- src/bem/_vars.scss | 28 +- 18 files changed, 1986 insertions(+), 1967 deletions(-) (limited to 'src') diff --git a/src/_contexts.scss b/src/_contexts.scss index 7ffbb4e..ed376a2 100644 --- a/src/_contexts.scss +++ b/src/_contexts.scss @@ -15,6 +15,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; @use './functions'; /// @@ -34,7 +37,7 @@ $stacks: (); /// @throw If context stack already exists /// @mixin create($stack-id) { - $noop: create($stack-id); + $noop: create($stack-id); } /// @@ -43,13 +46,13 @@ $stacks: (); /// @param {string} $stack-id - ID of context stack /// @function create($stack-id) { - @if map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $stacks: map-merge($stacks, ($stack-id: ())) !global; + $stacks: map.merge($stacks, ($stack-id: ())) !global; - @return null; + @return null; } /// @@ -58,7 +61,7 @@ $stacks: (); /// @param {string} $stack-id - ID of context stack /// @mixin clear($stack-id) { - $noop: clear($stack-id); + $noop: clear($stack-id); } /// @@ -67,14 +70,14 @@ $stacks: (); /// @param {string} $stack-id - ID of context stack /// @function clear($stack-id) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $context-stack: (); - $stacks: map-merge($stacks, ($stack-id: $context-stack)) !global; + $context-stack: (); + $stacks: map.merge($stacks, ($stack-id: $context-stack)) !global; - @return null; + @return null; } /// @@ -83,7 +86,7 @@ $stacks: (); /// @param {string} $stack-id - ID of context stack /// @mixin delete($stack-id) { - $noop: delete($stack-id); + $noop: delete($stack-id); } /// @@ -92,13 +95,13 @@ $stacks: (); /// @param {string} $stack-id - ID of context stack /// @function delete($stack-id) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $stacks: map-remove($stacks, $stack-id) !global; + $stacks: map.remove($stacks, $stack-id) !global; - @return null; + @return null; } /// @@ -109,7 +112,7 @@ $stacks: (); /// @param {any} $data [()] - Data that belongs to the context /// @mixin push($stack-id, $id, $data: ()) { - $noop: push($stack-id, $id, $data); + $noop: push($stack-id, $id, $data); } /// @@ -122,16 +125,16 @@ $stacks: (); /// @return {list} A list with two items: 1 = context id, 2 = context data /// @function push($stack-id, $id, $data: ()) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $context: $id $data; - $context-stack: map-get($stacks, $stack-id); - $context-stack: append($context-stack, $context); - $stacks: map-merge($stacks, ($stack-id: $context-stack)) !global; + $context: $id $data; + $context-stack: map.get($stacks, $stack-id); + $context-stack: list.append($context-stack, $context); + $stacks: map.merge($stacks, ($stack-id: $context-stack)) !global; - @return $context; + @return $context; } /// @@ -142,7 +145,7 @@ $stacks: (); /// @throw If context stack doesn't exist /// @mixin pop($stack-id) { - $noop: pop($stack-id); + $noop: pop($stack-id); } /// @@ -153,27 +156,27 @@ $stacks: (); /// @return {list} A list with two items: 1 = context id, 2 = context data /// @function pop($stack-id) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $context-stack: map-get($stacks, $stack-id); + $context-stack: map.get($stacks, $stack-id); - @if length($context-stack) == 0 { - @error 'Context stack "#{inspect($stack-id)}" is already empty.'; - } + @if list.length($context-stack) == 0 { + @error 'Context stack "#{inspect($stack-id)}" is already empty.'; + } - $popped-context: nth($context-stack, -1); + $popped-context: list.nth($context-stack, -1); - @if length($context-stack) == 1 { - $context-stack: (); - } @else { - $context-stack: functions.list-slice($context-stack, 1, length($context-stack) - 1); - } + @if list.length($context-stack) == 1 { + $context-stack: (); + } @else { + $context-stack: functions.list-slice($context-stack, 1, list.length($context-stack) - 1); + } - $stacks: map-merge($stacks, ($stack-id: $context-stack)) !global; + $stacks: map.merge($stacks, ($stack-id: $context-stack)) !global; - @return $popped-context; + @return $popped-context; } /// @@ -186,15 +189,15 @@ $stacks: (); /// @throw If assertion fails /// @function assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) { - @if not contains($stack-id, $context-ids, $check-head-only) { - @error 'Must be called inside of contexts "#{inspect($context-ids)}".'; - } + @if not contains($stack-id, $context-ids, $check-head-only) { + @error 'Must be called inside of contexts "#{inspect($context-ids)}".'; + } - @return null; + @return null; } @mixin assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) { - $noop: assert-stack-must-contain($stack-id, $context-ids, $check-head-only); + $noop: assert-stack-must-contain($stack-id, $context-ids, $check-head-only); } /// @@ -207,15 +210,15 @@ $stacks: (); /// @throw If assertion fails /// @function assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) { - @if contains($stack-id, $context-ids, $check-head-only) { - @error 'Must not be called inside of contexts "#{inspect($context-ids)}".'; - } + @if contains($stack-id, $context-ids, $check-head-only) { + @error 'Must not be called inside of contexts "#{inspect($context-ids)}".'; + } - @return null; + @return null; } @mixin assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) { - $noop: assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only); + $noop: assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only); } /// @@ -228,29 +231,29 @@ $stacks: (); /// @return {bool} `true` if the context stack contains one of the context IDs, otherwise `false` /// @function contains($stack-id, $context-ids, $check-head-only: false) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $context-stack: map-get($stacks, $stack-id); + $context-stack: map.get($stacks, $stack-id); - @if length($context-stack) == 0 { - @return false; - } + @if list.length($context-stack) == 0 { + @return false; + } - $end-idx: if($check-head-only, length($context-stack), 1); + $end-idx: if($check-head-only, list.length($context-stack), 1); - @for $i from length($context-stack) through $end-idx { - $context: nth($context-stack, $i); + @for $i from list.length($context-stack) through $end-idx { + $context: list.nth($context-stack, $i); - @each $chk-context in $context-ids { - @if nth($context, 1) == $chk-context { - @return true; - } - } - } + @each $chk-context in $context-ids { + @if list.nth($context, 1) == $chk-context { + @return true; + } + } + } - @return false; + @return false; } /// @@ -262,15 +265,15 @@ $stacks: (); /// @throw If assertion fails /// @function assert-stack-count($stack-id, $max-count) { - @if count($stack-id) > $max-count { - @error 'Maximum context count "#{inspect($max-count)}" exceeded.'; - } + @if count($stack-id) > $max-count { + @error 'Maximum context count "#{inspect($max-count)}" exceeded.'; + } - @return null; + @return null; } @mixin assert-stack-count($stack-id, $max-count) { - $noop: assert-stack-count($stack-id, $max-count); + $noop: assert-stack-count($stack-id, $max-count); } /// @@ -281,13 +284,13 @@ $stacks: (); /// @return {number} The number of contexts /// @function count($stack-id) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } - $context-stack: map-get($stacks, $stack-id); + $context-stack: map.get($stacks, $stack-id); - @return length($context-stack); + @return list.length($context-stack); } /// @@ -299,37 +302,37 @@ $stacks: (); /// @return {list} Null if no match was found, otherwise a list with two items: 1. context ID, 2. context data. /// @function get($stack-id, $type-or-level: null) { - @if not map-has-key($stacks, $stack-id) { - @error 'Context stack "#{inspect($stack-id)}" does not exist.'; - } - - $context-stack: map-get($stacks, $stack-id); - - @if length($context-stack) == 0 { - @return null; - } - - @if type-of($type-or-level) == number { - $context: nth($context-stack, -$type-or-level); - - @return $context; - } @else { - @for $i from -1 through -(length($context-stack)) { - $context: nth($context-stack, $i); - - @if type-of($type-or-level) == list { - @for $j from 1 through length($type-or-level) { - $ctx: nth($type-or-level, $j); - - @if nth($context, 1) == $ctx { - @return $context; - } - } - } @else if nth($context, 1) == $type-or-level { - @return $context; - } - } - } - - @return null; + @if not map.has-key($stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context-stack: map.get($stacks, $stack-id); + + @if list.length($context-stack) == 0 { + @return null; + } + + @if meta.type-of($type-or-level) == number { + $context: list.nth($context-stack, -$type-or-level); + + @return $context; + } @else { + @for $i from -1 through -(list.length($context-stack)) { + $context: list.nth($context-stack, $i); + + @if meta.type-of($type-or-level) == list { + @for $j from 1 through list.length($type-or-level) { + $ctx: list.nth($type-or-level, $j); + + @if list.nth($context, 1) == $ctx { + @return $context; + } + } + } @else if list.nth($context, 1) == $type-or-level { + @return $context; + } + } + } + + @return null; } diff --git a/src/_easing.scss b/src/_easing.scss index 6d66ea7..939eda2 100644 --- a/src/_easing.scss +++ b/src/_easing.scss @@ -55,62 +55,62 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function cubic-bezier($x1, $y1, $x2, $y2, $x) { - // - // Cover simple cases - // + // + // Cover simple cases + // - @if ($x1 == $y1) and ($x2 == $y2) { - @return $x; - } - @if $x == 0 { - @return 0; - } - @if $x == 1 { - @return 1; - } + @if ($x1 == $y1) and ($x2 == $y2) { + @return $x; + } + @if $x == 0 { + @return 0; + } + @if $x == 1 { + @return 1; + } - // - // Generate samples - // + // + // Generate samples + // - $sample-pool-key: $x1 + '_' + $x2; + $sample-pool-key: $x1 + '_' + $x2; - @if not map.has-key($cubic-bezier-sample-pool, $sample-pool-key) { - $samples: (); + @if not map.has-key($cubic-bezier-sample-pool, $sample-pool-key) { + $samples: (); - @for $i from 0 through $cubic-bezier-sample-pool-size { - $samples: list.append($samples, cubic-bezier-func($x1, $x2, math.div($i, $cubic-bezier-sample-pool-size))); - } + @for $i from 0 through $cubic-bezier-sample-pool-size { + $samples: list.append($samples, cubic-bezier-func($x1, $x2, math.div($i, $cubic-bezier-sample-pool-size))); + } - $cubic-bezier-sample-pool: map.merge($cubic-bezier-sample-pool, ($sample-pool-key: $samples)) !global; - } + $cubic-bezier-sample-pool: map.merge($cubic-bezier-sample-pool, ($sample-pool-key: $samples)) !global; + } - // - // Calculate cubic bezier - // + // + // Calculate cubic bezier + // - @return cubic-bezier-func($y1, $y2, cubic-bezier-t-for-x($x1, $x2, $x)); + @return cubic-bezier-func($y1, $y2, cubic-bezier-t-for-x($x1, $x2, $x)); } /// /// @access private /// @function cubic-bezier-func-a($p1, $p2) { - @return 1 - 3 * $p2 + 3 * $p1; + @return 1 - 3 * $p2 + 3 * $p1; } /// /// @access private /// @function cubic-bezier-func-b($p1, $p2) { - @return 3 * $p2 - 6 * $p1; + @return 3 * $p2 - 6 * $p1; } /// /// @access private /// @function cubic-bezier-func-c($p1) { - @return 3 * $p1; + @return 3 * $p1; } /// @@ -119,7 +119,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @access private /// @function cubic-bezier-func($p1, $p2, $t) { - @return ((cubic-bezier-func-a($p1, $p2) * $t + cubic-bezier-func-b($p1, $p2)) * $t + cubic-bezier-func-c($p1)) * $t; + @return ((cubic-bezier-func-a($p1, $p2) * $t + cubic-bezier-func-b($p1, $p2)) * $t + cubic-bezier-func-c($p1)) * $t; } /// @@ -128,7 +128,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @access private /// @function cubic-bezier-func-slope($p1, $p2, $t) { - @return 3 * cubic-bezier-func-a($p1, $p2) * $t * $t + 2 * cubic-bezier-func-b($p1, $p2) * $t + cubic-bezier-func-c($p1); + @return 3 * cubic-bezier-func-a($p1, $p2) * $t * $t + 2 * cubic-bezier-func-b($p1, $p2) * $t + cubic-bezier-func-c($p1); } /// @@ -137,18 +137,18 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @access private /// @function cubic-bezier-newton-raphson($x1, $x2, $x, $t) { - @for $i from 1 through $cubic-bezier-newton-iters { - $cur-slope: cubic-bezier-func-slope($x1, $x2, $t); + @for $i from 1 through $cubic-bezier-newton-iters { + $cur-slope: cubic-bezier-func-slope($x1, $x2, $t); - @if $cur-slope == 0 { - @return $t; - } + @if $cur-slope == 0 { + @return $t; + } - $cur-x: cubic-bezier-func($x1, $x2, $t) - $x; - $t: $t - math.div($cur-x, $cur-slope); - } + $cur-x: cubic-bezier-func($x1, $x2, $t) - $x; + $t: $t - math.div($cur-x, $cur-slope); + } - @return $t; + @return $t; } /// @@ -157,26 +157,26 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @access private /// @function cubic-bezier-binary-subdivide($x1, $x2, $x, $a, $b) { - $cur-x: 0; - $cur-t: 0; - $i: 0; + $cur-x: 0; + $cur-t: 0; + $i: 0; - @while $i < $cubic-bezier-subdiv-max-iters { - $cur-t: $a + ($b - $a) / 2; - $cur-x: cubic-bezier-func($x1, $x2, $cur-t) - $x; + @while $i < $cubic-bezier-subdiv-max-iters { + $cur-t: $a + ($b - $a) / 2; + $cur-x: cubic-bezier-func($x1, $x2, $cur-t) - $x; - @if $cur-x > 0 { - $b: $cur-t; - } @else { - $a: $cur-t; - } + @if $cur-x > 0 { + $b: $cur-t; + } @else { + $a: $cur-t; + } - @if math.abs($cur-x) < $cubic-bezier-subdiv-precision { - @return $cur-t; - } - } + @if math.abs($cur-x) < $cubic-bezier-subdiv-precision { + @return $cur-t; + } + } - @return $cur-t; + @return $cur-t; } /// @@ -185,30 +185,30 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @access private /// @function cubic-bezier-t-for-x($x1, $x2, $x) { - $sample-pool-key: $x1 + '_' + $x2; - $samples: map.get($cubic-bezier-sample-pool, $sample-pool-key); + $sample-pool-key: $x1 + '_' + $x2; + $samples: map.get($cubic-bezier-sample-pool, $sample-pool-key); - $intv-start: 0; - $cur-sample: 1; - $last-sample: $cubic-bezier-sample-pool-size; + $intv-start: 0; + $cur-sample: 1; + $last-sample: $cubic-bezier-sample-pool-size; - @while ($cur-sample != $last-sample) and (list.nth($samples, $cur-sample) <= $x) { - $intv-start: $intv-start + math.div(1, $cubic-bezier-sample-pool-size); - $cur-sample: $cur-sample + 1; - } - $cur-sample: $cur-sample - 1; + @while ($cur-sample != $last-sample) and (list.nth($samples, $cur-sample) <= $x) { + $intv-start: $intv-start + math.div(1, $cubic-bezier-sample-pool-size); + $cur-sample: $cur-sample + 1; + } + $cur-sample: $cur-sample - 1; - $dist: math.div($x - list.nth($samples, $cur-sample), list.nth($samples, $cur-sample + 1) - list.nth($samples, $cur-sample)); - $guess-t: $intv-start + math.div($dist, $cubic-bezier-sample-pool-size); + $dist: math.div($x - list.nth($samples, $cur-sample), list.nth($samples, $cur-sample + 1) - list.nth($samples, $cur-sample)); + $guess-t: $intv-start + math.div($dist, $cubic-bezier-sample-pool-size); - $init-slope: cubic-bezier-func-slope($x1, $x2, $guess-t); - @if $init-slope >= $cubic-bezier-newton-min-slope { - @return cubic-bezier-newton-raphson($x1, $x2, $x, $guess-t); - } @else if $init-slope == 0 { - @return $guess-t; - } @else { - @return cubic-bezier-binary-subdivide($x1, $x2, $x, $intv-start, $intv-start + 1 / $cubic-bezier-sample-pool-size); - } + $init-slope: cubic-bezier-func-slope($x1, $x2, $guess-t); + @if $init-slope >= $cubic-bezier-newton-min-slope { + @return cubic-bezier-newton-raphson($x1, $x2, $x, $guess-t); + } @else if $init-slope == 0 { + @return $guess-t; + } @else { + @return cubic-bezier-binary-subdivide($x1, $x2, $x, $intv-start, $intv-start + 1 / $cubic-bezier-sample-pool-size); + } } /// @@ -219,7 +219,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function linear($x) { - @return $x; + @return $x; } /// @@ -230,7 +230,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease($x) { - @return cubic-bezier(.25, .1, .25, 1, $x); + @return cubic-bezier(.25, .1, .25, 1, $x); } /// @@ -241,7 +241,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in($x) { - @return cubic-bezier(.42, 0, 1, 1, $x); + @return cubic-bezier(.42, 0, 1, 1, $x); } /// @@ -252,7 +252,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out($x) { - @return cubic-bezier(0, 0, .58, 1, $x); + @return cubic-bezier(0, 0, .58, 1, $x); } /// @@ -263,7 +263,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out($x) { - @return cubic-bezier(.42, 0, .58, 1, $x); + @return cubic-bezier(.42, 0, .58, 1, $x); } /// @@ -274,7 +274,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-sine($x) { - @return cubic-bezier(.47, 0, .745, .715, $x); + @return cubic-bezier(.47, 0, .745, .715, $x); } /// @@ -285,7 +285,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-sine($x) { - @return cubic-bezier(.39, .575, .565, 1, $x); + @return cubic-bezier(.39, .575, .565, 1, $x); } /// @@ -296,7 +296,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-sine($x) { - @return cubic-bezier(.445, .05, .55, .95, $x); + @return cubic-bezier(.445, .05, .55, .95, $x); } /// @@ -307,7 +307,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-quad($x) { - @return cubic-bezier(.55, .085, .68, .53, $x); + @return cubic-bezier(.55, .085, .68, .53, $x); } /// @@ -318,7 +318,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-quad($x) { - @return cubic-bezier(.25, .46, .45, .94, $x); + @return cubic-bezier(.25, .46, .45, .94, $x); } /// @@ -329,7 +329,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-quad($x) { - @return cubic-bezier(.455, .03, .515, .955, $x); + @return cubic-bezier(.455, .03, .515, .955, $x); } /// @@ -340,7 +340,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-cubic($x) { - @return cubic-bezier(.55, .055, .675, .19, $x); + @return cubic-bezier(.55, .055, .675, .19, $x); } /// @@ -351,7 +351,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-cubic($x) { - @return cubic-bezier(.215, .61, .355, 1, $x); + @return cubic-bezier(.215, .61, .355, 1, $x); } /// @@ -362,7 +362,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-cubic($x) { - @return cubic-bezier(.645, .045, .355, 1, $x); + @return cubic-bezier(.645, .045, .355, 1, $x); } /// @@ -373,7 +373,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-quart($x) { - @return cubic-bezier(.895, .03, .685, .22, $x); + @return cubic-bezier(.895, .03, .685, .22, $x); } /// @@ -384,7 +384,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-quart($x) { - @return cubic-bezier(.165, .84, .44, 1, $x); + @return cubic-bezier(.165, .84, .44, 1, $x); } /// @@ -395,7 +395,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-quart($x) { - @return cubic-bezier(.77, 0, .175, 1, $x); + @return cubic-bezier(.77, 0, .175, 1, $x); } /// @@ -406,7 +406,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-quint($x) { - @return cubic-bezier(.755, .05, .855, .06, $x); + @return cubic-bezier(.755, .05, .855, .06, $x); } /// @@ -417,7 +417,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-quint($x) { - @return cubic-bezier(.23, 1, .32, 1, $x); + @return cubic-bezier(.23, 1, .32, 1, $x); } /// @@ -428,7 +428,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-quint($x) { - @return cubic-bezier(.86, 0, .07, 1, $x); + @return cubic-bezier(.86, 0, .07, 1, $x); } /// @@ -439,7 +439,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-expo($x) { - @return cubic-bezier(.95, .05, .795, .035, $x); + @return cubic-bezier(.95, .05, .795, .035, $x); } /// @@ -450,7 +450,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-expo($x) { - @return cubic-bezier(.19, 1, .22, 1, $x); + @return cubic-bezier(.19, 1, .22, 1, $x); } /// @@ -461,7 +461,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-expo($x) { - @return cubic-bezier(1, 0, 0, 1, $x); + @return cubic-bezier(1, 0, 0, 1, $x); } /// @@ -472,7 +472,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-circ($x) { - @return cubic-bezier(.6, .04, .98, .335, $x); + @return cubic-bezier(.6, .04, .98, .335, $x); } /// @@ -483,7 +483,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-out-circ($x) { - @return cubic-bezier(.075, .82, .165, 1, $x); + @return cubic-bezier(.075, .82, .165, 1, $x); } /// @@ -494,5 +494,5 @@ $cubic-bezier-subdiv-max-iters: 10 !default; /// @return {number} /// @function ease-in-out-circ($x) { - @return cubic-bezier(.785, .135, .15, .86, $x); + @return cubic-bezier(.785, .135, .15, .86, $x); } diff --git a/src/_functions.scss b/src/_functions.scss index 0d139b4..74cc1b5 100644 --- a/src/_functions.scss +++ b/src/_functions.scss @@ -19,21 +19,21 @@ $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9); $units: ( - 'px': 1px, - 'cm': 1cm, - 'mm': 1mm, - '%': 1%, - 'ch': 1ch, - 'pc': 1pc, - 'in': 1in, - 'em': 1em, - 'rem': 1rem, - 'pt': 1pt, - 'ex': 1ex, - 'vw': 1vw, - 'vh': 1vh, - 'vmin': 1vmin, - 'vmax': 1vmax + 'px': 1px, + 'cm': 1cm, + 'mm': 1mm, + '%': 1%, + 'ch': 1ch, + 'pc': 1pc, + 'in': 1in, + 'em': 1em, + 'rem': 1rem, + 'pt': 1pt, + 'ex': 1ex, + 'vw': 1vw, + 'vh': 1vh, + 'vmin': 1vmin, + 'vmax': 1vmax ); /// @@ -46,13 +46,13 @@ $units: ( /// @return {string} A string with all instances of $search replaced with $replace /// @function str-replace($string, $search, $replace) { - $index: string.index($string, $search); + $index: string.index($string, $search); - @if $index { - @return string.slice($string, 1, $index - 1) + $replace + str-replace(string.slice($string, $index + string.length($search)), $search, $replace); - } + @if $index { + @return string.slice($string, 1, $index - 1) + $replace + str-replace(string.slice($string, $index + string.length($search)), $search, $replace); + } - @return $string; + @return $string; } /// @@ -64,17 +64,17 @@ $units: ( /// @return {string} /// @function str-implode($list, $glue: '') { - $result: ''; + $result: ''; - @each $item in $list { - $result: $result + if(list.length($item) > 1, str-implode($item, $glue), $item); + @each $item in $list { + $result: $result + if(list.length($item) > 1, str-implode($item, $glue), $item); - @if $item != list.nth($list, list.length($list)) { - $result: $result + $glue; - } - } + @if $item != list.nth($list, list.length($list)) { + $result: $result + $glue; + } + } - @return $result; + @return $result; } /// @@ -87,17 +87,17 @@ $units: ( /// @return {list} A slice of the list /// @function list-slice($list, $start: 1, $end: list.length($list)) { - $result: (); + $result: (); - @if $end >= $start { - @for $i from $start through $end { - @if $i != 0 { - $result: list.append($result, list.nth($list, $i), list.separator($list)); - } - } - } + @if $end >= $start { + @for $i from $start through $end { + @if $i != 0 { + $result: list.append($result, list.nth($list, $i), list.separator($list)); + } + } + } - @return $result; + @return $result; } /// @@ -109,15 +109,15 @@ $units: ( /// @return {list} A list with $value at the beginning, followed by the other items /// @function list-prepend($list, $value) { - $result: list.append((), $value, list.separator($list)); + $result: list.append((), $value, list.separator($list)); - @if list.length($list) > 0 { - @for $i from 1 through list.length($list) { - $result: list.append($result, list.nth($list, $i), list.separator($list)); - } - } + @if list.length($list) > 0 { + @for $i from 1 through list.length($list) { + $result: list.append($result, list.nth($list, $i), list.separator($list)); + } + } - @return $result; + @return $result; } /// @@ -128,15 +128,15 @@ $units: ( /// @return {list} Teh reversed list /// @function list-reverse($list) { - @if list.length($list) == 0 { - @return $list; - } - - $result: (); - @for $i from list.length($list) * -1 through -1 { - $result: list.append($result, list.nth($list, math.abs($i))); - } - @return $result; + @if list.length($list) == 0 { + @return $list; + } + + $result: (); + @for $i from list.length($list) * -1 through -1 { + $result: list.append($result, list.nth($list, math.abs($i))); + } + @return $result; } /// @@ -150,51 +150,51 @@ $units: ( /// @return {list} Sorted list /// @function quicksort($l, $left: 1, $right: list.length($l)) { - @if $left < $right { - $pvr: quicksort-partition($l, $left, $right); - $pivot: list.nth($pvr, 1); - $l: list.nth($pvr, 2); - $l: quicksort($l, $left, $pivot); - $l: quicksort($l, $pivot + 1, $right); - } - - @return $l; + @if $left < $right { + $pvr: quicksort-partition($l, $left, $right); + $pivot: list.nth($pvr, 1); + $l: list.nth($pvr, 2); + $l: quicksort($l, $left, $pivot); + $l: quicksort($l, $pivot + 1, $right); + } + + @return $l; } /// /// @access private /// @function quicksort-partition($l, $left, $right) { - $start: true; - $i: $left; - $j: $right - 1; - $pivot: list.nth($l, $right); - - @while ($i < $j) or $start { - @while (list.nth($l, $i) < $pivot) and ($i < $right - 1) { - $i: $i + 1; - } - - @while (list.nth($l, $j)>= $pivot) and ($j > $left) { - $j: $j - 1; - } - - @if $i < $j { - $i-val: list.nth($l, $i); - $l: list.set-nth($l, $i, list.nth($l, $j)); - $l: list.set-nth($l, $j, $i-val); - } - - $start: false; - } - - @if list.nth($l, $i) > $pivot { - $i-val: list.nth($l, $i); - $l: list.set-nth($l, $i, list.nth($l, $right)); - $l: list.set-nth($l, $right, $i-val); - } - - @return $i $l; + $start: true; + $i: $left; + $j: $right - 1; + $pivot: list.nth($l, $right); + + @while ($i < $j) or $start { + @while (list.nth($l, $i) < $pivot) and ($i < $right - 1) { + $i: $i + 1; + } + + @while (list.nth($l, $j)>= $pivot) and ($j > $left) { + $j: $j - 1; + } + + @if $i < $j { + $i-val: list.nth($l, $i); + $l: list.set-nth($l, $i, list.nth($l, $j)); + $l: list.set-nth($l, $j, $i-val); + } + + $start: false; + } + + @if list.nth($l, $i) > $pivot { + $i-val: list.nth($l, $i); + $l: list.set-nth($l, $i, list.nth($l, $right)); + $l: list.set-nth($l, $right, $i-val); + } + + @return $i $l; } /// @@ -208,10 +208,10 @@ $units: ( /// @return {any} Either the value assigned to $key or $default /// @function map-get-default($map, $key, $keys...) { - $default: list.nth($keys, list.length($keys)); - $keys: list-slice($keys, 1, list.length($keys) - 1); + $default: list.nth($keys, list.length($keys)); + $keys: list-slice($keys, 1, list.length($keys) - 1); - @return if(map.has-key($map, $key, $keys...), map.get($map, $key, $keys...), $default); + @return if(map.has-key($map, $key, $keys...), map.get($map, $key, $keys...), $default); } /// @@ -222,29 +222,29 @@ $units: ( /// @return {string} /// @function map-print($map) { - $output: ''; - - @each $key, $value in $map { - $value-str: ''; - - @if meta.type-of($value) == map { - $value-str: '[ ' + map-print($value) + ' ]'; - } @else if meta.type-of($value) == list { - $value-str: '[ ' + str-implode($value, ', ') + ' ]'; - } @else if meta.type-of($value) == string { - $value-str: '\'' + $value + '\''; - } @else { - $value-str: $value; - } - - @if $output == '' { - $output: $key + ': ' + $value-str; - } @else { - $output: $output + ', ' + $key + ': ' + $value-str; - } - } - - @return $output; + $output: ''; + + @each $key, $value in $map { + $value-str: ''; + + @if meta.type-of($value) == map { + $value-str: '[ ' + map-print($value) + ' ]'; + } @else if meta.type-of($value) == list { + $value-str: '[ ' + str-implode($value, ', ') + ' ]'; + } @else if meta.type-of($value) == string { + $value-str: '\'' + $value + '\''; + } @else { + $value-str: $value; + } + + @if $output == '' { + $output: $key + ': ' + $value-str; + } @else { + $output: $output + ', ' + $key + ': ' + $value-str; + } + } + + @return $output; } /// @@ -256,35 +256,35 @@ $units: ( /// @return {bool} `true` if the selector matches at least one suffix, otherwise `false`. /// @function selector-suffix-match($selector, $suffixes) { - $match: true; - - @each $sel in $selector { - @if $match { - $sel-match: false; - - @each $suffix in $suffixes { - @if not $sel-match { - $suf-match: true; - - @for $i from 1 through list.length($suffix) { - @if $suf-match and (list.nth($sel, -$i) != list.nth($suffix, -$i)) { - $suf-match: false; - } - } - - @if $suf-match { - $sel-match: true; - } - } - } - - @if not $sel-match { - $match: false; - } - } - } - - @return $match; + $match: true; + + @each $sel in $selector { + @if $match { + $sel-match: false; + + @each $suffix in $suffixes { + @if not $sel-match { + $suf-match: true; + + @for $i from 1 through list.length($suffix) { + @if $suf-match and (list.nth($sel, -$i) != list.nth($suffix, -$i)) { + $suf-match: false; + } + } + + @if $suf-match { + $sel-match: true; + } + } + } + + @if not $sel-match { + $match: false; + } + } + } + + @return $match; } /// @@ -295,7 +295,7 @@ $units: ( /// @return {number} Unit-less variable /// @function strip-unit($n) { - @return math.div($n, $n * 0 + 1); + @return math.div($n, $n * 0 + 1); } /// @@ -307,7 +307,7 @@ $units: ( /// @return {number} Pixel value converted to rem /// @function px-to-rem($size, $base: vars.$root-size) { - @return math.div($size, $base) * 1rem; + @return math.div($size, $base) * 1rem; } /// @@ -318,35 +318,35 @@ $units: ( /// @return {number} /// @function to-number($value) { - @if meta.type-of($value) == 'number' { - @return $value; - } - @if meta.type-of($value) != 'string' { - @error 'Value for `to-number` should be a number or a string.'; - } + @if meta.type-of($value) == 'number' { + @return $value; + } + @if meta.type-of($value) != 'string' { + @error 'Value for `to-number` should be a number or a string.'; + } - $result: 0; - $digits: 0; - $minus: string.slice($value, 1, 1) == '-'; + $result: 0; + $digits: 0; + $minus: string.slice($value, 1, 1) == '-'; - @for $i from if($minus, 2, 1) through string.length($value) { - $character: string.slice($value, $i, $i); + @for $i from if($minus, 2, 1) through string.length($value) { + $character: string.slice($value, $i, $i); - @if not list.index(map.keys($numbers), $character) and $character != '.' { - @return to-length(if($minus, -$result, $result), string.slice($value, $i)); - } + @if not list.index(map.keys($numbers), $character) and $character != '.' { + @return to-length(if($minus, -$result, $result), string.slice($value, $i)); + } - @if $character == '.' { - $digits: 1; - } @else if $digits == 0 { - $result: $result * 10 + map.get($numbers, $character); - } @else { - $digits: $digits * 10; - $result: $result + math.div(map.get($numbers, $character), $digits); - } - } + @if $character == '.' { + $digits: 1; + } @else if $digits == 0 { + $result: $result * 10 + map.get($numbers, $character); + } @else { + $digits: $digits * 10; + $result: $result + math.div(map.get($numbers, $character), $digits); + } + } - @return if($minus, -$result, $result); + @return if($minus, -$result, $result); } /// @@ -358,11 +358,11 @@ $units: ( /// @return {number} $value expressed in $unit /// @function to-length($value, $unit) { - @if not list.index(map.keys($units), $unit) { - @error 'Invalid unit `#{$unit}`.'; - } + @if not list.index(map.keys($units), $unit) { + @error 'Invalid unit `#{$unit}`.'; + } - @return $value * map.get($units, $unit); + @return $value * map.get($units, $unit); } /// @@ -371,5 +371,5 @@ $units: ( /// @content /// @mixin execute { - @content; + @content; } diff --git a/src/_gradients.scss b/src/_gradients.scss index 6575482..345a9f1 100644 --- a/src/_gradients.scss +++ b/src/_gradients.scss @@ -15,8 +15,11 @@ /// @access public //// +@use 'sass:color'; +@use 'sass:list'; @use 'sass:math'; @use 'sass:meta'; +@use 'sass:string'; @use './functions'; @use './easing'; @@ -135,144 +138,136 @@ $easing-gradient-steps: 10 !default; /// } /// @function easing-gradient($type, $dir, $stop, $stops...) { - $pos-template: null; - $stops: functions.list-prepend($stops, $stop); - - $last-positioned-stop: 1; - $generated-stops: (); - - // - // Generate gradient - // - - @for $i from 1 through length($stops) { - $stop: nth($stops, $i); - - @if $i == 1 { - @if not easing-gradient-is-color-stop($stop) { - @error 'The first color stop argument must be a color stop.'; - } - - @if type-of($stop) == color { - // - // The first color stop is unpositioned. The default position for the first - // color stop is 0, which is explicitly added for easier calculations. - // - - $stop: $stop 0; - $stops: set-nth($stops, $i, $stop); - } - - $generated-stops: append($generated-stops, functions.str-implode($stop, ' ')); - } @else if easing-gradient-is-positioned-color-stop($stop) or ($i == length($stops)) { - @if not easing-gradient-is-color-stop($stop) { - @error 'The last color stop argument must be a color stop.'; - } - - // - // Either the current stops list item is a positioned color stop, or the end of - // the stops list has been reached. - // - - @if (type-of($stop) == color) and ($i == length($stops)) { - // - // The current stop is an unpositioned color stop, which means this is the end - // of the stops list. The default position for the last color stop is 100%, which - // is explicitly added for easier calculations. - // - - $stop: $stop 100%; - $stops: set-nth($stops, $i, $stop); - } - - // - // Now the current color stop is guaranteed to be a positioned color stop. - // - - @if $i > $last-positioned-stop + 1 { - // - // There is at least one stops list item (unpositioned color stop or easing function) - // between the last positioned color stop and the current stops list item. Interpolate - // the positions of all stops list items that are color stops. - // - - $interpolated-stops: easing-gradient-interpolate-stop-positions( - nth($stops, $last-positioned-stop), - functions.list-slice($stops, $last-positioned-stop + 1, $i - 1), - $stop - ); - - $new-stops: join( - functions.list-slice($stops, 1, $last-positioned-stop), - $interpolated-stops - ); - $new-stops: join( - $new-stops, - functions.list-slice($stops, $i) - ); - $stops: $new-stops; - } - - // - // Now all color stops between this one and the last positioned one have - // interpolated positions. - // Next task is to perform an easing transition between all color stops that - // have an easing function specified. The rest can be left alone since the - // browser will automatically apply a linear transition between them. - // - - $j: $last-positioned-stop + 1; - @while $j <= $i { - $easing: null; - $prev-stop: nth($stops, $j - 1); - $next-stop: nth($stops, $j); - - @if not easing-gradient-is-color-stop($next-stop) { - $j: $j + 1; - - $easing: $next-stop; - $next-stop: nth($stops, $j); - - @if not easing-gradient-is-color-stop($next-stop) { - @error 'There can be at most one interpolation hint between to color stops.'; - } - } - - @if $easing != null { - @if type-of($easing) == number { - @error 'Midpoint shifts are not supported.'; - } - - $easing-func: null; - $easing-args: (); - - @if type-of($easing) == list { - $easing-args: functions.list-slice($easing, 2); - $easing: nth($easing, 1); - } - - $generated-stops: join( - $generated-stops, - easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args) - ); - } @else { - $generated-stops: append($generated-stops, functions.str-implode($next-stop, ' ')); - } - - $j: $j + 1; - } - - $last-positioned-stop: $i; - } - } - - @if $type == 'linear' { - @return linear-gradient($dir, unquote(functions.str-implode($generated-stops, ', '))); - } @else if $type == 'radial' { - @return radial-gradient($dir, unquote(functions.str-implode($generated-stops, ', '))); - } @else { - @error 'Invalid gradient type: #{inspect($type)}.'; - } + $pos-template: null; + $stops: functions.list-prepend($stops, $stop); + + $last-positioned-stop: 1; + $generated-stops: (); + + // + // Generate gradient + // + + @for $i from 1 through list.length($stops) { + $stop: list.nth($stops, $i); + + @if $i == 1 { + @if not easing-gradient-is-color-stop($stop) { + @error 'The first color stop argument must be a color stop.'; + } + + @if meta.type-of($stop) == color { + // + // The first color stop is unpositioned. The default position for the first + // color stop is 0, which is explicitly added for easier calculations. + // + + $stop: $stop 0; + $stops: list.set-nth($stops, $i, $stop); + } + + $generated-stops: list.append($generated-stops, functions.str-implode($stop, ' ')); + } @else if easing-gradient-is-positioned-color-stop($stop) or ($i == list.length($stops)) { + @if not easing-gradient-is-color-stop($stop) { + @error 'The last color stop argument must be a color stop.'; + } + + // + // Either the current stops list item is a positioned color stop, or the end of + // the stops list has been reached. + // + + @if (meta.type-of($stop) == color) and ($i == list.length($stops)) { + // + // The current stop is an unpositioned color stop, which means this is the end + // of the stops list. The default position for the last color stop is 100%, which + // is explicitly added for easier calculations. + // + + $stop: $stop 100%; + $stops: list.set-nth($stops, $i, $stop); + } + + // + // Now the current color stop is guaranteed to be a positioned color stop. + // + + @if $i > $last-positioned-stop + 1 { + // + // There is at least one stops list item (unpositioned color stop or easing function) + // between the last positioned color stop and the current stops list item. Interpolate + // the positions of all stops list items that are color stops. + // + + $interpolated-stops: easing-gradient-interpolate-stop-positions(list.nth($stops, $last-positioned-stop), + functions.list-slice($stops, $last-positioned-stop + 1, $i - 1), + $stop); + + $new-stops: list.join(functions.list-slice($stops, 1, $last-positioned-stop), + $interpolated-stops); + $new-stops: list.join($new-stops, + functions.list-slice($stops, $i)); + $stops: $new-stops; + } + + // + // Now all color stops between this one and the last positioned one have + // interpolated positions. + // Next task is to perform an easing transition between all color stops that + // have an easing function specified. The rest can be left alone since the + // browser will automatically apply a linear transition between them. + // + + $j: $last-positioned-stop + 1; + @while $j <= $i { + $easing: null; + $prev-stop: list.nth($stops, $j - 1); + $next-stop: list.nth($stops, $j); + + @if not easing-gradient-is-color-stop($next-stop) { + $j: $j + 1; + + $easing: $next-stop; + $next-stop: list.nth($stops, $j); + + @if not easing-gradient-is-color-stop($next-stop) { + @error 'There can be at most one interpolation hint between to color stops.'; + } + } + + @if $easing != null { + @if meta.type-of($easing) == number { + @error 'Midpoint shifts are not supported.'; + } + + $easing-func: null; + $easing-args: (); + + @if meta.type-of($easing) == list { + $easing-args: functions.list-slice($easing, 2); + $easing: list.nth($easing, 1); + } + + $generated-stops: list.join($generated-stops, + easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args)); + } @else { + $generated-stops: list.append($generated-stops, functions.str-implode($next-stop, ' ')); + } + + $j: $j + 1; + } + + $last-positioned-stop: $i; + } + } + + @if $type == 'linear' { + @return linear-gradient($dir, string.unquote(functions.str-implode($generated-stops, ', '))); + } @else if $type == 'radial' { + @return radial-gradient($dir, string.unquote(functions.str-implode($generated-stops, ', '))); + } @else { + @error 'Invalid gradient type: #{inspect($type)}.'; + } } /// @@ -281,7 +276,7 @@ $easing-gradient-steps: 10 !default; /// @see {function} easing-gradient /// @function easing-linear-gradient($dir, $stop, $stops...) { - @return easing-gradient('linear', $dir, $stop, $stops...); + @return easing-gradient('linear', $dir, $stop, $stops...); } /// @@ -290,7 +285,7 @@ $easing-gradient-steps: 10 !default; /// @see {function} easing-gradient /// @function easing-radial-gradient($dir, $stop, $stops...) { - @return easing-gradient('radial', $dir, $stop, $stops...); + @return easing-gradient('radial', $dir, $stop, $stops...); } /// @@ -299,24 +294,24 @@ $easing-gradient-steps: 10 !default; /// @access private /// @function easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args: ()) { - @if $easing == 'steps' { - $steps: null; - $jump: null; - - @if length($easing-args) > 1 { - $steps: nth($easing-args, 1); - $jump: nth($easing-args, 2); - } @else { - $steps: nth($easing-args, 1); - $jump: jump-end; - } - - @return easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump); - } @else { - $easing-func: get-function($easing, $module: easing); - - @return easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args); - } + @if $easing == 'steps' { + $steps: null; + $jump: null; + + @if list.length($easing-args) > 1 { + $steps: list.nth($easing-args, 1); + $jump: list.nth($easing-args, 2); + } @else { + $steps: list.nth($easing-args, 1); + $jump: jump-end; + } + + @return easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump); + } @else { + $easing-func: meta.get-function($easing, $module: easing); + + @return easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args); + } } /// @@ -325,74 +320,74 @@ $easing-gradient-steps: 10 !default; /// @access private /// @function easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args: ()) { - $prev-stop-color: nth($prev-stop, 1); - $prev-stop-pos: nth($prev-stop, 2); - $next-stop-color: nth($next-stop, 1); - $next-stop-pos: nth($next-stop, 2); - - $stops: (); - - @if ((type-of($prev-stop-pos) == number) and (type-of($next-stop-pos) == number) and (unit($prev-stop-pos) == unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { - // - // The transition color stop positions can be statically calculated. - // - - $distance: $next-stop-pos - $prev-stop-pos; - - @for $i from 1 through $easing-gradient-steps { - $perc: math.div($i, $easing-gradient-steps); - - $color: null; - $pos: $prev-stop-pos + $perc * $distance; - @if $perc == 1 { - $color: $next-stop-color; - } @else { - $color: mix($next-stop-color, $prev-stop-color, call($easing-func, append($easing-args, $perc)...) * 100%); - } - - $stops: append($stops, $color + ' ' + $pos); - } - } @else { - // - // The transition color stop positions have to be dynamically calculated with the calc() function. - // - - @if type-of($prev-stop-pos) != number { - // must be calc() - @if type-of($prev-stop-pos) != calculation { - @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; - } - - $prev-stop-pos: meta.calc-args($prev-stop-pos); - } - - @if type-of($next-stop-pos) != number { - // must be calc() - @if type-of($next-stop-pos) != calculation { - @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; - } - - $next-stop-pos: meta.calc-args($next-stop-pos); - } - - @for $i from 1 through $easing-gradient-steps { - $perc: math.div($i, $easing-gradient-steps); - - $color: null; - $pos: null; - @if $perc == 1 { - $color: $next-stop-color; - $pos: calc(#{$next-stop-pos}); - } @else { - $color: mix($next-stop-color, $prev-stop-color, call($easing-func, append($easing-args, $perc)...) * 100%); - $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); - } - - $stops: append($stops, $color + ' ' + $pos); - } - } - - @return $stops; + $prev-stop-color: list.nth($prev-stop, 1); + $prev-stop-pos: list.nth($prev-stop, 2); + $next-stop-color: list.nth($next-stop, 1); + $next-stop-pos: list.nth($next-stop, 2); + + $stops: (); + + @if ((meta.type-of($prev-stop-pos) == number) and (meta.type-of($next-stop-pos) == number) and (math.unit($prev-stop-pos) == math.unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { + // + // The transition color stop positions can be statically calculated. + // + + $distance: $next-stop-pos - $prev-stop-pos; + + @for $i from 1 through $easing-gradient-steps { + $perc: math.div($i, $easing-gradient-steps); + + $color: null; + $pos: $prev-stop-pos + $perc * $distance; + @if $perc == 1 { + $color: $next-stop-color; + } @else { + $color: color.mix($next-stop-color, $prev-stop-color, meta.call($easing-func, list.append($easing-args, $perc)...) * 100%); + } + + $stops: list.append($stops, $color + ' ' + $pos); + } + } @else { + // + // The transition color stop positions have to be dynamically calculated with the calc() function. + // + + @if meta.type-of($prev-stop-pos) != number { + // must be calc() + @if meta.type-of($prev-stop-pos) != calculation { + @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; + } + + $prev-stop-pos: meta.calc-args($prev-stop-pos); + } + + @if meta.type-of($next-stop-pos) != number { + // must be calc() + @if meta.type-of($next-stop-pos) != calculation { + @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; + } + + $next-stop-pos: meta.calc-args($next-stop-pos); + } + + @for $i from 1 through $easing-gradient-steps { + $perc: math.div($i, $easing-gradient-steps); + + $color: null; + $pos: null; + @if $perc == 1 { + $color: $next-stop-color; + $pos: calc(#{$next-stop-pos}); + } @else { + $color: color.mix($next-stop-color, $prev-stop-color, meta.call($easing-func, list.append($easing-args, $perc)...) * 100%); + $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); + } + + $stops: list.append($stops, $color + ' ' + $pos); + } + } + + @return $stops; } /// @@ -401,110 +396,110 @@ $easing-gradient-steps: 10 !default; /// @access private /// @function easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump: jump-end) { - $prev-stop-color: nth($prev-stop, 1); - $prev-stop-pos: nth($prev-stop, 2); - $next-stop-color: nth($next-stop, 1); - $next-stop-pos: nth($next-stop, 2); - - $stops: (); - - @if ((type-of($prev-stop-pos) == number) and (type-of($next-stop-pos) == number) and (unit($prev-stop-pos) == unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { - // - // The transition color stop positions can be statically calculated. - // - - $distance: $next-stop-pos - $prev-stop-pos; - - @for $i from 1 through $steps { - $x1: math.div($i - 1, $steps); - $x2: math.div($i, $steps); - $y: null; - - @if $jump == jump-start { - $y: math.div($i, $steps); - } @else if $jump == jump-end { - $y: math.div($i - 1, $steps); - } @else if $jump == jump-both { - $y: math.div($i, $steps + 1); - } @else if $jump == jump-none { - $y: math.div($i - 1, $steps - 1); - } @else { - @error 'Invalid $jump: #{inspect($jump)}'; - } - - $color: null; - $pos1: if($x1 == 0, $prev-stop-pos, $prev-stop-pos + $x1 * $distance); - $pos2: if($x2 == 1, $next-stop-pos, $prev-stop-pos + $x2 * $distance); - - @if $y == 0 { - $color: $prev-stop-color; - } @else if $y == 1 { - $color: $next-stop-color; - } @else { - $color: mix($next-stop-color, $prev-stop-color, $y * 100%); - } - - $stops: append($stops, $color + ' ' + $pos1); - $stops: append($stops, $color + ' ' + $pos2); - } - } @else { - // - // The transition color stop positions have to be dynamically calculated with the calc() function. - // - - @if type-of($prev-stop-pos) != number { - // must be calc() - @if type-of($prev-stop-pos) != calculation { - @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; - } - - $prev-stop-pos: meta.calc-args($prev-stop-pos); - } - - @if type-of($next-stop-pos) != number { - // must be calc() - @if type-of($next-stop-pos) != calculation { - @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; - } - - $next-stop-pos: meta.calc-args($next-stop-pos); - } - - @for $i from 1 through $steps { - $x1: math.div($i - 1, $steps); - $x2: math.div($i, $steps); - $y: null; - - @if $jump == jump-start { - $y: math.div($i, $steps); - } @else if $jump == jump-end { - $y: math.div($i - 1, $steps); - } @else if $jump == jump-both { - $y: math.div($i, $steps + 1); - } @else if $jump == jump-none { - $y: math.div($i - 1, $steps - 1); - } @else { - @error 'Invalid $jump: #{inspect($jump)}'; - } - - $color: null; - $pos1: if($x1 == 0, $prev-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$x1})); - $pos2: if($x2 == 1, $next-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$x2})); - - @if $y == 0 { - $color: $prev-stop-color; - } @else if $y == 1 { - $color: $next-stop-color; - } @else { - $color: mix($next-stop-color, $prev-stop-color, $y * 100%); - } - - $stops: append($stops, $color + ' ' + $pos1); - $stops: append($stops, $color + ' ' + $pos2); - } - } - - @return $stops; + $prev-stop-color: list.nth($prev-stop, 1); + $prev-stop-pos: list.nth($prev-stop, 2); + $next-stop-color: list.nth($next-stop, 1); + $next-stop-pos: list.nth($next-stop, 2); + + $stops: (); + + @if ((meta.type-of($prev-stop-pos) == number) and (meta.type-of($next-stop-pos) == number) and (math.unit($prev-stop-pos) == math.unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { + // + // The transition color stop positions can be statically calculated. + // + + $distance: $next-stop-pos - $prev-stop-pos; + + @for $i from 1 through $steps { + $xx1: math.div($i - 1, $steps); + $xx2: math.div($i, $steps); + $y: null; + + @if $jump == jump-start { + $y: math.div($i, $steps); + } @else if $jump == jump-end { + $y: math.div($i - 1, $steps); + } @else if $jump == jump-both { + $y: math.div($i, $steps + 1); + } @else if $jump == jump-none { + $y: math.div($i - 1, $steps - 1); + } @else { + @error 'Invalid $jump: #{inspect($jump)}'; + } + + $color: null; + $pos1: if($xx1 == 0, $prev-stop-pos, $prev-stop-pos + $xx1 * $distance); + $pos2: if($xx2 == 1, $next-stop-pos, $prev-stop-pos + $xx2 * $distance); + + @if $y == 0 { + $color: $prev-stop-color; + } @else if $y == 1 { + $color: $next-stop-color; + } @else { + $color: color.mix($next-stop-color, $prev-stop-color, $y * 100%); + } + + $stops: list.append($stops, $color + ' ' + $pos1); + $stops: list.append($stops, $color + ' ' + $pos2); + } + } @else { + // + // The transition color stop positions have to be dynamically calculated with the calc() function. + // + + @if meta.type-of($prev-stop-pos) != number { + // must be calc() + @if meta.type-of($prev-stop-pos) != calculation { + @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; + } + + $prev-stop-pos: meta.calc-args($prev-stop-pos); + } + + @if meta.type-of($next-stop-pos) != number { + // must be calc() + @if meta.type-of($next-stop-pos) != calculation { + @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; + } + + $next-stop-pos: meta.calc-args($next-stop-pos); + } + + @for $i from 1 through $steps { + $xx1: math.div($i - 1, $steps); + $xx2: math.div($i, $steps); + $y: null; + + @if $jump == jump-start { + $y: math.div($i, $steps); + } @else if $jump == jump-end { + $y: math.div($i - 1, $steps); + } @else if $jump == jump-both { + $y: math.div($i, $steps + 1); + } @else if $jump == jump-none { + $y: math.div($i - 1, $steps - 1); + } @else { + @error 'Invalid $jump: #{inspect($jump)}'; + } + + $color: null; + $pos1: if($xx1 == 0, $prev-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$xx1})); + $pos2: if($xx2 == 1, $next-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$xx2})); + + @if $y == 0 { + $color: $prev-stop-color; + } @else if $y == 1 { + $color: $next-stop-color; + } @else { + $color: color.mix($next-stop-color, $prev-stop-color, $y * 100%); + } + + $stops: list.append($stops, $color + ' ' + $pos1); + $stops: list.append($stops, $color + ' ' + $pos2); + } + } + + @return $stops; } /// @@ -513,72 +508,72 @@ $easing-gradient-steps: 10 !default; /// @access private /// @function easing-gradient-interpolate-stop-positions($prev-stop, $stops, $next-stop) { - $prev-stop-pos: nth($prev-stop, 2); - $next-stop-pos: nth($next-stop, 2); - - $stops-num: 0; - @for $i from 1 through length($stops) { - $stop: nth($stops, $i); - @if easing-gradient-is-color-stop($stop) { - $stops-num: $stops-num + 1; - } - } - - $i: 1; - $cur-stop-num: 1; - - @if ((type-of($prev-stop-pos) == number) and (type-of($next-stop-pos) == number) and (unit($prev-stop-pos) == unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { - // - // The color stop positions can be statically calculated. - // - - $distance: $next-stop-pos - $prev-stop-pos; - - @for $i from 1 through length($stops) { - $stop: nth($stops, $i); - @if easing-gradient-is-color-stop($stop) { - $pos: $prev-stop-pos + math.div($distance, $stops-num + 1) * $cur-stop-num; - $stops: set-nth($stops, $i, $stop $pos); - - $cur-stop-num: $cur-stop-num + 1; - } - } - } @else { - // - // The color stop positions have to be dynamically calculated with the calc() function. - // - - @if type-of($prev-stop-pos) != number { - // must be calc() - @if type-of($prev-stop-pos) != calculation { - @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; - } - - $prev-stop-pos: meta.calc-args($prev-stop-pos); - } - - @if type-of($next-stop-pos) != number { - // must be calc() - @if type-of($next-stop-pos) != calculation { - @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; - } - - $next-stop-pos: meta.calc-args($next-stop-pos); - } - - @for $i from 1 through length($stops) { - $stop: nth($stops, $i); - @if easing-gradient-is-color-stop($stop) { - $perc: math.div($cur-stop-num, $stops-num + 1); - $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); - $stops: set-nth($stops, $i, $stop $pos); - - $cur-stop-num: $cur-stop-num + 1; - } - } - } - - @return $stops; + $prev-stop-pos: list.nth($prev-stop, 2); + $next-stop-pos: list.nth($next-stop, 2); + + $stops-num: 0; + @for $i from 1 through list.length($stops) { + $stop: list.nth($stops, $i); + @if easing-gradient-is-color-stop($stop) { + $stops-num: $stops-num + 1; + } + } + + $i: 1; + $cur-stop-num: 1; + + @if ((meta.type-of($prev-stop-pos) == number) and (meta.type-of($next-stop-pos) == number) and (math.unit($prev-stop-pos) == math.unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { + // + // The color stop positions can be statically calculated. + // + + $distance: $next-stop-pos - $prev-stop-pos; + + @for $i from 1 through list.length($stops) { + $stop: list.nth($stops, $i); + @if easing-gradient-is-color-stop($stop) { + $pos: $prev-stop-pos + math.div($distance, $stops-num + 1) * $cur-stop-num; + $stops: list.set-nth($stops, $i, $stop $pos); + + $cur-stop-num: $cur-stop-num + 1; + } + } + } @else { + // + // The color stop positions have to be dynamically calculated with the calc() function. + // + + @if meta.type-of($prev-stop-pos) != number { + // must be calc() + @if meta.type-of($prev-stop-pos) != calculation { + @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; + } + + $prev-stop-pos: meta.calc-args($prev-stop-pos); + } + + @if meta.type-of($next-stop-pos) != number { + // must be calc() + @if meta.type-of($next-stop-pos) != calculation { + @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; + } + + $next-stop-pos: meta.calc-args($next-stop-pos); + } + + @for $i from 1 through list.length($stops) { + $stop: list.nth($stops, $i); + @if easing-gradient-is-color-stop($stop) { + $perc: math.div($cur-stop-num, $stops-num + 1); + $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); + $stops: list.set-nth($stops, $i, $stop $pos); + + $cur-stop-num: $cur-stop-num + 1; + } + } + } + + @return $stops; } /// @@ -587,7 +582,7 @@ $easing-gradient-steps: 10 !default; /// @access private /// @function easing-gradient-is-color-stop($input) { - @return (type-of($input) == color) or easing-gradient-is-positioned-color-stop($input); + @return (meta.type-of($input) == color) or easing-gradient-is-positioned-color-stop($input); } /// @@ -596,5 +591,5 @@ $easing-gradient-steps: 10 !default; /// @access private /// @function easing-gradient-is-positioned-color-stop($input) { - @return (type-of($input) == list) and (type-of(nth($input, 1)) == color); + @return (meta.type-of($input) == list) and (meta.type-of(list.nth($input, 1)) == color); } diff --git a/src/_harmony.scss b/src/_harmony.scss index aaab726..c0cb772 100644 --- a/src/_harmony.scss +++ b/src/_harmony.scss @@ -8,7 +8,10 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; @use 'sass:math'; +@use 'sass:meta'; @use './functions'; @use './responsive'; @@ -26,35 +29,35 @@ /// @return {number} /// @function modular-scale($times, $base, $ratio) { - @if type-of($base) == number { - @return $base * math.pow($ratio, $times); - } + @if meta.type-of($base) == number { + @return $base * math.pow($ratio, $times); + } - $main-base: nth($base, 1); - $norm-bases: (); + $main-base: list.nth($base, 1); + $norm-bases: (); - @each $b in functions.list-slice($base, 2) { - @if $b > $main-base { - @while $b > $main-base { - $b: math.div($b, $ratio); - } - $b: $b * $ratio; - } @else if $b < $main-base { - @while $b < $main-base { - $b: $b * $ratio; - } - } + @each $b in functions.list-slice($base, 2) { + @if $b > $main-base { + @while $b > $main-base { + $b: math.div($b, $ratio); + } + $b: $b * $ratio; + } @else if $b < $main-base { + @while $b < $main-base { + $b: $b * $ratio; + } + } - $norm-bases: append($norm-bases, $b); - } + $norm-bases: list.append($norm-bases, $b); + } - $all-bases: append($norm-bases, $main-base); - $all-bases: functions.quicksort($all-bases); + $all-bases: list.append($norm-bases, $main-base); + $all-bases: functions.quicksort($all-bases); - $base-index: $times % length($all-bases) + 1; - $exp: math.floor(math.div($times, length($all-bases))); + $base-index: $times % list.length($all-bases) + 1; + $exp: math.floor(math.div($times, list.length($all-bases))); - @return nth($all-bases, $base-index) * math.pow($ratio, $exp); + @return list.nth($all-bases, $base-index) * math.pow($ratio, $exp); } /// @@ -86,15 +89,13 @@ /// } /// @mixin responsive-modular-scale($props, $times, $responsive-map, $fluid: true) { - $new-map: (); + $new-map: (); - @each $key, $value in $responsive-map { - $new-map: map-merge( - $new-map, ( - $key: modular-scale($times, $value...) - ) - ); - } + @each $key, $value in $responsive-map { + $new-map: map.merge($new-map, ( + $key: modular-scale($times, $value...) + )); + } - @include responsive.property($props, $new-map, $fluid); + @include responsive.property($props, $new-map, $fluid); } diff --git a/src/_props.scss b/src/_props.scss index 300fc28..17e9de7 100644 --- a/src/_props.scss +++ b/src/_props.scss @@ -3,137 +3,137 @@ @use 'sass:meta'; @function is-prop-ref($value) { - @if meta.type-of($value) != 'list' { - @return false; - } - @if list.length($value) != 4 { - @return false; - } - @if list.nth($value, 1) != 'prop-ref' { - @return false; - } - @return true; + @if meta.type-of($value) != 'list' { + @return false; + } + @if list.length($value) != 4 { + @return false; + } + @if list.nth($value, 1) != 'prop-ref' { + @return false; + } + @return true; } @function def($name, $value: (), $metadata: ()) { - @return ('prop-ref' $name $value $metadata); + @return ('prop-ref' $name $value $metadata); } @function merge($ref, $value) { - @if not is-prop-ref($ref) { - @return $ref; - } + @if not is-prop-ref($ref) { + @return $ref; + } - $v: list.nth($ref, 3); - $ref: list.set-nth($ref, 3, map.deep-merge($v, $value)); - @return $ref; + $v: list.nth($ref, 3); + $ref: list.set-nth($ref, 3, map.deep-merge($v, $value)); + @return $ref; } @function get-deep($name, $value, $key: null, $keys...) { - @if is-prop-ref($value) { - @return get($value, $key, $keys); - } - @if meta.type-of($value) == 'map' and $key != null { - @if meta.type-of($key) != 'string' { - @error 'Expected string, got #{$key}'; - } - @return get-deep(#{$name}#{$key}, map.get($value, $key), $keys...); - } - @return $name $value; + @if is-prop-ref($value) { + @return get($value, $key, $keys); + } + @if meta.type-of($value) == 'map' and $key != null { + @if meta.type-of($key) != 'string' { + @error 'Expected string, got #{$key}'; + } + @return get-deep(#{$name}#{$key}, map.get($value, $key), $keys...); + } + @return $name $value; } @function map-to-vars($name, $map) { - @if meta.type-of($map) != 'map' { - @if meta.type-of($name) != 'string' { - @error 'Expected variable name, got #{$name} instead'; - } - @return var($name); - } + @if meta.type-of($map) != 'map' { + @if meta.type-of($name) != 'string' { + @error 'Expected variable name, got #{$name} instead'; + } + @return var($name); + } - $out: (); + $out: (); - @each $key, $value in $map { - $out: map.set($out, $key, map-to-vars(#{$name}#{$key}, $value)); - } + @each $key, $value in $map { + $out: map.set($out, $key, map-to-vars(#{$name}#{$key}, $value)); + } - @return $out; + @return $out; } @function get($ref, $key: null, $keys...) { - @if not is-prop-ref($ref) { - @return $ref; - } - - $name: list.nth($ref, 2); - $value: get(list.nth($ref, 3)); - - @if meta.type-of($value) == 'map' { - $res: get-deep($name, $value, $key, $keys...); - $name: list.nth($res, 1); - $value: list.nth($res, 2); - } @else if meta.type-of($value) == 'list' { - $i: 1; - @each $item in $value { - $value: list.set-nth($value, $i, get($item)); - $i: $i + 1; - } - } - - @return map-to-vars($name, $value); + @if not is-prop-ref($ref) { + @return $ref; + } + + $name: list.nth($ref, 2); + $value: get(list.nth($ref, 3)); + + @if meta.type-of($value) == 'map' { + $res: get-deep($name, $value, $key, $keys...); + $name: list.nth($res, 1); + $value: list.nth($res, 2); + } @else if meta.type-of($value) == 'list' { + $i: 1; + @each $item in $value { + $value: list.set-nth($value, $i, get($item)); + $i: $i + 1; + } + } + + @return map-to-vars($name, $value); } @mixin materialize-helper($name, $value) { - @if meta.type-of($value) == 'map' { - @each $key, $value in $value { - @include materialize-helper(#{$name}#{$key}, $value); - } - } @else { - #{$name}: #{$value}; - } + @if meta.type-of($value) == 'map' { + @each $key, $value in $value { + @include materialize-helper(#{$name}#{$key}, $value); + } + } @else { + #{$name}: #{$value}; + } } @mixin materialize($ref, $match-meta: ()) { - @if is-prop-ref($ref) { - $name: list.nth($ref, 2); - $value: get(list.nth($ref, 3)); - $meta: get(list.nth($ref, 4)); - - $match: true; - @if meta.type-of($match-meta) == 'list' { - @each $item in $match-meta { - $match: $match and list.index($meta, $item) != null; - } - } @else if $match-meta == null and list.length($meta) == 0 { - $match: true; - } @else { - $match: list.index($meta, $match-meta) != null; - } - - @if $match { - @include materialize-helper($name, $value); - } - } @else if meta.type-of($ref) == 'list' { - @each $r in $ref { - @if is-prop-ref($r) { - $name: list.nth($r, 2); - $value: get(list.nth($r, 3)); - $meta: get(list.nth($r, 4)); - - $match: true; - @if meta.type-of($match-meta) == 'list' { - @each $item in $match-meta { - $match: $match and list.index($meta, $item) != null; - } - } @else if $match-meta == null and list.length($meta) == 0 { - $match: true; - } @else { - $match: list.index($meta, $match-meta) != null; - } + @if is-prop-ref($ref) { + $name: list.nth($ref, 2); + $value: get(list.nth($ref, 3)); + $meta: get(list.nth($ref, 4)); + + $match: true; + @if meta.type-of($match-meta) == 'list' { + @each $item in $match-meta { + $match: $match and list.index($meta, $item) != null; + } + } @else if $match-meta == null and list.length($meta) == 0 { + $match: true; + } @else { + $match: list.index($meta, $match-meta) != null; + } + + @if $match { + @include materialize-helper($name, $value); + } + } @else if meta.type-of($ref) == 'list' { + @each $r in $ref { + @if is-prop-ref($r) { + $name: list.nth($r, 2); + $value: get(list.nth($r, 3)); + $meta: get(list.nth($r, 4)); + + $match: true; + @if meta.type-of($match-meta) == 'list' { + @each $item in $match-meta { + $match: $match and list.index($meta, $item) != null; + } + } @else if $match-meta == null and list.length($meta) == 0 { + $match: true; + } @else { + $match: list.index($meta, $match-meta) != null; + } - @if $match { - @include materialize-helper($name, $value); - } - } - } - } + @if $match { + @include materialize-helper($name, $value); + } + } + } + } } diff --git a/src/_responsive.scss b/src/_responsive.scss index 4d98638..f613a6d 100644 --- a/src/_responsive.scss +++ b/src/_responsive.scss @@ -17,6 +17,11 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:math'; +@use 'sass:meta'; +@use 'sass:string'; @use './functions'; @use './contexts'; @@ -99,15 +104,15 @@ $named-viewports: () !default; /// } /// @mixin property($props, $responsive-map, $fluid: true, $vertical: false) { - @include env(map-keys($responsive-map), $fluid, $vertical) { - @if type-of($props) == list { - @each $prop in $props { - #{$prop}: set(map-values($responsive-map)); - } - } @else { - #{$props}: set(map-values($responsive-map)); - } - } + @include env(map.keys($responsive-map), $fluid, $vertical) { + @if meta.type-of($props) == list { + @each $prop in $props { + #{$prop}: set(map.values($responsive-map)); + } + } @else { + #{$props}: set(map.values($responsive-map)); + } + } } /// @@ -150,153 +155,153 @@ $named-viewports: () !default; /// } /// @mixin env($viewports, $fluid: true, $vertical: false) { - @if length($viewports) <= 1 { - @error '$viewports must contain at least two viewports.'; - } - - $new-viewports: (); - - @each $viewport in $viewports { - @if map-has-key($named-viewports, $viewport) { - $viewport: map-get($named-viewports, $viewport); - } - - @if (type-of($viewport) != number) or unitless($viewport) { - @error '$viewports contains invalid viewports.'; - } - - $new-viewports: append($new-viewports, $viewport); - } - - $viewports: functions.quicksort($new-viewports); - - @if $new-viewports != $viewports { - @error '$viewports was not sorted in ascending order.'; - } - - @if $fluid { - $first-vp: nth($viewports, 1); - $last-vp: nth($viewports, length($viewports)); - - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': set, - 'index': 1, - 'fluid': $fluid, - 'vertical': $vertical, - )); - - @content; - - @include contexts.pop($context-id); - - @for $i from 1 to length($viewports) { - $prev-vp: nth($viewports, $i); - $next-vp: nth($viewports, $i + 1); - - @if not $vertical { - @media (min-width: $prev-vp) and (max-width: $next-vp) { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': transition, - 'index': $i, - 'fluid': $fluid, - 'vertical': $vertical, - )); - - @content; - - @include contexts.pop($context-id); - } - } @else { - @media (min-height: $prev-vp) and (max-height: $next-vp) { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': transition, - 'index': $i, - 'fluid': $fluid, - 'vertical': $vertical, - )); - - @content; - - @include contexts.pop($context-id); - } - } - } - - @if not $vertical { - @media (min-width: $last-vp) { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': set, - 'index': length($viewports), - 'fluid': $fluid, - 'vertical': $vertical, - )); - - @content; - - @include contexts.pop($context-id); - } - } @else { - @media (min-height: $last-vp) { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': set, - 'index': length($viewports), - 'fluid': $fluid, - 'vertical': $vertical, - )); - - @content; - - @include contexts.pop($context-id); - } - } - } @else { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': set, - 'index': 1, - 'fluid': $fluid, - 'vertical': $vertical, - )); - - @content; - - @include contexts.pop($context-id); - - @for $i from 2 through length($viewports) { - $vp: nth($viewports, $i); - - @if not $vertical { - @media (min-width: $vp) { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': set, - 'index': $i - )); - - @content; - - @include contexts.pop($context-id); - } - } @else { - @media (min-height: $vp) { - @include contexts.push($context-id, 'env', ( - 'viewports': $viewports, - 'mode': set, - 'index': $i - )); - - @content; - - @include contexts.pop($context-id); - } - } - } - } + @if list.length($viewports) <= 1 { + @error '$viewports must contain at least two viewports.'; + } + + $new-viewports: (); + + @each $viewport in $viewports { + @if map.has-key($named-viewports, $viewport) { + $viewport: map.get($named-viewports, $viewport); + } + + @if (meta.type-of($viewport) != number) or math.is-unitless($viewport) { + @error '$viewports contains invalid viewports.'; + } + + $new-viewports: list.append($new-viewports, $viewport); + } + + $viewports: functions.quicksort($new-viewports); + + @if $new-viewports != $viewports { + @error '$viewports was not sorted in ascending order.'; + } + + @if $fluid { + $first-vp: list.nth($viewports, 1); + $last-vp: list.nth($viewports, list.length($viewports)); + + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': 1, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include contexts.pop($context-id); + + @for $i from 1 to list.length($viewports) { + $prev-vp: list.nth($viewports, $i); + $next-vp: list.nth($viewports, $i + 1); + + @if not $vertical { + @media (min-width: $prev-vp) and (max-width: $next-vp) { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': transition, + 'index': $i, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include contexts.pop($context-id); + } + } @else { + @media (min-height: $prev-vp) and (max-height: $next-vp) { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': transition, + 'index': $i, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include contexts.pop($context-id); + } + } + } + + @if not $vertical { + @media (min-width: $last-vp) { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': list.length($viewports), + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include contexts.pop($context-id); + } + } @else { + @media (min-height: $last-vp) { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': list.length($viewports), + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include contexts.pop($context-id); + } + } + } @else { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': 1, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include contexts.pop($context-id); + + @for $i from 2 through list.length($viewports) { + $vp: list.nth($viewports, $i); + + @if not $vertical { + @media (min-width: $vp) { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': $i + )); + + @content; + + @include contexts.pop($context-id); + } + } @else { + @media (min-height: $vp) { + @include contexts.push($context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': $i + )); + + @content; + + @include contexts.pop($context-id); + } + } + } + } } /// @@ -307,29 +312,29 @@ $named-viewports: () !default; /// @return {number|string} /// @function set($values, $without-calc: false) { - $noop: contexts.assert-stack-must-contain($context-id, 'env'); - - $data: nth(contexts.get($context-id, 'env'), 2); - $viewports: map-get($data, 'viewports'); - $mode: map-get($data, 'mode'); - $fluid: map-get($data, 'fluid'); - $vertical: map-get($data, 'vertical'); - - @if length($values) != length($viewports) { - @error '$values must contain the same number of items as the responsive environment\'s $viewports.'; - } - - @if $mode == set { - @return nth($values, map-get($data, 'index')); - } @else { - $index: map-get($data, 'index'); - $prev-vp: nth($viewports, $index); - $next-vp: nth($viewports, $index + 1); - $prev-value: nth($values, $index); - $next-value: nth($values, $index + 1); - - @return fluid-calc($prev-value, $next-value, $prev-vp, $next-vp, $vertical, $without-calc); - } + $noop: contexts.assert-stack-must-contain($context-id, 'env'); + + $data: list.nth(contexts.get($context-id, 'env'), 2); + $viewports: map.get($data, 'viewports'); + $mode: map.get($data, 'mode'); + $fluid: map.get($data, 'fluid'); + $vertical: map.get($data, 'vertical'); + + @if list.length($values) != list.length($viewports) { + @error '$values must contain the same number of items as the responsive environment\'s $viewports.'; + } + + @if $mode == set { + @return list.nth($values, map.get($data, 'index')); + } @else { + $index: map.get($data, 'index'); + $prev-vp: list.nth($viewports, $index); + $next-vp: list.nth($viewports, $index + 1); + $prev-value: list.nth($values, $index); + $next-value: list.nth($values, $index + 1); + + @return fluid-calc($prev-value, $next-value, $prev-vp, $next-vp, $vertical, $without-calc); + } } /// @@ -345,62 +350,62 @@ $named-viewports: () !default; /// @access private /// @function fluid-calc($min-value, $max-value, $min-viewport, $max-viewport, $vertical: false, $without-calc: false) { - $value-unit: unit($min-value); - $max-value-unit: unit($max-value); - $viewport-unit: unit($min-viewport); - $max-viewport-unit: unit($max-viewport); - - @if $min-value == 0 { - $value-unit: $max-value-unit; - } - @if $max-value == 0 { - $max-value-unit: $value-unit; - } - @if $min-viewport == 0 { - $viewport-unit: $max-viewport-unit; - } - @if $max-viewport == 0 { - $max-viewport-unit: $viewport-unit; - } - - @if ($value-unit != $max-value-unit) or ($viewport-unit != $max-viewport-unit) { - @error 'Units of $min-value and $max-value, $min-viewport and $max-viewport must match.'; - } - - @if ($value-unit == rem) and ($viewport-unit == px) { - $min-viewport: functions.px-to-rem($min-viewport); - $max-viewport: functions.px-to-rem($max-viewport); - $viewport-unit: rem; - } @else if ($value-unit == px) and ($viewport-unit == rem) { - $min-value: functions.px-to-rem($min-value); - $max-value: functions.px-to-rem($max-value); - $value-unit: rem; - } - - @if $value-unit != $viewport-unit { - @error 'This combination of units is not supported.'; - } - - $value-diff: functions.strip-unit($max-value - $min-value); - $viewport-diff: functions.strip-unit($max-viewport - $min-viewport); - - $calc: ''; - - @if $min-value != 0 { - $calc: '#{$min-value} + '; - } - - @if not $vertical { - $calc: unquote('#{$calc}#{$value-diff} * (100vw - #{$min-viewport}) / #{$viewport-diff}'); - } @else { - $calc: unquote('#{$calc}#{$value-diff} * (100vh - #{$min-viewport}) / #{$viewport-diff}'); - } - - @if $without-calc { - @return $calc; - } @else { - @return calc(#{$calc}); - } + $value-unit: math.unit($min-value); + $max-value-unit: math.unit($max-value); + $viewport-unit: math.unit($min-viewport); + $max-viewport-unit: math.unit($max-viewport); + + @if $min-value == 0 { + $value-unit: $max-value-unit; + } + @if $max-value == 0 { + $max-value-unit: $value-unit; + } + @if $min-viewport == 0 { + $viewport-unit: $max-viewport-unit; + } + @if $max-viewport == 0 { + $max-viewport-unit: $viewport-unit; + } + + @if ($value-unit != $max-value-unit) or ($viewport-unit != $max-viewport-unit) { + @error 'Units of $min-value and $max-value, $min-viewport and $max-viewport must match.'; + } + + @if ($value-unit == rem) and ($viewport-unit == px) { + $min-viewport: functions.px-to-rem($min-viewport); + $max-viewport: functions.px-to-rem($max-viewport); + $viewport-unit: rem; + } @else if ($value-unit == px) and ($viewport-unit == rem) { + $min-value: functions.px-to-rem($min-value); + $max-value: functions.px-to-rem($max-value); + $value-unit: rem; + } + + @if $value-unit != $viewport-unit { + @error 'This combination of units is not supported.'; + } + + $value-diff: functions.strip-unit($max-value - $min-value); + $viewport-diff: functions.strip-unit($max-viewport - $min-viewport); + + $calc: ''; + + @if $min-value != 0 { + $calc: '#{$min-value} + '; + } + + @if not $vertical { + $calc: string.unquote('#{$calc}#{$value-diff} * (100vw - #{$min-viewport}) / #{$viewport-diff}'); + } @else { + $calc: string.unquote('#{$calc}#{$value-diff} * (100vh - #{$min-viewport}) / #{$viewport-diff}'); + } + + @if $without-calc { + @return $calc; + } @else { + @return calc(#{$calc}); + } } @include contexts.create($context-id); diff --git a/src/bem/_block.scss b/src/bem/_block.scss index cfa9f33..a4b2a47 100644 --- a/src/bem/_block.scss +++ b/src/bem/_block.scss @@ -4,6 +4,10 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use 'sass:selector'; @use './validators'; @use './vars'; @use './functions' as bemfunctions; @@ -37,34 +41,34 @@ /// } /// @mixin block($name, $type: null) { - $result: block($name, $type); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'block', - (name: $name, type: $type), - $selector, - $context - ); - - @if $type != null { - vars.$blocks: append(vars.$blocks, $name + '_' + $type); - } @else { - vars.$blocks: append(vars.$blocks, $name); - } - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @if $type != null { - @layer #{$type} { - @content; - } - } @else { - @content; - } - } - @include contexts.pop(vars.$context-id); + $result: block($name, $type); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'block', + (name: $name, type: $type), + $selector, + $context + ); + + @if $type != null { + vars.$blocks: list.append(vars.$blocks, $name + '_' + $type); + } @else { + vars.$blocks: list.append(vars.$blocks, $name); + } + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @if $type != null { + @layer #{$type} { + @content; + } + } @else { + @content; + } + } + @include contexts.pop(vars.$context-id); } /// @@ -75,47 +79,47 @@ /// @see {mixin} block /// @function block($name, $type: null) { - // - // Possible outcomes: - // - ({b,e,m,s}) block - // - - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - - $selector: null; - $base-selector: null; - - @if $type != null { - $namespace: map-get(vars.$namespaces, $type); - - @if not $namespace { - @error '"#{$type}" is not a valid type.'; - } - - $base-selector: selector-parse('.' + $namespace + '-' + $name); - - @if $type != 'theme' or & { - $selector: $base-selector; - } @else if not & { - $selector: bemfunctions.theme-selector($name); - } - } @else { - $base-selector: selector-parse('.' + $name); - $selector: $base-selector; - } - - @if & { - $selector: selector-nest(&, $selector); - } - - $context: 'block', ( - 'name': $name, - 'type': $type, - 'selector': $selector, - 'base-selector': $base-selector - ); - - @return $selector $context; + // + // Possible outcomes: + // - ({b,e,m,s}) block + // + + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + + $selector: null; + $base-selector: null; + + @if $type != null { + $namespace: map.get(vars.$namespaces, $type); + + @if not $namespace { + @error '"#{$type}" is not a valid type.'; + } + + $base-selector: selector.parse('.' + $namespace + '-' + $name); + + @if $type != 'theme' or & { + $selector: $base-selector; + } @else if not & { + $selector: bemfunctions.theme-selector($name); + } + } @else { + $base-selector: selector.parse('.' + $name); + $selector: $base-selector; + } + + @if & { + $selector: selector.nest(&, $selector); + } + + $context: 'block', ( + 'name': $name, + 'type': $type, + 'selector': $selector, + 'base-selector': $base-selector + ); + + @return $selector $context; } /// @@ -126,9 +130,9 @@ /// @content /// @mixin object($name) { - @include block($name, 'object') { - @content; - } + @include block($name, 'object') { + @content; + } } /// @@ -139,7 +143,7 @@ /// @see {mixin} object /// @function object($name) { - @return block($name, 'object'); + @return block($name, 'object'); } /// @@ -150,9 +154,9 @@ /// @content /// @mixin component($name) { - @include block($name, 'component') { - @content; - } + @include block($name, 'component') { + @content; + } } /// @@ -163,7 +167,7 @@ /// @see {mixin} component /// @function component($name) { - @return block($name, 'component'); + @return block($name, 'component'); } /// @@ -174,9 +178,9 @@ /// @content /// @mixin layout($name) { - @include block($name, 'layout') { - @content; - } + @include block($name, 'layout') { + @content; + } } /// @@ -187,7 +191,7 @@ /// @see {mixin} layout /// @function layout($name) { - @return block($name, 'layout'); + @return block($name, 'layout'); } /// @@ -198,9 +202,9 @@ /// @content /// @mixin utility($name) { - @include block($name, 'utility') { - @content; - } + @include block($name, 'utility') { + @content; + } } /// @@ -211,7 +215,7 @@ /// @see {mixin} utility /// @function utility($name) { - @return block($name, 'utility'); + @return block($name, 'utility'); } /// @@ -222,9 +226,9 @@ /// @content /// @mixin scope($name) { - @include block($name, 'scope') { - @content; - } + @include block($name, 'scope') { + @content; + } } /// @@ -235,7 +239,7 @@ /// @see {mixin} scope /// @function scope($name) { - @return block($name, 'scope'); + @return block($name, 'scope'); } /// @@ -246,9 +250,9 @@ /// @content /// @mixin theme($name) { - @include block($name, 'theme') { - @content; - } + @include block($name, 'theme') { + @content; + } } /// @@ -259,7 +263,7 @@ /// @see {mixin} theme /// @function theme($name) { - @return block($name, 'theme'); + @return block($name, 'theme'); } /// @@ -270,9 +274,9 @@ /// @content /// @mixin js($name) { - @include block($name, 'js') { - @content; - } + @include block($name, 'js') { + @content; + } } /// @@ -283,7 +287,7 @@ /// @see {mixin} js /// @function js($name) { - @return block($name, 'js'); + @return block($name, 'js'); } /// @@ -294,9 +298,9 @@ /// @content /// @mixin qa($name) { - @include block($name, 'qa') { - @content; - } + @include block($name, 'qa') { + @content; + } } /// @@ -307,7 +311,7 @@ /// @see {mixin} qa /// @function qa($name) { - @return block($name, 'qa'); + @return block($name, 'qa'); } /// @@ -318,9 +322,9 @@ /// @content /// @mixin hack($name) { - @include block($name, 'hack') { - @content; - } + @include block($name, 'hack') { + @content; + } } /// @@ -331,7 +335,7 @@ /// @see {mixin} hack /// @function hack($name) { - @return block($name, 'hack'); + @return block($name, 'hack'); } /// @@ -383,22 +387,22 @@ /// // Compilation will fail because c-someBlock is defined after c-anotherBlock__elem /// @mixin composed-of($block, $blocks...) { - @each $block in functions.list-prepend($blocks, $block) { - @if type-of($block) == string { - @if not index(vars.$blocks, $block) { - @error 'Block "#{$block}" does not exist.'; - } - } @else { - $name: nth($block, 1); - $type: nth($block, 2); - - @if not map-get(vars.$namespaces, $type) { - @error '"#{$type}" is not a valid type.'; - } - - @if not index(vars.$blocks, $name + '_' + $type) { - @error 'Block "#{$name}" does not exist.'; - } - } - } + @each $block in functions.list-prepend($blocks, $block) { + @if meta.type-of($block) == string { + @if not list.index(vars.$blocks, $block) { + @error 'Block "#{$block}" does not exist.'; + } + } @else { + $name: list.nth($block, 1); + $type: list.nth($block, 2); + + @if not map.get(vars.$namespaces, $type) { + @error '"#{$type}" is not a valid type.'; + } + + @if not list.index(vars.$blocks, $name + '_' + $type) { + @error 'Block "#{$name}" does not exist.'; + } + } + } } diff --git a/src/bem/_debug.scss b/src/bem/_debug.scss index 8ea0f05..b1f20a7 100644 --- a/src/bem/_debug.scss +++ b/src/bem/_debug.scss @@ -4,15 +4,16 @@ /// @access public //// +@use 'sass:map'; @use './vars'; @if vars.$debug { - @each $type, $color in vars.$debug-colors { - $namespace: map-get(vars.$namespaces, $type); + @each $type, $color in vars.$debug-colors { + $namespace: map.get(vars.$namespaces, $type); - [class^='#{$namespace}-'], - [class*=' #{$namespace}-'] { - outline: 5px solid $color; - } - } + [class^='#{$namespace}-'], + [class*=' #{$namespace}-'] { + outline: 5px solid $color; + } + } } diff --git a/src/bem/_element.scss b/src/bem/_element.scss index 64862b0..9f108fe 100644 --- a/src/bem/_element.scss +++ b/src/bem/_element.scss @@ -4,6 +4,11 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use 'sass:selector'; +@use 'sass:string'; @use './validators'; @use './vars'; @use '../functions'; @@ -92,22 +97,22 @@ /// } /// @mixin elem($name, $names...) { - $result: elem($name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'element', - (name: $name, names: $names), - $selector, - $context - ); - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + $result: elem($name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'element', + (name: $name, names: $names), + $selector, + $context + ); + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -118,99 +123,93 @@ /// @see {mixin} element /// @function elem($name, $names...) { - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - - $parent-context: contexts.get(vars.$context-id, 'block' 'element'); - - $selector: (); - $parts-data: (); - - @if nth($parent-context, 1) == 'element' { - @if vars.$element-nesting-policy == 'disallow' { - @error 'Element nesting is forbidden.'; - } - - @if vars.$element-nesting-policy == 'append' { - $element-selector: map-get(nth($parent-context, 2), 'selector'); - - @if not functions.selector-suffix-match(&, $element-selector) { - @error 'A nested element must be an immediate children of the parent element.'; - } - - // - // Possible outcomes: - // - {e}__element - // - [manual selector] {e}__element - // - - @each $name in join($name, $names) { - $sel: selector-append(&, vars.$element-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } - - $parent-context: contexts.get(vars.$context-id, 'block'); - } - - @if length($selector) == 0 { - $parent-selector: map-get(nth($parent-context, 2), 'selector'); - - @if functions.selector-suffix-match(&, $parent-selector) { - // - // Possible outcomes: - // - {b}__element - // - [manual selector] {b}__element - // - - @each $name in join($name, $names) { - $sel: selector-append(&, vars.$element-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } @else { - // - // Possible outcomes: - // - {b} [manual selector] {b}__element - // - {e,m,s} ([manual selector]) {b}__element - // - - @if nth($parent-context, 1) != 'block' { - $parent-context: contexts.get(vars.$context-id, 'block'); - } - - $block-base-selector: map-get(nth($parent-context, 2), 'base-selector'); - - @each $name in join($name, $names) { - $sel: selector-nest(&, selector-append($block-base-selector, vars.$element-separator + $name)); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } - } - - $context: 'element', ( - 'parts': $parts-data, - 'selector': $selector - ); - - @return $selector $context; + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + + $parent-context: contexts.get(vars.$context-id, 'block' 'element'); + + $selector: (); + $parts-data: (); + + @if list.nth($parent-context, 1) == 'element' { + @if vars.$element-nesting-policy == 'disallow' { + @error 'Element nesting is forbidden.'; + } + + @if vars.$element-nesting-policy == 'append' { + $element-selector: map.get(list.nth($parent-context, 2), 'selector'); + + @if not functions.selector-suffix-match(&, $element-selector) { + @error 'A nested element must be an immediate children of the parent element.'; + } + + // + // Possible outcomes: + // - {e}__element + // - [manual selector] {e}__element + // + + @each $name in list.join($name, $names) { + $sel: selector.append(&, vars.$element-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + + $parent-context: contexts.get(vars.$context-id, 'block'); + } + + @if list.length($selector) == 0 { + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); + + @if functions.selector-suffix-match(&, $parent-selector) { + // + // Possible outcomes: + // - {b}__element + // - [manual selector] {b}__element + // + + @each $name in list.join($name, $names) { + $sel: selector.append(&, vars.$element-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } @else { + // + // Possible outcomes: + // - {b} [manual selector] {b}__element + // - {e,m,s} ([manual selector]) {b}__element + // + + @if list.nth($parent-context, 1) != 'block' { + $parent-context: contexts.get(vars.$context-id, 'block'); + } + + $block-base-selector: map.get(list.nth($parent-context, 2), 'base-selector'); + + @each $name in list.join($name, $names) { + $sel: selector.nest(&, selector.append($block-base-selector, vars.$element-separator + $name)); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; } /// @@ -291,22 +290,22 @@ /// } /// @mixin related-elem($sign, $name, $names...) { - $result: related-elem($sign, $name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'related-element', - (sign: $sign, name: $name, names: $names), - $selector, - $context - ); - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + $result: related-elem($sign, $name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'related-element', + (sign: $sign, name: $name, names: $names), + $selector, + $context + ); + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -318,44 +317,42 @@ /// @see {mixin} related-element /// @function related-elem($sign, $name, $names...) { - // - // Generating this selector is simple: Take the latest block context, use it - // to generate the element part, and insert it at the end of the current selector. - // Possible outcomes: - // - {e} ({m,s}) ([manual selector]) + {e} - // - {e} ({m,s}) ([manual selector]) ~ {e} - // - - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); - - @if $sign != '+' and $sign != '~' { - @error 'Invalid relationship sign #{inspect($sign)}.'; - } - - $block-context: contexts.get(vars.$context-id, 'block'); - $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); - - $selector: (); - $parts-data: (); - - @each $name in join($name, $names) { - $sel: selector-nest(&, $sign, selector-append($block-base-selector, vars.$element-separator + $name)); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - - $context: 'element', ( - 'parts': $parts-data, - 'selector': $selector - ); - - @return $selector $context; + // + // Generating this selector is simple: Take the latest block context, use it + // to generate the element part, and insert it at the end of the current selector. + // Possible outcomes: + // - {e} ({m,s}) ([manual selector]) + {e} + // - {e} ({m,s}) ([manual selector]) ~ {e} + // + + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); + + @if $sign != '+' and $sign != '~' { + @error 'Invalid relationship sign #{inspect($sign)}.'; + } + + $block-context: contexts.get(vars.$context-id, 'block'); + $block-base-selector: map.get(list.nth($block-context, 2), 'base-selector'); + + $selector: (); + $parts-data: (); + + @each $name in list.join($name, $names) { + $sel: selector.nest(&, $sign, selector.append($block-base-selector, vars.$element-separator + $name)); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; } /// @@ -369,9 +366,9 @@ /// @content /// @mixin sibling-elem($name, $names...) { - @include related-elem('~', $name, $names...) { - @content; - } + @include related-elem('~', $name, $names...) { + @content; + } } /// @@ -383,7 +380,7 @@ /// @see {mixin} sibling-element /// @function sibling-elem($name, $names...) { - @return related-elem('~', $name, $names...); + @return related-elem('~', $name, $names...); } /// @@ -397,9 +394,9 @@ /// @content /// @mixin next-elem($name, $names...) { - @include related-elem('+', $name, $names...) { - @content; - } + @include related-elem('+', $name, $names...) { + @content; + } } /// @@ -411,7 +408,7 @@ /// @see {mixin} next-element /// @function next-elem($name, $names...) { - @return related-elem('+', $name, $names...); + @return related-elem('+', $name, $names...); } /// @@ -467,22 +464,22 @@ /// } /// @mixin related-twin-elem($sign) { - $result: related-twin-elem($sign); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'next-twin-elem', - (), - $selector, - $context - ); - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + $result: related-twin-elem($sign); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'next-twin-elem', + (), + $selector, + $context + ); + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -494,96 +491,94 @@ /// @see {mixin} next-twin-elem /// @function related-twin-elem($sign) { - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); - - $element-context: contexts.get(vars.$context-id, 'element'); - $element-selector: map-get(nth($element-context, 2), 'selector'); - - $block-context: contexts.get(vars.$context-id, 'block'); - $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); - - $selector: (); - $parts-data: (); - - // - // To determine the twin for each element, iterate the sub-selectors from the current selector - // and check if it contains the currently inspected element. This has to be done with string - // comparison since none of Sass selector functions is of use here. - // Finally, the current twin will be appended to the extracted sub-selector as a successor - // element. - // - @each $part-data in map-get(nth($element-context, 2), 'parts') { - $part-selector: map-get($part-data, 'selector'); - $part-name: map-get($part-data, 'name'); - - $sel: (); - @if functions.selector-suffix-match(&, $element-selector) { - // - // This mixin is included in the selector the last element mixin created. - // Possible outcomes: - // - {e} + {e} - // - [manual selector] {e} + {e} - // - - @each $s in & { - @each $ps in $part-selector { - @if nth($s, -1) == nth($ps, -1) { - $sel-ent: selector-nest($s, $sign, selector-append($block-base-selector, vars.$element-separator + $part-name)); - $sel: join($sel, $sel-ent, comma); - } - } - } - } @else { - // - // This mixin is NOT included in the selector the last element mixin created. - // Possible outcomes: - // - {e} {m,s} + {e} - // - {e} [manual selector] + {e} - // - {e} {m,s} [manual selector] + {e} - // - - @each $s in & { - @each $ps in $part-selector { - @if str-index(inspect($s), inspect($ps)) { - $char-index: str-length(inspect($ps)) + 1; - $match: index(' ' ':' ',', str-slice(inspect($s), $char-index, $char-index)) != null; - - @if not $match { - @each $separator in vars.$element-separator vars.$modifier-separator vars.$suffix-separator { - @if str-slice(inspect($s), $char-index, $char-index + str-length($separator) - 1) == $separator { - $match: true; - } - } - } - - @if $match { - $sel-ent: selector-nest($s, '+', selector-append($block-base-selector, vars.$element-separator + $part-name)); - $sel: join($sel, $sel-ent, comma); - } - } - } - } - } - @if length($sel) != length($part-selector) { - @error 'Could not generate twin element selector.'; - } - - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $part-name, - 'selector': $sel - ) - ); - } - - $context: 'element', ( - 'parts': $parts-data, - 'selector': $selector - ); - - @return $selector $context; + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); + + $element-context: contexts.get(vars.$context-id, 'element'); + $element-selector: map.get(list.nth($element-context, 2), 'selector'); + + $block-context: contexts.get(vars.$context-id, 'block'); + $block-base-selector: map.get(list.nth($block-context, 2), 'base-selector'); + + $selector: (); + $parts-data: (); + + // + // To determine the twin for each element, iterate the sub-selectors from the current selector + // and check if it contains the currently inspected element. This has to be done with string + // comparison since none of Sass selector functions is of use here. + // Finally, the current twin will be appended to the extracted sub-selector as a successor + // element. + // + @each $part-data in map.get(list.nth($element-context, 2), 'parts') { + $part-selector: map.get($part-data, 'selector'); + $part-name: map.get($part-data, 'name'); + + $sel: (); + @if functions.selector-suffix-match(&, $element-selector) { + // + // This mixin is included in the selector the last element mixin created. + // Possible outcomes: + // - {e} + {e} + // - [manual selector] {e} + {e} + // + + @each $s in & { + @each $ps in $part-selector { + @if list.nth($s, -1) == list.nth($ps, -1) { + $sel-ent: selector.nest($s, $sign, selector.append($block-base-selector, vars.$element-separator + $part-name)); + $sel: list.join($sel, $sel-ent, comma); + } + } + } + } @else { + // + // This mixin is NOT included in the selector the last element mixin created. + // Possible outcomes: + // - {e} {m,s} + {e} + // - {e} [manual selector] + {e} + // - {e} {m,s} [manual selector] + {e} + // + + @each $s in & { + @each $ps in $part-selector { + @if string.index(meta.inspect($s), meta.inspect($ps)) { + $char-index: string.length(meta.inspect($ps)) + 1; + $match: list.index(' ' ':' ',', string.slice(meta.inspect($s), $char-index, $char-index)) != null; + + @if not $match { + @each $separator in vars.$element-separator vars.$modifier-separator vars.$suffix-separator { + @if string.slice(meta.inspect($s), $char-index, $char-index + string.length($separator) - 1) == $separator { + $match: true; + } + } + } + + @if $match { + $sel-ent: selector.nest($s, '+', selector.append($block-base-selector, vars.$element-separator + $part-name)); + $sel: list.join($sel, $sel-ent, comma); + } + } + } + } + } + @if list.length($sel) != list.length($part-selector) { + @error 'Could not generate twin element selector.'; + } + + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $part-name, + 'selector': $sel + )); + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; } /// @@ -594,9 +589,9 @@ /// @content /// @mixin sibling-twin-element { - @include related-twin-elem('~') { - @content; - } + @include related-twin-elem('~') { + @content; + } } /// @@ -608,7 +603,7 @@ /// @see {mixin} sibling-twin-element /// @function sibling-twin-elem() { - @return related-twin-elem('~'); + @return related-twin-elem('~'); } /// @@ -619,9 +614,9 @@ /// @content /// @mixin next-twin-elem { - @include related-twin-elem('+') { - @content; - } + @include related-twin-elem('+') { + @content; + } } /// @@ -633,5 +628,5 @@ /// @see {mixin} next-twin-elem /// @function next-twin-elem() { - @return related-twin-elem('+'); + @return related-twin-elem('+'); } diff --git a/src/bem/_functions.scss b/src/bem/_functions.scss index b7bd5ec..7f52b93 100644 --- a/src/bem/_functions.scss +++ b/src/bem/_functions.scss @@ -4,25 +4,28 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:selector'; @use './vars'; /// /// @access private /// @function theme-selector($name, $names...) { - $namespace: map-get(vars.$namespaces, 'theme'); - $selector: null; + $namespace: map.get(vars.$namespaces, 'theme'); + $selector: null; - @each $name in join($name, $names) { - $sel: '.' + $namespace + '-' + $name; + @each $name in list.join($name, $names) { + $sel: '.' + $namespace + '-' + $name; - @if $selector == null { - $selector: join(selector-parse($sel), selector-parse('[class*=\' t-\'] ' + $sel), comma); - $selector: join($selector, selector-parse('[class^=\'t-\'] ' + $sel), comma); - } @else { - $selector: selector-nest($selector, $sel); - } - } + @if $selector == null { + $selector: list.join(selector.parse($sel), selector.parse('[class*=\' t-\'] ' + $sel), comma); + $selector: list.join($selector, selector.parse('[class^=\'t-\'] ' + $sel), comma); + } @else { + $selector: selector.nest($selector, $sel); + } + } - @return $selector; + @return $selector; } diff --git a/src/bem/_modifier.scss b/src/bem/_modifier.scss index 07267fe..10e2826 100644 --- a/src/bem/_modifier.scss +++ b/src/bem/_modifier.scss @@ -4,6 +4,11 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use 'sass:selector'; +@use 'sass:string'; @use './validators'; @use './vars'; @use '../functions'; @@ -111,22 +116,22 @@ /// } /// @mixin modifier($name, $names...) { - $result: modifier($name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: modifier($name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'modifier', - (name: $name, names: $names), - $selector, - $context - ); + @include validators.validate( + 'modifier', + (name: $name, names: $names), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -137,121 +142,115 @@ /// @see {mixin} modifier /// @function modifier($name, $names...) { - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier' 'suffix' 'state'); - $parent-selector: map-get(nth($parent-context, 2), 'selector'); - $selector: (); - $parts-data: (); + $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier' 'suffix' 'state'); + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); + $selector: (); + $parts-data: (); - @if not functions.selector-suffix-match(&, $parent-selector) { - // - // The current selector doesn't match the parent selector. - // The user manually added a selector between parent context and this modifier call. - // This case is forbidden because any outcome semantically wouldn't make sense: - // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier - // - {b,e,m,s}--modifier [manual selector] - // The first case would make the modifier behave like an element. - // The second case is unintuitive, the code would be more clear by nesting the manual - // selector in the modifier instead. - // + @if not functions.selector-suffix-match(&, $parent-selector) { + // + // The current selector doesn't match the parent selector. + // The user manually added a selector between parent context and this modifier call. + // This case is forbidden because any outcome semantically wouldn't make sense: + // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier + // - {b,e,m,s}--modifier [manual selector] + // The first case would make the modifier behave like an element. + // The second case is unintuitive, the code would be more clear by nesting the manual + // selector in the modifier instead. + // - @error 'A modifier must be an immediate child of the parent context'; - } + @error 'A modifier must be an immediate child of the parent context'; + } - @each $name in functions.list-prepend($names, $name) { - $extend: false; - @if type-of($name) == list { - $extend: nth($name, 2); - $name: nth($name, 1); - } + @each $name in functions.list-prepend($names, $name) { + $extend: false; + @if meta.type-of($name) == list { + $extend: list.nth($name, 2); + $name: list.nth($name, 1); + } - @if index('block' 'element', nth($parent-context, 1)) or $extend == true { - // - // Either the parent context is block or element, or a modifier or suffix - // is to be extended. The modifier part can simply be appended. - // Possible outcomes: - // - {b,e,m,s}--modifier - // + @if list.index('block' 'element', list.nth($parent-context, 1)) or $extend == true { + // + // Either the parent context is block or element, or a modifier or suffix + // is to be extended. The modifier part can simply be appended. + // Possible outcomes: + // - {b,e,m,s}--modifier + // - $sel: selector-append(&, vars.$modifier-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } @else { - // - // Parent context is modifier, suffix or state and $extend is false. - // + $sel: selector.append(&, vars.$modifier-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } @else { + // + // Parent context is modifier, suffix or state and $extend is false. + // - $be-context: contexts.get(vars.$context-id, 'block' 'element'); + $be-context: contexts.get(vars.$context-id, 'block' 'element'); - @if nth($be-context, 1) == 'element' { - // - // Latest context is element. Since element contexts can consist of multiple single - // elements, inspect all elements and append its selector with the suffix "--$name". - // This has to be done with string comparison since none of Sass selector functions - // is of use here. - // Possible outcomes: - // - {m,s}.{e}--modifier - // + @if list.nth($be-context, 1) == 'element' { + // + // Latest context is element. Since element contexts can consist of multiple single + // elements, inspect all elements and append its selector with the suffix "--$name". + // This has to be done with string comparison since none of Sass selector functions + // is of use here. + // Possible outcomes: + // - {m,s}.{e}--modifier + // - $nsel: (); + $nsel: (); - @each $elem-part-data in map-get(nth($be-context, 2), 'parts') { - $elem-part-selector: map-get($elem-part-data, 'selector'); + @each $elem-part-data in map.get(list.nth($be-context, 2), 'parts') { + $elem-part-selector: map.get($elem-part-data, 'selector'); - $sel: (); - @each $s in & { - @each $ps in $elem-part-selector { - @if str-index(inspect($s), inspect($ps) + vars.$modifier-separator) or str-index(inspect($s), inspect($ps) + vars.$suffix-separator) { - $sel: join($sel, selector-unify($s, selector-append($ps, vars.$modifier-separator + $name)), comma); - } - } - } - @if length($sel) == 0 { - @error 'Could not generate modifier selector.'; - } + $sel: (); + @each $s in & { + @each $ps in $elem-part-selector { + @if string.index(meta.inspect($s), meta.inspect($ps) + vars.$modifier-separator) or string.index(meta.inspect($s), meta.inspect($ps) + vars.$suffix-separator) { + $sel: list.join($sel, selector.unify($s, selector.append($ps, vars.$modifier-separator + $name)), comma); + } + } + } + @if list.length($sel) == 0 { + @error 'Could not generate modifier selector.'; + } - $nsel: join($nsel, $sel, comma); - } + $nsel: list.join($nsel, $sel, comma); + } - $selector: join($selector, $nsel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $nsel - ) - ); - } @else { - // - // Latest context is block. Just append the modifier part. - // Possible outcomes: - // - {m,s}.{b}--modifier - // + $selector: list.join($selector, $nsel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $nsel + )); + } @else { + // + // Latest context is block. Just append the modifier part. + // Possible outcomes: + // - {m,s}.{b}--modifier + // - $block-base-selector: map-get(nth($be-context, 2), 'base-selector'); + $block-base-selector: map.get(list.nth($be-context, 2), 'base-selector'); - $sel: selector-append(&, $block-base-selector, vars.$modifier-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } - } + $sel: selector.append(&, $block-base-selector, vars.$modifier-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + } - $context: 'modifier', ( - 'parts': $parts-data, - 'selector': $selector - ); + $context: 'modifier', ( + 'parts': $parts-data, + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } diff --git a/src/bem/_multi.scss b/src/bem/_multi.scss index 1de5cdc..c0beeeb 100644 --- a/src/bem/_multi.scss +++ b/src/bem/_multi.scss @@ -4,6 +4,10 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:meta'; +@use 'sass:selector'; +@use 'sass:string'; @use '../functions'; @use '../contexts'; @use './block'; @@ -81,67 +85,67 @@ /// } /// @mixin multi($first, $others...) { - @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - @each $entity in functions.list-prepend($others, $first) { - $is-manual-selector: false; + @each $entity in functions.list-prepend($others, $first) { + $is-manual-selector: false; - @if type-of($entity) == string { - @if find-bem-function($entity) == null { - $is-manual-selector: true; - } - } + @if meta.type-of($entity) == string { + @if find-bem-function($entity) == null { + $is-manual-selector: true; + } + } - @if $is-manual-selector { - $sel: if(&, selector-nest(&, $entity), selector-parse($entity)); + @if $is-manual-selector { + $sel: if(&, selector.nest(&, $entity), selector.parse($entity)); - @at-root #{$sel} { - @content; - } - } @else { - $entity-func-id: null; + @at-root #{$sel} { + @content; + } + } @else { + $entity-func-id: null; - @if type-of($entity) == list { - $entity-func-id: nth($entity, 1); - $entity: functions.list-slice($entity, 2); - } @else { - $entity-func-id: $entity; - $entity: (); - } + @if meta.type-of($entity) == list { + $entity-func-id: list.nth($entity, 1); + $entity: functions.list-slice($entity, 2); + } @else { + $entity-func-id: $entity; + $entity: (); + } - @if str-slice($entity-func-id, str-length($entity-func-id)) == ':' { - $entity-func-id: unquote(str-slice($entity-func-id, 1, str-length($entity-func-id) - 1)); - } + @if string.slice($entity-func-id, string.length($entity-func-id)) == ':' { + $entity-func-id: string.unquote(string.slice($entity-func-id, 1, string.length($entity-func-id) - 1)); + } - $sel-func: find-bem-function($entity-func-id); + $sel-func: find-bem-function($entity-func-id); - @if $sel-func == null { - @error 'Function "#{inspect($entity-func-id)}" was not found.'; - } + @if $sel-func == null { + @error 'Function "#{inspect($entity-func-id)}" was not found.'; + } - $entity-result: call($sel-func, $entity...); - $entity-result-selector: nth($entity-result, 1); - $entity-result-context: nth($entity-result, 2); + $entity-result: meta.call($sel-func, $entity...); + $entity-result-selector: list.nth($entity-result, 1); + $entity-result-context: list.nth($entity-result, 2); - @if $entity-result-context != null { - @include contexts.push(vars.$context-id, $entity-result-context...); - } - @at-root #{$entity-result-selector} { - @content; - } - @if $entity-result-context != null { - @include contexts.pop(vars.$context-id); - } - } - } + @if $entity-result-context != null { + @include contexts.push(vars.$context-id, $entity-result-context...); + } + @at-root #{$entity-result-selector} { + @content; + } + @if $entity-result-context != null { + @include contexts.pop(vars.$context-id); + } + } + } } @function find-bem-function($name) { - @each $module in (block element modifier state suffix theme) { - @if function-exists($name, $module) { - @return get-function($name, $module: $module); - } - } + @each $module in (block element modifier state suffix theme) { + @if meta.function-exists($name, $module) { + @return meta.get-function($name, $module: $module); + } + } - @return null; + @return null; } diff --git a/src/bem/_state.scss b/src/bem/_state.scss index 41bacee..bd0efb1 100644 --- a/src/bem/_state.scss +++ b/src/bem/_state.scss @@ -4,6 +4,8 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:selector'; @use './validators'; @use './vars'; @use '../contexts'; @@ -56,22 +58,22 @@ /// } /// @mixin state($prefix, $state, $states...) { - $result: state($prefix, $state, $states...); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: state($prefix, $state, $states...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'state', - (prefix: $prefix, state: $state, states: $states), - $selector, - $context - ); + @include validators.validate( + 'state', + (prefix: $prefix, state: $state, states: $states), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -82,29 +84,27 @@ /// @see {mixin} has /// @function state($prefix, $state, $states...) { - $selector: (); - $parts-data: (); + $selector: (); + $parts-data: (); - @each $state in join($state, $states) { - $sel: selector-parse('.#{$prefix}-#{$state}'); - @if & { - $sel: selector-append(&, $sel); - } - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $state, - 'selector': $sel - ) - ); - } + @each $state in list.join($state, $states) { + $sel: selector.parse('.#{$prefix}-#{$state}'); + @if & { + $sel: selector.append(&, $sel); + } + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $state, + 'selector': $sel + )); + } - $context: 'state', ( - 'parts': $parts-data, - 'selector': $selector - ); + $context: 'state', ( + 'parts': $parts-data, + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } /// @@ -113,9 +113,9 @@ /// It's a shorthand for state('is', $state, $states...). /// @mixin is($state, $states...) { - @include state('is', $state, $states...) { - @content; - } + @include state('is', $state, $states...) { + @content; + } } /// @@ -126,7 +126,7 @@ /// @see {mixin} is /// @function is($state, $states...) { - @return state('is', $state, $states...); + @return state('is', $state, $states...); } /// @@ -135,9 +135,9 @@ /// It's a shorthand for state('has', $state, $states...). /// @mixin has($state, $states...) { - @include state('has', $state, $states...) { - @content; - } + @include state('has', $state, $states...) { + @content; + } } /// @@ -148,5 +148,5 @@ /// @see {mixin} has /// @function has($state, $states...) { - @return state('has', $state, $states...); + @return state('has', $state, $states...); } diff --git a/src/bem/_suffix.scss b/src/bem/_suffix.scss index 2ddb54d..93e4066 100644 --- a/src/bem/_suffix.scss +++ b/src/bem/_suffix.scss @@ -4,6 +4,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:selector'; @use './validators'; @use './vars'; @use '../functions'; @@ -54,22 +57,22 @@ /// } /// @mixin suffix($name) { - $result: suffix($name); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: suffix($name); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'suffix', - (name: $name), - $selector, - $context - ); + @include validators.validate( + 'suffix', + (name: $name), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -80,44 +83,44 @@ /// @see {mixin} suffix /// @function suffix($name) { - // - // Suffixes can be used on block, element and modifier. - // + // + // Suffixes can be used on block, element and modifier. + // - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - $noop: contexts.assert-stack-must-not-contain(vars.$context-id, 'suffix'); + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + $noop: contexts.assert-stack-must-not-contain(vars.$context-id, 'suffix'); - $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier'); - $parent-selector: map-get(nth($parent-context, 2), 'selector'); + $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier'); + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); - @if not functions.selector-suffix-match(&, $parent-selector) { - // - // The current selector doesn't match the parent selector. - // The user manually added a selector between parent context and this suffix call. - // This case is forbidden because any outcome semantically wouldn't make sense: - // - {b,e,m} [manual selector] {b,e,m}@suffix - // - {b,e,m}@suffix [manual selector] - // The first case would make the modifier behave like an element. - // The second case is unintuitive, the code would be more clear by nesting the manual - // selector in the suffix instead. - // + @if not functions.selector-suffix-match(&, $parent-selector) { + // + // The current selector doesn't match the parent selector. + // The user manually added a selector between parent context and this suffix call. + // This case is forbidden because any outcome semantically wouldn't make sense: + // - {b,e,m} [manual selector] {b,e,m}@suffix + // - {b,e,m}@suffix [manual selector] + // The first case would make the modifier behave like an element. + // The second case is unintuitive, the code would be more clear by nesting the manual + // selector in the suffix instead. + // - @error 'A suffix must be an immediate child of the parent context'; - } + @error 'A suffix must be an immediate child of the parent context'; + } - // - // The suffix part can simply be appended. - // Possible outcomes: - // - {b,e,m}@suffix - // + // + // The suffix part can simply be appended. + // Possible outcomes: + // - {b,e,m}@suffix + // - $selector: selector-append(&, vars.$suffix-separator + $name); + $selector: selector.append(&, vars.$suffix-separator + $name); - $context: 'suffix', ( - 'name': $name, - 'selector': $selector - ); + $context: 'suffix', ( + 'name': $name, + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } diff --git a/src/bem/_theme.scss b/src/bem/_theme.scss index ff1ba49..535cc81 100644 --- a/src/bem/_theme.scss +++ b/src/bem/_theme.scss @@ -4,6 +4,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:selector'; @use './functions'; @use './validators'; @use './vars'; @@ -18,22 +21,22 @@ /// @content /// @mixin at-theme($name, $names...) { - $result: at-theme($name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: at-theme($name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'at-theme', - (name: $name, names: $names), - $selector, - $context - ); + @include validators.validate( + 'at-theme', + (name: $name, names: $names), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -45,22 +48,22 @@ /// @see {mixin} at-theme /// @function at-theme($name, $names...) { - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - $parent-context: contexts.get(vars.$context-id, 'block'); - $parent-selector: map-get(nth($parent-context, 2), 'selector'); + $parent-context: contexts.get(vars.$context-id, 'block'); + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); - //@if not functions.selector-suffix-match(&, $parent-selector) { - // @error 'An at-theme rule must be an immediate child of a block'; - //} + //@if not functions.selector-suffix-match(&, $parent-selector) { + // @error 'An at-theme rule must be an immediate child of a block'; + //} - $selector: functions.theme-selector($name, $names...); - $selector: selector-nest($selector, &); + $selector: functions.theme-selector($name, $names...); + $selector: selector.nest($selector, &); - $context: 'at-theme', ( - 'name': join($name, $names), - 'selector': $selector - ); + $context: 'at-theme', ( + 'name': list.join($name, $names), + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } diff --git a/src/bem/_validators.scss b/src/bem/_validators.scss index 042e15e..bc3c9b7 100644 --- a/src/bem/_validators.scss +++ b/src/bem/_validators.scss @@ -16,6 +16,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; @use './vars'; @use '../functions'; @use '../contexts'; @@ -46,7 +49,7 @@ $validators: (); /// @param {string} $func-names - Other function names. /// @mixin add($func-name, $func-names...) { - $noop: add($func-name, $func-names...); + $noop: add($func-name, $func-names...); } /// @@ -55,11 +58,11 @@ $validators: (); /// @see {mixin} add /// @function add($func-name, $func-names...) { - @each $fn-name in join($func-name, $func-names) { - $fn: get-function($fn-name); - $validators: map-merge($validators, ($fn-name: $fn)); - } - @return null; + @each $fn-name in list.join($func-name, $func-names) { + $fn: meta.get-function($fn-name); + $validators: map.merge($validators, ($fn-name: $fn)); + } + @return null; } /// @@ -69,7 +72,7 @@ $validators: (); /// @param {string} $func-names - Other function names. /// @mixin remove($func-name, $func-names...) { - $noop: remove($func-name, $func-names...); + $noop: remove($func-name, $func-names...); } /// @@ -78,20 +81,20 @@ $validators: (); /// @see {mixin} remove /// @function remove($func-name, $func-names...) { - $validators: map-remove($validators, $func-name, $func-names...); - @return null; + $validators: map.remove($validators, $func-name, $func-names...); + @return null; } /// /// @access private /// @mixin validate($type, $args, $selector, $context) { - @each $id, $fn in $validators { - $result: call($fn, $type, $args, $selector, $context); - @if not nth($result, 1) { - @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; - } - } + @each $id, $fn in $validators { + $result: meta.call($fn, $type, $args, $selector, $context); + @if not list.nth($result, 1) { + @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; + } + } } // @@ -105,76 +108,76 @@ $validators: (); /// namespace used. /// @function enforce-namespace-order($type, $args, $selector, $context) { - @if not global-variable-exists(namespace-order, vars) { - vars.$namespace-order: map-keys(vars.$namespaces); - } - @if not global-variable-exists(cur-namespace-index, vars) { - vars.$cur-namespace-index: 1; - } - - @if $type == 'block' { - $block-type: map-get($args, 'type'); - - @if $block-type != null { - $ns-index: index(vars.$namespace-order, $block-type); - - @if $ns-index != null { - @if $ns-index < vars.$cur-namespace-index { - @return false 'Namespace "#{$block-type}" comes before current namespace #{nth(vars.$namespace-order, vars.$cur-namespace-index)}'; - } - - vars.$cur-namespace-index: $ns-index; - } - } - } - - @return true ''; + @if not meta.global-variable-exists(namespace-order, vars) { + vars.$namespace-order: map.keys(vars.$namespaces); + } + @if not meta.global-variable-exists(cur-namespace-index, vars) { + vars.$cur-namespace-index: 1; + } + + @if $type == 'block' { + $block-type: map.get($args, 'type'); + + @if $block-type != null { + $ns-index: list.index(vars.$namespace-order, $block-type); + + @if $ns-index != null { + @if $ns-index < vars.$cur-namespace-index { + @return false 'Namespace "#{$block-type}" comes before current namespace #{nth(vars.$namespace-order, vars.$cur-namespace-index)}'; + } + + vars.$cur-namespace-index: $ns-index; + } + } + } + + @return true ''; } /// /// A validator that makes all BEM entities immutable. /// @function immutable-entities($type, $args, $selector, $context) { - @if not global-variable-exists(generated-selectors, vars) { - vars.$generated-selectors: (); - } - - $block-name: null; - $block-type: null; - $block-id: null; - - @if $type == 'block' { - $block-name: map-get($args, 'name'); - $block-type: map-get($args, 'type'); - } @else { - $block-context: contexts.get(vars.$context-id, 'block'); - $block-name: map-get(nth($block-context, 2), 'name'); - $block-type: map-get(nth($block-context, 2), 'type'); - } - - @if $block-type != null { - $block-id: $block-name + '_' + $block-type; - } @else { - $block-id: $block-name; - } - - @if $type == 'block' { - @if map-has-key(vars.$generated-selectors, $block-id) { - @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; - } - - vars.$generated-selectors: map-merge(vars.$generated-selectors, ($block-id: ())); - } @else { - $selectors: map-get(vars.$generated-selectors, $block-id); - - @if index($selectors, $selector) { - @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; - } - - $selectors: append($selectors, $selector); - - vars.$generated-selectors: map-merge(vars.$generated-selectors, ($block-id: $selectors)); - } - - @return true ''; + @if not meta.global-variable-exists(generated-selectors, vars) { + vars.$generated-selectors: (); + } + + $block-name: null; + $block-type: null; + $block-id: null; + + @if $type == 'block' { + $block-name: map.get($args, 'name'); + $block-type: map.get($args, 'type'); + } @else { + $block-context: contexts.get(vars.$context-id, 'block'); + $block-name: map.get(list.nth($block-context, 2), 'name'); + $block-type: map.get(list.nth($block-context, 2), 'type'); + } + + @if $block-type != null { + $block-id: $block-name + '_' + $block-type; + } @else { + $block-id: $block-name; + } + + @if $type == 'block' { + @if map.has-key(vars.$generated-selectors, $block-id) { + @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; + } + + vars.$generated-selectors: map.merge(vars.$generated-selectors, ($block-id: ())); + } @else { + $selectors: map.get(vars.$generated-selectors, $block-id); + + @if list.index($selectors, $selector) { + @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; + } + + $selectors: list.append($selectors, $selector); + + vars.$generated-selectors: map.merge(vars.$generated-selectors, ($block-id: $selectors)); + } + + @return true ''; } diff --git a/src/bem/_vars.scss b/src/bem/_vars.scss index 3d0f92a..823bf0a 100644 --- a/src/bem/_vars.scss +++ b/src/bem/_vars.scss @@ -41,15 +41,15 @@ $suffix-separator: '\\@' !default; /// @type map /// $namespaces: ( - object: 'o', - component: 'c', - layout: 'l', - scope: 's', - theme: 't', - utility: 'u', - js: 'js', - qa: 'qa', - hack: '_' + object: 'o', + component: 'c', + layout: 'l', + scope: 's', + theme: 't', + utility: 'u', + js: 'js', + qa: 'qa', + hack: '_' ) !default; /// @@ -100,9 +100,9 @@ $debug: false !default; /// @type map /// $debug-colors: ( - object: #ffa500, - component: #00f, - layout: #ff0, - utility: #008000, - hack: #f00 + object: #ffa500, + component: #00f, + layout: #ff0, + utility: #008000, + hack: #f00 ) !default; -- cgit v1.2.3-70-g09d2