aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/_contexts.scss217
-rw-r--r--src/_easing.scss206
-rw-r--r--src/_functions.scss320
-rw-r--r--src/_gradients.scss643
-rw-r--r--src/_harmony.scss65
-rw-r--r--src/_props.scss202
-rw-r--r--src/_responsive.scss391
-rw-r--r--src/bem/_block.scss222
-rw-r--r--src/bem/_debug.scss15
-rw-r--r--src/bem/_element.scss483
-rw-r--r--src/bem/_functions.scss27
-rw-r--r--src/bem/_modifier.scss227
-rw-r--r--src/bem/_multi.scss102
-rw-r--r--src/bem/_state.scss84
-rw-r--r--src/bem/_suffix.scss95
-rw-r--r--src/bem/_theme.scss57
-rw-r--r--src/bem/_validators.scss137
-rw-r--r--src/bem/_vars.scss28
18 files changed, 1770 insertions, 1751 deletions
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 @@
15/// @access public 15/// @access public
16//// 16////
17 17
18@use 'sass:list';
19@use 'sass:map';
20@use 'sass:meta';
18@use './functions'; 21@use './functions';
19 22
20/// 23///
@@ -34,7 +37,7 @@ $stacks: ();
34/// @throw If context stack already exists 37/// @throw If context stack already exists
35/// 38///
36@mixin create($stack-id) { 39@mixin create($stack-id) {
37 $noop: create($stack-id); 40 $noop: create($stack-id);
38} 41}
39 42
40/// 43///
@@ -43,13 +46,13 @@ $stacks: ();
43/// @param {string} $stack-id - ID of context stack 46/// @param {string} $stack-id - ID of context stack
44/// 47///
45@function create($stack-id) { 48@function create($stack-id) {
46 @if map-has-key($stacks, $stack-id) { 49 @if map.has-key($stacks, $stack-id) {
47 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 50 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
48 } 51 }
49 52
50 $stacks: map-merge($stacks, ($stack-id: ())) !global; 53 $stacks: map.merge($stacks, ($stack-id: ())) !global;
51 54
52 @return null; 55 @return null;
53} 56}
54 57
55/// 58///
@@ -58,7 +61,7 @@ $stacks: ();
58/// @param {string} $stack-id - ID of context stack 61/// @param {string} $stack-id - ID of context stack
59/// 62///
60@mixin clear($stack-id) { 63@mixin clear($stack-id) {
61 $noop: clear($stack-id); 64 $noop: clear($stack-id);
62} 65}
63 66
64/// 67///
@@ -67,14 +70,14 @@ $stacks: ();
67/// @param {string} $stack-id - ID of context stack 70/// @param {string} $stack-id - ID of context stack
68/// 71///
69@function clear($stack-id) { 72@function clear($stack-id) {
70 @if not map-has-key($stacks, $stack-id) { 73 @if not map.has-key($stacks, $stack-id) {
71 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 74 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
72 } 75 }
73 76
74 $context-stack: (); 77 $context-stack: ();
75 $stacks: map-merge($stacks, ($stack-id: $context-stack)) !global; 78 $stacks: map.merge($stacks, ($stack-id: $context-stack)) !global;
76 79
77 @return null; 80 @return null;
78} 81}
79 82
80/// 83///
@@ -83,7 +86,7 @@ $stacks: ();
83/// @param {string} $stack-id - ID of context stack 86/// @param {string} $stack-id - ID of context stack
84/// 87///
85@mixin delete($stack-id) { 88@mixin delete($stack-id) {
86 $noop: delete($stack-id); 89 $noop: delete($stack-id);
87} 90}
88 91
89/// 92///
@@ -92,13 +95,13 @@ $stacks: ();
92/// @param {string} $stack-id - ID of context stack 95/// @param {string} $stack-id - ID of context stack
93/// 96///
94@function delete($stack-id) { 97@function delete($stack-id) {
95 @if not map-has-key($stacks, $stack-id) { 98 @if not map.has-key($stacks, $stack-id) {
96 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 99 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
97 } 100 }
98 101
99 $stacks: map-remove($stacks, $stack-id) !global; 102 $stacks: map.remove($stacks, $stack-id) !global;
100 103
101 @return null; 104 @return null;
102} 105}
103 106
104/// 107///
@@ -109,7 +112,7 @@ $stacks: ();
109/// @param {any} $data [()] - Data that belongs to the context 112/// @param {any} $data [()] - Data that belongs to the context
110/// 113///
111@mixin push($stack-id, $id, $data: ()) { 114@mixin push($stack-id, $id, $data: ()) {
112 $noop: push($stack-id, $id, $data); 115 $noop: push($stack-id, $id, $data);
113} 116}
114 117
115/// 118///
@@ -122,16 +125,16 @@ $stacks: ();
122/// @return {list} A list with two items: 1 = context id, 2 = context data 125/// @return {list} A list with two items: 1 = context id, 2 = context data
123/// 126///
124@function push($stack-id, $id, $data: ()) { 127@function push($stack-id, $id, $data: ()) {
125 @if not map-has-key($stacks, $stack-id) { 128 @if not map.has-key($stacks, $stack-id) {
126 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 129 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
127 } 130 }
128 131
129 $context: $id $data; 132 $context: $id $data;
130 $context-stack: map-get($stacks, $stack-id); 133 $context-stack: map.get($stacks, $stack-id);
131 $context-stack: append($context-stack, $context); 134 $context-stack: list.append($context-stack, $context);
132 $stacks: map-merge($stacks, ($stack-id: $context-stack)) !global; 135 $stacks: map.merge($stacks, ($stack-id: $context-stack)) !global;
133 136
134 @return $context; 137 @return $context;
135} 138}
136 139
137/// 140///
@@ -142,7 +145,7 @@ $stacks: ();
142/// @throw If context stack doesn't exist 145/// @throw If context stack doesn't exist
143/// 146///
144@mixin pop($stack-id) { 147@mixin pop($stack-id) {
145 $noop: pop($stack-id); 148 $noop: pop($stack-id);
146} 149}
147 150
148/// 151///
@@ -153,27 +156,27 @@ $stacks: ();
153/// @return {list} A list with two items: 1 = context id, 2 = context data 156/// @return {list} A list with two items: 1 = context id, 2 = context data
154/// 157///
155@function pop($stack-id) { 158@function pop($stack-id) {
156 @if not map-has-key($stacks, $stack-id) { 159 @if not map.has-key($stacks, $stack-id) {
157 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 160 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
158 } 161 }
159 162
160 $context-stack: map-get($stacks, $stack-id); 163 $context-stack: map.get($stacks, $stack-id);
161 164
162 @if length($context-stack) == 0 { 165 @if list.length($context-stack) == 0 {
163 @error 'Context stack "#{inspect($stack-id)}" is already empty.'; 166 @error 'Context stack "#{inspect($stack-id)}" is already empty.';
164 } 167 }
165 168
166 $popped-context: nth($context-stack, -1); 169 $popped-context: list.nth($context-stack, -1);
167 170
168 @if length($context-stack) == 1 { 171 @if list.length($context-stack) == 1 {
169 $context-stack: (); 172 $context-stack: ();
170 } @else { 173 } @else {
171 $context-stack: functions.list-slice($context-stack, 1, length($context-stack) - 1); 174 $context-stack: functions.list-slice($context-stack, 1, list.length($context-stack) - 1);
172 } 175 }
173 176
174 $stacks: map-merge($stacks, ($stack-id: $context-stack)) !global; 177 $stacks: map.merge($stacks, ($stack-id: $context-stack)) !global;
175 178
176 @return $popped-context; 179 @return $popped-context;
177} 180}
178 181
179/// 182///
@@ -186,15 +189,15 @@ $stacks: ();
186/// @throw If assertion fails 189/// @throw If assertion fails
187/// 190///
188@function assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) { 191@function assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) {
189 @if not contains($stack-id, $context-ids, $check-head-only) { 192 @if not contains($stack-id, $context-ids, $check-head-only) {
190 @error 'Must be called inside of contexts "#{inspect($context-ids)}".'; 193 @error 'Must be called inside of contexts "#{inspect($context-ids)}".';
191 } 194 }
192 195
193 @return null; 196 @return null;
194} 197}
195 198
196@mixin assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) { 199@mixin assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) {
197 $noop: assert-stack-must-contain($stack-id, $context-ids, $check-head-only); 200 $noop: assert-stack-must-contain($stack-id, $context-ids, $check-head-only);
198} 201}
199 202
200/// 203///
@@ -207,15 +210,15 @@ $stacks: ();
207/// @throw If assertion fails 210/// @throw If assertion fails
208/// 211///
209@function assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) { 212@function assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) {
210 @if contains($stack-id, $context-ids, $check-head-only) { 213 @if contains($stack-id, $context-ids, $check-head-only) {
211 @error 'Must not be called inside of contexts "#{inspect($context-ids)}".'; 214 @error 'Must not be called inside of contexts "#{inspect($context-ids)}".';
212 } 215 }
213 216
214 @return null; 217 @return null;
215} 218}
216 219
217@mixin assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) { 220@mixin assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) {
218 $noop: assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only); 221 $noop: assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only);
219} 222}
220 223
221/// 224///
@@ -228,29 +231,29 @@ $stacks: ();
228/// @return {bool} `true` if the context stack contains one of the context IDs, otherwise `false` 231/// @return {bool} `true` if the context stack contains one of the context IDs, otherwise `false`
229/// 232///
230@function contains($stack-id, $context-ids, $check-head-only: false) { 233@function contains($stack-id, $context-ids, $check-head-only: false) {
231 @if not map-has-key($stacks, $stack-id) { 234 @if not map.has-key($stacks, $stack-id) {
232 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 235 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
233 } 236 }
234 237
235 $context-stack: map-get($stacks, $stack-id); 238 $context-stack: map.get($stacks, $stack-id);
236 239
237 @if length($context-stack) == 0 { 240 @if list.length($context-stack) == 0 {
238 @return false; 241 @return false;
239 } 242 }
240 243
241 $end-idx: if($check-head-only, length($context-stack), 1); 244 $end-idx: if($check-head-only, list.length($context-stack), 1);
242 245
243 @for $i from length($context-stack) through $end-idx { 246 @for $i from list.length($context-stack) through $end-idx {
244 $context: nth($context-stack, $i); 247 $context: list.nth($context-stack, $i);
245 248
246 @each $chk-context in $context-ids { 249 @each $chk-context in $context-ids {
247 @if nth($context, 1) == $chk-context { 250 @if list.nth($context, 1) == $chk-context {
248 @return true; 251 @return true;
249 } 252 }
250 } 253 }
251 } 254 }
252 255
253 @return false; 256 @return false;
254} 257}
255 258
256/// 259///
@@ -262,15 +265,15 @@ $stacks: ();
262/// @throw If assertion fails 265/// @throw If assertion fails
263/// 266///
264@function assert-stack-count($stack-id, $max-count) { 267@function assert-stack-count($stack-id, $max-count) {
265 @if count($stack-id) > $max-count { 268 @if count($stack-id) > $max-count {
266 @error 'Maximum context count "#{inspect($max-count)}" exceeded.'; 269 @error 'Maximum context count "#{inspect($max-count)}" exceeded.';
267 } 270 }
268 271
269 @return null; 272 @return null;
270} 273}
271 274
272@mixin assert-stack-count($stack-id, $max-count) { 275@mixin assert-stack-count($stack-id, $max-count) {
273 $noop: assert-stack-count($stack-id, $max-count); 276 $noop: assert-stack-count($stack-id, $max-count);
274} 277}
275 278
276/// 279///
@@ -281,13 +284,13 @@ $stacks: ();
281/// @return {number} The number of contexts 284/// @return {number} The number of contexts
282/// 285///
283@function count($stack-id) { 286@function count($stack-id) {
284 @if not map-has-key($stacks, $stack-id) { 287 @if not map.has-key($stacks, $stack-id) {
285 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 288 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
286 } 289 }
287 290
288 $context-stack: map-get($stacks, $stack-id); 291 $context-stack: map.get($stacks, $stack-id);
289 292
290 @return length($context-stack); 293 @return list.length($context-stack);
291} 294}
292 295
293/// 296///
@@ -299,37 +302,37 @@ $stacks: ();
299/// @return {list} Null if no match was found, otherwise a list with two items: 1. context ID, 2. context data. 302/// @return {list} Null if no match was found, otherwise a list with two items: 1. context ID, 2. context data.
300/// 303///
301@function get($stack-id, $type-or-level: null) { 304@function get($stack-id, $type-or-level: null) {
302 @if not map-has-key($stacks, $stack-id) { 305 @if not map.has-key($stacks, $stack-id) {
303 @error 'Context stack "#{inspect($stack-id)}" does not exist.'; 306 @error 'Context stack "#{inspect($stack-id)}" does not exist.';
304 } 307 }
305 308
306 $context-stack: map-get($stacks, $stack-id); 309 $context-stack: map.get($stacks, $stack-id);
307 310
308 @if length($context-stack) == 0 { 311 @if list.length($context-stack) == 0 {
309 @return null; 312 @return null;
310 } 313 }
311 314
312 @if type-of($type-or-level) == number { 315 @if meta.type-of($type-or-level) == number {
313 $context: nth($context-stack, -$type-or-level); 316 $context: list.nth($context-stack, -$type-or-level);
314 317
315 @return $context; 318 @return $context;
316 } @else { 319 } @else {
317 @for $i from -1 through -(length($context-stack)) { 320 @for $i from -1 through -(list.length($context-stack)) {
318 $context: nth($context-stack, $i); 321 $context: list.nth($context-stack, $i);
319 322
320 @if type-of($type-or-level) == list { 323 @if meta.type-of($type-or-level) == list {
321 @for $j from 1 through length($type-or-level) { 324 @for $j from 1 through list.length($type-or-level) {
322 $ctx: nth($type-or-level, $j); 325 $ctx: list.nth($type-or-level, $j);
323 326
324 @if nth($context, 1) == $ctx { 327 @if list.nth($context, 1) == $ctx {
325 @return $context; 328 @return $context;
326 } 329 }
327 } 330 }
328 } @else if nth($context, 1) == $type-or-level { 331 } @else if list.nth($context, 1) == $type-or-level {
329 @return $context; 332 @return $context;
330 } 333 }
331 } 334 }
332 } 335 }
333 336
334 @return null; 337 @return null;
335} 338}
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;
55/// @return {number} 55/// @return {number}
56/// 56///
57@function cubic-bezier($x1, $y1, $x2, $y2, $x) { 57@function cubic-bezier($x1, $y1, $x2, $y2, $x) {
58 // 58 //
59 // Cover simple cases 59 // Cover simple cases
60 // 60 //
61 61
62 @if ($x1 == $y1) and ($x2 == $y2) { 62 @if ($x1 == $y1) and ($x2 == $y2) {
63 @return $x; 63 @return $x;
64 } 64 }
65 @if $x == 0 { 65 @if $x == 0 {
66 @return 0; 66 @return 0;
67 } 67 }
68 @if $x == 1 { 68 @if $x == 1 {
69 @return 1; 69 @return 1;
70 } 70 }
71 71
72 // 72 //
73 // Generate samples 73 // Generate samples
74 // 74 //
75 75
76 $sample-pool-key: $x1 + '_' + $x2; 76 $sample-pool-key: $x1 + '_' + $x2;
77 77
78 @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) {
79 $samples: (); 79 $samples: ();
80 80
81 @for $i from 0 through $cubic-bezier-sample-pool-size { 81 @for $i from 0 through $cubic-bezier-sample-pool-size {
82 $samples: list.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)));
83 } 83 }
84 84
85 $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;
86 } 86 }
87 87
88 // 88 //
89 // Calculate cubic bezier 89 // Calculate cubic bezier
90 // 90 //
91 91
92 @return cubic-bezier-func($y1, $y2, cubic-bezier-t-for-x($x1, $x2, $x)); 92 @return cubic-bezier-func($y1, $y2, cubic-bezier-t-for-x($x1, $x2, $x));
93} 93}
94 94
95/// 95///
96/// @access private 96/// @access private
97/// 97///
98@function cubic-bezier-func-a($p1, $p2) { 98@function cubic-bezier-func-a($p1, $p2) {
99 @return 1 - 3 * $p2 + 3 * $p1; 99 @return 1 - 3 * $p2 + 3 * $p1;
100} 100}
101 101
102/// 102///
103/// @access private 103/// @access private
104/// 104///
105@function cubic-bezier-func-b($p1, $p2) { 105@function cubic-bezier-func-b($p1, $p2) {
106 @return 3 * $p2 - 6 * $p1; 106 @return 3 * $p2 - 6 * $p1;
107} 107}
108 108
109/// 109///
110/// @access private 110/// @access private
111/// 111///
112@function cubic-bezier-func-c($p1) { 112@function cubic-bezier-func-c($p1) {
113 @return 3 * $p1; 113 @return 3 * $p1;
114} 114}
115 115
116/// 116///
@@ -119,7 +119,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
119/// @access private 119/// @access private
120/// 120///
121@function cubic-bezier-func($p1, $p2, $t) { 121@function cubic-bezier-func($p1, $p2, $t) {
122 @return ((cubic-bezier-func-a($p1, $p2) * $t + cubic-bezier-func-b($p1, $p2)) * $t + cubic-bezier-func-c($p1)) * $t; 122 @return ((cubic-bezier-func-a($p1, $p2) * $t + cubic-bezier-func-b($p1, $p2)) * $t + cubic-bezier-func-c($p1)) * $t;
123} 123}
124 124
125/// 125///
@@ -128,7 +128,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
128/// @access private 128/// @access private
129/// 129///
130@function cubic-bezier-func-slope($p1, $p2, $t) { 130@function cubic-bezier-func-slope($p1, $p2, $t) {
131 @return 3 * cubic-bezier-func-a($p1, $p2) * $t * $t + 2 * cubic-bezier-func-b($p1, $p2) * $t + cubic-bezier-func-c($p1); 131 @return 3 * cubic-bezier-func-a($p1, $p2) * $t * $t + 2 * cubic-bezier-func-b($p1, $p2) * $t + cubic-bezier-func-c($p1);
132} 132}
133 133
134/// 134///
@@ -137,18 +137,18 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
137/// @access private 137/// @access private
138/// 138///
139@function cubic-bezier-newton-raphson($x1, $x2, $x, $t) { 139@function cubic-bezier-newton-raphson($x1, $x2, $x, $t) {
140 @for $i from 1 through $cubic-bezier-newton-iters { 140 @for $i from 1 through $cubic-bezier-newton-iters {
141 $cur-slope: cubic-bezier-func-slope($x1, $x2, $t); 141 $cur-slope: cubic-bezier-func-slope($x1, $x2, $t);
142 142
143 @if $cur-slope == 0 { 143 @if $cur-slope == 0 {
144 @return $t; 144 @return $t;
145 } 145 }
146 146
147 $cur-x: cubic-bezier-func($x1, $x2, $t) - $x; 147 $cur-x: cubic-bezier-func($x1, $x2, $t) - $x;
148 $t: $t - math.div($cur-x, $cur-slope); 148 $t: $t - math.div($cur-x, $cur-slope);
149 } 149 }
150 150
151 @return $t; 151 @return $t;
152} 152}
153 153
154/// 154///
@@ -157,26 +157,26 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
157/// @access private 157/// @access private
158/// 158///
159@function cubic-bezier-binary-subdivide($x1, $x2, $x, $a, $b) { 159@function cubic-bezier-binary-subdivide($x1, $x2, $x, $a, $b) {
160 $cur-x: 0; 160 $cur-x: 0;
161 $cur-t: 0; 161 $cur-t: 0;
162 $i: 0; 162 $i: 0;
163 163
164 @while $i < $cubic-bezier-subdiv-max-iters { 164 @while $i < $cubic-bezier-subdiv-max-iters {
165 $cur-t: $a + ($b - $a) / 2; 165 $cur-t: $a + ($b - $a) / 2;
166 $cur-x: cubic-bezier-func($x1, $x2, $cur-t) - $x; 166 $cur-x: cubic-bezier-func($x1, $x2, $cur-t) - $x;
167 167
168 @if $cur-x > 0 { 168 @if $cur-x > 0 {
169 $b: $cur-t; 169 $b: $cur-t;
170 } @else { 170 } @else {
171 $a: $cur-t; 171 $a: $cur-t;
172 } 172 }
173 173
174 @if math.abs($cur-x) < $cubic-bezier-subdiv-precision { 174 @if math.abs($cur-x) < $cubic-bezier-subdiv-precision {
175 @return $cur-t; 175 @return $cur-t;
176 } 176 }
177 } 177 }
178 178
179 @return $cur-t; 179 @return $cur-t;
180} 180}
181 181
182/// 182///
@@ -185,30 +185,30 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
185/// @access private 185/// @access private
186/// 186///
187@function cubic-bezier-t-for-x($x1, $x2, $x) { 187@function cubic-bezier-t-for-x($x1, $x2, $x) {
188 $sample-pool-key: $x1 + '_' + $x2; 188 $sample-pool-key: $x1 + '_' + $x2;
189 $samples: map.get($cubic-bezier-sample-pool, $sample-pool-key); 189 $samples: map.get($cubic-bezier-sample-pool, $sample-pool-key);
190 190
191 $intv-start: 0; 191 $intv-start: 0;
192 $cur-sample: 1; 192 $cur-sample: 1;
193 $last-sample: $cubic-bezier-sample-pool-size; 193 $last-sample: $cubic-bezier-sample-pool-size;
194 194
195 @while ($cur-sample != $last-sample) and (list.nth($samples, $cur-sample) <= $x) { 195 @while ($cur-sample != $last-sample) and (list.nth($samples, $cur-sample) <= $x) {
196 $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);
197 $cur-sample: $cur-sample + 1; 197 $cur-sample: $cur-sample + 1;
198 } 198 }
199 $cur-sample: $cur-sample - 1; 199 $cur-sample: $cur-sample - 1;
200 200
201 $dist: math.div($x - list.nth($samples, $cur-sample), list.nth($samples, $cur-sample + 1) - list.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));
202 $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);
203 203
204 $init-slope: cubic-bezier-func-slope($x1, $x2, $guess-t); 204 $init-slope: cubic-bezier-func-slope($x1, $x2, $guess-t);
205 @if $init-slope >= $cubic-bezier-newton-min-slope { 205 @if $init-slope >= $cubic-bezier-newton-min-slope {
206 @return cubic-bezier-newton-raphson($x1, $x2, $x, $guess-t); 206 @return cubic-bezier-newton-raphson($x1, $x2, $x, $guess-t);
207 } @else if $init-slope == 0 { 207 } @else if $init-slope == 0 {
208 @return $guess-t; 208 @return $guess-t;
209 } @else { 209 } @else {
210 @return cubic-bezier-binary-subdivide($x1, $x2, $x, $intv-start, $intv-start + 1 / $cubic-bezier-sample-pool-size); 210 @return cubic-bezier-binary-subdivide($x1, $x2, $x, $intv-start, $intv-start + 1 / $cubic-bezier-sample-pool-size);
211 } 211 }
212} 212}
213 213
214/// 214///
@@ -219,7 +219,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
219/// @return {number} 219/// @return {number}
220/// 220///
221@function linear($x) { 221@function linear($x) {
222 @return $x; 222 @return $x;
223} 223}
224 224
225/// 225///
@@ -230,7 +230,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
230/// @return {number} 230/// @return {number}
231/// 231///
232@function ease($x) { 232@function ease($x) {
233 @return cubic-bezier(.25, .1, .25, 1, $x); 233 @return cubic-bezier(.25, .1, .25, 1, $x);
234} 234}
235 235
236/// 236///
@@ -241,7 +241,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
241/// @return {number} 241/// @return {number}
242/// 242///
243@function ease-in($x) { 243@function ease-in($x) {
244 @return cubic-bezier(.42, 0, 1, 1, $x); 244 @return cubic-bezier(.42, 0, 1, 1, $x);
245} 245}
246 246
247/// 247///
@@ -252,7 +252,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
252/// @return {number} 252/// @return {number}
253/// 253///
254@function ease-out($x) { 254@function ease-out($x) {
255 @return cubic-bezier(0, 0, .58, 1, $x); 255 @return cubic-bezier(0, 0, .58, 1, $x);
256} 256}
257 257
258/// 258///
@@ -263,7 +263,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
263/// @return {number} 263/// @return {number}
264/// 264///
265@function ease-in-out($x) { 265@function ease-in-out($x) {
266 @return cubic-bezier(.42, 0, .58, 1, $x); 266 @return cubic-bezier(.42, 0, .58, 1, $x);
267} 267}
268 268
269/// 269///
@@ -274,7 +274,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
274/// @return {number} 274/// @return {number}
275/// 275///
276@function ease-in-sine($x) { 276@function ease-in-sine($x) {
277 @return cubic-bezier(.47, 0, .745, .715, $x); 277 @return cubic-bezier(.47, 0, .745, .715, $x);
278} 278}
279 279
280/// 280///
@@ -285,7 +285,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
285/// @return {number} 285/// @return {number}
286/// 286///
287@function ease-out-sine($x) { 287@function ease-out-sine($x) {
288 @return cubic-bezier(.39, .575, .565, 1, $x); 288 @return cubic-bezier(.39, .575, .565, 1, $x);
289} 289}
290 290
291/// 291///
@@ -296,7 +296,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
296/// @return {number} 296/// @return {number}
297/// 297///
298@function ease-in-out-sine($x) { 298@function ease-in-out-sine($x) {
299 @return cubic-bezier(.445, .05, .55, .95, $x); 299 @return cubic-bezier(.445, .05, .55, .95, $x);
300} 300}
301 301
302/// 302///
@@ -307,7 +307,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
307/// @return {number} 307/// @return {number}
308/// 308///
309@function ease-in-quad($x) { 309@function ease-in-quad($x) {
310 @return cubic-bezier(.55, .085, .68, .53, $x); 310 @return cubic-bezier(.55, .085, .68, .53, $x);
311} 311}
312 312
313/// 313///
@@ -318,7 +318,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
318/// @return {number} 318/// @return {number}
319/// 319///
320@function ease-out-quad($x) { 320@function ease-out-quad($x) {
321 @return cubic-bezier(.25, .46, .45, .94, $x); 321 @return cubic-bezier(.25, .46, .45, .94, $x);
322} 322}
323 323
324/// 324///
@@ -329,7 +329,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
329/// @return {number} 329/// @return {number}
330/// 330///
331@function ease-in-out-quad($x) { 331@function ease-in-out-quad($x) {
332 @return cubic-bezier(.455, .03, .515, .955, $x); 332 @return cubic-bezier(.455, .03, .515, .955, $x);
333} 333}
334 334
335/// 335///
@@ -340,7 +340,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
340/// @return {number} 340/// @return {number}
341/// 341///
342@function ease-in-cubic($x) { 342@function ease-in-cubic($x) {
343 @return cubic-bezier(.55, .055, .675, .19, $x); 343 @return cubic-bezier(.55, .055, .675, .19, $x);
344} 344}
345 345
346/// 346///
@@ -351,7 +351,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
351/// @return {number} 351/// @return {number}
352/// 352///
353@function ease-out-cubic($x) { 353@function ease-out-cubic($x) {
354 @return cubic-bezier(.215, .61, .355, 1, $x); 354 @return cubic-bezier(.215, .61, .355, 1, $x);
355} 355}
356 356
357/// 357///
@@ -362,7 +362,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
362/// @return {number} 362/// @return {number}
363/// 363///
364@function ease-in-out-cubic($x) { 364@function ease-in-out-cubic($x) {
365 @return cubic-bezier(.645, .045, .355, 1, $x); 365 @return cubic-bezier(.645, .045, .355, 1, $x);
366} 366}
367 367
368/// 368///
@@ -373,7 +373,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
373/// @return {number} 373/// @return {number}
374/// 374///
375@function ease-in-quart($x) { 375@function ease-in-quart($x) {
376 @return cubic-bezier(.895, .03, .685, .22, $x); 376 @return cubic-bezier(.895, .03, .685, .22, $x);
377} 377}
378 378
379/// 379///
@@ -384,7 +384,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
384/// @return {number} 384/// @return {number}
385/// 385///
386@function ease-out-quart($x) { 386@function ease-out-quart($x) {
387 @return cubic-bezier(.165, .84, .44, 1, $x); 387 @return cubic-bezier(.165, .84, .44, 1, $x);
388} 388}
389 389
390/// 390///
@@ -395,7 +395,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
395/// @return {number} 395/// @return {number}
396/// 396///
397@function ease-in-out-quart($x) { 397@function ease-in-out-quart($x) {
398 @return cubic-bezier(.77, 0, .175, 1, $x); 398 @return cubic-bezier(.77, 0, .175, 1, $x);
399} 399}
400 400
401/// 401///
@@ -406,7 +406,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
406/// @return {number} 406/// @return {number}
407/// 407///
408@function ease-in-quint($x) { 408@function ease-in-quint($x) {
409 @return cubic-bezier(.755, .05, .855, .06, $x); 409 @return cubic-bezier(.755, .05, .855, .06, $x);
410} 410}
411 411
412/// 412///
@@ -417,7 +417,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
417/// @return {number} 417/// @return {number}
418/// 418///
419@function ease-out-quint($x) { 419@function ease-out-quint($x) {
420 @return cubic-bezier(.23, 1, .32, 1, $x); 420 @return cubic-bezier(.23, 1, .32, 1, $x);
421} 421}
422 422
423/// 423///
@@ -428,7 +428,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
428/// @return {number} 428/// @return {number}
429/// 429///
430@function ease-in-out-quint($x) { 430@function ease-in-out-quint($x) {
431 @return cubic-bezier(.86, 0, .07, 1, $x); 431 @return cubic-bezier(.86, 0, .07, 1, $x);
432} 432}
433 433
434/// 434///
@@ -439,7 +439,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
439/// @return {number} 439/// @return {number}
440/// 440///
441@function ease-in-expo($x) { 441@function ease-in-expo($x) {
442 @return cubic-bezier(.95, .05, .795, .035, $x); 442 @return cubic-bezier(.95, .05, .795, .035, $x);
443} 443}
444 444
445/// 445///
@@ -450,7 +450,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
450/// @return {number} 450/// @return {number}
451/// 451///
452@function ease-out-expo($x) { 452@function ease-out-expo($x) {
453 @return cubic-bezier(.19, 1, .22, 1, $x); 453 @return cubic-bezier(.19, 1, .22, 1, $x);
454} 454}
455 455
456/// 456///
@@ -461,7 +461,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
461/// @return {number} 461/// @return {number}
462/// 462///
463@function ease-in-out-expo($x) { 463@function ease-in-out-expo($x) {
464 @return cubic-bezier(1, 0, 0, 1, $x); 464 @return cubic-bezier(1, 0, 0, 1, $x);
465} 465}
466 466
467/// 467///
@@ -472,7 +472,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
472/// @return {number} 472/// @return {number}
473/// 473///
474@function ease-in-circ($x) { 474@function ease-in-circ($x) {
475 @return cubic-bezier(.6, .04, .98, .335, $x); 475 @return cubic-bezier(.6, .04, .98, .335, $x);
476} 476}
477 477
478/// 478///
@@ -483,7 +483,7 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
483/// @return {number} 483/// @return {number}
484/// 484///
485@function ease-out-circ($x) { 485@function ease-out-circ($x) {
486 @return cubic-bezier(.075, .82, .165, 1, $x); 486 @return cubic-bezier(.075, .82, .165, 1, $x);
487} 487}
488 488
489/// 489///
@@ -494,5 +494,5 @@ $cubic-bezier-subdiv-max-iters: 10 !default;
494/// @return {number} 494/// @return {number}
495/// 495///
496@function ease-in-out-circ($x) { 496@function ease-in-out-circ($x) {
497 @return cubic-bezier(.785, .135, .15, .86, $x); 497 @return cubic-bezier(.785, .135, .15, .86, $x);
498} 498}
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 @@
19$numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9); 19$numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);
20 20
21$units: ( 21$units: (
22 'px': 1px, 22 'px': 1px,
23 'cm': 1cm, 23 'cm': 1cm,
24 'mm': 1mm, 24 'mm': 1mm,
25 '%': 1%, 25 '%': 1%,
26 'ch': 1ch, 26 'ch': 1ch,
27 'pc': 1pc, 27 'pc': 1pc,
28 'in': 1in, 28 'in': 1in,
29 'em': 1em, 29 'em': 1em,
30 'rem': 1rem, 30 'rem': 1rem,
31 'pt': 1pt, 31 'pt': 1pt,
32 'ex': 1ex, 32 'ex': 1ex,
33 'vw': 1vw, 33 'vw': 1vw,
34 'vh': 1vh, 34 'vh': 1vh,
35 'vmin': 1vmin, 35 'vmin': 1vmin,
36 'vmax': 1vmax 36 'vmax': 1vmax
37); 37);
38 38
39/// 39///
@@ -46,13 +46,13 @@ $units: (
46/// @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
47/// 47///
48@function str-replace($string, $search, $replace) { 48@function str-replace($string, $search, $replace) {
49 $index: string.index($string, $search); 49 $index: string.index($string, $search);
50 50
51 @if $index { 51 @if $index {
52 @return string.slice($string, 1, $index - 1) + $replace + str-replace(string.slice($string, $index + string.length($search)), $search, $replace); 52 @return string.slice($string, 1, $index - 1) + $replace + str-replace(string.slice($string, $index + string.length($search)), $search, $replace);
53 } 53 }
54 54
55 @return $string; 55 @return $string;
56} 56}
57 57
58/// 58///
@@ -64,17 +64,17 @@ $units: (
64/// @return {string} 64/// @return {string}
65/// 65///
66@function str-implode($list, $glue: '') { 66@function str-implode($list, $glue: '') {
67 $result: ''; 67 $result: '';
68 68
69 @each $item in $list { 69 @each $item in $list {
70 $result: $result + if(list.length($item) > 1, str-implode($item, $glue), $item); 70 $result: $result + if(list.length($item) > 1, str-implode($item, $glue), $item);
71 71
72 @if $item != list.nth($list, list.length($list)) { 72 @if $item != list.nth($list, list.length($list)) {
73 $result: $result + $glue; 73 $result: $result + $glue;
74 } 74 }
75 } 75 }
76 76
77 @return $result; 77 @return $result;
78} 78}
79 79
80/// 80///
@@ -87,17 +87,17 @@ $units: (
87/// @return {list} A slice of the list 87/// @return {list} A slice of the list
88/// 88///
89@function list-slice($list, $start: 1, $end: list.length($list)) { 89@function list-slice($list, $start: 1, $end: list.length($list)) {
90 $result: (); 90 $result: ();
91 91
92 @if $end >= $start { 92 @if $end >= $start {
93 @for $i from $start through $end { 93 @for $i from $start through $end {
94 @if $i != 0 { 94 @if $i != 0 {
95 $result: list.append($result, list.nth($list, $i), list.separator($list)); 95 $result: list.append($result, list.nth($list, $i), list.separator($list));
96 } 96 }
97 } 97 }
98 } 98 }
99 99
100 @return $result; 100 @return $result;
101} 101}
102 102
103/// 103///
@@ -109,15 +109,15 @@ $units: (
109/// @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
110/// 110///
111@function list-prepend($list, $value) { 111@function list-prepend($list, $value) {
112 $result: list.append((), $value, list.separator($list)); 112 $result: list.append((), $value, list.separator($list));
113 113
114 @if list.length($list) > 0 { 114 @if list.length($list) > 0 {
115 @for $i from 1 through list.length($list) { 115 @for $i from 1 through list.length($list) {
116 $result: list.append($result, list.nth($list, $i), list.separator($list)); 116 $result: list.append($result, list.nth($list, $i), list.separator($list));
117 } 117 }
118 } 118 }
119 119
120 @return $result; 120 @return $result;
121} 121}
122 122
123/// 123///
@@ -128,15 +128,15 @@ $units: (
128/// @return {list} Teh reversed list 128/// @return {list} Teh reversed list
129/// 129///
130@function list-reverse($list) { 130@function list-reverse($list) {
131 @if list.length($list) == 0 { 131 @if list.length($list) == 0 {
132 @return $list; 132 @return $list;
133 } 133 }
134 134
135 $result: (); 135 $result: ();
136 @for $i from list.length($list) * -1 through -1 { 136 @for $i from list.length($list) * -1 through -1 {
137 $result: list.append($result, list.nth($list, math.abs($i))); 137 $result: list.append($result, list.nth($list, math.abs($i)));
138 } 138 }
139 @return $result; 139 @return $result;
140} 140}
141 141
142/// 142///
@@ -150,51 +150,51 @@ $units: (
150/// @return {list} Sorted list 150/// @return {list} Sorted list
151/// 151///
152@function quicksort($l, $left: 1, $right: list.length($l)) { 152@function quicksort($l, $left: 1, $right: list.length($l)) {
153 @if $left < $right { 153 @if $left < $right {
154 $pvr: quicksort-partition($l, $left, $right); 154 $pvr: quicksort-partition($l, $left, $right);
155 $pivot: list.nth($pvr, 1); 155 $pivot: list.nth($pvr, 1);
156 $l: list.nth($pvr, 2); 156 $l: list.nth($pvr, 2);
157 $l: quicksort($l, $left, $pivot); 157 $l: quicksort($l, $left, $pivot);
158 $l: quicksort($l, $pivot + 1, $right); 158 $l: quicksort($l, $pivot + 1, $right);
159 } 159 }
160 160
161 @return $l; 161 @return $l;
162} 162}
163 163
164/// 164///
165/// @access private 165/// @access private
166/// 166///
167@function quicksort-partition($l, $left, $right) { 167@function quicksort-partition($l, $left, $right) {
168 $start: true; 168 $start: true;
169 $i: $left; 169 $i: $left;
170 $j: $right - 1; 170 $j: $right - 1;
171 $pivot: list.nth($l, $right); 171 $pivot: list.nth($l, $right);
172 172
173 @while ($i < $j) or $start { 173 @while ($i < $j) or $start {
174 @while (list.nth($l, $i) < $pivot) and ($i < $right - 1) { 174 @while (list.nth($l, $i) < $pivot) and ($i < $right - 1) {
175 $i: $i + 1; 175 $i: $i + 1;
176 } 176 }
177 177
178 @while (list.nth($l, $j)>= $pivot) and ($j > $left) { 178 @while (list.nth($l, $j)>= $pivot) and ($j > $left) {
179 $j: $j - 1; 179 $j: $j - 1;
180 } 180 }
181 181
182 @if $i < $j { 182 @if $i < $j {
183 $i-val: list.nth($l, $i); 183 $i-val: list.nth($l, $i);
184 $l: list.set-nth($l, $i, list.nth($l, $j)); 184 $l: list.set-nth($l, $i, list.nth($l, $j));
185 $l: list.set-nth($l, $j, $i-val); 185 $l: list.set-nth($l, $j, $i-val);
186 } 186 }
187 187
188 $start: false; 188 $start: false;
189 } 189 }
190 190
191 @if list.nth($l, $i) > $pivot { 191 @if list.nth($l, $i) > $pivot {
192 $i-val: list.nth($l, $i); 192 $i-val: list.nth($l, $i);
193 $l: list.set-nth($l, $i, list.nth($l, $right)); 193 $l: list.set-nth($l, $i, list.nth($l, $right));
194 $l: list.set-nth($l, $right, $i-val); 194 $l: list.set-nth($l, $right, $i-val);
195 } 195 }
196 196
197 @return $i $l; 197 @return $i $l;
198} 198}
199 199
200/// 200///
@@ -208,10 +208,10 @@ $units: (
208/// @return {any} Either the value assigned to $key or $default 208/// @return {any} Either the value assigned to $key or $default
209/// 209///
210@function map-get-default($map, $key, $keys...) { 210@function map-get-default($map, $key, $keys...) {
211 $default: list.nth($keys, list.length($keys)); 211 $default: list.nth($keys, list.length($keys));
212 $keys: list-slice($keys, 1, list.length($keys) - 1); 212 $keys: list-slice($keys, 1, list.length($keys) - 1);
213 213
214 @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);
215} 215}
216 216
217/// 217///
@@ -222,29 +222,29 @@ $units: (
222/// @return {string} 222/// @return {string}
223/// 223///
224@function map-print($map) { 224@function map-print($map) {
225 $output: ''; 225 $output: '';
226 226
227 @each $key, $value in $map { 227 @each $key, $value in $map {
228 $value-str: ''; 228 $value-str: '';
229 229
230 @if meta.type-of($value) == map { 230 @if meta.type-of($value) == map {
231 $value-str: '[ ' + map-print($value) + ' ]'; 231 $value-str: '[ ' + map-print($value) + ' ]';
232 } @else if meta.type-of($value) == list { 232 } @else if meta.type-of($value) == list {
233 $value-str: '[ ' + str-implode($value, ', ') + ' ]'; 233 $value-str: '[ ' + str-implode($value, ', ') + ' ]';
234 } @else if meta.type-of($value) == string { 234 } @else if meta.type-of($value) == string {
235 $value-str: '\'' + $value + '\''; 235 $value-str: '\'' + $value + '\'';
236 } @else { 236 } @else {
237 $value-str: $value; 237 $value-str: $value;
238 } 238 }
239 239
240 @if $output == '' { 240 @if $output == '' {
241 $output: $key + ': ' + $value-str; 241 $output: $key + ': ' + $value-str;
242 } @else { 242 } @else {
243 $output: $output + ', ' + $key + ': ' + $value-str; 243 $output: $output + ', ' + $key + ': ' + $value-str;
244 } 244 }
245 } 245 }
246 246
247 @return $output; 247 @return $output;
248} 248}
249 249
250/// 250///
@@ -256,35 +256,35 @@ $units: (
256/// @return {bool} `true` if the selector matches at least one suffix, otherwise `false`. 256/// @return {bool} `true` if the selector matches at least one suffix, otherwise `false`.
257/// 257///
258@function selector-suffix-match($selector, $suffixes) { 258@function selector-suffix-match($selector, $suffixes) {
259 $match: true; 259 $match: true;
260 260
261 @each $sel in $selector { 261 @each $sel in $selector {
262 @if $match { 262 @if $match {
263 $sel-match: false; 263 $sel-match: false;
264 264
265 @each $suffix in $suffixes { 265 @each $suffix in $suffixes {
266 @if not $sel-match { 266 @if not $sel-match {
267 $suf-match: true; 267 $suf-match: true;
268 268
269 @for $i from 1 through list.length($suffix) { 269 @for $i from 1 through list.length($suffix) {
270 @if $suf-match and (list.nth($sel, -$i) != list.nth($suffix, -$i)) { 270 @if $suf-match and (list.nth($sel, -$i) != list.nth($suffix, -$i)) {
271 $suf-match: false; 271 $suf-match: false;
272 } 272 }
273 } 273 }
274 274
275 @if $suf-match { 275 @if $suf-match {
276 $sel-match: true; 276 $sel-match: true;
277 } 277 }
278 } 278 }
279 } 279 }
280 280
281 @if not $sel-match { 281 @if not $sel-match {
282 $match: false; 282 $match: false;
283 } 283 }
284 } 284 }
285 } 285 }
286 286
287 @return $match; 287 @return $match;
288} 288}
289 289
290/// 290///
@@ -295,7 +295,7 @@ $units: (
295/// @return {number} Unit-less variable 295/// @return {number} Unit-less variable
296/// 296///
297@function strip-unit($n) { 297@function strip-unit($n) {
298 @return math.div($n, $n * 0 + 1); 298 @return math.div($n, $n * 0 + 1);
299} 299}
300 300
301/// 301///
@@ -307,7 +307,7 @@ $units: (
307/// @return {number} Pixel value converted to rem 307/// @return {number} Pixel value converted to rem
308/// 308///
309@function px-to-rem($size, $base: vars.$root-size) { 309@function px-to-rem($size, $base: vars.$root-size) {
310 @return math.div($size, $base) * 1rem; 310 @return math.div($size, $base) * 1rem;
311} 311}
312 312
313/// 313///
@@ -318,35 +318,35 @@ $units: (
318/// @return {number} 318/// @return {number}
319/// 319///
320@function to-number($value) { 320@function to-number($value) {
321 @if meta.type-of($value) == 'number' { 321 @if meta.type-of($value) == 'number' {
322 @return $value; 322 @return $value;
323 } 323 }
324 @if meta.type-of($value) != 'string' { 324 @if meta.type-of($value) != 'string' {
325 @error 'Value for `to-number` should be a number or a string.'; 325 @error 'Value for `to-number` should be a number or a string.';
326 } 326 }
327 327
328 $result: 0; 328 $result: 0;
329 $digits: 0; 329 $digits: 0;
330 $minus: string.slice($value, 1, 1) == '-'; 330 $minus: string.slice($value, 1, 1) == '-';
331 331
332 @for $i from if($minus, 2, 1) through string.length($value) { 332 @for $i from if($minus, 2, 1) through string.length($value) {
333 $character: string.slice($value, $i, $i); 333 $character: string.slice($value, $i, $i);
334 334
335 @if not list.index(map.keys($numbers), $character) and $character != '.' { 335 @if not list.index(map.keys($numbers), $character) and $character != '.' {
336 @return to-length(if($minus, -$result, $result), string.slice($value, $i)); 336 @return to-length(if($minus, -$result, $result), string.slice($value, $i));
337 } 337 }
338 338
339 @if $character == '.' { 339 @if $character == '.' {
340 $digits: 1; 340 $digits: 1;
341 } @else if $digits == 0 { 341 } @else if $digits == 0 {
342 $result: $result * 10 + map.get($numbers, $character); 342 $result: $result * 10 + map.get($numbers, $character);
343 } @else { 343 } @else {
344 $digits: $digits * 10; 344 $digits: $digits * 10;
345 $result: $result + math.div(map.get($numbers, $character), $digits); 345 $result: $result + math.div(map.get($numbers, $character), $digits);
346 } 346 }
347 } 347 }
348 348
349 @return if($minus, -$result, $result); 349 @return if($minus, -$result, $result);
350} 350}
351 351
352/// 352///
@@ -358,11 +358,11 @@ $units: (
358/// @return {number} $value expressed in $unit 358/// @return {number} $value expressed in $unit
359/// 359///
360@function to-length($value, $unit) { 360@function to-length($value, $unit) {
361 @if not list.index(map.keys($units), $unit) { 361 @if not list.index(map.keys($units), $unit) {
362 @error 'Invalid unit `#{$unit}`.'; 362 @error 'Invalid unit `#{$unit}`.';
363 } 363 }
364 364
365 @return $value * map.get($units, $unit); 365 @return $value * map.get($units, $unit);
366} 366}
367 367
368/// 368///
@@ -371,5 +371,5 @@ $units: (
371/// @content 371/// @content
372/// 372///
373@mixin execute { 373@mixin execute {
374 @content; 374 @content;
375} 375}
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 @@
15/// @access public 15/// @access public
16//// 16////
17 17
18@use 'sass:color';
19@use 'sass:list';
18@use 'sass:math'; 20@use 'sass:math';
19@use 'sass:meta'; 21@use 'sass:meta';
22@use 'sass:string';
20@use './functions'; 23@use './functions';
21@use './easing'; 24@use './easing';
22 25
@@ -135,144 +138,136 @@ $easing-gradient-steps: 10 !default;
135/// } 138/// }
136/// 139///
137@function easing-gradient($type, $dir, $stop, $stops...) { 140@function easing-gradient($type, $dir, $stop, $stops...) {
138 $pos-template: null; 141 $pos-template: null;
139 $stops: functions.list-prepend($stops, $stop); 142 $stops: functions.list-prepend($stops, $stop);
140 143
141 $last-positioned-stop: 1; 144 $last-positioned-stop: 1;
142 $generated-stops: (); 145 $generated-stops: ();
143 146
144 // 147 //
145 // Generate gradient 148 // Generate gradient
146 // 149 //
147 150
148 @for $i from 1 through length($stops) { 151 @for $i from 1 through list.length($stops) {
149 $stop: nth($stops, $i); 152 $stop: list.nth($stops, $i);
150 153
151 @if $i == 1 { 154 @if $i == 1 {
152 @if not easing-gradient-is-color-stop($stop) { 155 @if not easing-gradient-is-color-stop($stop) {
153 @error 'The first color stop argument must be a color stop.'; 156 @error 'The first color stop argument must be a color stop.';
154 } 157 }
155 158
156 @if type-of($stop) == color { 159 @if meta.type-of($stop) == color {
157 // 160 //
158 // The first color stop is unpositioned. The default position for the first 161 // The first color stop is unpositioned. The default position for the first
159 // color stop is 0, which is explicitly added for easier calculations. 162 // color stop is 0, which is explicitly added for easier calculations.
160 // 163 //
161 164
162 $stop: $stop 0; 165 $stop: $stop 0;
163 $stops: set-nth($stops, $i, $stop); 166 $stops: list.set-nth($stops, $i, $stop);
164 } 167 }
165 168
166 $generated-stops: append($generated-stops, functions.str-implode($stop, ' ')); 169 $generated-stops: list.append($generated-stops, functions.str-implode($stop, ' '));
167 } @else if easing-gradient-is-positioned-color-stop($stop) or ($i == length($stops)) { 170 } @else if easing-gradient-is-positioned-color-stop($stop) or ($i == list.length($stops)) {
168 @if not easing-gradient-is-color-stop($stop) { 171 @if not easing-gradient-is-color-stop($stop) {
169 @error 'The last color stop argument must be a color stop.'; 172 @error 'The last color stop argument must be a color stop.';
170 } 173 }
171 174
172 // 175 //
173 // Either the current stops list item is a positioned color stop, or the end of 176 // Either the current stops list item is a positioned color stop, or the end of
174 // the stops list has been reached. 177 // the stops list has been reached.
175 // 178 //
176 179
177 @if (type-of($stop) == color) and ($i == length($stops)) { 180 @if (meta.type-of($stop) == color) and ($i == list.length($stops)) {
178 // 181 //
179 // The current stop is an unpositioned color stop, which means this is the end 182 // The current stop is an unpositioned color stop, which means this is the end
180 // of the stops list. The default position for the last color stop is 100%, which 183 // of the stops list. The default position for the last color stop is 100%, which
181 // is explicitly added for easier calculations. 184 // is explicitly added for easier calculations.
182 // 185 //
183 186
184 $stop: $stop 100%; 187 $stop: $stop 100%;
185 $stops: set-nth($stops, $i, $stop); 188 $stops: list.set-nth($stops, $i, $stop);
186 } 189 }
187 190
188 // 191 //
189 // Now the current color stop is guaranteed to be a positioned color stop. 192 // Now the current color stop is guaranteed to be a positioned color stop.
190 // 193 //
191 194
192 @if $i > $last-positioned-stop + 1 { 195 @if $i > $last-positioned-stop + 1 {
193 // 196 //
194 // There is at least one stops list item (unpositioned color stop or easing function) 197 // There is at least one stops list item (unpositioned color stop or easing function)
195 // between the last positioned color stop and the current stops list item. Interpolate 198 // between the last positioned color stop and the current stops list item. Interpolate
196 // the positions of all stops list items that are color stops. 199 // the positions of all stops list items that are color stops.
197 // 200 //
198 201
199 $interpolated-stops: easing-gradient-interpolate-stop-positions( 202 $interpolated-stops: easing-gradient-interpolate-stop-positions(list.nth($stops, $last-positioned-stop),
200 nth($stops, $last-positioned-stop), 203 functions.list-slice($stops, $last-positioned-stop + 1, $i - 1),
201 functions.list-slice($stops, $last-positioned-stop + 1, $i - 1), 204 $stop);
202 $stop
203 );
204 205
205 $new-stops: join( 206 $new-stops: list.join(functions.list-slice($stops, 1, $last-positioned-stop),
206 functions.list-slice($stops, 1, $last-positioned-stop), 207 $interpolated-stops);
207 $interpolated-stops 208 $new-stops: list.join($new-stops,
208 ); 209 functions.list-slice($stops, $i));
209 $new-stops: join( 210 $stops: $new-stops;
210 $new-stops, 211 }
211 functions.list-slice($stops, $i)
212 );
213 $stops: $new-stops;
214 }
215 212
216 // 213 //
217 // Now all color stops between this one and the last positioned one have 214 // Now all color stops between this one and the last positioned one have
218 // interpolated positions. 215 // interpolated positions.
219 // Next task is to perform an easing transition between all color stops that 216 // Next task is to perform an easing transition between all color stops that
220 // have an easing function specified. The rest can be left alone since the 217 // have an easing function specified. The rest can be left alone since the
221 // browser will automatically apply a linear transition between them. 218 // browser will automatically apply a linear transition between them.
222 // 219 //
223 220
224 $j: $last-positioned-stop + 1; 221 $j: $last-positioned-stop + 1;
225 @while $j <= $i { 222 @while $j <= $i {
226 $easing: null; 223 $easing: null;
227 $prev-stop: nth($stops, $j - 1); 224 $prev-stop: list.nth($stops, $j - 1);
228 $next-stop: nth($stops, $j); 225 $next-stop: list.nth($stops, $j);
229 226
230 @if not easing-gradient-is-color-stop($next-stop) { 227 @if not easing-gradient-is-color-stop($next-stop) {
231 $j: $j + 1; 228 $j: $j + 1;
232 229
233 $easing: $next-stop; 230 $easing: $next-stop;
234 $next-stop: nth($stops, $j); 231 $next-stop: list.nth($stops, $j);
235 232
236 @if not easing-gradient-is-color-stop($next-stop) { 233 @if not easing-gradient-is-color-stop($next-stop) {
237 @error 'There can be at most one interpolation hint between to color stops.'; 234 @error 'There can be at most one interpolation hint between to color stops.';
238 } 235 }
239 } 236 }
240 237
241 @if $easing != null { 238 @if $easing != null {
242 @if type-of($easing) == number { 239 @if meta.type-of($easing) == number {
243 @error 'Midpoint shifts are not supported.'; 240 @error 'Midpoint shifts are not supported.';
244 } 241 }
245 242
246 $easing-func: null; 243 $easing-func: null;
247 $easing-args: (); 244 $easing-args: ();
248 245
249 @if type-of($easing) == list { 246 @if meta.type-of($easing) == list {
250 $easing-args: functions.list-slice($easing, 2); 247 $easing-args: functions.list-slice($easing, 2);
251 $easing: nth($easing, 1); 248 $easing: list.nth($easing, 1);
252 } 249 }
253 250
254 $generated-stops: join( 251 $generated-stops: list.join($generated-stops,
255 $generated-stops, 252 easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args));
256 easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args) 253 } @else {
257 ); 254 $generated-stops: list.append($generated-stops, functions.str-implode($next-stop, ' '));
258 } @else { 255 }
259 $generated-stops: append($generated-stops, functions.str-implode($next-stop, ' '));
260 }
261 256
262 $j: $j + 1; 257 $j: $j + 1;
263 } 258 }
264 259
265 $last-positioned-stop: $i; 260 $last-positioned-stop: $i;
266 } 261 }
267 } 262 }
268 263
269 @if $type == 'linear' { 264 @if $type == 'linear' {
270 @return linear-gradient($dir, unquote(functions.str-implode($generated-stops, ', '))); 265 @return linear-gradient($dir, string.unquote(functions.str-implode($generated-stops, ', ')));
271 } @else if $type == 'radial' { 266 } @else if $type == 'radial' {
272 @return radial-gradient($dir, unquote(functions.str-implode($generated-stops, ', '))); 267 @return radial-gradient($dir, string.unquote(functions.str-implode($generated-stops, ', ')));
273 } @else { 268 } @else {
274 @error 'Invalid gradient type: #{inspect($type)}.'; 269 @error 'Invalid gradient type: #{inspect($type)}.';
275 } 270 }
276} 271}
277 272
278/// 273///
@@ -281,7 +276,7 @@ $easing-gradient-steps: 10 !default;
281/// @see {function} easing-gradient 276/// @see {function} easing-gradient
282/// 277///
283@function easing-linear-gradient($dir, $stop, $stops...) { 278@function easing-linear-gradient($dir, $stop, $stops...) {
284 @return easing-gradient('linear', $dir, $stop, $stops...); 279 @return easing-gradient('linear', $dir, $stop, $stops...);
285} 280}
286 281
287/// 282///
@@ -290,7 +285,7 @@ $easing-gradient-steps: 10 !default;
290/// @see {function} easing-gradient 285/// @see {function} easing-gradient
291/// 286///
292@function easing-radial-gradient($dir, $stop, $stops...) { 287@function easing-radial-gradient($dir, $stop, $stops...) {
293 @return easing-gradient('radial', $dir, $stop, $stops...); 288 @return easing-gradient('radial', $dir, $stop, $stops...);
294} 289}
295 290
296/// 291///
@@ -299,24 +294,24 @@ $easing-gradient-steps: 10 !default;
299/// @access private 294/// @access private
300/// 295///
301@function easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args: ()) { 296@function easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args: ()) {
302 @if $easing == 'steps' { 297 @if $easing == 'steps' {
303 $steps: null; 298 $steps: null;
304 $jump: null; 299 $jump: null;
305 300
306 @if length($easing-args) > 1 { 301 @if list.length($easing-args) > 1 {
307 $steps: nth($easing-args, 1); 302 $steps: list.nth($easing-args, 1);
308 $jump: nth($easing-args, 2); 303 $jump: list.nth($easing-args, 2);
309 } @else { 304 } @else {
310 $steps: nth($easing-args, 1); 305 $steps: list.nth($easing-args, 1);
311 $jump: jump-end; 306 $jump: jump-end;
312 } 307 }
313 308
314 @return easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump); 309 @return easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump);
315 } @else { 310 } @else {
316 $easing-func: get-function($easing, $module: easing); 311 $easing-func: meta.get-function($easing, $module: easing);
317 312
318 @return easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args); 313 @return easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args);
319 } 314 }
320} 315}
321 316
322/// 317///
@@ -325,74 +320,74 @@ $easing-gradient-steps: 10 !default;
325/// @access private 320/// @access private
326/// 321///
327@function easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args: ()) { 322@function easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args: ()) {
328 $prev-stop-color: nth($prev-stop, 1); 323 $prev-stop-color: list.nth($prev-stop, 1);
329 $prev-stop-pos: nth($prev-stop, 2); 324 $prev-stop-pos: list.nth($prev-stop, 2);
330 $next-stop-color: nth($next-stop, 1); 325 $next-stop-color: list.nth($next-stop, 1);
331 $next-stop-pos: nth($next-stop, 2); 326 $next-stop-pos: list.nth($next-stop, 2);
332 327
333 $stops: (); 328 $stops: ();
334 329
335 @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) { 330 @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) {
336 // 331 //
337 // The transition color stop positions can be statically calculated. 332 // The transition color stop positions can be statically calculated.
338 // 333 //
339 334
340 $distance: $next-stop-pos - $prev-stop-pos; 335 $distance: $next-stop-pos - $prev-stop-pos;
341 336
342 @for $i from 1 through $easing-gradient-steps { 337 @for $i from 1 through $easing-gradient-steps {
343 $perc: math.div($i, $easing-gradient-steps); 338 $perc: math.div($i, $easing-gradient-steps);
344 339
345 $color: null; 340 $color: null;
346 $pos: $prev-stop-pos + $perc * $distance; 341 $pos: $prev-stop-pos + $perc * $distance;
347 @if $perc == 1 { 342 @if $perc == 1 {
348 $color: $next-stop-color; 343 $color: $next-stop-color;
349 } @else { 344 } @else {
350 $color: mix($next-stop-color, $prev-stop-color, call($easing-func, append($easing-args, $perc)...) * 100%); 345 $color: color.mix($next-stop-color, $prev-stop-color, meta.call($easing-func, list.append($easing-args, $perc)...) * 100%);
351 } 346 }
352 347
353 $stops: append($stops, $color + ' ' + $pos); 348 $stops: list.append($stops, $color + ' ' + $pos);
354 } 349 }
355 } @else { 350 } @else {
356 // 351 //
357 // The transition color stop positions have to be dynamically calculated with the calc() function. 352 // The transition color stop positions have to be dynamically calculated with the calc() function.
358 // 353 //
359 354
360 @if type-of($prev-stop-pos) != number { 355 @if meta.type-of($prev-stop-pos) != number {
361 // must be calc() 356 // must be calc()
362 @if type-of($prev-stop-pos) != calculation { 357 @if meta.type-of($prev-stop-pos) != calculation {
363 @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; 358 @error 'Invalid color stop position: #{inspect($prev-stop-pos)}';
364 } 359 }
365 360
366 $prev-stop-pos: meta.calc-args($prev-stop-pos); 361 $prev-stop-pos: meta.calc-args($prev-stop-pos);
367 } 362 }
368 363
369 @if type-of($next-stop-pos) != number { 364 @if meta.type-of($next-stop-pos) != number {
370 // must be calc() 365 // must be calc()
371 @if type-of($next-stop-pos) != calculation { 366 @if meta.type-of($next-stop-pos) != calculation {
372 @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; 367 @error 'Invalid color stop position: #{inspect($next-stop-pos)}';
373 } 368 }
374 369
375 $next-stop-pos: meta.calc-args($next-stop-pos); 370 $next-stop-pos: meta.calc-args($next-stop-pos);
376 } 371 }
377 372
378 @for $i from 1 through $easing-gradient-steps { 373 @for $i from 1 through $easing-gradient-steps {
379 $perc: math.div($i, $easing-gradient-steps); 374 $perc: math.div($i, $easing-gradient-steps);
380 375
381 $color: null; 376 $color: null;
382 $pos: null; 377 $pos: null;
383 @if $perc == 1 { 378 @if $perc == 1 {
384 $color: $next-stop-color; 379 $color: $next-stop-color;
385 $pos: calc(#{$next-stop-pos}); 380 $pos: calc(#{$next-stop-pos});
386 } @else { 381 } @else {
387 $color: mix($next-stop-color, $prev-stop-color, call($easing-func, append($easing-args, $perc)...) * 100%); 382 $color: color.mix($next-stop-color, $prev-stop-color, meta.call($easing-func, list.append($easing-args, $perc)...) * 100%);
388 $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); 383 $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc});
389 } 384 }
390 385
391 $stops: append($stops, $color + ' ' + $pos); 386 $stops: list.append($stops, $color + ' ' + $pos);
392 } 387 }
393 } 388 }
394 389
395 @return $stops; 390 @return $stops;
396} 391}
397 392
398/// 393///
@@ -401,110 +396,110 @@ $easing-gradient-steps: 10 !default;
401/// @access private 396/// @access private
402/// 397///
403@function easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump: jump-end) { 398@function easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump: jump-end) {
404 $prev-stop-color: nth($prev-stop, 1); 399 $prev-stop-color: list.nth($prev-stop, 1);
405 $prev-stop-pos: nth($prev-stop, 2); 400 $prev-stop-pos: list.nth($prev-stop, 2);
406 $next-stop-color: nth($next-stop, 1); 401 $next-stop-color: list.nth($next-stop, 1);
407 $next-stop-pos: nth($next-stop, 2); 402 $next-stop-pos: list.nth($next-stop, 2);
408 403
409 $stops: (); 404 $stops: ();
410 405
411 @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) { 406 @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) {
412 // 407 //
413 // The transition color stop positions can be statically calculated. 408 // The transition color stop positions can be statically calculated.
414 // 409 //
415 410
416 $distance: $next-stop-pos - $prev-stop-pos; 411 $distance: $next-stop-pos - $prev-stop-pos;
417 412
418 @for $i from 1 through $steps { 413 @for $i from 1 through $steps {
419 $x1: math.div($i - 1, $steps); 414 $xx1: math.div($i - 1, $steps);
420 $x2: math.div($i, $steps); 415 $xx2: math.div($i, $steps);
421 $y: null; 416 $y: null;
422 417
423 @if $jump == jump-start { 418 @if $jump == jump-start {
424 $y: math.div($i, $steps); 419 $y: math.div($i, $steps);
425 } @else if $jump == jump-end { 420 } @else if $jump == jump-end {
426 $y: math.div($i - 1, $steps); 421 $y: math.div($i - 1, $steps);
427 } @else if $jump == jump-both { 422 } @else if $jump == jump-both {
428 $y: math.div($i, $steps + 1); 423 $y: math.div($i, $steps + 1);
429 } @else if $jump == jump-none { 424 } @else if $jump == jump-none {
430 $y: math.div($i - 1, $steps - 1); 425 $y: math.div($i - 1, $steps - 1);
431 } @else { 426 } @else {
432 @error 'Invalid $jump: #{inspect($jump)}'; 427 @error 'Invalid $jump: #{inspect($jump)}';
433 } 428 }
434 429
435 $color: null; 430 $color: null;
436 $pos1: if($x1 == 0, $prev-stop-pos, $prev-stop-pos + $x1 * $distance); 431 $pos1: if($xx1 == 0, $prev-stop-pos, $prev-stop-pos + $xx1 * $distance);
437 $pos2: if($x2 == 1, $next-stop-pos, $prev-stop-pos + $x2 * $distance); 432 $pos2: if($xx2 == 1, $next-stop-pos, $prev-stop-pos + $xx2 * $distance);
438 433
439 @if $y == 0 { 434 @if $y == 0 {
440 $color: $prev-stop-color; 435 $color: $prev-stop-color;
441 } @else if $y == 1 { 436 } @else if $y == 1 {
442 $color: $next-stop-color; 437 $color: $next-stop-color;
443 } @else { 438 } @else {
444 $color: mix($next-stop-color, $prev-stop-color, $y * 100%); 439 $color: color.mix($next-stop-color, $prev-stop-color, $y * 100%);
445 } 440 }
446 441
447 $stops: append($stops, $color + ' ' + $pos1); 442 $stops: list.append($stops, $color + ' ' + $pos1);
448 $stops: append($stops, $color + ' ' + $pos2); 443 $stops: list.append($stops, $color + ' ' + $pos2);
449 } 444 }
450 } @else { 445 } @else {
451 // 446 //
452 // The transition color stop positions have to be dynamically calculated with the calc() function. 447 // The transition color stop positions have to be dynamically calculated with the calc() function.
453 // 448 //
454 449
455 @if type-of($prev-stop-pos) != number { 450 @if meta.type-of($prev-stop-pos) != number {
456 // must be calc() 451 // must be calc()
457 @if type-of($prev-stop-pos) != calculation { 452 @if meta.type-of($prev-stop-pos) != calculation {
458 @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; 453 @error 'Invalid color stop position: #{inspect($prev-stop-pos)}';
459 } 454 }
460 455
461 $prev-stop-pos: meta.calc-args($prev-stop-pos); 456 $prev-stop-pos: meta.calc-args($prev-stop-pos);
462 } 457 }
463 458
464 @if type-of($next-stop-pos) != number { 459 @if meta.type-of($next-stop-pos) != number {
465 // must be calc() 460 // must be calc()
466 @if type-of($next-stop-pos) != calculation { 461 @if meta.type-of($next-stop-pos) != calculation {
467 @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; 462 @error 'Invalid color stop position: #{inspect($next-stop-pos)}';
468 } 463 }
469 464
470 $next-stop-pos: meta.calc-args($next-stop-pos); 465 $next-stop-pos: meta.calc-args($next-stop-pos);
471 } 466 }
472 467
473 @for $i from 1 through $steps { 468 @for $i from 1 through $steps {
474 $x1: math.div($i - 1, $steps); 469 $xx1: math.div($i - 1, $steps);
475 $x2: math.div($i, $steps); 470 $xx2: math.div($i, $steps);
476 $y: null; 471 $y: null;
477 472
478 @if $jump == jump-start { 473 @if $jump == jump-start {
479 $y: math.div($i, $steps); 474 $y: math.div($i, $steps);
480 } @else if $jump == jump-end { 475 } @else if $jump == jump-end {
481 $y: math.div($i - 1, $steps); 476 $y: math.div($i - 1, $steps);
482 } @else if $jump == jump-both { 477 } @else if $jump == jump-both {
483 $y: math.div($i, $steps + 1); 478 $y: math.div($i, $steps + 1);
484 } @else if $jump == jump-none { 479 } @else if $jump == jump-none {
485 $y: math.div($i - 1, $steps - 1); 480 $y: math.div($i - 1, $steps - 1);
486 } @else { 481 } @else {
487 @error 'Invalid $jump: #{inspect($jump)}'; 482 @error 'Invalid $jump: #{inspect($jump)}';
488 } 483 }
489 484
490 $color: null; 485 $color: null;
491 $pos1: if($x1 == 0, $prev-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$x1})); 486 $pos1: if($xx1 == 0, $prev-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$xx1}));
492 $pos2: if($x2 == 1, $next-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$x2})); 487 $pos2: if($xx2 == 1, $next-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$xx2}));
493 488
494 @if $y == 0 { 489 @if $y == 0 {
495 $color: $prev-stop-color; 490 $color: $prev-stop-color;
496 } @else if $y == 1 { 491 } @else if $y == 1 {
497 $color: $next-stop-color; 492 $color: $next-stop-color;
498 } @else { 493 } @else {
499 $color: mix($next-stop-color, $prev-stop-color, $y * 100%); 494 $color: color.mix($next-stop-color, $prev-stop-color, $y * 100%);
500 } 495 }
501 496
502 $stops: append($stops, $color + ' ' + $pos1); 497 $stops: list.append($stops, $color + ' ' + $pos1);
503 $stops: append($stops, $color + ' ' + $pos2); 498 $stops: list.append($stops, $color + ' ' + $pos2);
504 } 499 }
505 } 500 }
506 501
507 @return $stops; 502 @return $stops;
508} 503}
509 504
510/// 505///
@@ -513,72 +508,72 @@ $easing-gradient-steps: 10 !default;
513/// @access private 508/// @access private
514/// 509///
515@function easing-gradient-interpolate-stop-positions($prev-stop, $stops, $next-stop) { 510@function easing-gradient-interpolate-stop-positions($prev-stop, $stops, $next-stop) {
516 $prev-stop-pos: nth($prev-stop, 2); 511 $prev-stop-pos: list.nth($prev-stop, 2);
517 $next-stop-pos: nth($next-stop, 2); 512 $next-stop-pos: list.nth($next-stop, 2);
518 513
519 $stops-num: 0; 514 $stops-num: 0;
520 @for $i from 1 through length($stops) { 515 @for $i from 1 through list.length($stops) {
521 $stop: nth($stops, $i); 516 $stop: list.nth($stops, $i);
522 @if easing-gradient-is-color-stop($stop) { 517 @if easing-gradient-is-color-stop($stop) {
523 $stops-num: $stops-num + 1; 518 $stops-num: $stops-num + 1;
524 } 519 }
525 } 520 }
526 521
527 $i: 1; 522 $i: 1;
528 $cur-stop-num: 1; 523 $cur-stop-num: 1;
529 524
530 @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) { 525 @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) {
531 // 526 //
532 // The color stop positions can be statically calculated. 527 // The color stop positions can be statically calculated.
533 // 528 //
534 529
535 $distance: $next-stop-pos - $prev-stop-pos; 530 $distance: $next-stop-pos - $prev-stop-pos;
536 531
537 @for $i from 1 through length($stops) { 532 @for $i from 1 through list.length($stops) {
538 $stop: nth($stops, $i); 533 $stop: list.nth($stops, $i);
539 @if easing-gradient-is-color-stop($stop) { 534 @if easing-gradient-is-color-stop($stop) {
540 $pos: $prev-stop-pos + math.div($distance, $stops-num + 1) * $cur-stop-num; 535 $pos: $prev-stop-pos + math.div($distance, $stops-num + 1) * $cur-stop-num;
541 $stops: set-nth($stops, $i, $stop $pos); 536 $stops: list.set-nth($stops, $i, $stop $pos);
542 537
543 $cur-stop-num: $cur-stop-num + 1; 538 $cur-stop-num: $cur-stop-num + 1;
544 } 539 }
545 } 540 }
546 } @else { 541 } @else {
547 // 542 //
548 // The color stop positions have to be dynamically calculated with the calc() function. 543 // The color stop positions have to be dynamically calculated with the calc() function.
549 // 544 //
550 545
551 @if type-of($prev-stop-pos) != number { 546 @if meta.type-of($prev-stop-pos) != number {
552 // must be calc() 547 // must be calc()
553 @if type-of($prev-stop-pos) != calculation { 548 @if meta.type-of($prev-stop-pos) != calculation {
554 @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; 549 @error 'Invalid color stop position: #{inspect($prev-stop-pos)}';
555 } 550 }
556 551
557 $prev-stop-pos: meta.calc-args($prev-stop-pos); 552 $prev-stop-pos: meta.calc-args($prev-stop-pos);
558 } 553 }
559 554
560 @if type-of($next-stop-pos) != number { 555 @if meta.type-of($next-stop-pos) != number {
561 // must be calc() 556 // must be calc()
562 @if type-of($next-stop-pos) != calculation { 557 @if meta.type-of($next-stop-pos) != calculation {
563 @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; 558 @error 'Invalid color stop position: #{inspect($next-stop-pos)}';
564 } 559 }
565 560
566 $next-stop-pos: meta.calc-args($next-stop-pos); 561 $next-stop-pos: meta.calc-args($next-stop-pos);
567 } 562 }
568 563
569 @for $i from 1 through length($stops) { 564 @for $i from 1 through list.length($stops) {
570 $stop: nth($stops, $i); 565 $stop: list.nth($stops, $i);
571 @if easing-gradient-is-color-stop($stop) { 566 @if easing-gradient-is-color-stop($stop) {
572 $perc: math.div($cur-stop-num, $stops-num + 1); 567 $perc: math.div($cur-stop-num, $stops-num + 1);
573 $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); 568 $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc});
574 $stops: set-nth($stops, $i, $stop $pos); 569 $stops: list.set-nth($stops, $i, $stop $pos);
575 570
576 $cur-stop-num: $cur-stop-num + 1; 571 $cur-stop-num: $cur-stop-num + 1;
577 } 572 }
578 } 573 }
579 } 574 }
580 575
581 @return $stops; 576 @return $stops;
582} 577}
583 578
584/// 579///
@@ -587,7 +582,7 @@ $easing-gradient-steps: 10 !default;
587/// @access private 582/// @access private
588/// 583///
589@function easing-gradient-is-color-stop($input) { 584@function easing-gradient-is-color-stop($input) {
590 @return (type-of($input) == color) or easing-gradient-is-positioned-color-stop($input); 585 @return (meta.type-of($input) == color) or easing-gradient-is-positioned-color-stop($input);
591} 586}
592 587
593/// 588///
@@ -596,5 +591,5 @@ $easing-gradient-steps: 10 !default;
596/// @access private 591/// @access private
597/// 592///
598@function easing-gradient-is-positioned-color-stop($input) { 593@function easing-gradient-is-positioned-color-stop($input) {
599 @return (type-of($input) == list) and (type-of(nth($input, 1)) == color); 594 @return (meta.type-of($input) == list) and (meta.type-of(list.nth($input, 1)) == color);
600} 595}
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 @@
8/// @access public 8/// @access public
9//// 9////
10 10
11@use 'sass:list';
12@use 'sass:map';
11@use 'sass:math'; 13@use 'sass:math';
14@use 'sass:meta';
12@use './functions'; 15@use './functions';
13@use './responsive'; 16@use './responsive';
14 17
@@ -26,35 +29,35 @@
26/// @return {number} 29/// @return {number}
27/// 30///
28@function modular-scale($times, $base, $ratio) { 31@function modular-scale($times, $base, $ratio) {
29 @if type-of($base) == number { 32 @if meta.type-of($base) == number {
30 @return $base * math.pow($ratio, $times); 33 @return $base * math.pow($ratio, $times);
31 } 34 }
32 35
33 $main-base: nth($base, 1); 36 $main-base: list.nth($base, 1);
34 $norm-bases: (); 37 $norm-bases: ();
35 38
36 @each $b in functions.list-slice($base, 2) { 39 @each $b in functions.list-slice($base, 2) {
37 @if $b > $main-base { 40 @if $b > $main-base {
38 @while $b > $main-base { 41 @while $b > $main-base {
39 $b: math.div($b, $ratio); 42 $b: math.div($b, $ratio);
40 } 43 }
41 $b: $b * $ratio; 44 $b: $b * $ratio;
42 } @else if $b < $main-base { 45 } @else if $b < $main-base {
43 @while $b < $main-base { 46 @while $b < $main-base {
44 $b: $b * $ratio; 47 $b: $b * $ratio;
45 } 48 }
46 } 49 }
47 50
48 $norm-bases: append($norm-bases, $b); 51 $norm-bases: list.append($norm-bases, $b);
49 } 52 }
50 53
51 $all-bases: append($norm-bases, $main-base); 54 $all-bases: list.append($norm-bases, $main-base);
52 $all-bases: functions.quicksort($all-bases); 55 $all-bases: functions.quicksort($all-bases);
53 56
54 $base-index: $times % length($all-bases) + 1; 57 $base-index: $times % list.length($all-bases) + 1;
55 $exp: math.floor(math.div($times, length($all-bases))); 58 $exp: math.floor(math.div($times, list.length($all-bases)));
56 59
57 @return nth($all-bases, $base-index) * math.pow($ratio, $exp); 60 @return list.nth($all-bases, $base-index) * math.pow($ratio, $exp);
58} 61}
59 62
60/// 63///
@@ -86,15 +89,13 @@
86/// } 89/// }
87/// 90///
88@mixin responsive-modular-scale($props, $times, $responsive-map, $fluid: true) { 91@mixin responsive-modular-scale($props, $times, $responsive-map, $fluid: true) {
89 $new-map: (); 92 $new-map: ();
90 93
91 @each $key, $value in $responsive-map { 94 @each $key, $value in $responsive-map {
92 $new-map: map-merge( 95 $new-map: map.merge($new-map, (
93 $new-map, ( 96 $key: modular-scale($times, $value...)
94 $key: modular-scale($times, $value...) 97 ));
95 ) 98 }
96 );
97 }
98 99
99 @include responsive.property($props, $new-map, $fluid); 100 @include responsive.property($props, $new-map, $fluid);
100} 101}
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 @@
3@use 'sass:meta'; 3@use 'sass:meta';
4 4
5@function is-prop-ref($value) { 5@function is-prop-ref($value) {
6 @if meta.type-of($value) != 'list' { 6 @if meta.type-of($value) != 'list' {
7 @return false; 7 @return false;
8 } 8 }
9 @if list.length($value) != 4 { 9 @if list.length($value) != 4 {
10 @return false; 10 @return false;
11 } 11 }
12 @if list.nth($value, 1) != 'prop-ref' { 12 @if list.nth($value, 1) != 'prop-ref' {
13 @return false; 13 @return false;
14 } 14 }
15 @return true; 15 @return true;
16} 16}
17 17
18@function def($name, $value: (), $metadata: ()) { 18@function def($name, $value: (), $metadata: ()) {
19 @return ('prop-ref' $name $value $metadata); 19 @return ('prop-ref' $name $value $metadata);
20} 20}
21 21
22@function merge($ref, $value) { 22@function merge($ref, $value) {
23 @if not is-prop-ref($ref) { 23 @if not is-prop-ref($ref) {
24 @return $ref; 24 @return $ref;
25 } 25 }
26 26
27 $v: list.nth($ref, 3); 27 $v: list.nth($ref, 3);
28 $ref: list.set-nth($ref, 3, map.deep-merge($v, $value)); 28 $ref: list.set-nth($ref, 3, map.deep-merge($v, $value));
29 @return $ref; 29 @return $ref;
30} 30}
31 31
32@function get-deep($name, $value, $key: null, $keys...) { 32@function get-deep($name, $value, $key: null, $keys...) {
33 @if is-prop-ref($value) { 33 @if is-prop-ref($value) {
34 @return get($value, $key, $keys); 34 @return get($value, $key, $keys);
35 } 35 }
36 @if meta.type-of($value) == 'map' and $key != null { 36 @if meta.type-of($value) == 'map' and $key != null {
37 @if meta.type-of($key) != 'string' { 37 @if meta.type-of($key) != 'string' {
38 @error 'Expected string, got #{$key}'; 38 @error 'Expected string, got #{$key}';
39 } 39 }
40 @return get-deep(#{$name}#{$key}, map.get($value, $key), $keys...); 40 @return get-deep(#{$name}#{$key}, map.get($value, $key), $keys...);
41 } 41 }
42 @return $name $value; 42 @return $name $value;
43} 43}
44 44
45@function map-to-vars($name, $map) { 45@function map-to-vars($name, $map) {
46 @if meta.type-of($map) != 'map' { 46 @if meta.type-of($map) != 'map' {
47 @if meta.type-of($name) != 'string' { 47 @if meta.type-of($name) != 'string' {
48 @error 'Expected variable name, got #{$name} instead'; 48 @error 'Expected variable name, got #{$name} instead';
49 } 49 }
50 @return var($name); 50 @return var($name);
51 } 51 }
52 52
53 $out: (); 53 $out: ();
54 54
55 @each $key, $value in $map { 55 @each $key, $value in $map {
56 $out: map.set($out, $key, map-to-vars(#{$name}#{$key}, $value)); 56 $out: map.set($out, $key, map-to-vars(#{$name}#{$key}, $value));
57 } 57 }
58 58
59 @return $out; 59 @return $out;
60} 60}
61 61
62@function get($ref, $key: null, $keys...) { 62@function get($ref, $key: null, $keys...) {
63 @if not is-prop-ref($ref) { 63 @if not is-prop-ref($ref) {
64 @return $ref; 64 @return $ref;
65 } 65 }
66 66
67 $name: list.nth($ref, 2); 67 $name: list.nth($ref, 2);
68 $value: get(list.nth($ref, 3)); 68 $value: get(list.nth($ref, 3));
69 69
70 @if meta.type-of($value) == 'map' { 70 @if meta.type-of($value) == 'map' {
71 $res: get-deep($name, $value, $key, $keys...); 71 $res: get-deep($name, $value, $key, $keys...);
72 $name: list.nth($res, 1); 72 $name: list.nth($res, 1);
73 $value: list.nth($res, 2); 73 $value: list.nth($res, 2);
74 } @else if meta.type-of($value) == 'list' { 74 } @else if meta.type-of($value) == 'list' {
75 $i: 1; 75 $i: 1;
76 @each $item in $value { 76 @each $item in $value {
77 $value: list.set-nth($value, $i, get($item)); 77 $value: list.set-nth($value, $i, get($item));
78 $i: $i + 1; 78 $i: $i + 1;
79 } 79 }
80 } 80 }
81 81
82 @return map-to-vars($name, $value); 82 @return map-to-vars($name, $value);
83} 83}
84 84
85@mixin materialize-helper($name, $value) { 85@mixin materialize-helper($name, $value) {
86 @if meta.type-of($value) == 'map' { 86 @if meta.type-of($value) == 'map' {
87 @each $key, $value in $value { 87 @each $key, $value in $value {
88 @include materialize-helper(#{$name}#{$key}, $value); 88 @include materialize-helper(#{$name}#{$key}, $value);
89 } 89 }
90 } @else { 90 } @else {
91 #{$name}: #{$value}; 91 #{$name}: #{$value};
92 } 92 }
93} 93}
94 94
95@mixin materialize($ref, $match-meta: ()) { 95@mixin materialize($ref, $match-meta: ()) {
96 @if is-prop-ref($ref) { 96 @if is-prop-ref($ref) {
97 $name: list.nth($ref, 2); 97 $name: list.nth($ref, 2);
98 $value: get(list.nth($ref, 3)); 98 $value: get(list.nth($ref, 3));
99 $meta: get(list.nth($ref, 4)); 99 $meta: get(list.nth($ref, 4));
100 100
101 $match: true; 101 $match: true;
102 @if meta.type-of($match-meta) == 'list' { 102 @if meta.type-of($match-meta) == 'list' {
103 @each $item in $match-meta { 103 @each $item in $match-meta {
104 $match: $match and list.index($meta, $item) != null; 104 $match: $match and list.index($meta, $item) != null;
105 } 105 }
106 } @else if $match-meta == null and list.length($meta) == 0 { 106 } @else if $match-meta == null and list.length($meta) == 0 {
107 $match: true; 107 $match: true;
108 } @else { 108 } @else {
109 $match: list.index($meta, $match-meta) != null; 109 $match: list.index($meta, $match-meta) != null;
110 } 110 }
111 111
112 @if $match { 112 @if $match {
113 @include materialize-helper($name, $value); 113 @include materialize-helper($name, $value);
114 } 114 }
115 } @else if meta.type-of($ref) == 'list' { 115 } @else if meta.type-of($ref) == 'list' {
116 @each $r in $ref { 116 @each $r in $ref {
117 @if is-prop-ref($r) { 117 @if is-prop-ref($r) {
118 $name: list.nth($r, 2); 118 $name: list.nth($r, 2);
119 $value: get(list.nth($r, 3)); 119 $value: get(list.nth($r, 3));
120 $meta: get(list.nth($r, 4)); 120 $meta: get(list.nth($r, 4));
121 121
122 $match: true; 122 $match: true;
123 @if meta.type-of($match-meta) == 'list' { 123 @if meta.type-of($match-meta) == 'list' {
124 @each $item in $match-meta { 124 @each $item in $match-meta {
125 $match: $match and list.index($meta, $item) != null; 125 $match: $match and list.index($meta, $item) != null;
126 } 126 }
127 } @else if $match-meta == null and list.length($meta) == 0 { 127 } @else if $match-meta == null and list.length($meta) == 0 {
128 $match: true; 128 $match: true;
129 } @else { 129 } @else {
130 $match: list.index($meta, $match-meta) != null; 130 $match: list.index($meta, $match-meta) != null;
131 } 131 }
132 132
133 @if $match { 133 @if $match {
134 @include materialize-helper($name, $value); 134 @include materialize-helper($name, $value);
135 } 135 }
136 } 136 }
137 } 137 }
138 } 138 }
139} 139}
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 @@
17/// @access public 17/// @access public
18//// 18////
19 19
20@use 'sass:list';
21@use 'sass:map';
22@use 'sass:math';
23@use 'sass:meta';
24@use 'sass:string';
20@use './functions'; 25@use './functions';
21@use './contexts'; 26@use './contexts';
22 27
@@ -99,15 +104,15 @@ $named-viewports: () !default;
99/// } 104/// }
100/// 105///
101@mixin property($props, $responsive-map, $fluid: true, $vertical: false) { 106@mixin property($props, $responsive-map, $fluid: true, $vertical: false) {
102 @include env(map-keys($responsive-map), $fluid, $vertical) { 107 @include env(map.keys($responsive-map), $fluid, $vertical) {
103 @if type-of($props) == list { 108 @if meta.type-of($props) == list {
104 @each $prop in $props { 109 @each $prop in $props {
105 #{$prop}: set(map-values($responsive-map)); 110 #{$prop}: set(map.values($responsive-map));
106 } 111 }
107 } @else { 112 } @else {
108 #{$props}: set(map-values($responsive-map)); 113 #{$props}: set(map.values($responsive-map));
109 } 114 }
110 } 115 }
111} 116}
112 117
113/// 118///
@@ -150,153 +155,153 @@ $named-viewports: () !default;
150/// } 155/// }
151/// 156///
152@mixin env($viewports, $fluid: true, $vertical: false) { 157@mixin env($viewports, $fluid: true, $vertical: false) {
153 @if length($viewports) <= 1 { 158 @if list.length($viewports) <= 1 {
154 @error '$viewports must contain at least two viewports.'; 159 @error '$viewports must contain at least two viewports.';
155 } 160 }
156 161
157 $new-viewports: (); 162 $new-viewports: ();
158 163
159 @each $viewport in $viewports { 164 @each $viewport in $viewports {
160 @if map-has-key($named-viewports, $viewport) { 165 @if map.has-key($named-viewports, $viewport) {
161 $viewport: map-get($named-viewports, $viewport); 166 $viewport: map.get($named-viewports, $viewport);
162 } 167 }
163 168
164 @if (type-of($viewport) != number) or unitless($viewport) { 169 @if (meta.type-of($viewport) != number) or math.is-unitless($viewport) {
165 @error '$viewports contains invalid viewports.'; 170 @error '$viewports contains invalid viewports.';
166 } 171 }
167 172
168 $new-viewports: append($new-viewports, $viewport); 173 $new-viewports: list.append($new-viewports, $viewport);
169 } 174 }
170 175
171 $viewports: functions.quicksort($new-viewports); 176 $viewports: functions.quicksort($new-viewports);
172 177
173 @if $new-viewports != $viewports { 178 @if $new-viewports != $viewports {
174 @error '$viewports was not sorted in ascending order.'; 179 @error '$viewports was not sorted in ascending order.';
175 } 180 }
176 181
177 @if $fluid { 182 @if $fluid {
178 $first-vp: nth($viewports, 1); 183 $first-vp: list.nth($viewports, 1);
179 $last-vp: nth($viewports, length($viewports)); 184 $last-vp: list.nth($viewports, list.length($viewports));
180 185
181 @include contexts.push($context-id, 'env', ( 186 @include contexts.push($context-id, 'env', (
182 'viewports': $viewports, 187 'viewports': $viewports,
183 'mode': set, 188 'mode': set,
184 'index': 1, 189 'index': 1,
185 'fluid': $fluid, 190 'fluid': $fluid,
186 'vertical': $vertical, 191 'vertical': $vertical,
187 )); 192 ));
188 193
189 @content; 194 @content;
190 195
191 @include contexts.pop($context-id); 196 @include contexts.pop($context-id);
192 197
193 @for $i from 1 to length($viewports) { 198 @for $i from 1 to list.length($viewports) {
194 $prev-vp: nth($viewports, $i); 199 $prev-vp: list.nth($viewports, $i);
195 $next-vp: nth($viewports, $i + 1); 200 $next-vp: list.nth($viewports, $i + 1);
196 201
197 @if not $vertical { 202 @if not $vertical {
198 @media (min-width: $prev-vp) and (max-width: $next-vp) { 203 @media (min-width: $prev-vp) and (max-width: $next-vp) {
199 @include contexts.push($context-id, 'env', ( 204 @include contexts.push($context-id, 'env', (
200 'viewports': $viewports, 205 'viewports': $viewports,
201 'mode': transition, 206 'mode': transition,
202 'index': $i, 207 'index': $i,
203 'fluid': $fluid, 208 'fluid': $fluid,
204 'vertical': $vertical, 209 'vertical': $vertical,
205 )); 210 ));
206 211
207 @content; 212 @content;
208 213
209 @include contexts.pop($context-id); 214 @include contexts.pop($context-id);
210 } 215 }
211 } @else { 216 } @else {
212 @media (min-height: $prev-vp) and (max-height: $next-vp) { 217 @media (min-height: $prev-vp) and (max-height: $next-vp) {
213 @include contexts.push($context-id, 'env', ( 218 @include contexts.push($context-id, 'env', (
214 'viewports': $viewports, 219 'viewports': $viewports,
215 'mode': transition, 220 'mode': transition,
216 'index': $i, 221 'index': $i,
217 'fluid': $fluid, 222 'fluid': $fluid,
218 'vertical': $vertical, 223 'vertical': $vertical,
219 )); 224 ));
220 225
221 @content; 226 @content;
222 227
223 @include contexts.pop($context-id); 228 @include contexts.pop($context-id);
224 } 229 }
225 } 230 }
226 } 231 }
227 232
228 @if not $vertical { 233 @if not $vertical {
229 @media (min-width: $last-vp) { 234 @media (min-width: $last-vp) {
230 @include contexts.push($context-id, 'env', ( 235 @include contexts.push($context-id, 'env', (
231 'viewports': $viewports, 236 'viewports': $viewports,
232 'mode': set, 237 'mode': set,
233 'index': length($viewports), 238 'index': list.length($viewports),
234 'fluid': $fluid, 239 'fluid': $fluid,
235 'vertical': $vertical, 240 'vertical': $vertical,
236 )); 241 ));
237 242
238 @content; 243 @content;
239 244
240 @include contexts.pop($context-id); 245 @include contexts.pop($context-id);
241 } 246 }
242 } @else { 247 } @else {
243 @media (min-height: $last-vp) { 248 @media (min-height: $last-vp) {
244 @include contexts.push($context-id, 'env', ( 249 @include contexts.push($context-id, 'env', (
245 'viewports': $viewports, 250 'viewports': $viewports,
246 'mode': set, 251 'mode': set,
247 'index': length($viewports), 252 'index': list.length($viewports),
248 'fluid': $fluid, 253 'fluid': $fluid,
249 'vertical': $vertical, 254 'vertical': $vertical,
250 )); 255 ));
251 256
252 @content; 257 @content;
253 258
254 @include contexts.pop($context-id); 259 @include contexts.pop($context-id);
255 } 260 }
256 } 261 }
257 } @else { 262 } @else {
258 @include contexts.push($context-id, 'env', ( 263 @include contexts.push($context-id, 'env', (
259 'viewports': $viewports, 264 'viewports': $viewports,
260 'mode': set, 265 'mode': set,
261 'index': 1, 266 'index': 1,
262 'fluid': $fluid, 267 'fluid': $fluid,
263 'vertical': $vertical, 268 'vertical': $vertical,
264 )); 269 ));
265 270
266 @content; 271 @content;
267 272
268 @include contexts.pop($context-id); 273 @include contexts.pop($context-id);
269 274
270 @for $i from 2 through length($viewports) { 275 @for $i from 2 through list.length($viewports) {
271 $vp: nth($viewports, $i); 276 $vp: list.nth($viewports, $i);
272 277
273 @if not $vertical { 278 @if not $vertical {
274 @media (min-width: $vp) { 279 @media (min-width: $vp) {
275 @include contexts.push($context-id, 'env', ( 280 @include contexts.push($context-id, 'env', (
276 'viewports': $viewports, 281 'viewports': $viewports,
277 'mode': set, 282 'mode': set,
278 'index': $i 283 'index': $i
279 )); 284 ));
280 285
281 @content; 286 @content;
282 287
283 @include contexts.pop($context-id); 288 @include contexts.pop($context-id);
284 } 289 }
285 } @else { 290 } @else {
286 @media (min-height: $vp) { 291 @media (min-height: $vp) {
287 @include contexts.push($context-id, 'env', ( 292 @include contexts.push($context-id, 'env', (
288 'viewports': $viewports, 293 'viewports': $viewports,
289 'mode': set, 294 'mode': set,
290 'index': $i 295 'index': $i
291 )); 296 ));
292 297
293 @content; 298 @content;
294 299
295 @include contexts.pop($context-id); 300 @include contexts.pop($context-id);
296 } 301 }
297 } 302 }
298 } 303 }
299 } 304 }
300} 305}
301 306
302/// 307///
@@ -307,29 +312,29 @@ $named-viewports: () !default;
307/// @return {number|string} 312/// @return {number|string}
308/// 313///
309@function set($values, $without-calc: false) { 314@function set($values, $without-calc: false) {
310 $noop: contexts.assert-stack-must-contain($context-id, 'env'); 315 $noop: contexts.assert-stack-must-contain($context-id, 'env');
311 316
312 $data: nth(contexts.get($context-id, 'env'), 2); 317 $data: list.nth(contexts.get($context-id, 'env'), 2);
313 $viewports: map-get($data, 'viewports'); 318 $viewports: map.get($data, 'viewports');
314 $mode: map-get($data, 'mode'); 319 $mode: map.get($data, 'mode');
315 $fluid: map-get($data, 'fluid'); 320 $fluid: map.get($data, 'fluid');
316 $vertical: map-get($data, 'vertical'); 321 $vertical: map.get($data, 'vertical');
317 322
318 @if length($values) != length($viewports) { 323 @if list.length($values) != list.length($viewports) {
319 @error '$values must contain the same number of items as the responsive environment\'s $viewports.'; 324 @error '$values must contain the same number of items as the responsive environment\'s $viewports.';
320 } 325 }
321 326
322 @if $mode == set { 327 @if $mode == set {
323 @return nth($values, map-get($data, 'index')); 328 @return list.nth($values, map.get($data, 'index'));
324 } @else { 329 } @else {
325 $index: map-get($data, 'index'); 330 $index: map.get($data, 'index');
326 $prev-vp: nth($viewports, $index); 331 $prev-vp: list.nth($viewports, $index);
327 $next-vp: nth($viewports, $index + 1); 332 $next-vp: list.nth($viewports, $index + 1);
328 $prev-value: nth($values, $index); 333 $prev-value: list.nth($values, $index);
329 $next-value: nth($values, $index + 1); 334 $next-value: list.nth($values, $index + 1);
330 335
331 @return fluid-calc($prev-value, $next-value, $prev-vp, $next-vp, $vertical, $without-calc); 336 @return fluid-calc($prev-value, $next-value, $prev-vp, $next-vp, $vertical, $without-calc);
332 } 337 }
333} 338}
334 339
335/// 340///
@@ -345,62 +350,62 @@ $named-viewports: () !default;
345/// @access private 350/// @access private
346/// 351///
347@function fluid-calc($min-value, $max-value, $min-viewport, $max-viewport, $vertical: false, $without-calc: false) { 352@function fluid-calc($min-value, $max-value, $min-viewport, $max-viewport, $vertical: false, $without-calc: false) {
348 $value-unit: unit($min-value); 353 $value-unit: math.unit($min-value);
349 $max-value-unit: unit($max-value); 354 $max-value-unit: math.unit($max-value);
350 $viewport-unit: unit($min-viewport); 355 $viewport-unit: math.unit($min-viewport);
351 $max-viewport-unit: unit($max-viewport); 356 $max-viewport-unit: math.unit($max-viewport);
352 357
353 @if $min-value == 0 { 358 @if $min-value == 0 {
354 $value-unit: $max-value-unit; 359 $value-unit: $max-value-unit;
355 } 360 }
356 @if $max-value == 0 { 361 @if $max-value == 0 {
357 $max-value-unit: $value-unit; 362 $max-value-unit: $value-unit;
358 } 363 }
359 @if $min-viewport == 0 { 364 @if $min-viewport == 0 {
360 $viewport-unit: $max-viewport-unit; 365 $viewport-unit: $max-viewport-unit;
361 } 366 }
362 @if $max-viewport == 0 { 367 @if $max-viewport == 0 {
363 $max-viewport-unit: $viewport-unit; 368 $max-viewport-unit: $viewport-unit;
364 } 369 }
365 370
366 @if ($value-unit != $max-value-unit) or ($viewport-unit != $max-viewport-unit) { 371 @if ($value-unit != $max-value-unit) or ($viewport-unit != $max-viewport-unit) {
367 @error 'Units of $min-value and $max-value, $min-viewport and $max-viewport must match.'; 372 @error 'Units of $min-value and $max-value, $min-viewport and $max-viewport must match.';
368 } 373 }
369 374
370 @if ($value-unit == rem) and ($viewport-unit == px) { 375 @if ($value-unit == rem) and ($viewport-unit == px) {
371 $min-viewport: functions.px-to-rem($min-viewport); 376 $min-viewport: functions.px-to-rem($min-viewport);
372 $max-viewport: functions.px-to-rem($max-viewport); 377 $max-viewport: functions.px-to-rem($max-viewport);
373 $viewport-unit: rem; 378 $viewport-unit: rem;
374 } @else if ($value-unit == px) and ($viewport-unit == rem) { 379 } @else if ($value-unit == px) and ($viewport-unit == rem) {
375 $min-value: functions.px-to-rem($min-value); 380 $min-value: functions.px-to-rem($min-value);
376 $max-value: functions.px-to-rem($max-value); 381 $max-value: functions.px-to-rem($max-value);
377 $value-unit: rem; 382 $value-unit: rem;
378 } 383 }
379 384
380 @if $value-unit != $viewport-unit { 385 @if $value-unit != $viewport-unit {
381 @error 'This combination of units is not supported.'; 386 @error 'This combination of units is not supported.';
382 } 387 }
383 388
384 $value-diff: functions.strip-unit($max-value - $min-value); 389 $value-diff: functions.strip-unit($max-value - $min-value);
385 $viewport-diff: functions.strip-unit($max-viewport - $min-viewport); 390 $viewport-diff: functions.strip-unit($max-viewport - $min-viewport);
386 391
387 $calc: ''; 392 $calc: '';
388 393
389 @if $min-value != 0 { 394 @if $min-value != 0 {
390 $calc: '#{$min-value} + '; 395 $calc: '#{$min-value} + ';
391 } 396 }
392 397
393 @if not $vertical { 398 @if not $vertical {
394 $calc: unquote('#{$calc}#{$value-diff} * (100vw - #{$min-viewport}) / #{$viewport-diff}'); 399 $calc: string.unquote('#{$calc}#{$value-diff} * (100vw - #{$min-viewport}) / #{$viewport-diff}');
395 } @else { 400 } @else {
396 $calc: unquote('#{$calc}#{$value-diff} * (100vh - #{$min-viewport}) / #{$viewport-diff}'); 401 $calc: string.unquote('#{$calc}#{$value-diff} * (100vh - #{$min-viewport}) / #{$viewport-diff}');
397 } 402 }
398 403
399 @if $without-calc { 404 @if $without-calc {
400 @return $calc; 405 @return $calc;
401 } @else { 406 } @else {
402 @return calc(#{$calc}); 407 @return calc(#{$calc});
403 } 408 }
404} 409}
405 410
406@include contexts.create($context-id); 411@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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:map';
9@use 'sass:meta';
10@use 'sass:selector';
7@use './validators'; 11@use './validators';
8@use './vars'; 12@use './vars';
9@use './functions' as bemfunctions; 13@use './functions' as bemfunctions;
@@ -37,34 +41,34 @@
37/// } 41/// }
38/// 42///
39@mixin block($name, $type: null) { 43@mixin block($name, $type: null) {
40 $result: block($name, $type); 44 $result: block($name, $type);
41 $selector: nth($result, 1); 45 $selector: list.nth($result, 1);
42 $context: nth($result, 2); 46 $context: list.nth($result, 2);
43 47
44 @include validators.validate( 48 @include validators.validate(
45 'block', 49 'block',
46 (name: $name, type: $type), 50 (name: $name, type: $type),
47 $selector, 51 $selector,
48 $context 52 $context
49 ); 53 );
50 54
51 @if $type != null { 55 @if $type != null {
52 vars.$blocks: append(vars.$blocks, $name + '_' + $type); 56 vars.$blocks: list.append(vars.$blocks, $name + '_' + $type);
53 } @else { 57 } @else {
54 vars.$blocks: append(vars.$blocks, $name); 58 vars.$blocks: list.append(vars.$blocks, $name);
55 } 59 }
56 60
57 @include contexts.push(vars.$context-id, $context...); 61 @include contexts.push(vars.$context-id, $context...);
58 @at-root #{$selector} { 62 @at-root #{$selector} {
59 @if $type != null { 63 @if $type != null {
60 @layer #{$type} { 64 @layer #{$type} {
61 @content; 65 @content;
62 } 66 }
63 } @else { 67 } @else {
64 @content; 68 @content;
65 } 69 }
66 } 70 }
67 @include contexts.pop(vars.$context-id); 71 @include contexts.pop(vars.$context-id);
68} 72}
69 73
70/// 74///
@@ -75,47 +79,47 @@
75/// @see {mixin} block 79/// @see {mixin} block
76/// 80///
77@function block($name, $type: null) { 81@function block($name, $type: null) {
78 // 82 //
79 // Possible outcomes: 83 // Possible outcomes:
80 // - ({b,e,m,s}) block 84 // - ({b,e,m,s}) block
81 // 85 //
82 86
83 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 87 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
84 88
85 $selector: null; 89 $selector: null;
86 $base-selector: null; 90 $base-selector: null;
87 91
88 @if $type != null { 92 @if $type != null {
89 $namespace: map-get(vars.$namespaces, $type); 93 $namespace: map.get(vars.$namespaces, $type);
90 94
91 @if not $namespace { 95 @if not $namespace {
92 @error '"#{$type}" is not a valid type.'; 96 @error '"#{$type}" is not a valid type.';
93 } 97 }
94 98
95 $base-selector: selector-parse('.' + $namespace + '-' + $name); 99 $base-selector: selector.parse('.' + $namespace + '-' + $name);
96 100
97 @if $type != 'theme' or & { 101 @if $type != 'theme' or & {
98 $selector: $base-selector; 102 $selector: $base-selector;
99 } @else if not & { 103 } @else if not & {
100 $selector: bemfunctions.theme-selector($name); 104 $selector: bemfunctions.theme-selector($name);
101 } 105 }
102 } @else { 106 } @else {
103 $base-selector: selector-parse('.' + $name); 107 $base-selector: selector.parse('.' + $name);
104 $selector: $base-selector; 108 $selector: $base-selector;
105 } 109 }
106 110
107 @if & { 111 @if & {
108 $selector: selector-nest(&, $selector); 112 $selector: selector.nest(&, $selector);
109 } 113 }
110 114
111 $context: 'block', ( 115 $context: 'block', (
112 'name': $name, 116 'name': $name,
113 'type': $type, 117 'type': $type,
114 'selector': $selector, 118 'selector': $selector,
115 'base-selector': $base-selector 119 'base-selector': $base-selector
116 ); 120 );
117 121
118 @return $selector $context; 122 @return $selector $context;
119} 123}
120 124
121/// 125///
@@ -126,9 +130,9 @@
126/// @content 130/// @content
127/// 131///
128@mixin object($name) { 132@mixin object($name) {
129 @include block($name, 'object') { 133 @include block($name, 'object') {
130 @content; 134 @content;
131 } 135 }
132} 136}
133 137
134/// 138///
@@ -139,7 +143,7 @@
139/// @see {mixin} object 143/// @see {mixin} object
140/// 144///
141@function object($name) { 145@function object($name) {
142 @return block($name, 'object'); 146 @return block($name, 'object');
143} 147}
144 148
145/// 149///
@@ -150,9 +154,9 @@
150/// @content 154/// @content
151/// 155///
152@mixin component($name) { 156@mixin component($name) {
153 @include block($name, 'component') { 157 @include block($name, 'component') {
154 @content; 158 @content;
155 } 159 }
156} 160}
157 161
158/// 162///
@@ -163,7 +167,7 @@
163/// @see {mixin} component 167/// @see {mixin} component
164/// 168///
165@function component($name) { 169@function component($name) {
166 @return block($name, 'component'); 170 @return block($name, 'component');
167} 171}
168 172
169/// 173///
@@ -174,9 +178,9 @@
174/// @content 178/// @content
175/// 179///
176@mixin layout($name) { 180@mixin layout($name) {
177 @include block($name, 'layout') { 181 @include block($name, 'layout') {
178 @content; 182 @content;
179 } 183 }
180} 184}
181 185
182/// 186///
@@ -187,7 +191,7 @@
187/// @see {mixin} layout 191/// @see {mixin} layout
188/// 192///
189@function layout($name) { 193@function layout($name) {
190 @return block($name, 'layout'); 194 @return block($name, 'layout');
191} 195}
192 196
193/// 197///
@@ -198,9 +202,9 @@
198/// @content 202/// @content
199/// 203///
200@mixin utility($name) { 204@mixin utility($name) {
201 @include block($name, 'utility') { 205 @include block($name, 'utility') {
202 @content; 206 @content;
203 } 207 }
204} 208}
205 209
206/// 210///
@@ -211,7 +215,7 @@
211/// @see {mixin} utility 215/// @see {mixin} utility
212/// 216///
213@function utility($name) { 217@function utility($name) {
214 @return block($name, 'utility'); 218 @return block($name, 'utility');
215} 219}
216 220
217/// 221///
@@ -222,9 +226,9 @@
222/// @content 226/// @content
223/// 227///
224@mixin scope($name) { 228@mixin scope($name) {
225 @include block($name, 'scope') { 229 @include block($name, 'scope') {
226 @content; 230 @content;
227 } 231 }
228} 232}
229 233
230/// 234///
@@ -235,7 +239,7 @@
235/// @see {mixin} scope 239/// @see {mixin} scope
236/// 240///
237@function scope($name) { 241@function scope($name) {
238 @return block($name, 'scope'); 242 @return block($name, 'scope');
239} 243}
240 244
241/// 245///
@@ -246,9 +250,9 @@
246/// @content 250/// @content
247/// 251///
248@mixin theme($name) { 252@mixin theme($name) {
249 @include block($name, 'theme') { 253 @include block($name, 'theme') {
250 @content; 254 @content;
251 } 255 }
252} 256}
253 257
254/// 258///
@@ -259,7 +263,7 @@
259/// @see {mixin} theme 263/// @see {mixin} theme
260/// 264///
261@function theme($name) { 265@function theme($name) {
262 @return block($name, 'theme'); 266 @return block($name, 'theme');
263} 267}
264 268
265/// 269///
@@ -270,9 +274,9 @@
270/// @content 274/// @content
271/// 275///
272@mixin js($name) { 276@mixin js($name) {
273 @include block($name, 'js') { 277 @include block($name, 'js') {
274 @content; 278 @content;
275 } 279 }
276} 280}
277 281
278/// 282///
@@ -283,7 +287,7 @@
283/// @see {mixin} js 287/// @see {mixin} js
284/// 288///
285@function js($name) { 289@function js($name) {
286 @return block($name, 'js'); 290 @return block($name, 'js');
287} 291}
288 292
289/// 293///
@@ -294,9 +298,9 @@
294/// @content 298/// @content
295/// 299///
296@mixin qa($name) { 300@mixin qa($name) {
297 @include block($name, 'qa') { 301 @include block($name, 'qa') {
298 @content; 302 @content;
299 } 303 }
300} 304}
301 305
302/// 306///
@@ -307,7 +311,7 @@
307/// @see {mixin} qa 311/// @see {mixin} qa
308/// 312///
309@function qa($name) { 313@function qa($name) {
310 @return block($name, 'qa'); 314 @return block($name, 'qa');
311} 315}
312 316
313/// 317///
@@ -318,9 +322,9 @@
318/// @content 322/// @content
319/// 323///
320@mixin hack($name) { 324@mixin hack($name) {
321 @include block($name, 'hack') { 325 @include block($name, 'hack') {
322 @content; 326 @content;
323 } 327 }
324} 328}
325 329
326/// 330///
@@ -331,7 +335,7 @@
331/// @see {mixin} hack 335/// @see {mixin} hack
332/// 336///
333@function hack($name) { 337@function hack($name) {
334 @return block($name, 'hack'); 338 @return block($name, 'hack');
335} 339}
336 340
337/// 341///
@@ -383,22 +387,22 @@
383/// // Compilation will fail because c-someBlock is defined after c-anotherBlock__elem 387/// // Compilation will fail because c-someBlock is defined after c-anotherBlock__elem
384/// 388///
385@mixin composed-of($block, $blocks...) { 389@mixin composed-of($block, $blocks...) {
386 @each $block in functions.list-prepend($blocks, $block) { 390 @each $block in functions.list-prepend($blocks, $block) {
387 @if type-of($block) == string { 391 @if meta.type-of($block) == string {
388 @if not index(vars.$blocks, $block) { 392 @if not list.index(vars.$blocks, $block) {
389 @error 'Block "#{$block}" does not exist.'; 393 @error 'Block "#{$block}" does not exist.';
390 } 394 }
391 } @else { 395 } @else {
392 $name: nth($block, 1); 396 $name: list.nth($block, 1);
393 $type: nth($block, 2); 397 $type: list.nth($block, 2);
394 398
395 @if not map-get(vars.$namespaces, $type) { 399 @if not map.get(vars.$namespaces, $type) {
396 @error '"#{$type}" is not a valid type.'; 400 @error '"#{$type}" is not a valid type.';
397 } 401 }
398 402
399 @if not index(vars.$blocks, $name + '_' + $type) { 403 @if not list.index(vars.$blocks, $name + '_' + $type) {
400 @error 'Block "#{$name}" does not exist.'; 404 @error 'Block "#{$name}" does not exist.';
401 } 405 }
402 } 406 }
403 } 407 }
404} 408}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:map';
7@use './vars'; 8@use './vars';
8 9
9@if vars.$debug { 10@if vars.$debug {
10 @each $type, $color in vars.$debug-colors { 11 @each $type, $color in vars.$debug-colors {
11 $namespace: map-get(vars.$namespaces, $type); 12 $namespace: map.get(vars.$namespaces, $type);
12 13
13 [class^='#{$namespace}-'], 14 [class^='#{$namespace}-'],
14 [class*=' #{$namespace}-'] { 15 [class*=' #{$namespace}-'] {
15 outline: 5px solid $color; 16 outline: 5px solid $color;
16 } 17 }
17 } 18 }
18} 19}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:map';
9@use 'sass:meta';
10@use 'sass:selector';
11@use 'sass:string';
7@use './validators'; 12@use './validators';
8@use './vars'; 13@use './vars';
9@use '../functions'; 14@use '../functions';
@@ -92,22 +97,22 @@
92/// } 97/// }
93/// 98///
94@mixin elem($name, $names...) { 99@mixin elem($name, $names...) {
95 $result: elem($name, $names...); 100 $result: elem($name, $names...);
96 $selector: nth($result, 1); 101 $selector: list.nth($result, 1);
97 $context: nth($result, 2); 102 $context: list.nth($result, 2);
98 103
99 @include validators.validate( 104 @include validators.validate(
100 'element', 105 'element',
101 (name: $name, names: $names), 106 (name: $name, names: $names),
102 $selector, 107 $selector,
103 $context 108 $context
104 ); 109 );
105 110
106 @include contexts.push(vars.$context-id, $context...); 111 @include contexts.push(vars.$context-id, $context...);
107 @at-root #{$selector} { 112 @at-root #{$selector} {
108 @content; 113 @content;
109 } 114 }
110 @include contexts.pop(vars.$context-id); 115 @include contexts.pop(vars.$context-id);
111} 116}
112 117
113/// 118///
@@ -118,99 +123,93 @@
118/// @see {mixin} element 123/// @see {mixin} element
119/// 124///
120@function elem($name, $names...) { 125@function elem($name, $names...) {
121 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 126 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
122 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); 127 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block');
123 128
124 $parent-context: contexts.get(vars.$context-id, 'block' 'element'); 129 $parent-context: contexts.get(vars.$context-id, 'block' 'element');
125 130
126 $selector: (); 131 $selector: ();
127 $parts-data: (); 132 $parts-data: ();
128 133
129 @if nth($parent-context, 1) == 'element' { 134 @if list.nth($parent-context, 1) == 'element' {
130 @if vars.$element-nesting-policy == 'disallow' { 135 @if vars.$element-nesting-policy == 'disallow' {
131 @error 'Element nesting is forbidden.'; 136 @error 'Element nesting is forbidden.';
132 } 137 }
133 138
134 @if vars.$element-nesting-policy == 'append' { 139 @if vars.$element-nesting-policy == 'append' {
135 $element-selector: map-get(nth($parent-context, 2), 'selector'); 140 $element-selector: map.get(list.nth($parent-context, 2), 'selector');
136 141
137 @if not functions.selector-suffix-match(&, $element-selector) { 142 @if not functions.selector-suffix-match(&, $element-selector) {
138 @error 'A nested element must be an immediate children of the parent element.'; 143 @error 'A nested element must be an immediate children of the parent element.';
139 } 144 }
140 145
141 // 146 //
142 // Possible outcomes: 147 // Possible outcomes:
143 // - {e}__element 148 // - {e}__element
144 // - [manual selector] {e}__element 149 // - [manual selector] {e}__element
145 // 150 //
146 151
147 @each $name in join($name, $names) { 152 @each $name in list.join($name, $names) {
148 $sel: selector-append(&, vars.$element-separator + $name); 153 $sel: selector.append(&, vars.$element-separator + $name);
149 $selector: join($selector, $sel, comma); 154 $selector: list.join($selector, $sel, comma);
150 $parts-data: append( 155 $parts-data: list.append($parts-data, (
151 $parts-data, ( 156 'name': $name,
152 'name': $name, 157 'selector': $sel
153 'selector': $sel 158 ));
154 ) 159 }
155 ); 160 }
156 }
157 }
158 161
159 $parent-context: contexts.get(vars.$context-id, 'block'); 162 $parent-context: contexts.get(vars.$context-id, 'block');
160 } 163 }
161 164
162 @if length($selector) == 0 { 165 @if list.length($selector) == 0 {
163 $parent-selector: map-get(nth($parent-context, 2), 'selector'); 166 $parent-selector: map.get(list.nth($parent-context, 2), 'selector');
164 167
165 @if functions.selector-suffix-match(&, $parent-selector) { 168 @if functions.selector-suffix-match(&, $parent-selector) {
166 // 169 //
167 // Possible outcomes: 170 // Possible outcomes:
168 // - {b}__element 171 // - {b}__element
169 // - [manual selector] {b}__element 172 // - [manual selector] {b}__element
170 // 173 //
171 174
172 @each $name in join($name, $names) { 175 @each $name in list.join($name, $names) {
173 $sel: selector-append(&, vars.$element-separator + $name); 176 $sel: selector.append(&, vars.$element-separator + $name);
174 $selector: join($selector, $sel, comma); 177 $selector: list.join($selector, $sel, comma);
175 $parts-data: append( 178 $parts-data: list.append($parts-data, (
176 $parts-data, ( 179 'name': $name,
177 'name': $name, 180 'selector': $sel
178 'selector': $sel 181 ));
179 ) 182 }
180 ); 183 } @else {
181 } 184 //
182 } @else { 185 // Possible outcomes:
183 // 186 // - {b} [manual selector] {b}__element
184 // Possible outcomes: 187 // - {e,m,s} ([manual selector]) {b}__element
185 // - {b} [manual selector] {b}__element 188 //
186 // - {e,m,s} ([manual selector]) {b}__element
187 //
188 189
189 @if nth($parent-context, 1) != 'block' { 190 @if list.nth($parent-context, 1) != 'block' {
190 $parent-context: contexts.get(vars.$context-id, 'block'); 191 $parent-context: contexts.get(vars.$context-id, 'block');
191 } 192 }
192 193
193 $block-base-selector: map-get(nth($parent-context, 2), 'base-selector'); 194 $block-base-selector: map.get(list.nth($parent-context, 2), 'base-selector');
194 195
195 @each $name in join($name, $names) { 196 @each $name in list.join($name, $names) {
196 $sel: selector-nest(&, selector-append($block-base-selector, vars.$element-separator + $name)); 197 $sel: selector.nest(&, selector.append($block-base-selector, vars.$element-separator + $name));
197 $selector: join($selector, $sel, comma); 198 $selector: list.join($selector, $sel, comma);
198 $parts-data: append( 199 $parts-data: list.append($parts-data, (
199 $parts-data, ( 200 'name': $name,
200 'name': $name, 201 'selector': $sel
201 'selector': $sel 202 ));
202 ) 203 }
203 ); 204 }
204 } 205 }
205 }
206 }
207 206
208 $context: 'element', ( 207 $context: 'element', (
209 'parts': $parts-data, 208 'parts': $parts-data,
210 'selector': $selector 209 'selector': $selector
211 ); 210 );
212 211
213 @return $selector $context; 212 @return $selector $context;
214} 213}
215 214
216/// 215///
@@ -291,22 +290,22 @@
291/// } 290/// }
292/// 291///
293@mixin related-elem($sign, $name, $names...) { 292@mixin related-elem($sign, $name, $names...) {
294 $result: related-elem($sign, $name, $names...); 293 $result: related-elem($sign, $name, $names...);
295 $selector: nth($result, 1); 294 $selector: list.nth($result, 1);
296 $context: nth($result, 2); 295 $context: list.nth($result, 2);
297 296
298 @include validators.validate( 297 @include validators.validate(
299 'related-element', 298 'related-element',
300 (sign: $sign, name: $name, names: $names), 299 (sign: $sign, name: $name, names: $names),
301 $selector, 300 $selector,
302 $context 301 $context
303 ); 302 );
304 303
305 @include contexts.push(vars.$context-id, $context...); 304 @include contexts.push(vars.$context-id, $context...);
306 @at-root #{$selector} { 305 @at-root #{$selector} {
307 @content; 306 @content;
308 } 307 }
309 @include contexts.pop(vars.$context-id); 308 @include contexts.pop(vars.$context-id);
310} 309}
311 310
312/// 311///
@@ -318,44 +317,42 @@
318/// @see {mixin} related-element 317/// @see {mixin} related-element
319/// 318///
320@function related-elem($sign, $name, $names...) { 319@function related-elem($sign, $name, $names...) {
321 // 320 //
322 // Generating this selector is simple: Take the latest block context, use it 321 // Generating this selector is simple: Take the latest block context, use it
323 // to generate the element part, and insert it at the end of the current selector. 322 // to generate the element part, and insert it at the end of the current selector.
324 // Possible outcomes: 323 // Possible outcomes:
325 // - {e} ({m,s}) ([manual selector]) + {e} 324 // - {e} ({m,s}) ([manual selector]) + {e}
326 // - {e} ({m,s}) ([manual selector]) ~ {e} 325 // - {e} ({m,s}) ([manual selector]) ~ {e}
327 // 326 //
328 327
329 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 328 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
330 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); 329 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element');
331 330
332 @if $sign != '+' and $sign != '~' { 331 @if $sign != '+' and $sign != '~' {
333 @error 'Invalid relationship sign #{inspect($sign)}.'; 332 @error 'Invalid relationship sign #{inspect($sign)}.';
334 } 333 }
335 334
336 $block-context: contexts.get(vars.$context-id, 'block'); 335 $block-context: contexts.get(vars.$context-id, 'block');
337 $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); 336 $block-base-selector: map.get(list.nth($block-context, 2), 'base-selector');
338 337
339 $selector: (); 338 $selector: ();
340 $parts-data: (); 339 $parts-data: ();
341 340
342 @each $name in join($name, $names) { 341 @each $name in list.join($name, $names) {
343 $sel: selector-nest(&, $sign, selector-append($block-base-selector, vars.$element-separator + $name)); 342 $sel: selector.nest(&, $sign, selector.append($block-base-selector, vars.$element-separator + $name));
344 $selector: join($selector, $sel, comma); 343 $selector: list.join($selector, $sel, comma);
345 $parts-data: append( 344 $parts-data: list.append($parts-data, (
346 $parts-data, ( 345 'name': $name,
347 'name': $name, 346 'selector': $sel
348 'selector': $sel 347 ));
349 ) 348 }
350 );
351 }
352 349
353 $context: 'element', ( 350 $context: 'element', (
354 'parts': $parts-data, 351 'parts': $parts-data,
355 'selector': $selector 352 'selector': $selector
356 ); 353 );
357 354
358 @return $selector $context; 355 @return $selector $context;
359} 356}
360 357
361/// 358///
@@ -369,9 +366,9 @@
369/// @content 366/// @content
370/// 367///
371@mixin sibling-elem($name, $names...) { 368@mixin sibling-elem($name, $names...) {
372 @include related-elem('~', $name, $names...) { 369 @include related-elem('~', $name, $names...) {
373 @content; 370 @content;
374 } 371 }
375} 372}
376 373
377/// 374///
@@ -383,7 +380,7 @@
383/// @see {mixin} sibling-element 380/// @see {mixin} sibling-element
384/// 381///
385@function sibling-elem($name, $names...) { 382@function sibling-elem($name, $names...) {
386 @return related-elem('~', $name, $names...); 383 @return related-elem('~', $name, $names...);
387} 384}
388 385
389/// 386///
@@ -397,9 +394,9 @@
397/// @content 394/// @content
398/// 395///
399@mixin next-elem($name, $names...) { 396@mixin next-elem($name, $names...) {
400 @include related-elem('+', $name, $names...) { 397 @include related-elem('+', $name, $names...) {
401 @content; 398 @content;
402 } 399 }
403} 400}
404 401
405/// 402///
@@ -411,7 +408,7 @@
411/// @see {mixin} next-element 408/// @see {mixin} next-element
412/// 409///
413@function next-elem($name, $names...) { 410@function next-elem($name, $names...) {
414 @return related-elem('+', $name, $names...); 411 @return related-elem('+', $name, $names...);
415} 412}
416 413
417/// 414///
@@ -467,22 +464,22 @@
467/// } 464/// }
468/// 465///
469@mixin related-twin-elem($sign) { 466@mixin related-twin-elem($sign) {
470 $result: related-twin-elem($sign); 467 $result: related-twin-elem($sign);
471 $selector: nth($result, 1); 468 $selector: list.nth($result, 1);
472 $context: nth($result, 2); 469 $context: list.nth($result, 2);
473 470
474 @include validators.validate( 471 @include validators.validate(
475 'next-twin-elem', 472 'next-twin-elem',
476 (), 473 (),
477 $selector, 474 $selector,
478 $context 475 $context
479 ); 476 );
480 477
481 @include contexts.push(vars.$context-id, $context...); 478 @include contexts.push(vars.$context-id, $context...);
482 @at-root #{$selector} { 479 @at-root #{$selector} {
483 @content; 480 @content;
484 } 481 }
485 @include contexts.pop(vars.$context-id); 482 @include contexts.pop(vars.$context-id);
486} 483}
487 484
488/// 485///
@@ -494,96 +491,94 @@
494/// @see {mixin} next-twin-elem 491/// @see {mixin} next-twin-elem
495/// 492///
496@function related-twin-elem($sign) { 493@function related-twin-elem($sign) {
497 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 494 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
498 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); 495 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element');
499 496
500 $element-context: contexts.get(vars.$context-id, 'element'); 497 $element-context: contexts.get(vars.$context-id, 'element');
501 $element-selector: map-get(nth($element-context, 2), 'selector'); 498 $element-selector: map.get(list.nth($element-context, 2), 'selector');
502 499
503 $block-context: contexts.get(vars.$context-id, 'block'); 500 $block-context: contexts.get(vars.$context-id, 'block');
504 $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); 501 $block-base-selector: map.get(list.nth($block-context, 2), 'base-selector');
505 502
506 $selector: (); 503 $selector: ();
507 $parts-data: (); 504 $parts-data: ();
508 505
509 // 506 //
510 // To determine the twin for each element, iterate the sub-selectors from the current selector 507 // To determine the twin for each element, iterate the sub-selectors from the current selector
511 // and check if it contains the currently inspected element. This has to be done with string 508 // and check if it contains the currently inspected element. This has to be done with string
512 // comparison since none of Sass selector functions is of use here. 509 // comparison since none of Sass selector functions is of use here.
513 // Finally, the current twin will be appended to the extracted sub-selector as a successor 510 // Finally, the current twin will be appended to the extracted sub-selector as a successor
514 // element. 511 // element.
515 // 512 //
516 @each $part-data in map-get(nth($element-context, 2), 'parts') { 513 @each $part-data in map.get(list.nth($element-context, 2), 'parts') {
517 $part-selector: map-get($part-data, 'selector'); 514 $part-selector: map.get($part-data, 'selector');
518 $part-name: map-get($part-data, 'name'); 515 $part-name: map.get($part-data, 'name');
519 516
520 $sel: (); 517 $sel: ();
521 @if functions.selector-suffix-match(&, $element-selector) { 518 @if functions.selector-suffix-match(&, $element-selector) {
522 // 519 //
523 // This mixin is included in the selector the last element mixin created. 520 // This mixin is included in the selector the last element mixin created.
524 // Possible outcomes: 521 // Possible outcomes:
525 // - {e} + {e} 522 // - {e} + {e}
526 // - [manual selector] {e} + {e} 523 // - [manual selector] {e} + {e}
527 // 524 //
528 525
529 @each $s in & { 526 @each $s in & {
530 @each $ps in $part-selector { 527 @each $ps in $part-selector {
531 @if nth($s, -1) == nth($ps, -1) { 528 @if list.nth($s, -1) == list.nth($ps, -1) {
532 $sel-ent: selector-nest($s, $sign, selector-append($block-base-selector, vars.$element-separator + $part-name)); 529 $sel-ent: selector.nest($s, $sign, selector.append($block-base-selector, vars.$element-separator + $part-name));
533 $sel: join($sel, $sel-ent, comma); 530 $sel: list.join($sel, $sel-ent, comma);
534 } 531 }
535 } 532 }
536 } 533 }
537 } @else { 534 } @else {
538 // 535 //
539 // This mixin is NOT included in the selector the last element mixin created. 536 // This mixin is NOT included in the selector the last element mixin created.
540 // Possible outcomes: 537 // Possible outcomes:
541 // - {e} {m,s} + {e} 538 // - {e} {m,s} + {e}
542 // - {e} [manual selector] + {e} 539 // - {e} [manual selector] + {e}
543 // - {e} {m,s} [manual selector] + {e} 540 // - {e} {m,s} [manual selector] + {e}
544 // 541 //
545 542
546 @each $s in & { 543 @each $s in & {
547 @each $ps in $part-selector { 544 @each $ps in $part-selector {
548 @if str-index(inspect($s), inspect($ps)) { 545 @if string.index(meta.inspect($s), meta.inspect($ps)) {
549 $char-index: str-length(inspect($ps)) + 1; 546 $char-index: string.length(meta.inspect($ps)) + 1;
550 $match: index(' ' ':' ',', str-slice(inspect($s), $char-index, $char-index)) != null; 547 $match: list.index(' ' ':' ',', string.slice(meta.inspect($s), $char-index, $char-index)) != null;
551 548
552 @if not $match { 549 @if not $match {
553 @each $separator in vars.$element-separator vars.$modifier-separator vars.$suffix-separator { 550 @each $separator in vars.$element-separator vars.$modifier-separator vars.$suffix-separator {
554 @if str-slice(inspect($s), $char-index, $char-index + str-length($separator) - 1) == $separator { 551 @if string.slice(meta.inspect($s), $char-index, $char-index + string.length($separator) - 1) == $separator {
555 $match: true; 552 $match: true;
556 } 553 }
557 } 554 }
558 } 555 }
559 556
560 @if $match { 557 @if $match {
561 $sel-ent: selector-nest($s, '+', selector-append($block-base-selector, vars.$element-separator + $part-name)); 558 $sel-ent: selector.nest($s, '+', selector.append($block-base-selector, vars.$element-separator + $part-name));
562 $sel: join($sel, $sel-ent, comma); 559 $sel: list.join($sel, $sel-ent, comma);
563 } 560 }
564 } 561 }
565 } 562 }
566 } 563 }
567 } 564 }
568 @if length($sel) != length($part-selector) { 565 @if list.length($sel) != list.length($part-selector) {
569 @error 'Could not generate twin element selector.'; 566 @error 'Could not generate twin element selector.';
570 } 567 }
571 568
572 $selector: join($selector, $sel, comma); 569 $selector: list.join($selector, $sel, comma);
573 $parts-data: append( 570 $parts-data: list.append($parts-data, (
574 $parts-data, ( 571 'name': $part-name,
575 'name': $part-name, 572 'selector': $sel
576 'selector': $sel 573 ));
577 ) 574 }
578 );
579 }
580 575
581 $context: 'element', ( 576 $context: 'element', (
582 'parts': $parts-data, 577 'parts': $parts-data,
583 'selector': $selector 578 'selector': $selector
584 ); 579 );
585 580
586 @return $selector $context; 581 @return $selector $context;
587} 582}
588 583
589/// 584///
@@ -594,9 +589,9 @@
594/// @content 589/// @content
595/// 590///
596@mixin sibling-twin-element { 591@mixin sibling-twin-element {
597 @include related-twin-elem('~') { 592 @include related-twin-elem('~') {
598 @content; 593 @content;
599 } 594 }
600} 595}
601 596
602/// 597///
@@ -608,7 +603,7 @@
608/// @see {mixin} sibling-twin-element 603/// @see {mixin} sibling-twin-element
609/// 604///
610@function sibling-twin-elem() { 605@function sibling-twin-elem() {
611 @return related-twin-elem('~'); 606 @return related-twin-elem('~');
612} 607}
613 608
614/// 609///
@@ -619,9 +614,9 @@
619/// @content 614/// @content
620/// 615///
621@mixin next-twin-elem { 616@mixin next-twin-elem {
622 @include related-twin-elem('+') { 617 @include related-twin-elem('+') {
623 @content; 618 @content;
624 } 619 }
625} 620}
626 621
627/// 622///
@@ -633,5 +628,5 @@
633/// @see {mixin} next-twin-elem 628/// @see {mixin} next-twin-elem
634/// 629///
635@function next-twin-elem() { 630@function next-twin-elem() {
636 @return related-twin-elem('+'); 631 @return related-twin-elem('+');
637} 632}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:map';
9@use 'sass:selector';
7@use './vars'; 10@use './vars';
8 11
9/// 12///
10/// @access private 13/// @access private
11/// 14///
12@function theme-selector($name, $names...) { 15@function theme-selector($name, $names...) {
13 $namespace: map-get(vars.$namespaces, 'theme'); 16 $namespace: map.get(vars.$namespaces, 'theme');
14 $selector: null; 17 $selector: null;
15 18
16 @each $name in join($name, $names) { 19 @each $name in list.join($name, $names) {
17 $sel: '.' + $namespace + '-' + $name; 20 $sel: '.' + $namespace + '-' + $name;
18 21
19 @if $selector == null { 22 @if $selector == null {
20 $selector: join(selector-parse($sel), selector-parse('[class*=\' t-\'] ' + $sel), comma); 23 $selector: list.join(selector.parse($sel), selector.parse('[class*=\' t-\'] ' + $sel), comma);
21 $selector: join($selector, selector-parse('[class^=\'t-\'] ' + $sel), comma); 24 $selector: list.join($selector, selector.parse('[class^=\'t-\'] ' + $sel), comma);
22 } @else { 25 } @else {
23 $selector: selector-nest($selector, $sel); 26 $selector: selector.nest($selector, $sel);
24 } 27 }
25 } 28 }
26 29
27 @return $selector; 30 @return $selector;
28} 31}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:map';
9@use 'sass:meta';
10@use 'sass:selector';
11@use 'sass:string';
7@use './validators'; 12@use './validators';
8@use './vars'; 13@use './vars';
9@use '../functions'; 14@use '../functions';
@@ -111,22 +116,22 @@
111/// } 116/// }
112/// 117///
113@mixin modifier($name, $names...) { 118@mixin modifier($name, $names...) {
114 $result: modifier($name, $names...); 119 $result: modifier($name, $names...);
115 $selector: nth($result, 1); 120 $selector: list.nth($result, 1);
116 $context: nth($result, 2); 121 $context: list.nth($result, 2);
117 122
118 @include validators.validate( 123 @include validators.validate(
119 'modifier', 124 'modifier',
120 (name: $name, names: $names), 125 (name: $name, names: $names),
121 $selector, 126 $selector,
122 $context 127 $context
123 ); 128 );
124 129
125 @include contexts.push(vars.$context-id, $context...); 130 @include contexts.push(vars.$context-id, $context...);
126 @at-root #{$selector} { 131 @at-root #{$selector} {
127 @content; 132 @content;
128 } 133 }
129 @include contexts.pop(vars.$context-id); 134 @include contexts.pop(vars.$context-id);
130} 135}
131 136
132/// 137///
@@ -137,121 +142,115 @@
137/// @see {mixin} modifier 142/// @see {mixin} modifier
138/// 143///
139@function modifier($name, $names...) { 144@function modifier($name, $names...) {
140 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 145 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
141 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); 146 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block');
142 147
143 $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier' 'suffix' 'state'); 148 $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier' 'suffix' 'state');
144 $parent-selector: map-get(nth($parent-context, 2), 'selector'); 149 $parent-selector: map.get(list.nth($parent-context, 2), 'selector');
145 $selector: (); 150 $selector: ();
146 $parts-data: (); 151 $parts-data: ();
147 152
148 @if not functions.selector-suffix-match(&, $parent-selector) { 153 @if not functions.selector-suffix-match(&, $parent-selector) {
149 // 154 //
150 // The current selector doesn't match the parent selector. 155 // The current selector doesn't match the parent selector.
151 // The user manually added a selector between parent context and this modifier call. 156 // The user manually added a selector between parent context and this modifier call.
152 // This case is forbidden because any outcome semantically wouldn't make sense: 157 // This case is forbidden because any outcome semantically wouldn't make sense:
153 // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier 158 // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier
154 // - {b,e,m,s}--modifier [manual selector] 159 // - {b,e,m,s}--modifier [manual selector]
155 // The first case would make the modifier behave like an element. 160 // The first case would make the modifier behave like an element.
156 // The second case is unintuitive, the code would be more clear by nesting the manual 161 // The second case is unintuitive, the code would be more clear by nesting the manual
157 // selector in the modifier instead. 162 // selector in the modifier instead.
158 // 163 //
159 164
160 @error 'A modifier must be an immediate child of the parent context'; 165 @error 'A modifier must be an immediate child of the parent context';
161 } 166 }
162 167
163 @each $name in functions.list-prepend($names, $name) { 168 @each $name in functions.list-prepend($names, $name) {
164 $extend: false; 169 $extend: false;
165 @if type-of($name) == list { 170 @if meta.type-of($name) == list {
166 $extend: nth($name, 2); 171 $extend: list.nth($name, 2);
167 $name: nth($name, 1); 172 $name: list.nth($name, 1);
168 } 173 }
169 174
170 @if index('block' 'element', nth($parent-context, 1)) or $extend == true { 175 @if list.index('block' 'element', list.nth($parent-context, 1)) or $extend == true {
171 // 176 //
172 // Either the parent context is block or element, or a modifier or suffix 177 // Either the parent context is block or element, or a modifier or suffix
173 // is to be extended. The modifier part can simply be appended. 178 // is to be extended. The modifier part can simply be appended.
174 // Possible outcomes: 179 // Possible outcomes:
175 // - {b,e,m,s}--modifier 180 // - {b,e,m,s}--modifier
176 // 181 //
177 182
178 $sel: selector-append(&, vars.$modifier-separator + $name); 183 $sel: selector.append(&, vars.$modifier-separator + $name);
179 $selector: join($selector, $sel, comma); 184 $selector: list.join($selector, $sel, comma);
180 $parts-data: append( 185 $parts-data: list.append($parts-data, (
181 $parts-data, ( 186 'name': $name,
182 'name': $name, 187 'selector': $sel
183 'selector': $sel 188 ));
184 ) 189 } @else {
185 ); 190 //
186 } @else { 191 // Parent context is modifier, suffix or state and $extend is false.
187 // 192 //
188 // Parent context is modifier, suffix or state and $extend is false.
189 //
190 193
191 $be-context: contexts.get(vars.$context-id, 'block' 'element'); 194 $be-context: contexts.get(vars.$context-id, 'block' 'element');
192 195
193 @if nth($be-context, 1) == 'element' { 196 @if list.nth($be-context, 1) == 'element' {
194 // 197 //
195 // Latest context is element. Since element contexts can consist of multiple single 198 // Latest context is element. Since element contexts can consist of multiple single
196 // elements, inspect all elements and append its selector with the suffix "--$name". 199 // elements, inspect all elements and append its selector with the suffix "--$name".
197 // This has to be done with string comparison since none of Sass selector functions 200 // This has to be done with string comparison since none of Sass selector functions
198 // is of use here. 201 // is of use here.
199 // Possible outcomes: 202 // Possible outcomes:
200 // - {m,s}.{e}--modifier 203 // - {m,s}.{e}--modifier
201 // 204 //
202 205
203 $nsel: (); 206 $nsel: ();
204 207
205 @each $elem-part-data in map-get(nth($be-context, 2), 'parts') { 208 @each $elem-part-data in map.get(list.nth($be-context, 2), 'parts') {
206 $elem-part-selector: map-get($elem-part-data, 'selector'); 209 $elem-part-selector: map.get($elem-part-data, 'selector');
207 210
208 $sel: (); 211 $sel: ();
209 @each $s in & { 212 @each $s in & {
210 @each $ps in $elem-part-selector { 213 @each $ps in $elem-part-selector {
211 @if str-index(inspect($s), inspect($ps) + vars.$modifier-separator) or str-index(inspect($s), inspect($ps) + vars.$suffix-separator) { 214 @if string.index(meta.inspect($s), meta.inspect($ps) + vars.$modifier-separator) or string.index(meta.inspect($s), meta.inspect($ps) + vars.$suffix-separator) {
212 $sel: join($sel, selector-unify($s, selector-append($ps, vars.$modifier-separator + $name)), comma); 215 $sel: list.join($sel, selector.unify($s, selector.append($ps, vars.$modifier-separator + $name)), comma);
213 } 216 }
214 } 217 }
215 } 218 }
216 @if length($sel) == 0 { 219 @if list.length($sel) == 0 {
217 @error 'Could not generate modifier selector.'; 220 @error 'Could not generate modifier selector.';
218 } 221 }
219 222
220 $nsel: join($nsel, $sel, comma); 223 $nsel: list.join($nsel, $sel, comma);
221 } 224 }
222 225
223 $selector: join($selector, $nsel, comma); 226 $selector: list.join($selector, $nsel, comma);
224 $parts-data: append( 227 $parts-data: list.append($parts-data, (
225 $parts-data, ( 228 'name': $name,
226 'name': $name, 229 'selector': $nsel
227 'selector': $nsel 230 ));
228 ) 231 } @else {
229 ); 232 //
230 } @else { 233 // Latest context is block. Just append the modifier part.
231 // 234 // Possible outcomes:
232 // Latest context is block. Just append the modifier part. 235 // - {m,s}.{b}--modifier
233 // Possible outcomes: 236 //
234 // - {m,s}.{b}--modifier
235 //
236 237
237 $block-base-selector: map-get(nth($be-context, 2), 'base-selector'); 238 $block-base-selector: map.get(list.nth($be-context, 2), 'base-selector');
238 239
239 $sel: selector-append(&, $block-base-selector, vars.$modifier-separator + $name); 240 $sel: selector.append(&, $block-base-selector, vars.$modifier-separator + $name);
240 $selector: join($selector, $sel, comma); 241 $selector: list.join($selector, $sel, comma);
241 $parts-data: append( 242 $parts-data: list.append($parts-data, (
242 $parts-data, ( 243 'name': $name,
243 'name': $name, 244 'selector': $sel
244 'selector': $sel 245 ));
245 ) 246 }
246 ); 247 }
247 } 248 }
248 }
249 }
250 249
251 $context: 'modifier', ( 250 $context: 'modifier', (
252 'parts': $parts-data, 251 'parts': $parts-data,
253 'selector': $selector 252 'selector': $selector
254 ); 253 );
255 254
256 @return $selector $context; 255 @return $selector $context;
257} 256}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:meta';
9@use 'sass:selector';
10@use 'sass:string';
7@use '../functions'; 11@use '../functions';
8@use '../contexts'; 12@use '../contexts';
9@use './block'; 13@use './block';
@@ -81,67 +85,67 @@
81/// } 85/// }
82/// 86///
83@mixin multi($first, $others...) { 87@mixin multi($first, $others...) {
84 @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 88 @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
85 89
86 @each $entity in functions.list-prepend($others, $first) { 90 @each $entity in functions.list-prepend($others, $first) {
87 $is-manual-selector: false; 91 $is-manual-selector: false;
88 92
89 @if type-of($entity) == string { 93 @if meta.type-of($entity) == string {
90 @if find-bem-function($entity) == null { 94 @if find-bem-function($entity) == null {
91 $is-manual-selector: true; 95 $is-manual-selector: true;
92 } 96 }
93 } 97 }
94 98
95 @if $is-manual-selector { 99 @if $is-manual-selector {
96 $sel: if(&, selector-nest(&, $entity), selector-parse($entity)); 100 $sel: if(&, selector.nest(&, $entity), selector.parse($entity));
97 101
98 @at-root #{$sel} { 102 @at-root #{$sel} {
99 @content; 103 @content;
100 } 104 }
101 } @else { 105 } @else {
102 $entity-func-id: null; 106 $entity-func-id: null;
103 107
104 @if type-of($entity) == list { 108 @if meta.type-of($entity) == list {
105 $entity-func-id: nth($entity, 1); 109 $entity-func-id: list.nth($entity, 1);
106 $entity: functions.list-slice($entity, 2); 110 $entity: functions.list-slice($entity, 2);
107 } @else { 111 } @else {
108 $entity-func-id: $entity; 112 $entity-func-id: $entity;
109 $entity: (); 113 $entity: ();
110 } 114 }
111 115
112 @if str-slice($entity-func-id, str-length($entity-func-id)) == ':' { 116 @if string.slice($entity-func-id, string.length($entity-func-id)) == ':' {
113 $entity-func-id: unquote(str-slice($entity-func-id, 1, str-length($entity-func-id) - 1)); 117 $entity-func-id: string.unquote(string.slice($entity-func-id, 1, string.length($entity-func-id) - 1));
114 } 118 }
115 119
116 $sel-func: find-bem-function($entity-func-id); 120 $sel-func: find-bem-function($entity-func-id);
117 121
118 @if $sel-func == null { 122 @if $sel-func == null {
119 @error 'Function "#{inspect($entity-func-id)}" was not found.'; 123 @error 'Function "#{inspect($entity-func-id)}" was not found.';
120 } 124 }
121 125
122 $entity-result: call($sel-func, $entity...); 126 $entity-result: meta.call($sel-func, $entity...);
123 $entity-result-selector: nth($entity-result, 1); 127 $entity-result-selector: list.nth($entity-result, 1);
124 $entity-result-context: nth($entity-result, 2); 128 $entity-result-context: list.nth($entity-result, 2);
125 129
126 @if $entity-result-context != null { 130 @if $entity-result-context != null {
127 @include contexts.push(vars.$context-id, $entity-result-context...); 131 @include contexts.push(vars.$context-id, $entity-result-context...);
128 } 132 }
129 @at-root #{$entity-result-selector} { 133 @at-root #{$entity-result-selector} {
130 @content; 134 @content;
131 } 135 }
132 @if $entity-result-context != null { 136 @if $entity-result-context != null {
133 @include contexts.pop(vars.$context-id); 137 @include contexts.pop(vars.$context-id);
134 } 138 }
135 } 139 }
136 } 140 }
137} 141}
138 142
139@function find-bem-function($name) { 143@function find-bem-function($name) {
140 @each $module in (block element modifier state suffix theme) { 144 @each $module in (block element modifier state suffix theme) {
141 @if function-exists($name, $module) { 145 @if meta.function-exists($name, $module) {
142 @return get-function($name, $module: $module); 146 @return meta.get-function($name, $module: $module);
143 } 147 }
144 } 148 }
145 149
146 @return null; 150 @return null;
147} 151}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:selector';
7@use './validators'; 9@use './validators';
8@use './vars'; 10@use './vars';
9@use '../contexts'; 11@use '../contexts';
@@ -56,22 +58,22 @@
56/// } 58/// }
57/// 59///
58@mixin state($prefix, $state, $states...) { 60@mixin state($prefix, $state, $states...) {
59 $result: state($prefix, $state, $states...); 61 $result: state($prefix, $state, $states...);
60 $selector: nth($result, 1); 62 $selector: list.nth($result, 1);
61 $context: nth($result, 2); 63 $context: list.nth($result, 2);
62 64
63 @include validators.validate( 65 @include validators.validate(
64 'state', 66 'state',
65 (prefix: $prefix, state: $state, states: $states), 67 (prefix: $prefix, state: $state, states: $states),
66 $selector, 68 $selector,
67 $context 69 $context
68 ); 70 );
69 71
70 @include contexts.push(vars.$context-id, $context...); 72 @include contexts.push(vars.$context-id, $context...);
71 @at-root #{$selector} { 73 @at-root #{$selector} {
72 @content; 74 @content;
73 } 75 }
74 @include contexts.pop(vars.$context-id); 76 @include contexts.pop(vars.$context-id);
75} 77}
76 78
77/// 79///
@@ -82,29 +84,27 @@
82/// @see {mixin} has 84/// @see {mixin} has
83/// 85///
84@function state($prefix, $state, $states...) { 86@function state($prefix, $state, $states...) {
85 $selector: (); 87 $selector: ();
86 $parts-data: (); 88 $parts-data: ();
87 89
88 @each $state in join($state, $states) { 90 @each $state in list.join($state, $states) {
89 $sel: selector-parse('.#{$prefix}-#{$state}'); 91 $sel: selector.parse('.#{$prefix}-#{$state}');
90 @if & { 92 @if & {
91 $sel: selector-append(&, $sel); 93 $sel: selector.append(&, $sel);
92 } 94 }
93 $selector: join($selector, $sel, comma); 95 $selector: list.join($selector, $sel, comma);
94 $parts-data: append( 96 $parts-data: list.append($parts-data, (
95 $parts-data, ( 97 'name': $state,
96 'name': $state, 98 'selector': $sel
97 'selector': $sel 99 ));
98 ) 100 }
99 );
100 }
101 101
102 $context: 'state', ( 102 $context: 'state', (
103 'parts': $parts-data, 103 'parts': $parts-data,
104 'selector': $selector 104 'selector': $selector
105 ); 105 );
106 106
107 @return $selector $context; 107 @return $selector $context;
108} 108}
109 109
110/// 110///
@@ -113,9 +113,9 @@
113/// It's a shorthand for state('is', $state, $states...). 113/// It's a shorthand for state('is', $state, $states...).
114/// 114///
115@mixin is($state, $states...) { 115@mixin is($state, $states...) {
116 @include state('is', $state, $states...) { 116 @include state('is', $state, $states...) {
117 @content; 117 @content;
118 } 118 }
119} 119}
120 120
121/// 121///
@@ -126,7 +126,7 @@
126/// @see {mixin} is 126/// @see {mixin} is
127/// 127///
128@function is($state, $states...) { 128@function is($state, $states...) {
129 @return state('is', $state, $states...); 129 @return state('is', $state, $states...);
130} 130}
131 131
132/// 132///
@@ -135,9 +135,9 @@
135/// It's a shorthand for state('has', $state, $states...). 135/// It's a shorthand for state('has', $state, $states...).
136/// 136///
137@mixin has($state, $states...) { 137@mixin has($state, $states...) {
138 @include state('has', $state, $states...) { 138 @include state('has', $state, $states...) {
139 @content; 139 @content;
140 } 140 }
141} 141}
142 142
143/// 143///
@@ -148,5 +148,5 @@
148/// @see {mixin} has 148/// @see {mixin} has
149/// 149///
150@function has($state, $states...) { 150@function has($state, $states...) {
151 @return state('has', $state, $states...); 151 @return state('has', $state, $states...);
152} 152}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:map';
9@use 'sass:selector';
7@use './validators'; 10@use './validators';
8@use './vars'; 11@use './vars';
9@use '../functions'; 12@use '../functions';
@@ -54,22 +57,22 @@
54/// } 57/// }
55/// 58///
56@mixin suffix($name) { 59@mixin suffix($name) {
57 $result: suffix($name); 60 $result: suffix($name);
58 $selector: nth($result, 1); 61 $selector: list.nth($result, 1);
59 $context: nth($result, 2); 62 $context: list.nth($result, 2);
60 63
61 @include validators.validate( 64 @include validators.validate(
62 'suffix', 65 'suffix',
63 (name: $name), 66 (name: $name),
64 $selector, 67 $selector,
65 $context 68 $context
66 ); 69 );
67 70
68 @include contexts.push(vars.$context-id, $context...); 71 @include contexts.push(vars.$context-id, $context...);
69 @at-root #{$selector} { 72 @at-root #{$selector} {
70 @content; 73 @content;
71 } 74 }
72 @include contexts.pop(vars.$context-id); 75 @include contexts.pop(vars.$context-id);
73} 76}
74 77
75/// 78///
@@ -80,44 +83,44 @@
80/// @see {mixin} suffix 83/// @see {mixin} suffix
81/// 84///
82@function suffix($name) { 85@function suffix($name) {
83 // 86 //
84 // Suffixes can be used on block, element and modifier. 87 // Suffixes can be used on block, element and modifier.
85 // 88 //
86 89
87 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); 90 $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth);
88 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); 91 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block');
89 $noop: contexts.assert-stack-must-not-contain(vars.$context-id, 'suffix'); 92 $noop: contexts.assert-stack-must-not-contain(vars.$context-id, 'suffix');
90 93
91 $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier'); 94 $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier');
92 $parent-selector: map-get(nth($parent-context, 2), 'selector'); 95 $parent-selector: map.get(list.nth($parent-context, 2), 'selector');
93 96
94 @if not functions.selector-suffix-match(&, $parent-selector) { 97 @if not functions.selector-suffix-match(&, $parent-selector) {
95 // 98 //
96 // The current selector doesn't match the parent selector. 99 // The current selector doesn't match the parent selector.
97 // The user manually added a selector between parent context and this suffix call. 100 // The user manually added a selector between parent context and this suffix call.
98 // This case is forbidden because any outcome semantically wouldn't make sense: 101 // This case is forbidden because any outcome semantically wouldn't make sense:
99 // - {b,e,m} [manual selector] {b,e,m}@suffix 102 // - {b,e,m} [manual selector] {b,e,m}@suffix
100 // - {b,e,m}@suffix [manual selector] 103 // - {b,e,m}@suffix [manual selector]
101 // The first case would make the modifier behave like an element. 104 // The first case would make the modifier behave like an element.
102 // The second case is unintuitive, the code would be more clear by nesting the manual 105 // The second case is unintuitive, the code would be more clear by nesting the manual
103 // selector in the suffix instead. 106 // selector in the suffix instead.
104 // 107 //
105 108
106 @error 'A suffix must be an immediate child of the parent context'; 109 @error 'A suffix must be an immediate child of the parent context';
107 } 110 }
108 111
109 // 112 //
110 // The suffix part can simply be appended. 113 // The suffix part can simply be appended.
111 // Possible outcomes: 114 // Possible outcomes:
112 // - {b,e,m}@suffix 115 // - {b,e,m}@suffix
113 // 116 //
114 117
115 $selector: selector-append(&, vars.$suffix-separator + $name); 118 $selector: selector.append(&, vars.$suffix-separator + $name);
116 119
117 $context: 'suffix', ( 120 $context: 'suffix', (
118 'name': $name, 121 'name': $name,
119 'selector': $selector 122 'selector': $selector
120 ); 123 );
121 124
122 @return $selector $context; 125 @return $selector $context;
123} 126}
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 @@
4/// @access public 4/// @access public
5//// 5////
6 6
7@use 'sass:list';
8@use 'sass:map';
9@use 'sass:selector';
7@use './functions'; 10@use './functions';
8@use './validators'; 11@use './validators';
9@use './vars'; 12@use './vars';
@@ -18,22 +21,22 @@
18/// @content 21/// @content
19/// 22///
20@mixin at-theme($name, $names...) { 23@mixin at-theme($name, $names...) {
21 $result: at-theme($name, $names...); 24 $result: at-theme($name, $names...);
22 $selector: nth($result, 1); 25 $selector: list.nth($result, 1);
23 $context: nth($result, 2); 26 $context: list.nth($result, 2);
24 27
25 @include validators.validate( 28 @include validators.validate(
26 'at-theme', 29 'at-theme',
27 (name: $name, names: $names), 30 (name: $name, names: $names),
28 $selector, 31 $selector,
29 $context 32 $context
30 ); 33 );
31 34
32 @include contexts.push(vars.$context-id, $context...); 35 @include contexts.push(vars.$context-id, $context...);
33 @at-root #{$selector} { 36 @at-root #{$selector} {
34 @content; 37 @content;
35 } 38 }
36 @include contexts.pop(vars.$context-id); 39 @include contexts.pop(vars.$context-id);
37} 40}
38 41
39/// 42///
@@ -45,22 +48,22 @@
45/// @see {mixin} at-theme 48/// @see {mixin} at-theme
46/// 49///
47@function at-theme($name, $names...) { 50@function at-theme($name, $names...) {
48 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); 51 $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block');
49 52
50 $parent-context: contexts.get(vars.$context-id, 'block'); 53 $parent-context: contexts.get(vars.$context-id, 'block');
51 $parent-selector: map-get(nth($parent-context, 2), 'selector'); 54 $parent-selector: map.get(list.nth($parent-context, 2), 'selector');
52 55
53 //@if not functions.selector-suffix-match(&, $parent-selector) { 56 //@if not functions.selector-suffix-match(&, $parent-selector) {
54 // @error 'An at-theme rule must be an immediate child of a block'; 57 // @error 'An at-theme rule must be an immediate child of a block';
55 //} 58 //}
56 59
57 $selector: functions.theme-selector($name, $names...); 60 $selector: functions.theme-selector($name, $names...);
58 $selector: selector-nest($selector, &); 61 $selector: selector.nest($selector, &);
59 62
60 $context: 'at-theme', ( 63 $context: 'at-theme', (
61 'name': join($name, $names), 64 'name': list.join($name, $names),
62 'selector': $selector 65 'selector': $selector
63 ); 66 );
64 67
65 @return $selector $context; 68 @return $selector $context;
66} 69}
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 @@
16/// @access public 16/// @access public
17//// 17////
18 18
19@use 'sass:list';
20@use 'sass:map';
21@use 'sass:meta';
19@use './vars'; 22@use './vars';
20@use '../functions'; 23@use '../functions';
21@use '../contexts'; 24@use '../contexts';
@@ -46,7 +49,7 @@ $validators: ();
46/// @param {string} $func-names - Other function names. 49/// @param {string} $func-names - Other function names.
47/// 50///
48@mixin add($func-name, $func-names...) { 51@mixin add($func-name, $func-names...) {
49 $noop: add($func-name, $func-names...); 52 $noop: add($func-name, $func-names...);
50} 53}
51 54
52/// 55///
@@ -55,11 +58,11 @@ $validators: ();
55/// @see {mixin} add 58/// @see {mixin} add
56/// 59///
57@function add($func-name, $func-names...) { 60@function add($func-name, $func-names...) {
58 @each $fn-name in join($func-name, $func-names) { 61 @each $fn-name in list.join($func-name, $func-names) {
59 $fn: get-function($fn-name); 62 $fn: meta.get-function($fn-name);
60 $validators: map-merge($validators, ($fn-name: $fn)); 63 $validators: map.merge($validators, ($fn-name: $fn));
61 } 64 }
62 @return null; 65 @return null;
63} 66}
64 67
65/// 68///
@@ -69,7 +72,7 @@ $validators: ();
69/// @param {string} $func-names - Other function names. 72/// @param {string} $func-names - Other function names.
70/// 73///
71@mixin remove($func-name, $func-names...) { 74@mixin remove($func-name, $func-names...) {
72 $noop: remove($func-name, $func-names...); 75 $noop: remove($func-name, $func-names...);
73} 76}
74 77
75/// 78///
@@ -78,20 +81,20 @@ $validators: ();
78/// @see {mixin} remove 81/// @see {mixin} remove
79/// 82///
80@function remove($func-name, $func-names...) { 83@function remove($func-name, $func-names...) {
81 $validators: map-remove($validators, $func-name, $func-names...); 84 $validators: map.remove($validators, $func-name, $func-names...);
82 @return null; 85 @return null;
83} 86}
84 87
85/// 88///
86/// @access private 89/// @access private
87/// 90///
88@mixin validate($type, $args, $selector, $context) { 91@mixin validate($type, $args, $selector, $context) {
89 @each $id, $fn in $validators { 92 @each $id, $fn in $validators {
90 $result: call($fn, $type, $args, $selector, $context); 93 $result: meta.call($fn, $type, $args, $selector, $context);
91 @if not nth($result, 1) { 94 @if not list.nth($result, 1) {
92 @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; 95 @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}';
93 } 96 }
94 } 97 }
95} 98}
96 99
97// 100//
@@ -105,76 +108,76 @@ $validators: ();
105/// namespace used. 108/// namespace used.
106/// 109///
107@function enforce-namespace-order($type, $args, $selector, $context) { 110@function enforce-namespace-order($type, $args, $selector, $context) {
108 @if not global-variable-exists(namespace-order, vars) { 111 @if not meta.global-variable-exists(namespace-order, vars) {
109 vars.$namespace-order: map-keys(vars.$namespaces); 112 vars.$namespace-order: map.keys(vars.$namespaces);
110 } 113 }
111 @if not global-variable-exists(cur-namespace-index, vars) { 114 @if not meta.global-variable-exists(cur-namespace-index, vars) {
112 vars.$cur-namespace-index: 1; 115 vars.$cur-namespace-index: 1;
113 } 116 }
114 117
115 @if $type == 'block' { 118 @if $type == 'block' {
116 $block-type: map-get($args, 'type'); 119 $block-type: map.get($args, 'type');
117 120
118 @if $block-type != null { 121 @if $block-type != null {
119 $ns-index: index(vars.$namespace-order, $block-type); 122 $ns-index: list.index(vars.$namespace-order, $block-type);
120 123
121 @if $ns-index != null { 124 @if $ns-index != null {
122 @if $ns-index < vars.$cur-namespace-index { 125 @if $ns-index < vars.$cur-namespace-index {
123 @return false 'Namespace "#{$block-type}" comes before current namespace #{nth(vars.$namespace-order, vars.$cur-namespace-index)}'; 126 @return false 'Namespace "#{$block-type}" comes before current namespace #{nth(vars.$namespace-order, vars.$cur-namespace-index)}';
124 } 127 }
125 128
126 vars.$cur-namespace-index: $ns-index; 129 vars.$cur-namespace-index: $ns-index;
127 } 130 }
128 } 131 }
129 } 132 }
130 133
131 @return true ''; 134 @return true '';
132} 135}
133 136
134/// 137///
135/// A validator that makes all BEM entities immutable. 138/// A validator that makes all BEM entities immutable.
136/// 139///
137@function immutable-entities($type, $args, $selector, $context) { 140@function immutable-entities($type, $args, $selector, $context) {
138 @if not global-variable-exists(generated-selectors, vars) { 141 @if not meta.global-variable-exists(generated-selectors, vars) {
139 vars.$generated-selectors: (); 142 vars.$generated-selectors: ();
140 } 143 }
141 144
142 $block-name: null; 145 $block-name: null;
143 $block-type: null; 146 $block-type: null;
144 $block-id: null; 147 $block-id: null;
145 148
146 @if $type == 'block' { 149 @if $type == 'block' {
147 $block-name: map-get($args, 'name'); 150 $block-name: map.get($args, 'name');
148 $block-type: map-get($args, 'type'); 151 $block-type: map.get($args, 'type');
149 } @else { 152 } @else {
150 $block-context: contexts.get(vars.$context-id, 'block'); 153 $block-context: contexts.get(vars.$context-id, 'block');
151 $block-name: map-get(nth($block-context, 2), 'name'); 154 $block-name: map.get(list.nth($block-context, 2), 'name');
152 $block-type: map-get(nth($block-context, 2), 'type'); 155 $block-type: map.get(list.nth($block-context, 2), 'type');
153 } 156 }
154 157
155 @if $block-type != null { 158 @if $block-type != null {
156 $block-id: $block-name + '_' + $block-type; 159 $block-id: $block-name + '_' + $block-type;
157 } @else { 160 } @else {
158 $block-id: $block-name; 161 $block-id: $block-name;
159 } 162 }
160 163
161 @if $type == 'block' { 164 @if $type == 'block' {
162 @if map-has-key(vars.$generated-selectors, $block-id) { 165 @if map.has-key(vars.$generated-selectors, $block-id) {
163 @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; 166 @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.';
164 } 167 }
165 168
166 vars.$generated-selectors: map-merge(vars.$generated-selectors, ($block-id: ())); 169 vars.$generated-selectors: map.merge(vars.$generated-selectors, ($block-id: ()));
167 } @else { 170 } @else {
168 $selectors: map-get(vars.$generated-selectors, $block-id); 171 $selectors: map.get(vars.$generated-selectors, $block-id);
169 172
170 @if index($selectors, $selector) { 173 @if list.index($selectors, $selector) {
171 @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; 174 @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.';
172 } 175 }
173 176
174 $selectors: append($selectors, $selector); 177 $selectors: list.append($selectors, $selector);
175 178
176 vars.$generated-selectors: map-merge(vars.$generated-selectors, ($block-id: $selectors)); 179 vars.$generated-selectors: map.merge(vars.$generated-selectors, ($block-id: $selectors));
177 } 180 }
178 181
179 @return true ''; 182 @return true '';
180} 183}
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;
41/// @type map 41/// @type map
42/// 42///
43$namespaces: ( 43$namespaces: (
44 object: 'o', 44 object: 'o',
45 component: 'c', 45 component: 'c',
46 layout: 'l', 46 layout: 'l',
47 scope: 's', 47 scope: 's',
48 theme: 't', 48 theme: 't',
49 utility: 'u', 49 utility: 'u',
50 js: 'js', 50 js: 'js',
51 qa: 'qa', 51 qa: 'qa',
52 hack: '_' 52 hack: '_'
53) !default; 53) !default;
54 54
55/// 55///
@@ -100,9 +100,9 @@ $debug: false !default;
100/// @type map 100/// @type map
101/// 101///
102$debug-colors: ( 102$debug-colors: (
103 object: #ffa500, 103 object: #ffa500,
104 component: #00f, 104 component: #00f,
105 layout: #ff0, 105 layout: #ff0,
106 utility: #008000, 106 utility: #008000,
107 hack: #f00 107 hack: #f00
108) !default; 108) !default;