aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/_easing.scss27
-rw-r--r--src/_functions.scss146
-rw-r--r--src/_iro-sass.scss (renamed from src/index.scss)10
-rw-r--r--src/_props.scss462
-rw-r--r--src/bem/_block.scss8
5 files changed, 233 insertions, 420 deletions
diff --git a/src/_easing.scss b/src/_easing.scss
index 8bcfd39..6d66ea7 100644
--- a/src/_easing.scss
+++ b/src/_easing.scss
@@ -10,6 +10,8 @@
10//// 10////
11 11
12@use 'sass:math'; 12@use 'sass:math';
13@use 'sass:map';
14@use 'sass:list';
13 15
14/// 16///
15/// @access private 17/// @access private
@@ -73,14 +75,14 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
73 75
74 $sample-pool-key: $x1 + '_' + $x2; 76 $sample-pool-key: $x1 + '_' + $x2;
75 77
76 @if not map-has-key($cubic-bezier-sample-pool, $sample-pool-key) { 78 @if not map.has-key($cubic-bezier-sample-pool, $sample-pool-key) {
77 $samples: (); 79 $samples: ();
78 80
79 @for $i from 0 through $cubic-bezier-sample-pool-size { 81 @for $i from 0 through $cubic-bezier-sample-pool-size {
80 $samples: append($samples, cubic-bezier-func($x1, $x2, math.div($i, $cubic-bezier-sample-pool-size))); 82 $samples: list.append($samples, cubic-bezier-func($x1, $x2, math.div($i, $cubic-bezier-sample-pool-size)));
81 } 83 }
82 84
83 $cubic-bezier-sample-pool: map-merge($cubic-bezier-sample-pool, ($sample-pool-key: $samples)) !global; 85 $cubic-bezier-sample-pool: map.merge($cubic-bezier-sample-pool, ($sample-pool-key: $samples)) !global;
84 } 86 }
85 87
86 // 88 //
@@ -169,7 +171,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
169 $a: $cur-t; 171 $a: $cur-t;
170 } 172 }
171 173
172 @if abs($cur-x) < $cubic-bezier-subdiv-precision { 174 @if math.abs($cur-x) < $cubic-bezier-subdiv-precision {
173 @return $cur-t; 175 @return $cur-t;
174 } 176 }
175 } 177 }
@@ -184,19 +186,19 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
184/// 186///
185@function cubic-bezier-t-for-x($x1, $x2, $x) { 187@function cubic-bezier-t-for-x($x1, $x2, $x) {
186 $sample-pool-key: $x1 + '_' + $x2; 188 $sample-pool-key: $x1 + '_' + $x2;
187 $samples: map-get($cubic-bezier-sample-pool, $sample-pool-key); 189 $samples: map.get($cubic-bezier-sample-pool, $sample-pool-key);
188 190
189 $intv-start: 0; 191 $intv-start: 0;
190 $cur-sample: 1; 192 $cur-sample: 1;
191 $last-sample: $cubic-bezier-sample-pool-size; 193 $last-sample: $cubic-bezier-sample-pool-size;
192 194
193 @while ($cur-sample != $last-sample) and (nth($samples, $cur-sample) <= $x) { 195 @while ($cur-sample != $last-sample) and (list.nth($samples, $cur-sample) <= $x) {
194 $intv-start: $intv-start + math.div(1, $cubic-bezier-sample-pool-size); 196 $intv-start: $intv-start + math.div(1, $cubic-bezier-sample-pool-size);
195 $cur-sample: $cur-sample + 1; 197 $cur-sample: $cur-sample + 1;
196 } 198 }
197 $cur-sample: $cur-sample - 1; 199 $cur-sample: $cur-sample - 1;
198 200
199 $dist: math.div($x - nth($samples, $cur-sample), nth($samples, $cur-sample + 1) - nth($samples, $cur-sample)); 201 $dist: math.div($x - list.nth($samples, $cur-sample), list.nth($samples, $cur-sample + 1) - list.nth($samples, $cur-sample));
200 $guess-t: $intv-start + math.div($dist, $cubic-bezier-sample-pool-size); 202 $guess-t: $intv-start + math.div($dist, $cubic-bezier-sample-pool-size);
201 203
202 $init-slope: cubic-bezier-func-slope($x1, $x2, $guess-t); 204 $init-slope: cubic-bezier-func-slope($x1, $x2, $guess-t);
@@ -210,6 +212,17 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
210} 212}
211 213
212/// 214///
215/// Linear easing function.
216///
217/// @param {number} $x - Progress between 0 and 1 inclusive
218///
219/// @return {number}
220///
221@function linear($x) {
222 @return $x;
223}
224
225///
213/// Sinusoidal easing function (in direction). 226/// Sinusoidal easing function (in direction).
214/// 227///
215/// @param {number} $x - Progress between 0 and 1 inclusive 228/// @param {number} $x - Progress between 0 and 1 inclusive
diff --git a/src/_functions.scss b/src/_functions.scss
index 9dd14b1..0d139b4 100644
--- a/src/_functions.scss
+++ b/src/_functions.scss
@@ -10,9 +10,32 @@
10//// 10////
11 11
12@use 'sass:map'; 12@use 'sass:map';
13@use 'sass:list';
13@use 'sass:math'; 14@use 'sass:math';
15@use 'sass:string';
16@use 'sass:meta';
14@use './vars'; 17@use './vars';
15 18
19$numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);
20
21$units: (
22 'px': 1px,
23 'cm': 1cm,
24 'mm': 1mm,
25 '%': 1%,
26 'ch': 1ch,
27 'pc': 1pc,
28 'in': 1in,
29 'em': 1em,
30 'rem': 1rem,
31 'pt': 1pt,
32 'ex': 1ex,
33 'vw': 1vw,
34 'vh': 1vh,
35 'vmin': 1vmin,
36 'vmax': 1vmax
37);
38
16/// 39///
17/// Replace a substring with a new string. 40/// Replace a substring with a new string.
18/// 41///
@@ -23,10 +46,10 @@
23/// @return {string} A string with all instances of $search replaced with $replace 46/// @return {string} A string with all instances of $search replaced with $replace
24/// 47///
25@function str-replace($string, $search, $replace) { 48@function str-replace($string, $search, $replace) {
26 $index: str-index($string, $search); 49 $index: string.index($string, $search);
27 50
28 @if $index { 51 @if $index {
29 @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); 52 @return string.slice($string, 1, $index - 1) + $replace + str-replace(string.slice($string, $index + string.length($search)), $search, $replace);
30 } 53 }
31 54
32 @return $string; 55 @return $string;
@@ -44,9 +67,9 @@
44 $result: ''; 67 $result: '';
45 68
46 @each $item in $list { 69 @each $item in $list {
47 $result: $result + if(length($item) > 1, str-implode($item, $glue), $item); 70 $result: $result + if(list.length($item) > 1, str-implode($item, $glue), $item);
48 71
49 @if $item != nth($list, length($list)) { 72 @if $item != list.nth($list, list.length($list)) {
50 $result: $result + $glue; 73 $result: $result + $glue;
51 } 74 }
52 } 75 }
@@ -63,13 +86,13 @@
63/// 86///
64/// @return {list} A slice of the list 87/// @return {list} A slice of the list
65/// 88///
66@function list-slice($list, $start: 1, $end: length($list)) { 89@function list-slice($list, $start: 1, $end: list.length($list)) {
67 $result: (); 90 $result: ();
68 91
69 @if $end >= $start { 92 @if $end >= $start {
70 @for $i from $start through $end { 93 @for $i from $start through $end {
71 @if $i != 0 { 94 @if $i != 0 {
72 $result: append($result, nth($list, $i), list-separator($list)); 95 $result: list.append($result, list.nth($list, $i), list.separator($list));
73 } 96 }
74 } 97 }
75 } 98 }
@@ -86,11 +109,11 @@
86/// @return {list} A list with $value at the beginning, followed by the other items 109/// @return {list} A list with $value at the beginning, followed by the other items
87/// 110///
88@function list-prepend($list, $value) { 111@function list-prepend($list, $value) {
89 $result: append((), $value, list-separator($list)); 112 $result: list.append((), $value, list.separator($list));
90 113
91 @if length($list) > 0 { 114 @if list.length($list) > 0 {
92 @for $i from 1 through length($list) { 115 @for $i from 1 through list.length($list) {
93 $result: append($result, nth($list, $i), list-separator($list)); 116 $result: list.append($result, list.nth($list, $i), list.separator($list));
94 } 117 }
95 } 118 }
96 119
@@ -105,13 +128,13 @@
105/// @return {list} Teh reversed list 128/// @return {list} Teh reversed list
106/// 129///
107@function list-reverse($list) { 130@function list-reverse($list) {
108 @if length($list) == 0 { 131 @if list.length($list) == 0 {
109 @return $list; 132 @return $list;
110 } 133 }
111 134
112 $result: (); 135 $result: ();
113 @for $i from length($list) * -1 through -1 { 136 @for $i from list.length($list) * -1 through -1 {
114 $result: append($result, nth($list, abs($i))); 137 $result: list.append($result, list.nth($list, math.abs($i)));
115 } 138 }
116 @return $result; 139 @return $result;
117} 140}
@@ -126,11 +149,11 @@
126/// 149///
127/// @return {list} Sorted list 150/// @return {list} Sorted list
128/// 151///
129@function quicksort($l, $left: 1, $right: length($l)) { 152@function quicksort($l, $left: 1, $right: list.length($l)) {
130 @if $left < $right { 153 @if $left < $right {
131 $pvr: quicksort-partition($l, $left, $right); 154 $pvr: quicksort-partition($l, $left, $right);
132 $pivot: nth($pvr, 1); 155 $pivot: list.nth($pvr, 1);
133 $l: nth($pvr, 2); 156 $l: list.nth($pvr, 2);
134 $l: quicksort($l, $left, $pivot); 157 $l: quicksort($l, $left, $pivot);
135 $l: quicksort($l, $pivot + 1, $right); 158 $l: quicksort($l, $pivot + 1, $right);
136 } 159 }
@@ -145,30 +168,30 @@
145 $start: true; 168 $start: true;
146 $i: $left; 169 $i: $left;
147 $j: $right - 1; 170 $j: $right - 1;
148 $pivot: nth($l, $right); 171 $pivot: list.nth($l, $right);
149 172
150 @while ($i < $j) or $start { 173 @while ($i < $j) or $start {
151 @while (nth($l, $i) < $pivot) and ($i < $right - 1) { 174 @while (list.nth($l, $i) < $pivot) and ($i < $right - 1) {
152 $i: $i + 1; 175 $i: $i + 1;
153 } 176 }
154 177
155 @while (nth($l, $j)>= $pivot) and ($j > $left) { 178 @while (list.nth($l, $j)>= $pivot) and ($j > $left) {
156 $j: $j - 1; 179 $j: $j - 1;
157 } 180 }
158 181
159 @if $i < $j { 182 @if $i < $j {
160 $i-val: nth($l, $i); 183 $i-val: list.nth($l, $i);
161 $l: set-nth($l, $i, nth($l, $j)); 184 $l: list.set-nth($l, $i, list.nth($l, $j));
162 $l: set-nth($l, $j, $i-val); 185 $l: list.set-nth($l, $j, $i-val);
163 } 186 }
164 187
165 $start: false; 188 $start: false;
166 } 189 }
167 190
168 @if nth($l, $i) > $pivot { 191 @if list.nth($l, $i) > $pivot {
169 $i-val: nth($l, $i); 192 $i-val: list.nth($l, $i);
170 $l: set-nth($l, $i, nth($l, $right)); 193 $l: list.set-nth($l, $i, list.nth($l, $right));
171 $l: set-nth($l, $right, $i-val); 194 $l: list.set-nth($l, $right, $i-val);
172 } 195 }
173 196
174 @return $i $l; 197 @return $i $l;
@@ -185,10 +208,10 @@
185/// @return {any} Either the value assigned to $key or $default 208/// @return {any} Either the value assigned to $key or $default
186/// 209///
187@function map-get-default($map, $key, $keys...) { 210@function map-get-default($map, $key, $keys...) {
188 $default: nth($keys, length($keys)); 211 $default: list.nth($keys, list.length($keys));
189 $keys: list-slice($keys, 1, length($keys) - 1); 212 $keys: list-slice($keys, 1, list.length($keys) - 1);
190 213
191 @return if(map-has-key($map, $key, $keys...), map-get($map, $key, $keys...), $default); 214 @return if(map.has-key($map, $key, $keys...), map.get($map, $key, $keys...), $default);
192} 215}
193 216
194/// 217///
@@ -204,11 +227,11 @@
204 @each $key, $value in $map { 227 @each $key, $value in $map {
205 $value-str: ''; 228 $value-str: '';
206 229
207 @if type-of($value) == map { 230 @if meta.type-of($value) == map {
208 $value-str: '[ ' + map-print($value) + ' ]'; 231 $value-str: '[ ' + map-print($value) + ' ]';
209 } @else if type-of($value) == list { 232 } @else if meta.type-of($value) == list {
210 $value-str: '[ ' + str-implode($value, ', ') + ' ]'; 233 $value-str: '[ ' + str-implode($value, ', ') + ' ]';
211 } @else if type-of($value) == string { 234 } @else if meta.type-of($value) == string {
212 $value-str: '\'' + $value + '\''; 235 $value-str: '\'' + $value + '\'';
213 } @else { 236 } @else {
214 $value-str: $value; 237 $value-str: $value;
@@ -243,8 +266,8 @@
243 @if not $sel-match { 266 @if not $sel-match {
244 $suf-match: true; 267 $suf-match: true;
245 268
246 @for $i from 1 through length($suffix) { 269 @for $i from 1 through list.length($suffix) {
247 @if $suf-match and (nth($sel, -$i) != nth($suffix, -$i)) { 270 @if $suf-match and (list.nth($sel, -$i) != list.nth($suffix, -$i)) {
248 $suf-match: false; 271 $suf-match: false;
249 } 272 }
250 } 273 }
@@ -287,6 +310,61 @@
287 @return math.div($size, $base) * 1rem; 310 @return math.div($size, $base) * 1rem;
288} 311}
289 312
313///
314/// Casts a string into a number
315///
316/// @param {string|number} $value
317///
318/// @return {number}
319///
320@function to-number($value) {
321 @if meta.type-of($value) == 'number' {
322 @return $value;
323 }
324 @if meta.type-of($value) != 'string' {
325 @error 'Value for `to-number` should be a number or a string.';
326 }
327
328 $result: 0;
329 $digits: 0;
330 $minus: string.slice($value, 1, 1) == '-';
331
332 @for $i from if($minus, 2, 1) through string.length($value) {
333 $character: string.slice($value, $i, $i);
334
335 @if not list.index(map.keys($numbers), $character) and $character != '.' {
336 @return to-length(if($minus, -$result, $result), string.slice($value, $i));
337 }
338
339 @if $character == '.' {
340 $digits: 1;
341 } @else if $digits == 0 {
342 $result: $result * 10 + map.get($numbers, $character);
343 } @else {
344 $digits: $digits * 10;
345 $result: $result + math.div(map.get($numbers, $character), $digits);
346 }
347 }
348
349 @return if($minus, -$result, $result);
350}
351
352///
353/// Add $unit to $value
354///
355/// @param {number} $value - Value to add unit to
356/// @param {string} $unit - String representation of the unit
357///
358/// @return {number} $value expressed in $unit
359///
360@function to-length($value, $unit) {
361 @if not list.index(map.keys($units), $unit) {
362 @error 'Invalid unit `#{$unit}`.';
363 }
364
365 @return $value * map.get($units, $unit);
366}
367
290/// 368///
291/// A mixin with the sole purpose of letting you use temporary variables without polluting the global namespace. 369/// A mixin with the sole purpose of letting you use temporary variables without polluting the global namespace.
292/// 370///
diff --git a/src/index.scss b/src/_iro-sass.scss
index cc9cda7..d1b8ee3 100644
--- a/src/index.scss
+++ b/src/_iro-sass.scss
@@ -1,9 +1,9 @@
1@forward 'bem' as bem-*; 1@forward 'vars' as vars-*;
2@forward 'functions' as fn-*;
2@forward 'contexts' as ctx-*; 3@forward 'contexts' as ctx-*;
4@forward 'props' as props-*;
5@forward 'bem' as bem-*;
3@forward 'easing' as easing-*; 6@forward 'easing' as easing-*;
4@forward 'functions' as fn-*;
5@forward 'gradients' as gradients-*; 7@forward 'gradients' as gradients-*;
6@forward 'harmony' as harmony-*;
7@forward 'props' as props-*;
8@forward 'responsive' as responsive-*; 8@forward 'responsive' as responsive-*;
9@forward 'vars' as vars-*; 9@forward 'harmony' as harmony-*;
diff --git a/src/_props.scss b/src/_props.scss
index 8d84aa1..300fc28 100644
--- a/src/_props.scss
+++ b/src/_props.scss
@@ -1,423 +1,139 @@
1//// 1@use 'sass:list';
2/// Property trees.
3///
4/// Property trees allow you to organize properties in a tree structure (internally nested maps).
5/// The intended use is to store all your properties at the beginning and for the rest of the
6/// stylesheet you just get them.
7///
8/// @group Property trees
9///
10/// @access public
11////
12
13@use 'sass:map'; 2@use 'sass:map';
14@use './functions'; 3@use 'sass:meta';
15@use './contexts';
16
17///
18/// The maximum depth of resolved iro-prop-ref() references.
19///
20/// @type number
21///
22$native-assign-max-depth: 2 !default;
23
24///
25/// Indicate if property names must start with two dashes (--).
26/// This is required if property trees are also used for native CSS custom properties.
27///
28/// @type bool
29///
30$enforce-double-dashes: true !default;
31
32///
33/// Default tree name to use if no name is specified.
34///
35/// @type string
36///
37$default-tree: 'default' !default;
38
39///
40/// List of all created property trees.
41///
42/// @type list
43///
44/// @access private
45///
46$trees: ();
47
48///
49/// Default context name used for the namespace context.
50///
51/// @type string
52///
53$namespace-context-id: 'namespace' !default;
54
55///
56/// Declare a namespace, meaning that all variables declared and accessed.
57///
58/// @param {string} $name - Name of the namespace
59///
60@mixin namespace($name) {
61 $key: '--#{$name}';
62 4
63 $ns-key: get-ns-key(); 5@function is-prop-ref($value) {
64 6 @if meta.type-of($value) != 'list' {
65 @if $ns-key != null { 7 @return false;
66 $key: append($ns-key, $key);
67 } @else {
68 $key: ($key);
69 } 8 }
70 9 @if list.length($value) != 4 {
71 @include contexts.push($namespace-context-id, 'namespace', ( 10 @return false;
72 'name': $name,
73 'key': $key
74 ));
75
76 @content;
77
78 @include contexts.pop($namespace-context-id);
79}
80
81///
82/// Get the current namespace name.
83///
84@function namespace() {
85 $noop: contexts.assert-stack-must-contain($namespace-context-id, 'namespace');
86
87 $data: nth(contexts.get($namespace-context-id, 'namespace'), 2);
88 $name: map-get($data, 'name');
89
90 @return $name;
91}
92
93///
94/// Save a property tree. If a tree with the sane name already exists, the trees
95/// will be merged.
96///
97/// @param {map} $map - Map containing properties
98/// @param {string} $tree [$default-tree] - ID the map is saved as
99/// @param {bool} $merge [true] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted.
100///
101@mixin store($map, $tree: $default-tree, $merge: true, $global: false) {
102 $noop: store($map, $tree, $merge, $global);
103}
104
105///
106/// Save a property tree.
107///
108/// @param {map} $map - Map containing properties
109/// @param {string} $tree [$default-tree] - ID the map is saved as
110/// @param {bool} $merge [true] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted.
111///
112@function store($map, $tree: $default-tree, $merge: true, $global: false) {
113 $prop-map: null;
114
115 @if $enforce-double-dashes {
116 @if not validate($map) {
117 @error 'Property tree keys must start with two dashes (--). If you don\'t use property trees for native CSS custom properties, set $enforce-double-dashes to false.';
118 }
119 } 11 }
120 12 @if list.nth($value, 1) != 'prop-ref' {
121 @if not $global { 13 @return false;
122 $ns-key: get-ns-key();
123
124 @if $ns-key != null {
125 $map: ($ns-key: $map);
126 }
127 } 14 }
128 15 @return true;
129 @if map-has-key($trees, $tree) {
130 @if $merge {
131 $map: map.deep-merge(map-get($trees, $tree), $map);
132 } @else {
133 @error 'Property tree #{inspect($tree)} does already exist.';
134 }
135 }
136
137 $trees: map-merge($trees, ($tree: $map)) !global;
138
139 @return null;
140} 16}
141 17
142/// 18@function def($name, $value: (), $metadata: ()) {
143/// Delete a property tree. 19 @return ('prop-ref' $name $value $metadata);
144///
145/// @param {string} $tree [$default-tree] - ID of the tree to be deleted
146///
147@mixin clear($tree: $default-tree) {
148 $noop: clear($tree);
149} 20}
150 21
151/// 22@function merge($ref, $value) {
152/// Delete a property tree. 23 @if not is-prop-ref($ref) {
153/// 24 @return $ref;
154/// @param {string} $tree [$default-tree] - ID of the tree to be deleted
155///
156/// @throw If the property tree does not exist
157///
158@function clear($tree: $default-tree) {
159 @if not map-has-key($trees, $tree) {
160 @error 'Property tree "#{inspect($tree)}" does not exist.';
161 } 25 }
162 26
163 $trees: map-remove($trees, $tree) !global; 27 $v: list.nth($ref, 3);
164 28 $ref: list.set-nth($ref, 3, map.deep-merge($v, $value));
165 @return null; 29 @return $ref;
166} 30}
167 31
168/// 32@function get-deep($name, $value, $key: null, $keys...) {
169/// Access a whole property or a subsection (i.e. value) of it. 33 @if is-prop-ref($value) {
170/// 34 @return get($value, $key, $keys);
171/// @param {string | list} $key [null] - Key of the property to read. If this is a list of keys, the map will be traversed in that order.
172/// @param {string} $tree [$default-tree] - ID of the property tree to use
173/// @param {any} $default [null] - Default value to return of no match was found. If null, this function will throw an error instead.
174///
175/// @return {any} Value assigned to property or $default
176///
177/// @throw If there was no match for $key and $default is null
178///
179@function get-static($key: (), $tree: $default-tree, $default: null, $global: false) {
180 @if not map-has-key($trees, $tree) {
181 @error 'Unknown tree "#{$tree}".';
182 } 35 }
183 36 @if meta.type-of($value) == 'map' and $key != null {
184 $result: map-get($trees, $tree); 37 @if meta.type-of($key) != 'string' {
185 38 @error 'Expected string, got #{$key}';
186 @if not $global {
187 $ns-key: get-ns-key();
188
189 @if $ns-key != null {
190 $orig-key: $key;
191 $key: $ns-key;
192
193 @if type-of($orig-key) == list {
194 @each $subkey in $orig-key {
195 $key: append($key, $subkey);
196 }
197 } @else {
198 $key: append($key, $orig-key);
199 }
200 } 39 }
40 @return get-deep(#{$name}#{$key}, map.get($value, $key), $keys...);
201 } 41 }
202 42 @return $name $value;
203 @if type-of($key) == list {
204 $stop: false;
205
206 @each $k in $key {
207 @if not $stop and map-has-key($result, $k) {
208 $result: map-get($result, $k);
209
210 @if type-of($result) == list and nth($result, 1) == 'iro-prop-ref' {
211 @if length($result) == 2 {
212 $result: get-static($tree: nth($result, 2), $global: true);
213 } @else {
214 $result: get-static(nth($result, 3), nth($result, 2), $global: true);
215 }
216 }
217 } @else {
218 $stop: true;
219 }
220 }
221
222 @if $stop {
223 $result: null;
224 }
225 } @else {
226 $result: map-get($result, $key);
227
228 @if type-of($result) == list and nth($result, 1) == 'iro-prop-ref' {
229 @if length($result) == 2 {
230 $result: get-static($tree: nth($result, 2), $global: true);
231 } @else {
232 $result: get-static(nth($result, 3), nth($result, 2), $global: true);
233 }
234 }
235 }
236
237 @if $result == null {
238 @if $default == null {
239 @error '"#{$key}" is null.';
240 } @else {
241 @return $default;
242 }
243 }
244
245 @return $result;
246} 43}
247 44
248/// 45@function map-to-vars($name, $map) {
249/// Generate a var() function call to get native CSS custom property. 46 @if meta.type-of($map) != 'map' {
250/// 47 @if meta.type-of($name) != 'string' {
251/// @param {string | list} $key - Key of the property to read. If this is a list of keys, the map will be traversed in that order. 48 @error 'Expected variable name, got #{$name} instead';
252/// @param {string | null} $tree [null] - Optional tree to check if the property actually exists.
253/// @param {any} $default [null] - Default value to return of no match was found.
254///
255/// @return {string} var()
256///
257@function get($key, $tree: $default-tree, $default: null, $global: false) {
258 @if $tree != null {
259 $noop: get-static($key, $tree, $default, $global);
260 }
261
262 @if not $global {
263 $ns-key: get-ns-key();
264
265 @if $ns-key != null {
266 $orig-key: $key;
267 $key: $ns-key;
268
269 @if type-of($orig-key) == list {
270 @each $subkey in $orig-key {
271 $key: append($key, $subkey);
272 }
273 } @else {
274 $key: append($key, $orig-key);
275 }
276 } 49 }
50 @return var($name);
277 } 51 }
278 52
279 $native-var: ''; 53 $out: ();
280 54
281 @if type-of($key) == list { 55 @each $key, $value in $map {
282 @each $subkey in $key { 56 $out: map.set($out, $key, map-to-vars(#{$name}#{$key}, $value));
283 $native-var: $native-var + $subkey;
284 }
285 } @else {
286 $native-var: $key;
287 } 57 }
288 58
289 @if $default == null { 59 @return $out;
290 @return var(#{$native-var});
291 } @else {
292 @return var(#{$native-var}, #{$default});
293 }
294} 60}
295 61
296/// 62@function get($ref, $key: null, $keys...) {
297/// Generate assignments for native CSS custom properties with the values from the specified tree. 63 @if not is-prop-ref($ref) {
298/// 64 @return $ref;
299/// @param {string} $tree [$default-tree] - ID of the property tree to use
300/// @param {string} $root [()] - Sub-tree to use for assignment
301///
302@mixin assign($tree: $default-tree, $root: (), $skip: (), $prefix: '', $global: false) {
303 $map: get-static($root, $tree, $global: $global);
304 $map: map-remove($map, $skip...);
305
306 @if type-of($prefix) == list {
307 $prefix: functions.str-implode($prefix);
308 } 65 }
309 66
310 @if not $global { 67 $name: list.nth($ref, 2);
311 $ns-key: get-ns-key(); 68 $value: get(list.nth($ref, 3));
312 69
313 @if $ns-key != null { 70 @if meta.type-of($value) == 'map' {
314 $prefix: $prefix + functions.str-implode($ns-key); 71 $res: get-deep($name, $value, $key, $keys...);
72 $name: list.nth($res, 1);
73 $value: list.nth($res, 2);
74 } @else if meta.type-of($value) == 'list' {
75 $i: 1;
76 @each $item in $value {
77 $value: list.set-nth($value, $i, get($item));
78 $i: $i + 1;
315 } 79 }
316 } 80 }
317 81
318 @include assign-internal($map, $prefix); 82 @return map-to-vars($name, $value);
319} 83}
320 84
321/// 85@mixin materialize-helper($name, $value) {
322/// @access private 86 @if meta.type-of($value) == 'map' {
323/// 87 @each $key, $value in $value {
324@mixin assign-internal($map, $prefix: '', $ref-depth: $native-assign-max-depth) { 88 @include materialize-helper(#{$name}#{$key}, $value);
325 @each $key, $value in $map {
326 $rd: $ref-depth;
327 @if type-of($value) == list and length($value) > 0 and nth($value, 1) == 'iro-prop-ref' {
328 @if $ref-depth != 0 {
329 $rd: $rd - 1;
330 @if length($value) == 2 {
331 $value: get-static($tree: nth($value, 2));
332 } @else {
333 $value: get-static(nth($value, 3), nth($value, 2));
334 }
335 } @else {
336 $value: null;
337 }
338 }
339 @if type-of($value) != map and $value != () {
340 #{$prefix + $key}: #{$value};
341 } @else {
342 @include assign-internal($value, $prefix + $key, $rd);
343 } 89 }
90 } @else {
91 #{$name}: #{$value};
344 } 92 }
345} 93}
346 94
347/// 95@mixin materialize($ref, $match-meta: ()) {
348/// Validate property names. 96 @if is-prop-ref($ref) {
349/// 97 $name: list.nth($ref, 2);
350/// @access private 98 $value: get(list.nth($ref, 3));
351/// 99 $meta: get(list.nth($ref, 4));
352@function validate($map) {
353 @each $key, $value in $map {
354 @if str-index($key, '--') != 1 {
355 @return false;
356 }
357 100
358 @if type-of($value) == map { 101 $match: true;
359 @if not validate($value) { 102 @if meta.type-of($match-meta) == 'list' {
360 @return false; 103 @each $item in $match-meta {
104 $match: $match and list.index($meta, $item) != null;
361 } 105 }
106 } @else if $match-meta == null and list.length($meta) == 0 {
107 $match: true;
108 } @else {
109 $match: list.index($meta, $match-meta) != null;
362 } 110 }
363 }
364
365 @return true;
366}
367
368///
369/// Generate a reference to another tree. Dereferencing is lazy, so you may specify a tree that hasn't been created yet.
370///
371/// @param {string} $tree [$default-tree] - ID of the property tree to use
372/// @param {string | list} $key - Key of the property to read. If this is a list of keys, the map will be traversed in that order.
373///
374/// @return {list} A special list that let's Ignis know that this is a lazy value.
375///
376/// @throw If there was no match for $key and $default is null
377///
378@function ref($tree: $default-tree, $key: null, $global: false) {
379 @if not $global {
380 $ns-key: get-ns-key();
381 111
382 @if $ns-key != null { 112 @if $match {
383 $orig-key: $key; 113 @include materialize-helper($name, $value);
384 $key: $ns-key; 114 }
115 } @else if meta.type-of($ref) == 'list' {
116 @each $r in $ref {
117 @if is-prop-ref($r) {
118 $name: list.nth($r, 2);
119 $value: get(list.nth($r, 3));
120 $meta: get(list.nth($r, 4));
385 121
386 @if $orig-key != null { 122 $match: true;
387 @if type-of($orig-key) == list { 123 @if meta.type-of($match-meta) == 'list' {
388 @each $subkey in $orig-key { 124 @each $item in $match-meta {
389 $key: append($key, $subkey); 125 $match: $match and list.index($meta, $item) != null;
390 } 126 }
127 } @else if $match-meta == null and list.length($meta) == 0 {
128 $match: true;
391 } @else { 129 } @else {
392 $key: append($key, $orig-key); 130 $match: list.index($meta, $match-meta) != null;
131 }
132
133 @if $match {
134 @include materialize-helper($name, $value);
393 } 135 }
394 } 136 }
395 } 137 }
396 } 138 }
397
398 @if $key == null {
399 @return ('iro-prop-ref' $tree);
400 } @else {
401 @return ('iro-prop-ref' $tree $key);
402 }
403}
404
405///
406/// Get the current namespace key.
407///
408/// @access private
409///
410@function get-ns-key() {
411 $ctx: contexts.get($namespace-context-id, 'namespace');
412
413 @if $ctx == null {
414 @return null;
415 }
416
417 $data: nth($ctx, 2);
418 $key: map-get($data, 'key');
419
420 @return $key;
421} 139}
422
423@include contexts.create($namespace-context-id);
diff --git a/src/bem/_block.scss b/src/bem/_block.scss
index 49af04b..cfa9f33 100644
--- a/src/bem/_block.scss
+++ b/src/bem/_block.scss
@@ -56,7 +56,13 @@
56 56
57 @include contexts.push(vars.$context-id, $context...); 57 @include contexts.push(vars.$context-id, $context...);
58 @at-root #{$selector} { 58 @at-root #{$selector} {
59 @content; 59 @if $type != null {
60 @layer #{$type} {
61 @content;
62 }
63 } @else {
64 @content;
65 }
60 } 66 }
61 @include contexts.pop(vars.$context-id); 67 @include contexts.pop(vars.$context-id);
62} 68}