aboutsummaryrefslogtreecommitdiffstats
path: root/src/bem/_element.scss
diff options
context:
space:
mode:
authorVolpeon <git@volpeon.ink>2025-08-13 12:01:46 +0200
committerVolpeon <git@volpeon.ink>2025-08-13 12:01:46 +0200
commitf0f84513f8efe533b6ee670a6f1a0c074387b2ec (patch)
tree845bc4bacf1bd99acb0dfcc7e4545a36b544d2f8 /src/bem/_element.scss
parentMore fix (diff)
downloadiro-sass-f0f84513f8efe533b6ee670a6f1a0c074387b2ec.tar.gz
iro-sass-f0f84513f8efe533b6ee670a6f1a0c074387b2ec.tar.bz2
iro-sass-f0f84513f8efe533b6ee670a6f1a0c074387b2ec.zip
Make use of SASS modulesHEADmaster
Diffstat (limited to 'src/bem/_element.scss')
-rw-r--r--src/bem/_element.scss483
1 files changed, 239 insertions, 244 deletions
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}