Skip to content

Commit e3198ca

Browse files
committed
[fix] Make BEM more robust
1 parent a83ced2 commit e3198ca

File tree

2 files changed

+100
-95
lines changed

2 files changed

+100
-95
lines changed

src/mixins/function.scss

Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,34 @@
22

33
/* BEM support Func
44
-------------------------- */
5-
@function selectorToString($selector) {
6-
$selector: inspect($selector);
7-
$selector: str-slice($selector, 2, -2);
85

9-
@return $selector;
10-
}
11-
12-
@function containsModifier($selector) {
13-
$selector: selectorToString($selector);
14-
15-
@if str-index($selector, $modifier-separator) {
16-
@return true;
17-
} @else {
18-
@return false;
19-
}
20-
}
6+
/// See [Combinators](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#Combinators "CSS selectors")
7+
$_selector-combinators: ("+", "~", ">", "||");
218

22-
@function containWhenFlag($selector) {
23-
$selector: selectorToString($selector);
9+
@function bem-extend($selectors, $extendee, $extender) {
10+
$returns: ();
2411

25-
@if str-index($selector, '.' + $state-prefix) {
26-
@return true;
27-
} @else {
28-
@return false;
12+
@if null == $selectors {
13+
$selectors: selector-parse("");
2914
}
30-
}
3115

32-
@function containPseudoClass($selector) {
33-
$selector: selectorToString($selector);
34-
35-
@if str-index($selector, ':') {
36-
@return true;
37-
} @else {
38-
@return false;
16+
@each $selector in $selectors {
17+
$len: length($selector);
18+
19+
@if nth($selector, $len) == $extendee {
20+
@if $len >= 2 {
21+
@if index($_selector-combinators, nth($selector, $len - 1)) == null {
22+
$returns: append($returns, set-nth($selector, $len, $extender), "comma");
23+
} @else {
24+
$returns: append($returns, append($selector, $extender), "comma");
25+
}
26+
} @else {
27+
$returns: append($returns, ($extender), "comma");
28+
}
29+
} @else {
30+
$returns: append($returns, append($selector, $extender), "comma");
31+
}
3932
}
40-
}
4133

42-
@function hitAllSpecialNestRule($selector) {
43-
@return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);
34+
@return $returns;
4435
}

src/mixins/mixins.scss

Lines changed: 77 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -67,98 +67,112 @@
6767

6868
/* BEM
6969
-------------------------- */
70+
71+
$_BEM: (null, null, null);
72+
7073
@mixin b($block) {
71-
$B: $namespace+'-'+$block !global;
74+
$lastBEM: $_BEM;
75+
$_BEM: ($block, null, null) !global;
7276

73-
.#{$B} {
77+
.#{$namespace}-#{$block} {
7478
@content;
7579
}
80+
81+
$_BEM: $lastBEM !global;
7682
}
7783

78-
@mixin e($element) {
79-
$E: $element !global;
80-
$selector: &;
81-
$currentSelector: "";
82-
@each $unit in $element {
83-
$currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
84-
}
84+
@mixin e($elements) {
85+
$block: nth($_BEM, 1);
8586

86-
@if hitAllSpecialNestRule($selector) {
87-
@at-root {
88-
#{$selector} {
89-
#{$currentSelector} {
90-
@content;
87+
@if null == $block {
88+
@error "Base-level rules cannot contain an element mixin";
89+
} @else {
90+
$selects: &;
91+
$old-elems: nth($_BEM, 2);
92+
93+
@if (null != $old-elems) {
94+
$selects: ();
95+
96+
@each $old-select in & {
97+
@each $old-element in $old-elems {
98+
$old-bem: ".#{$namespace}-#{$block}#{$element-separator}#{$old-element}";
99+
$old-len: length($old-select);
100+
101+
@if nth($old-select, $old-len) == $old-bem {
102+
$selects: append($selects, set-nth($old-select, $old-len, ".#{$namespace}-#{$block}"), "comma", );
103+
} @else {
104+
$selects: append($selects, $old-select, "comma", );
105+
}
91106
}
92107
}
93108
}
94-
} @else {
109+
110+
$lastBEM: $_BEM;
111+
$_BEM: ($block, $elements, null) !global;
112+
113+
$parent: ".#{$namespace}-#{$block}";
114+
$current: ();
115+
116+
@each $element in $elements {
117+
$current: append(
118+
$current,
119+
bem-extend($selects, $parent, "#{$parent}#{$element-separator}#{$element}"),
120+
"comma",
121+
);
122+
}
123+
95124
@at-root {
96-
#{$currentSelector} {
125+
#{$current} {
97126
@content;
98127
}
99128
}
100-
}
101-
}
102-
103-
@mixin m($modifier) {
104-
$selector: &;
105-
$currentSelector: "";
106-
@each $unit in $modifier {
107-
$currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
108-
}
109129

110-
@at-root {
111-
#{$currentSelector} {
112-
@content;
113-
}
130+
$_BEM: $lastBEM !global;
114131
}
115132
}
116133

117-
@mixin configurable-m($modifier, $E-flag: false) {
118-
$selector: &;
119-
$interpolation: '';
134+
@mixin m($modifiers) {
135+
$block: nth($_BEM, 1);
120136

121-
@if $E-flag {
122-
$interpolation: $element-separator + $E-flag;
123-
}
137+
@if null == $block {
138+
@error "Base-level rules cannot contain a modifier mixin";
139+
} @else if null != nth($_BEM, 3) {
140+
@error "Modifier-level rules cannot contain another modifier mixin";
141+
} @else {
142+
$elements: nth($_BEM, 2);
124143

125-
@at-root {
126-
#{$selector} {
127-
.#{$B+$interpolation+$modifier-separator+$modifier} {
128-
@content;
129-
}
144+
@if (null == $elements) {
145+
$elements: (null);
130146
}
131-
}
132-
}
133147

134-
@mixin spec-selector($specSelector: '', $element: $E, $modifier: false, $block: $B) {
135-
$modifierCombo: '';
148+
$lastBEM: $_BEM;
149+
$_BEM: ($block, $elements, $modifiers) !global;
136150

137-
@if $modifier {
138-
$modifierCombo: $modifier-separator + $modifier;
139-
}
151+
@each $element in $elements {
152+
$parent: ".#{$namespace}-#{$block}";
140153

141-
@at-root {
142-
#{&}#{$specSelector}.#{$block+$element-separator+$element+$modifierCombo} {
143-
@content;
144-
}
145-
}
146-
}
154+
@if (null != $element) {
155+
$parent: "#{$parent}#{$element-separator}#{$element}";
156+
}
147157

148-
@mixin meb($modifier: false, $element: $E, $block: $B) {
149-
$selector: &;
150-
$modifierCombo: '';
158+
$current: ();
151159

152-
@if $modifier {
153-
$modifierCombo: $modifier-separator + $modifier;
154-
}
160+
@each $modifier in $modifiers {
161+
$current: append(
162+
$current,
163+
bem-extend(&, $parent, "#{$parent}#{$modifier-separator}#{$modifier}"),
164+
"comma",
165+
);
166+
}
155167

156-
@at-root {
157-
#{$selector} {
158-
.#{$block+$element-separator+$element+$modifierCombo} {
159-
@content;
168+
@at-root {
169+
#{$current} {
170+
@content;
171+
}
160172
}
161173
}
174+
175+
$_BEM: $lastBEM !global;
162176
}
163177
}
164178

0 commit comments

Comments
 (0)