From f0f84513f8efe533b6ee670a6f1a0c074387b2ec Mon Sep 17 00:00:00 2001 From: Volpeon Date: Wed, 13 Aug 2025 12:01:46 +0200 Subject: Make use of SASS modules --- src/bem/_block.scss | 250 ++++++++++----------- src/bem/_debug.scss | 15 +- src/bem/_element.scss | 565 +++++++++++++++++++++++------------------------ src/bem/_functions.scss | 27 ++- src/bem/_modifier.scss | 227 ++++++++++--------- src/bem/_multi.scss | 102 +++++---- src/bem/_state.scss | 84 +++---- src/bem/_suffix.scss | 95 ++++---- src/bem/_theme.scss | 57 ++--- src/bem/_validators.scss | 165 +++++++------- src/bem/_vars.scss | 28 +-- 11 files changed, 815 insertions(+), 800 deletions(-) (limited to 'src/bem') diff --git a/src/bem/_block.scss b/src/bem/_block.scss index cfa9f33..a4b2a47 100644 --- a/src/bem/_block.scss +++ b/src/bem/_block.scss @@ -4,6 +4,10 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use 'sass:selector'; @use './validators'; @use './vars'; @use './functions' as bemfunctions; @@ -37,34 +41,34 @@ /// } /// @mixin block($name, $type: null) { - $result: block($name, $type); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'block', - (name: $name, type: $type), - $selector, - $context - ); - - @if $type != null { - vars.$blocks: append(vars.$blocks, $name + '_' + $type); - } @else { - vars.$blocks: append(vars.$blocks, $name); - } - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @if $type != null { - @layer #{$type} { - @content; - } - } @else { - @content; - } - } - @include contexts.pop(vars.$context-id); + $result: block($name, $type); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'block', + (name: $name, type: $type), + $selector, + $context + ); + + @if $type != null { + vars.$blocks: list.append(vars.$blocks, $name + '_' + $type); + } @else { + vars.$blocks: list.append(vars.$blocks, $name); + } + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @if $type != null { + @layer #{$type} { + @content; + } + } @else { + @content; + } + } + @include contexts.pop(vars.$context-id); } /// @@ -75,47 +79,47 @@ /// @see {mixin} block /// @function block($name, $type: null) { - // - // Possible outcomes: - // - ({b,e,m,s}) block - // - - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - - $selector: null; - $base-selector: null; - - @if $type != null { - $namespace: map-get(vars.$namespaces, $type); - - @if not $namespace { - @error '"#{$type}" is not a valid type.'; - } - - $base-selector: selector-parse('.' + $namespace + '-' + $name); - - @if $type != 'theme' or & { - $selector: $base-selector; - } @else if not & { - $selector: bemfunctions.theme-selector($name); - } - } @else { - $base-selector: selector-parse('.' + $name); - $selector: $base-selector; - } - - @if & { - $selector: selector-nest(&, $selector); - } - - $context: 'block', ( - 'name': $name, - 'type': $type, - 'selector': $selector, - 'base-selector': $base-selector - ); - - @return $selector $context; + // + // Possible outcomes: + // - ({b,e,m,s}) block + // + + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + + $selector: null; + $base-selector: null; + + @if $type != null { + $namespace: map.get(vars.$namespaces, $type); + + @if not $namespace { + @error '"#{$type}" is not a valid type.'; + } + + $base-selector: selector.parse('.' + $namespace + '-' + $name); + + @if $type != 'theme' or & { + $selector: $base-selector; + } @else if not & { + $selector: bemfunctions.theme-selector($name); + } + } @else { + $base-selector: selector.parse('.' + $name); + $selector: $base-selector; + } + + @if & { + $selector: selector.nest(&, $selector); + } + + $context: 'block', ( + 'name': $name, + 'type': $type, + 'selector': $selector, + 'base-selector': $base-selector + ); + + @return $selector $context; } /// @@ -126,9 +130,9 @@ /// @content /// @mixin object($name) { - @include block($name, 'object') { - @content; - } + @include block($name, 'object') { + @content; + } } /// @@ -139,7 +143,7 @@ /// @see {mixin} object /// @function object($name) { - @return block($name, 'object'); + @return block($name, 'object'); } /// @@ -150,9 +154,9 @@ /// @content /// @mixin component($name) { - @include block($name, 'component') { - @content; - } + @include block($name, 'component') { + @content; + } } /// @@ -163,7 +167,7 @@ /// @see {mixin} component /// @function component($name) { - @return block($name, 'component'); + @return block($name, 'component'); } /// @@ -174,9 +178,9 @@ /// @content /// @mixin layout($name) { - @include block($name, 'layout') { - @content; - } + @include block($name, 'layout') { + @content; + } } /// @@ -187,7 +191,7 @@ /// @see {mixin} layout /// @function layout($name) { - @return block($name, 'layout'); + @return block($name, 'layout'); } /// @@ -198,9 +202,9 @@ /// @content /// @mixin utility($name) { - @include block($name, 'utility') { - @content; - } + @include block($name, 'utility') { + @content; + } } /// @@ -211,7 +215,7 @@ /// @see {mixin} utility /// @function utility($name) { - @return block($name, 'utility'); + @return block($name, 'utility'); } /// @@ -222,9 +226,9 @@ /// @content /// @mixin scope($name) { - @include block($name, 'scope') { - @content; - } + @include block($name, 'scope') { + @content; + } } /// @@ -235,7 +239,7 @@ /// @see {mixin} scope /// @function scope($name) { - @return block($name, 'scope'); + @return block($name, 'scope'); } /// @@ -246,9 +250,9 @@ /// @content /// @mixin theme($name) { - @include block($name, 'theme') { - @content; - } + @include block($name, 'theme') { + @content; + } } /// @@ -259,7 +263,7 @@ /// @see {mixin} theme /// @function theme($name) { - @return block($name, 'theme'); + @return block($name, 'theme'); } /// @@ -270,9 +274,9 @@ /// @content /// @mixin js($name) { - @include block($name, 'js') { - @content; - } + @include block($name, 'js') { + @content; + } } /// @@ -283,7 +287,7 @@ /// @see {mixin} js /// @function js($name) { - @return block($name, 'js'); + @return block($name, 'js'); } /// @@ -294,9 +298,9 @@ /// @content /// @mixin qa($name) { - @include block($name, 'qa') { - @content; - } + @include block($name, 'qa') { + @content; + } } /// @@ -307,7 +311,7 @@ /// @see {mixin} qa /// @function qa($name) { - @return block($name, 'qa'); + @return block($name, 'qa'); } /// @@ -318,9 +322,9 @@ /// @content /// @mixin hack($name) { - @include block($name, 'hack') { - @content; - } + @include block($name, 'hack') { + @content; + } } /// @@ -331,7 +335,7 @@ /// @see {mixin} hack /// @function hack($name) { - @return block($name, 'hack'); + @return block($name, 'hack'); } /// @@ -383,22 +387,22 @@ /// // Compilation will fail because c-someBlock is defined after c-anotherBlock__elem /// @mixin composed-of($block, $blocks...) { - @each $block in functions.list-prepend($blocks, $block) { - @if type-of($block) == string { - @if not index(vars.$blocks, $block) { - @error 'Block "#{$block}" does not exist.'; - } - } @else { - $name: nth($block, 1); - $type: nth($block, 2); - - @if not map-get(vars.$namespaces, $type) { - @error '"#{$type}" is not a valid type.'; - } - - @if not index(vars.$blocks, $name + '_' + $type) { - @error 'Block "#{$name}" does not exist.'; - } - } - } + @each $block in functions.list-prepend($blocks, $block) { + @if meta.type-of($block) == string { + @if not list.index(vars.$blocks, $block) { + @error 'Block "#{$block}" does not exist.'; + } + } @else { + $name: list.nth($block, 1); + $type: list.nth($block, 2); + + @if not map.get(vars.$namespaces, $type) { + @error '"#{$type}" is not a valid type.'; + } + + @if not list.index(vars.$blocks, $name + '_' + $type) { + @error 'Block "#{$name}" does not exist.'; + } + } + } } diff --git a/src/bem/_debug.scss b/src/bem/_debug.scss index 8ea0f05..b1f20a7 100644 --- a/src/bem/_debug.scss +++ b/src/bem/_debug.scss @@ -4,15 +4,16 @@ /// @access public //// +@use 'sass:map'; @use './vars'; @if vars.$debug { - @each $type, $color in vars.$debug-colors { - $namespace: map-get(vars.$namespaces, $type); + @each $type, $color in vars.$debug-colors { + $namespace: map.get(vars.$namespaces, $type); - [class^='#{$namespace}-'], - [class*=' #{$namespace}-'] { - outline: 5px solid $color; - } - } + [class^='#{$namespace}-'], + [class*=' #{$namespace}-'] { + outline: 5px solid $color; + } + } } diff --git a/src/bem/_element.scss b/src/bem/_element.scss index 64862b0..9f108fe 100644 --- a/src/bem/_element.scss +++ b/src/bem/_element.scss @@ -4,6 +4,11 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use 'sass:selector'; +@use 'sass:string'; @use './validators'; @use './vars'; @use '../functions'; @@ -92,22 +97,22 @@ /// } /// @mixin elem($name, $names...) { - $result: elem($name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'element', - (name: $name, names: $names), - $selector, - $context - ); - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + $result: elem($name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'element', + (name: $name, names: $names), + $selector, + $context + ); + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -118,99 +123,93 @@ /// @see {mixin} element /// @function elem($name, $names...) { - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - - $parent-context: contexts.get(vars.$context-id, 'block' 'element'); - - $selector: (); - $parts-data: (); - - @if nth($parent-context, 1) == 'element' { - @if vars.$element-nesting-policy == 'disallow' { - @error 'Element nesting is forbidden.'; - } - - @if vars.$element-nesting-policy == 'append' { - $element-selector: map-get(nth($parent-context, 2), 'selector'); - - @if not functions.selector-suffix-match(&, $element-selector) { - @error 'A nested element must be an immediate children of the parent element.'; - } - - // - // Possible outcomes: - // - {e}__element - // - [manual selector] {e}__element - // - - @each $name in join($name, $names) { - $sel: selector-append(&, vars.$element-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } - - $parent-context: contexts.get(vars.$context-id, 'block'); - } - - @if length($selector) == 0 { - $parent-selector: map-get(nth($parent-context, 2), 'selector'); - - @if functions.selector-suffix-match(&, $parent-selector) { - // - // Possible outcomes: - // - {b}__element - // - [manual selector] {b}__element - // - - @each $name in join($name, $names) { - $sel: selector-append(&, vars.$element-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } @else { - // - // Possible outcomes: - // - {b} [manual selector] {b}__element - // - {e,m,s} ([manual selector]) {b}__element - // - - @if nth($parent-context, 1) != 'block' { - $parent-context: contexts.get(vars.$context-id, 'block'); - } - - $block-base-selector: map-get(nth($parent-context, 2), 'base-selector'); - - @each $name in join($name, $names) { - $sel: selector-nest(&, selector-append($block-base-selector, vars.$element-separator + $name)); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } - } - - $context: 'element', ( - 'parts': $parts-data, - 'selector': $selector - ); - - @return $selector $context; + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + + $parent-context: contexts.get(vars.$context-id, 'block' 'element'); + + $selector: (); + $parts-data: (); + + @if list.nth($parent-context, 1) == 'element' { + @if vars.$element-nesting-policy == 'disallow' { + @error 'Element nesting is forbidden.'; + } + + @if vars.$element-nesting-policy == 'append' { + $element-selector: map.get(list.nth($parent-context, 2), 'selector'); + + @if not functions.selector-suffix-match(&, $element-selector) { + @error 'A nested element must be an immediate children of the parent element.'; + } + + // + // Possible outcomes: + // - {e}__element + // - [manual selector] {e}__element + // + + @each $name in list.join($name, $names) { + $sel: selector.append(&, vars.$element-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + + $parent-context: contexts.get(vars.$context-id, 'block'); + } + + @if list.length($selector) == 0 { + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); + + @if functions.selector-suffix-match(&, $parent-selector) { + // + // Possible outcomes: + // - {b}__element + // - [manual selector] {b}__element + // + + @each $name in list.join($name, $names) { + $sel: selector.append(&, vars.$element-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } @else { + // + // Possible outcomes: + // - {b} [manual selector] {b}__element + // - {e,m,s} ([manual selector]) {b}__element + // + + @if list.nth($parent-context, 1) != 'block' { + $parent-context: contexts.get(vars.$context-id, 'block'); + } + + $block-base-selector: map.get(list.nth($parent-context, 2), 'base-selector'); + + @each $name in list.join($name, $names) { + $sel: selector.nest(&, selector.append($block-base-selector, vars.$element-separator + $name)); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; } /// @@ -291,22 +290,22 @@ /// } /// @mixin related-elem($sign, $name, $names...) { - $result: related-elem($sign, $name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'related-element', - (sign: $sign, name: $name, names: $names), - $selector, - $context - ); - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + $result: related-elem($sign, $name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'related-element', + (sign: $sign, name: $name, names: $names), + $selector, + $context + ); + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -318,44 +317,42 @@ /// @see {mixin} related-element /// @function related-elem($sign, $name, $names...) { - // - // Generating this selector is simple: Take the latest block context, use it - // to generate the element part, and insert it at the end of the current selector. - // Possible outcomes: - // - {e} ({m,s}) ([manual selector]) + {e} - // - {e} ({m,s}) ([manual selector]) ~ {e} - // - - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); - - @if $sign != '+' and $sign != '~' { - @error 'Invalid relationship sign #{inspect($sign)}.'; - } - - $block-context: contexts.get(vars.$context-id, 'block'); - $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); - - $selector: (); - $parts-data: (); - - @each $name in join($name, $names) { - $sel: selector-nest(&, $sign, selector-append($block-base-selector, vars.$element-separator + $name)); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - - $context: 'element', ( - 'parts': $parts-data, - 'selector': $selector - ); - - @return $selector $context; + // + // Generating this selector is simple: Take the latest block context, use it + // to generate the element part, and insert it at the end of the current selector. + // Possible outcomes: + // - {e} ({m,s}) ([manual selector]) + {e} + // - {e} ({m,s}) ([manual selector]) ~ {e} + // + + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); + + @if $sign != '+' and $sign != '~' { + @error 'Invalid relationship sign #{inspect($sign)}.'; + } + + $block-context: contexts.get(vars.$context-id, 'block'); + $block-base-selector: map.get(list.nth($block-context, 2), 'base-selector'); + + $selector: (); + $parts-data: (); + + @each $name in list.join($name, $names) { + $sel: selector.nest(&, $sign, selector.append($block-base-selector, vars.$element-separator + $name)); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; } /// @@ -369,9 +366,9 @@ /// @content /// @mixin sibling-elem($name, $names...) { - @include related-elem('~', $name, $names...) { - @content; - } + @include related-elem('~', $name, $names...) { + @content; + } } /// @@ -383,7 +380,7 @@ /// @see {mixin} sibling-element /// @function sibling-elem($name, $names...) { - @return related-elem('~', $name, $names...); + @return related-elem('~', $name, $names...); } /// @@ -397,9 +394,9 @@ /// @content /// @mixin next-elem($name, $names...) { - @include related-elem('+', $name, $names...) { - @content; - } + @include related-elem('+', $name, $names...) { + @content; + } } /// @@ -411,7 +408,7 @@ /// @see {mixin} next-element /// @function next-elem($name, $names...) { - @return related-elem('+', $name, $names...); + @return related-elem('+', $name, $names...); } /// @@ -467,22 +464,22 @@ /// } /// @mixin related-twin-elem($sign) { - $result: related-twin-elem($sign); - $selector: nth($result, 1); - $context: nth($result, 2); - - @include validators.validate( - 'next-twin-elem', - (), - $selector, - $context - ); - - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + $result: related-twin-elem($sign); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); + + @include validators.validate( + 'next-twin-elem', + (), + $selector, + $context + ); + + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -494,96 +491,94 @@ /// @see {mixin} next-twin-elem /// @function related-twin-elem($sign) { - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); - - $element-context: contexts.get(vars.$context-id, 'element'); - $element-selector: map-get(nth($element-context, 2), 'selector'); - - $block-context: contexts.get(vars.$context-id, 'block'); - $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); - - $selector: (); - $parts-data: (); - - // - // To determine the twin for each element, iterate the sub-selectors from the current selector - // and check if it contains the currently inspected element. This has to be done with string - // comparison since none of Sass selector functions is of use here. - // Finally, the current twin will be appended to the extracted sub-selector as a successor - // element. - // - @each $part-data in map-get(nth($element-context, 2), 'parts') { - $part-selector: map-get($part-data, 'selector'); - $part-name: map-get($part-data, 'name'); - - $sel: (); - @if functions.selector-suffix-match(&, $element-selector) { - // - // This mixin is included in the selector the last element mixin created. - // Possible outcomes: - // - {e} + {e} - // - [manual selector] {e} + {e} - // - - @each $s in & { - @each $ps in $part-selector { - @if nth($s, -1) == nth($ps, -1) { - $sel-ent: selector-nest($s, $sign, selector-append($block-base-selector, vars.$element-separator + $part-name)); - $sel: join($sel, $sel-ent, comma); - } - } - } - } @else { - // - // This mixin is NOT included in the selector the last element mixin created. - // Possible outcomes: - // - {e} {m,s} + {e} - // - {e} [manual selector] + {e} - // - {e} {m,s} [manual selector] + {e} - // - - @each $s in & { - @each $ps in $part-selector { - @if str-index(inspect($s), inspect($ps)) { - $char-index: str-length(inspect($ps)) + 1; - $match: index(' ' ':' ',', str-slice(inspect($s), $char-index, $char-index)) != null; - - @if not $match { - @each $separator in vars.$element-separator vars.$modifier-separator vars.$suffix-separator { - @if str-slice(inspect($s), $char-index, $char-index + str-length($separator) - 1) == $separator { - $match: true; - } - } - } - - @if $match { - $sel-ent: selector-nest($s, '+', selector-append($block-base-selector, vars.$element-separator + $part-name)); - $sel: join($sel, $sel-ent, comma); - } - } - } - } - } - @if length($sel) != length($part-selector) { - @error 'Could not generate twin element selector.'; - } - - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $part-name, - 'selector': $sel - ) - ); - } - - $context: 'element', ( - 'parts': $parts-data, - 'selector': $selector - ); - - @return $selector $context; + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'element'); + + $element-context: contexts.get(vars.$context-id, 'element'); + $element-selector: map.get(list.nth($element-context, 2), 'selector'); + + $block-context: contexts.get(vars.$context-id, 'block'); + $block-base-selector: map.get(list.nth($block-context, 2), 'base-selector'); + + $selector: (); + $parts-data: (); + + // + // To determine the twin for each element, iterate the sub-selectors from the current selector + // and check if it contains the currently inspected element. This has to be done with string + // comparison since none of Sass selector functions is of use here. + // Finally, the current twin will be appended to the extracted sub-selector as a successor + // element. + // + @each $part-data in map.get(list.nth($element-context, 2), 'parts') { + $part-selector: map.get($part-data, 'selector'); + $part-name: map.get($part-data, 'name'); + + $sel: (); + @if functions.selector-suffix-match(&, $element-selector) { + // + // This mixin is included in the selector the last element mixin created. + // Possible outcomes: + // - {e} + {e} + // - [manual selector] {e} + {e} + // + + @each $s in & { + @each $ps in $part-selector { + @if list.nth($s, -1) == list.nth($ps, -1) { + $sel-ent: selector.nest($s, $sign, selector.append($block-base-selector, vars.$element-separator + $part-name)); + $sel: list.join($sel, $sel-ent, comma); + } + } + } + } @else { + // + // This mixin is NOT included in the selector the last element mixin created. + // Possible outcomes: + // - {e} {m,s} + {e} + // - {e} [manual selector] + {e} + // - {e} {m,s} [manual selector] + {e} + // + + @each $s in & { + @each $ps in $part-selector { + @if string.index(meta.inspect($s), meta.inspect($ps)) { + $char-index: string.length(meta.inspect($ps)) + 1; + $match: list.index(' ' ':' ',', string.slice(meta.inspect($s), $char-index, $char-index)) != null; + + @if not $match { + @each $separator in vars.$element-separator vars.$modifier-separator vars.$suffix-separator { + @if string.slice(meta.inspect($s), $char-index, $char-index + string.length($separator) - 1) == $separator { + $match: true; + } + } + } + + @if $match { + $sel-ent: selector.nest($s, '+', selector.append($block-base-selector, vars.$element-separator + $part-name)); + $sel: list.join($sel, $sel-ent, comma); + } + } + } + } + } + @if list.length($sel) != list.length($part-selector) { + @error 'Could not generate twin element selector.'; + } + + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $part-name, + 'selector': $sel + )); + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; } /// @@ -594,9 +589,9 @@ /// @content /// @mixin sibling-twin-element { - @include related-twin-elem('~') { - @content; - } + @include related-twin-elem('~') { + @content; + } } /// @@ -608,7 +603,7 @@ /// @see {mixin} sibling-twin-element /// @function sibling-twin-elem() { - @return related-twin-elem('~'); + @return related-twin-elem('~'); } /// @@ -619,9 +614,9 @@ /// @content /// @mixin next-twin-elem { - @include related-twin-elem('+') { - @content; - } + @include related-twin-elem('+') { + @content; + } } /// @@ -633,5 +628,5 @@ /// @see {mixin} next-twin-elem /// @function next-twin-elem() { - @return related-twin-elem('+'); + @return related-twin-elem('+'); } diff --git a/src/bem/_functions.scss b/src/bem/_functions.scss index b7bd5ec..7f52b93 100644 --- a/src/bem/_functions.scss +++ b/src/bem/_functions.scss @@ -4,25 +4,28 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:selector'; @use './vars'; /// /// @access private /// @function theme-selector($name, $names...) { - $namespace: map-get(vars.$namespaces, 'theme'); - $selector: null; + $namespace: map.get(vars.$namespaces, 'theme'); + $selector: null; - @each $name in join($name, $names) { - $sel: '.' + $namespace + '-' + $name; + @each $name in list.join($name, $names) { + $sel: '.' + $namespace + '-' + $name; - @if $selector == null { - $selector: join(selector-parse($sel), selector-parse('[class*=\' t-\'] ' + $sel), comma); - $selector: join($selector, selector-parse('[class^=\'t-\'] ' + $sel), comma); - } @else { - $selector: selector-nest($selector, $sel); - } - } + @if $selector == null { + $selector: list.join(selector.parse($sel), selector.parse('[class*=\' t-\'] ' + $sel), comma); + $selector: list.join($selector, selector.parse('[class^=\'t-\'] ' + $sel), comma); + } @else { + $selector: selector.nest($selector, $sel); + } + } - @return $selector; + @return $selector; } diff --git a/src/bem/_modifier.scss b/src/bem/_modifier.scss index 07267fe..10e2826 100644 --- a/src/bem/_modifier.scss +++ b/src/bem/_modifier.scss @@ -4,6 +4,11 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; +@use 'sass:selector'; +@use 'sass:string'; @use './validators'; @use './vars'; @use '../functions'; @@ -111,22 +116,22 @@ /// } /// @mixin modifier($name, $names...) { - $result: modifier($name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: modifier($name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'modifier', - (name: $name, names: $names), - $selector, - $context - ); + @include validators.validate( + 'modifier', + (name: $name, names: $names), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -137,121 +142,115 @@ /// @see {mixin} modifier /// @function modifier($name, $names...) { - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier' 'suffix' 'state'); - $parent-selector: map-get(nth($parent-context, 2), 'selector'); - $selector: (); - $parts-data: (); + $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier' 'suffix' 'state'); + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); + $selector: (); + $parts-data: (); - @if not functions.selector-suffix-match(&, $parent-selector) { - // - // The current selector doesn't match the parent selector. - // The user manually added a selector between parent context and this modifier call. - // This case is forbidden because any outcome semantically wouldn't make sense: - // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier - // - {b,e,m,s}--modifier [manual selector] - // The first case would make the modifier behave like an element. - // The second case is unintuitive, the code would be more clear by nesting the manual - // selector in the modifier instead. - // + @if not functions.selector-suffix-match(&, $parent-selector) { + // + // The current selector doesn't match the parent selector. + // The user manually added a selector between parent context and this modifier call. + // This case is forbidden because any outcome semantically wouldn't make sense: + // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier + // - {b,e,m,s}--modifier [manual selector] + // The first case would make the modifier behave like an element. + // The second case is unintuitive, the code would be more clear by nesting the manual + // selector in the modifier instead. + // - @error 'A modifier must be an immediate child of the parent context'; - } + @error 'A modifier must be an immediate child of the parent context'; + } - @each $name in functions.list-prepend($names, $name) { - $extend: false; - @if type-of($name) == list { - $extend: nth($name, 2); - $name: nth($name, 1); - } + @each $name in functions.list-prepend($names, $name) { + $extend: false; + @if meta.type-of($name) == list { + $extend: list.nth($name, 2); + $name: list.nth($name, 1); + } - @if index('block' 'element', nth($parent-context, 1)) or $extend == true { - // - // Either the parent context is block or element, or a modifier or suffix - // is to be extended. The modifier part can simply be appended. - // Possible outcomes: - // - {b,e,m,s}--modifier - // + @if list.index('block' 'element', list.nth($parent-context, 1)) or $extend == true { + // + // Either the parent context is block or element, or a modifier or suffix + // is to be extended. The modifier part can simply be appended. + // Possible outcomes: + // - {b,e,m,s}--modifier + // - $sel: selector-append(&, vars.$modifier-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } @else { - // - // Parent context is modifier, suffix or state and $extend is false. - // + $sel: selector.append(&, vars.$modifier-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } @else { + // + // Parent context is modifier, suffix or state and $extend is false. + // - $be-context: contexts.get(vars.$context-id, 'block' 'element'); + $be-context: contexts.get(vars.$context-id, 'block' 'element'); - @if nth($be-context, 1) == 'element' { - // - // Latest context is element. Since element contexts can consist of multiple single - // elements, inspect all elements and append its selector with the suffix "--$name". - // This has to be done with string comparison since none of Sass selector functions - // is of use here. - // Possible outcomes: - // - {m,s}.{e}--modifier - // + @if list.nth($be-context, 1) == 'element' { + // + // Latest context is element. Since element contexts can consist of multiple single + // elements, inspect all elements and append its selector with the suffix "--$name". + // This has to be done with string comparison since none of Sass selector functions + // is of use here. + // Possible outcomes: + // - {m,s}.{e}--modifier + // - $nsel: (); + $nsel: (); - @each $elem-part-data in map-get(nth($be-context, 2), 'parts') { - $elem-part-selector: map-get($elem-part-data, 'selector'); + @each $elem-part-data in map.get(list.nth($be-context, 2), 'parts') { + $elem-part-selector: map.get($elem-part-data, 'selector'); - $sel: (); - @each $s in & { - @each $ps in $elem-part-selector { - @if str-index(inspect($s), inspect($ps) + vars.$modifier-separator) or str-index(inspect($s), inspect($ps) + vars.$suffix-separator) { - $sel: join($sel, selector-unify($s, selector-append($ps, vars.$modifier-separator + $name)), comma); - } - } - } - @if length($sel) == 0 { - @error 'Could not generate modifier selector.'; - } + $sel: (); + @each $s in & { + @each $ps in $elem-part-selector { + @if string.index(meta.inspect($s), meta.inspect($ps) + vars.$modifier-separator) or string.index(meta.inspect($s), meta.inspect($ps) + vars.$suffix-separator) { + $sel: list.join($sel, selector.unify($s, selector.append($ps, vars.$modifier-separator + $name)), comma); + } + } + } + @if list.length($sel) == 0 { + @error 'Could not generate modifier selector.'; + } - $nsel: join($nsel, $sel, comma); - } + $nsel: list.join($nsel, $sel, comma); + } - $selector: join($selector, $nsel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $nsel - ) - ); - } @else { - // - // Latest context is block. Just append the modifier part. - // Possible outcomes: - // - {m,s}.{b}--modifier - // + $selector: list.join($selector, $nsel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $nsel + )); + } @else { + // + // Latest context is block. Just append the modifier part. + // Possible outcomes: + // - {m,s}.{b}--modifier + // - $block-base-selector: map-get(nth($be-context, 2), 'base-selector'); + $block-base-selector: map.get(list.nth($be-context, 2), 'base-selector'); - $sel: selector-append(&, $block-base-selector, vars.$modifier-separator + $name); - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $name, - 'selector': $sel - ) - ); - } - } - } + $sel: selector.append(&, $block-base-selector, vars.$modifier-separator + $name); + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + } - $context: 'modifier', ( - 'parts': $parts-data, - 'selector': $selector - ); + $context: 'modifier', ( + 'parts': $parts-data, + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } diff --git a/src/bem/_multi.scss b/src/bem/_multi.scss index 1de5cdc..c0beeeb 100644 --- a/src/bem/_multi.scss +++ b/src/bem/_multi.scss @@ -4,6 +4,10 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:meta'; +@use 'sass:selector'; +@use 'sass:string'; @use '../functions'; @use '../contexts'; @use './block'; @@ -81,67 +85,67 @@ /// } /// @mixin multi($first, $others...) { - @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - @each $entity in functions.list-prepend($others, $first) { - $is-manual-selector: false; + @each $entity in functions.list-prepend($others, $first) { + $is-manual-selector: false; - @if type-of($entity) == string { - @if find-bem-function($entity) == null { - $is-manual-selector: true; - } - } + @if meta.type-of($entity) == string { + @if find-bem-function($entity) == null { + $is-manual-selector: true; + } + } - @if $is-manual-selector { - $sel: if(&, selector-nest(&, $entity), selector-parse($entity)); + @if $is-manual-selector { + $sel: if(&, selector.nest(&, $entity), selector.parse($entity)); - @at-root #{$sel} { - @content; - } - } @else { - $entity-func-id: null; + @at-root #{$sel} { + @content; + } + } @else { + $entity-func-id: null; - @if type-of($entity) == list { - $entity-func-id: nth($entity, 1); - $entity: functions.list-slice($entity, 2); - } @else { - $entity-func-id: $entity; - $entity: (); - } + @if meta.type-of($entity) == list { + $entity-func-id: list.nth($entity, 1); + $entity: functions.list-slice($entity, 2); + } @else { + $entity-func-id: $entity; + $entity: (); + } - @if str-slice($entity-func-id, str-length($entity-func-id)) == ':' { - $entity-func-id: unquote(str-slice($entity-func-id, 1, str-length($entity-func-id) - 1)); - } + @if string.slice($entity-func-id, string.length($entity-func-id)) == ':' { + $entity-func-id: string.unquote(string.slice($entity-func-id, 1, string.length($entity-func-id) - 1)); + } - $sel-func: find-bem-function($entity-func-id); + $sel-func: find-bem-function($entity-func-id); - @if $sel-func == null { - @error 'Function "#{inspect($entity-func-id)}" was not found.'; - } + @if $sel-func == null { + @error 'Function "#{inspect($entity-func-id)}" was not found.'; + } - $entity-result: call($sel-func, $entity...); - $entity-result-selector: nth($entity-result, 1); - $entity-result-context: nth($entity-result, 2); + $entity-result: meta.call($sel-func, $entity...); + $entity-result-selector: list.nth($entity-result, 1); + $entity-result-context: list.nth($entity-result, 2); - @if $entity-result-context != null { - @include contexts.push(vars.$context-id, $entity-result-context...); - } - @at-root #{$entity-result-selector} { - @content; - } - @if $entity-result-context != null { - @include contexts.pop(vars.$context-id); - } - } - } + @if $entity-result-context != null { + @include contexts.push(vars.$context-id, $entity-result-context...); + } + @at-root #{$entity-result-selector} { + @content; + } + @if $entity-result-context != null { + @include contexts.pop(vars.$context-id); + } + } + } } @function find-bem-function($name) { - @each $module in (block element modifier state suffix theme) { - @if function-exists($name, $module) { - @return get-function($name, $module: $module); - } - } + @each $module in (block element modifier state suffix theme) { + @if meta.function-exists($name, $module) { + @return meta.get-function($name, $module: $module); + } + } - @return null; + @return null; } diff --git a/src/bem/_state.scss b/src/bem/_state.scss index 41bacee..bd0efb1 100644 --- a/src/bem/_state.scss +++ b/src/bem/_state.scss @@ -4,6 +4,8 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:selector'; @use './validators'; @use './vars'; @use '../contexts'; @@ -56,22 +58,22 @@ /// } /// @mixin state($prefix, $state, $states...) { - $result: state($prefix, $state, $states...); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: state($prefix, $state, $states...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'state', - (prefix: $prefix, state: $state, states: $states), - $selector, - $context - ); + @include validators.validate( + 'state', + (prefix: $prefix, state: $state, states: $states), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -82,29 +84,27 @@ /// @see {mixin} has /// @function state($prefix, $state, $states...) { - $selector: (); - $parts-data: (); + $selector: (); + $parts-data: (); - @each $state in join($state, $states) { - $sel: selector-parse('.#{$prefix}-#{$state}'); - @if & { - $sel: selector-append(&, $sel); - } - $selector: join($selector, $sel, comma); - $parts-data: append( - $parts-data, ( - 'name': $state, - 'selector': $sel - ) - ); - } + @each $state in list.join($state, $states) { + $sel: selector.parse('.#{$prefix}-#{$state}'); + @if & { + $sel: selector.append(&, $sel); + } + $selector: list.join($selector, $sel, comma); + $parts-data: list.append($parts-data, ( + 'name': $state, + 'selector': $sel + )); + } - $context: 'state', ( - 'parts': $parts-data, - 'selector': $selector - ); + $context: 'state', ( + 'parts': $parts-data, + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } /// @@ -113,9 +113,9 @@ /// It's a shorthand for state('is', $state, $states...). /// @mixin is($state, $states...) { - @include state('is', $state, $states...) { - @content; - } + @include state('is', $state, $states...) { + @content; + } } /// @@ -126,7 +126,7 @@ /// @see {mixin} is /// @function is($state, $states...) { - @return state('is', $state, $states...); + @return state('is', $state, $states...); } /// @@ -135,9 +135,9 @@ /// It's a shorthand for state('has', $state, $states...). /// @mixin has($state, $states...) { - @include state('has', $state, $states...) { - @content; - } + @include state('has', $state, $states...) { + @content; + } } /// @@ -148,5 +148,5 @@ /// @see {mixin} has /// @function has($state, $states...) { - @return state('has', $state, $states...); + @return state('has', $state, $states...); } diff --git a/src/bem/_suffix.scss b/src/bem/_suffix.scss index 2ddb54d..93e4066 100644 --- a/src/bem/_suffix.scss +++ b/src/bem/_suffix.scss @@ -4,6 +4,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:selector'; @use './validators'; @use './vars'; @use '../functions'; @@ -54,22 +57,22 @@ /// } /// @mixin suffix($name) { - $result: suffix($name); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: suffix($name); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'suffix', - (name: $name), - $selector, - $context - ); + @include validators.validate( + 'suffix', + (name: $name), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -80,44 +83,44 @@ /// @see {mixin} suffix /// @function suffix($name) { - // - // Suffixes can be used on block, element and modifier. - // + // + // Suffixes can be used on block, element and modifier. + // - $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - $noop: contexts.assert-stack-must-not-contain(vars.$context-id, 'suffix'); + $noop: contexts.assert-stack-count(vars.$context-id, vars.$max-depth); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + $noop: contexts.assert-stack-must-not-contain(vars.$context-id, 'suffix'); - $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier'); - $parent-selector: map-get(nth($parent-context, 2), 'selector'); + $parent-context: contexts.get(vars.$context-id, 'block' 'element' 'modifier'); + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); - @if not functions.selector-suffix-match(&, $parent-selector) { - // - // The current selector doesn't match the parent selector. - // The user manually added a selector between parent context and this suffix call. - // This case is forbidden because any outcome semantically wouldn't make sense: - // - {b,e,m} [manual selector] {b,e,m}@suffix - // - {b,e,m}@suffix [manual selector] - // The first case would make the modifier behave like an element. - // The second case is unintuitive, the code would be more clear by nesting the manual - // selector in the suffix instead. - // + @if not functions.selector-suffix-match(&, $parent-selector) { + // + // The current selector doesn't match the parent selector. + // The user manually added a selector between parent context and this suffix call. + // This case is forbidden because any outcome semantically wouldn't make sense: + // - {b,e,m} [manual selector] {b,e,m}@suffix + // - {b,e,m}@suffix [manual selector] + // The first case would make the modifier behave like an element. + // The second case is unintuitive, the code would be more clear by nesting the manual + // selector in the suffix instead. + // - @error 'A suffix must be an immediate child of the parent context'; - } + @error 'A suffix must be an immediate child of the parent context'; + } - // - // The suffix part can simply be appended. - // Possible outcomes: - // - {b,e,m}@suffix - // + // + // The suffix part can simply be appended. + // Possible outcomes: + // - {b,e,m}@suffix + // - $selector: selector-append(&, vars.$suffix-separator + $name); + $selector: selector.append(&, vars.$suffix-separator + $name); - $context: 'suffix', ( - 'name': $name, - 'selector': $selector - ); + $context: 'suffix', ( + 'name': $name, + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } diff --git a/src/bem/_theme.scss b/src/bem/_theme.scss index ff1ba49..535cc81 100644 --- a/src/bem/_theme.scss +++ b/src/bem/_theme.scss @@ -4,6 +4,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:selector'; @use './functions'; @use './validators'; @use './vars'; @@ -18,22 +21,22 @@ /// @content /// @mixin at-theme($name, $names...) { - $result: at-theme($name, $names...); - $selector: nth($result, 1); - $context: nth($result, 2); + $result: at-theme($name, $names...); + $selector: list.nth($result, 1); + $context: list.nth($result, 2); - @include validators.validate( - 'at-theme', - (name: $name, names: $names), - $selector, - $context - ); + @include validators.validate( + 'at-theme', + (name: $name, names: $names), + $selector, + $context + ); - @include contexts.push(vars.$context-id, $context...); - @at-root #{$selector} { - @content; - } - @include contexts.pop(vars.$context-id); + @include contexts.push(vars.$context-id, $context...); + @at-root #{$selector} { + @content; + } + @include contexts.pop(vars.$context-id); } /// @@ -45,22 +48,22 @@ /// @see {mixin} at-theme /// @function at-theme($name, $names...) { - $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); + $noop: contexts.assert-stack-must-contain(vars.$context-id, 'block'); - $parent-context: contexts.get(vars.$context-id, 'block'); - $parent-selector: map-get(nth($parent-context, 2), 'selector'); + $parent-context: contexts.get(vars.$context-id, 'block'); + $parent-selector: map.get(list.nth($parent-context, 2), 'selector'); - //@if not functions.selector-suffix-match(&, $parent-selector) { - // @error 'An at-theme rule must be an immediate child of a block'; - //} + //@if not functions.selector-suffix-match(&, $parent-selector) { + // @error 'An at-theme rule must be an immediate child of a block'; + //} - $selector: functions.theme-selector($name, $names...); - $selector: selector-nest($selector, &); + $selector: functions.theme-selector($name, $names...); + $selector: selector.nest($selector, &); - $context: 'at-theme', ( - 'name': join($name, $names), - 'selector': $selector - ); + $context: 'at-theme', ( + 'name': list.join($name, $names), + 'selector': $selector + ); - @return $selector $context; + @return $selector $context; } diff --git a/src/bem/_validators.scss b/src/bem/_validators.scss index 042e15e..bc3c9b7 100644 --- a/src/bem/_validators.scss +++ b/src/bem/_validators.scss @@ -16,6 +16,9 @@ /// @access public //// +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:meta'; @use './vars'; @use '../functions'; @use '../contexts'; @@ -46,7 +49,7 @@ $validators: (); /// @param {string} $func-names - Other function names. /// @mixin add($func-name, $func-names...) { - $noop: add($func-name, $func-names...); + $noop: add($func-name, $func-names...); } /// @@ -55,11 +58,11 @@ $validators: (); /// @see {mixin} add /// @function add($func-name, $func-names...) { - @each $fn-name in join($func-name, $func-names) { - $fn: get-function($fn-name); - $validators: map-merge($validators, ($fn-name: $fn)); - } - @return null; + @each $fn-name in list.join($func-name, $func-names) { + $fn: meta.get-function($fn-name); + $validators: map.merge($validators, ($fn-name: $fn)); + } + @return null; } /// @@ -69,7 +72,7 @@ $validators: (); /// @param {string} $func-names - Other function names. /// @mixin remove($func-name, $func-names...) { - $noop: remove($func-name, $func-names...); + $noop: remove($func-name, $func-names...); } /// @@ -78,20 +81,20 @@ $validators: (); /// @see {mixin} remove /// @function remove($func-name, $func-names...) { - $validators: map-remove($validators, $func-name, $func-names...); - @return null; + $validators: map.remove($validators, $func-name, $func-names...); + @return null; } /// /// @access private /// @mixin validate($type, $args, $selector, $context) { - @each $id, $fn in $validators { - $result: call($fn, $type, $args, $selector, $context); - @if not nth($result, 1) { - @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; - } - } + @each $id, $fn in $validators { + $result: meta.call($fn, $type, $args, $selector, $context); + @if not list.nth($result, 1) { + @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; + } + } } // @@ -105,76 +108,76 @@ $validators: (); /// namespace used. /// @function enforce-namespace-order($type, $args, $selector, $context) { - @if not global-variable-exists(namespace-order, vars) { - vars.$namespace-order: map-keys(vars.$namespaces); - } - @if not global-variable-exists(cur-namespace-index, vars) { - vars.$cur-namespace-index: 1; - } - - @if $type == 'block' { - $block-type: map-get($args, 'type'); - - @if $block-type != null { - $ns-index: index(vars.$namespace-order, $block-type); - - @if $ns-index != null { - @if $ns-index < vars.$cur-namespace-index { - @return false 'Namespace "#{$block-type}" comes before current namespace #{nth(vars.$namespace-order, vars.$cur-namespace-index)}'; - } - - vars.$cur-namespace-index: $ns-index; - } - } - } - - @return true ''; + @if not meta.global-variable-exists(namespace-order, vars) { + vars.$namespace-order: map.keys(vars.$namespaces); + } + @if not meta.global-variable-exists(cur-namespace-index, vars) { + vars.$cur-namespace-index: 1; + } + + @if $type == 'block' { + $block-type: map.get($args, 'type'); + + @if $block-type != null { + $ns-index: list.index(vars.$namespace-order, $block-type); + + @if $ns-index != null { + @if $ns-index < vars.$cur-namespace-index { + @return false 'Namespace "#{$block-type}" comes before current namespace #{nth(vars.$namespace-order, vars.$cur-namespace-index)}'; + } + + vars.$cur-namespace-index: $ns-index; + } + } + } + + @return true ''; } /// /// A validator that makes all BEM entities immutable. /// @function immutable-entities($type, $args, $selector, $context) { - @if not global-variable-exists(generated-selectors, vars) { - vars.$generated-selectors: (); - } - - $block-name: null; - $block-type: null; - $block-id: null; - - @if $type == 'block' { - $block-name: map-get($args, 'name'); - $block-type: map-get($args, 'type'); - } @else { - $block-context: contexts.get(vars.$context-id, 'block'); - $block-name: map-get(nth($block-context, 2), 'name'); - $block-type: map-get(nth($block-context, 2), 'type'); - } - - @if $block-type != null { - $block-id: $block-name + '_' + $block-type; - } @else { - $block-id: $block-name; - } - - @if $type == 'block' { - @if map-has-key(vars.$generated-selectors, $block-id) { - @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; - } - - vars.$generated-selectors: map-merge(vars.$generated-selectors, ($block-id: ())); - } @else { - $selectors: map-get(vars.$generated-selectors, $block-id); - - @if index($selectors, $selector) { - @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; - } - - $selectors: append($selectors, $selector); - - vars.$generated-selectors: map-merge(vars.$generated-selectors, ($block-id: $selectors)); - } - - @return true ''; + @if not meta.global-variable-exists(generated-selectors, vars) { + vars.$generated-selectors: (); + } + + $block-name: null; + $block-type: null; + $block-id: null; + + @if $type == 'block' { + $block-name: map.get($args, 'name'); + $block-type: map.get($args, 'type'); + } @else { + $block-context: contexts.get(vars.$context-id, 'block'); + $block-name: map.get(list.nth($block-context, 2), 'name'); + $block-type: map.get(list.nth($block-context, 2), 'type'); + } + + @if $block-type != null { + $block-id: $block-name + '_' + $block-type; + } @else { + $block-id: $block-name; + } + + @if $type == 'block' { + @if map.has-key(vars.$generated-selectors, $block-id) { + @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; + } + + vars.$generated-selectors: map.merge(vars.$generated-selectors, ($block-id: ())); + } @else { + $selectors: map.get(vars.$generated-selectors, $block-id); + + @if list.index($selectors, $selector) { + @return false 'Entity "#{$type}" with arguments [ #{functions.map-print($args)} ] was already defined.'; + } + + $selectors: list.append($selectors, $selector); + + vars.$generated-selectors: map.merge(vars.$generated-selectors, ($block-id: $selectors)); + } + + @return true ''; } diff --git a/src/bem/_vars.scss b/src/bem/_vars.scss index 3d0f92a..823bf0a 100644 --- a/src/bem/_vars.scss +++ b/src/bem/_vars.scss @@ -41,15 +41,15 @@ $suffix-separator: '\\@' !default; /// @type map /// $namespaces: ( - object: 'o', - component: 'c', - layout: 'l', - scope: 's', - theme: 't', - utility: 'u', - js: 'js', - qa: 'qa', - hack: '_' + object: 'o', + component: 'c', + layout: 'l', + scope: 's', + theme: 't', + utility: 'u', + js: 'js', + qa: 'qa', + hack: '_' ) !default; /// @@ -100,9 +100,9 @@ $debug: false !default; /// @type map /// $debug-colors: ( - object: #ffa500, - component: #00f, - layout: #ff0, - utility: #008000, - hack: #f00 + object: #ffa500, + component: #00f, + layout: #ff0, + utility: #008000, + hack: #f00 ) !default; -- cgit v1.2.3-70-g09d2