From 499689c9a5fe70caa9f0c99794e28e8ea495b92e Mon Sep 17 00:00:00 2001 From: Zura Gabievi Date: Sun, 4 Dec 2016 22:42:04 +0400 Subject: [PATCH] Documentation update and new feature for relationship --- .editorconfig | 11 + .gitignore | 16 +- README.md | 2 +- bower.json | 2 +- functions/_bem-index.scss | 63 ++- functions/_explode.scss | 43 +- functions/_get-block.scss | 19 +- functions/_has-pseudo.scss | 4 +- functions/_has-state.scss | 12 +- functions/_implode.scss | 33 +- functions/_is-block.scss | 2 +- functions/_is-element.scss | 7 +- functions/_is-modifier.scss | 7 +- functions/_math-min.scss | 45 +- functions/_splice.scss | 30 +- functions/_str-replace.scss | 17 +- gulpfile.js | 31 ++ helpers/_block-selector.scss | 6 +- helpers/_component-selector.scss | 6 +- helpers/_element-selector.scss | 78 ++-- helpers/_hack-selector.scss | 6 +- helpers/_modifier-selector.scss | 30 +- helpers/_object-selector.scss | 6 +- helpers/_pseudo-selector.scss | 14 +- helpers/_relations-selector.scss | 54 ++- helpers/_scope-selector.scss | 6 +- helpers/_state-selector.scss | 24 +- helpers/_states-selector.scss | 21 +- helpers/_test-selector.scss | 6 +- helpers/_theme-selector.scss | 6 +- helpers/_utility-selector.scss | 6 +- mixins/_block.scss | 22 +- mixins/_component.scss | 24 +- mixins/_element.scss | 54 ++- mixins/_hack.scss | 24 +- mixins/_modifier.scss | 14 +- mixins/_object.scss | 22 +- mixins/_parse.scss | 154 +++---- mixins/_pseudo.scss | 38 +- mixins/_relations.scss | 60 ++- mixins/_scope.scss | 22 +- mixins/_state.scss | 38 +- mixins/_states.scss | 60 +-- mixins/_test.scss | 22 +- mixins/_theme.scss | 22 +- mixins/_utility.scss | 22 +- package.json | 18 +- test/_functions.scss | 108 +++++ test/_helpers.scss | 45 ++ test/_mixins.scss | 737 +++++++++++++++++++++++++++++++ test/test.scss | 10 + test/test_sass.js | 5 + test/true.yml | 2 + 53 files changed, 1538 insertions(+), 598 deletions(-) create mode 100644 .editorconfig create mode 100644 gulpfile.js create mode 100644 test/_functions.scss create mode 100644 test/_helpers.scss create mode 100644 test/_mixins.scss create mode 100644 test/test.scss create mode 100644 test/test_sass.js create mode 100644 test/true.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8bd90a1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.scss] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index 721f29a..20af8bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,14 @@ -.idea -.sass-cache -.sassdocrc - -node_modules -sassdoc +.idea/ +.sass-cache/ +test/.sass-cache/ +node_modules/ +gh-pages/ +coverage/ +**/.DS_Store +.sassdocrc /style.scss /style.css *.map + +yarn.lock diff --git a/README.md b/README.md index 5d70221..b1ca635 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # sass-bem -> **Important!** Changed `with` mixin and it will now get siblings with `~` sign. If you want to get first sibling with `+` sign, you can use `next` mixin. +> **Please upgrade to version 2.6.0**, we have some great features. Thanks to @szalonna and @MartinN3 resolved issue in documentation and updated some mixins. [![Bower](https://img.shields.io/bower/v/zgabievi/sass-bem.svg?style=flat-square)](http://bower.io/search/?q=sass-bem) [![NPM](https://img.shields.io/npm/v/sass-bem.svg?style=flat-square)](https://www.npmjs.com/package/sass-bem) diff --git a/bower.json b/bower.json index 1cddbd6..568b6ce 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "sass-bem", - "version": "2.5.3", + "version": "2.6.0", "main": "_bem.scss", "description": "Amazing package for sass to write bem classes, with namespaces and more advanced features.", "authors": [ diff --git a/functions/_bem-index.scss b/functions/_bem-index.scss index 0f53f25..6e8e5cf 100644 --- a/functions/_bem-index.scss +++ b/functions/_bem-index.scss @@ -9,39 +9,32 @@ /// @returns {Number} - Index of separators @function bem-index($string) { - $e_index: null; - $m_index: null; - - // - @if (str-index($string, unquote("#{$bem-element-separator}")) != null) { - $e_index: str-index($string, unquote("#{$bem-element-separator}")); - } - - // - @if (str-index($string, unquote("#{$bem-modifier-separator}")) != null) { - $m_index: str-index($string, unquote("#{$bem-modifier-separator}")); - } - - // - @if (str-index($string, ".is") != null) { - $m_index: str-index($string, ".is"); - } - - // - @if (str-index($string, ".js") != null) { - $m_index: str-index($string, ".js"); - } - - // - @if (str-index($string, ".has") != null) { - $m_index: str-index($string, ".has"); - } - - // - @if (str-index($string, ":") != null) { - $m_index: str-index($string, ":"); - } - - // - @return math-min($e_index, $m_index, 0); + $e_index: null; + $m_index: null; + + @if (str-index($string, unquote("#{$bem-element-separator}")) != null) { + $e_index: str-index($string, unquote("#{$bem-element-separator}")); + } + + @if (str-index($string, unquote("#{$bem-modifier-separator}")) != null) { + $m_index: str-index($string, unquote("#{$bem-modifier-separator}")); + } + + @if (str-index($string, ".is") != null) { + $m_index: str-index($string, ".is"); + } + + @if (str-index($string, ".js") != null) { + $m_index: str-index($string, ".js"); + } + + @if (str-index($string, ".has") != null) { + $m_index: str-index($string, ".has"); + } + + @if (str-index($string, ":") != null) { + $m_index: str-index($string, ":"); + } + + @return math-min($e_index, $m_index, 0); } diff --git a/functions/_explode.scss b/functions/_explode.scss index 76e740f..2e2b288 100644 --- a/functions/_explode.scss +++ b/functions/_explode.scss @@ -10,26 +10,23 @@ /// @returns {List} - List of exploded string @function explode($string, $separator) { - $list: (); - $length: str-length($string); - - // - @for $i from 1 through $length { - $index: str-index($string, $separator); - - // - @if str-length($string) >= 1 and $index == null { - $list: append($list, $string); - $string: ''; - } - - // - @if type-of($index) == number { - $each: str-slice($string, 0, ($index - 1)); - $list: append($list, $each); - $string: str-slice($string, ($index + 1), $length); - } - } - - @return $list; -} \ No newline at end of file + $list: (); + $length: str-length($string); + + @for $i from 1 through $length { + $index: str-index($string, $separator); + + @if str-length($string) >= 1 and $index == null { + $list: append($list, $string); + $string: ''; + } + + @if type-of($index) == number { + $each: str-slice($string, 0, ($index - 1)); + $list: append($list, $each); + $string: str-slice($string, ($index + 1), $length); + } + } + + @return $list; +} diff --git a/functions/_get-block.scss b/functions/_get-block.scss index ed88545..796173b 100644 --- a/functions/_get-block.scss +++ b/functions/_get-block.scss @@ -9,14 +9,11 @@ /// @returns {String} - Block element @function get-block($selector) { - $block: str-slice($selector, 2, bem-index($selector) - 1); - - // - @while (is-block($block) == false) { - - // - $block: str-slice($block, 0, bem-index($block) - 1); - } - - @return $block; -} \ No newline at end of file + $block: str-slice($selector, 2, bem-index($selector) - 1); + + @while (is-block($block) == false) { + $block: str-slice($block, 0, bem-index($block) - 1); + } + + @return $block; +} diff --git a/functions/_has-pseudo.scss b/functions/_has-pseudo.scss index 8188010..354a811 100644 --- a/functions/_has-pseudo.scss +++ b/functions/_has-pseudo.scss @@ -9,5 +9,5 @@ /// @returns {Boolean} @function has-pseudo($selector) { - @return str-index($selector, ":") != null; -} \ No newline at end of file + @return str-index($selector, ":") != null; +} diff --git a/functions/_has-state.scss b/functions/_has-state.scss index 7d04aec..57f4666 100644 --- a/functions/_has-state.scss +++ b/functions/_has-state.scss @@ -9,9 +9,9 @@ /// @returns {Boolean} @function has-state($selector) { - $separator_is: unquote(".is#{$bem-state-separator}"); - $separator_js: unquote(".js#{$bem-state-separator}"); - $separator_has: unquote(".has#{$bem-state-separator}"); - - @return str-index($selector, $separator_is) != null or str-index($selector, $separator_js) != null or str-index($selector, $separator_has) != null; -} \ No newline at end of file + $separator_is: unquote(".is#{$bem-state-separator}"); + $separator_js: unquote(".js#{$bem-state-separator}"); + $separator_has: unquote(".has#{$bem-state-separator}"); + + @return str-index($selector, $separator_is) != null or str-index($selector, $separator_js) != null or str-index($selector, $separator_has) != null; +} diff --git a/functions/_implode.scss b/functions/_implode.scss index 7871740..0c027e3 100644 --- a/functions/_implode.scss +++ b/functions/_implode.scss @@ -11,22 +11,17 @@ /// @returns {String} - Imploded list @function implode($list, $glue: '', $is-nested: false) { - $result: null; - - // - @for $i from 1 through length($list) { - $e: nth($list, $i); - - // - @if type-of($e) == list { - $result: unquote("#{$result}#{implode($e, $glue, true)}"); - } - - // - @else { - $result: if($i != length($list) or $is-nested, unquote("#{$result}#{$e}#{$glue}"), unquote("#{$result}#{$e}")); - } - } - - @return $result; -} \ No newline at end of file + $result: null; + + @for $i from 1 through length($list) { + $e: nth($list, $i); + + @if type-of($e) == list { + $result: unquote("#{$result}#{implode($e, $glue, true)}"); + } @else { + $result: if($i != length($list) or $is-nested, unquote("#{$result}#{$e}#{$glue}"), unquote("#{$result}#{$e}")); + } + } + + @return $result; +} diff --git a/functions/_is-block.scss b/functions/_is-block.scss index c8ed5be..ecb2081 100644 --- a/functions/_is-block.scss +++ b/functions/_is-block.scss @@ -9,5 +9,5 @@ /// @returns {Boolean} @function is-block($selector) { - @return (not is-element($selector) and not is-modifier($selector) and not has-state($selector) and not has-pseudo($selector)); + @return not is-element($selector) and not is-modifier($selector) and not has-state($selector) and not has-pseudo($selector); } diff --git a/functions/_is-element.scss b/functions/_is-element.scss index 4ac8ee7..885e01d 100644 --- a/functions/_is-element.scss +++ b/functions/_is-element.scss @@ -9,6 +9,7 @@ /// @returns {Boolean} @function is-element($selector) { - $separator: unquote("#{$bem-element-separator}"); - @return str-index($selector, $separator) != null; -} \ No newline at end of file + $separator: unquote("#{$bem-element-separator}"); + + @return str-index($selector, $separator) != null; +} diff --git a/functions/_is-modifier.scss b/functions/_is-modifier.scss index b961146..209365a 100644 --- a/functions/_is-modifier.scss +++ b/functions/_is-modifier.scss @@ -9,6 +9,7 @@ /// @returns {Boolean} @function is-modifier($selector) { - $separator: unquote("#{$bem-modifier-separator}"); - @return str-index($selector, $separator) != null; -} \ No newline at end of file + $separator: unquote("#{$bem-modifier-separator}"); + + @return str-index($selector, $separator) != null; +} diff --git a/functions/_math-min.scss b/functions/_math-min.scss index 8ffc482..aefcbb2 100644 --- a/functions/_math-min.scss +++ b/functions/_math-min.scss @@ -6,31 +6,26 @@ /// /// @param {String} $a - First number to be checked /// @param {String} $n - Second number to be checked -/// @param {String} $default - Default number to be returned if min wasn't found +/// @param {String} $default [0] - Default number to be returned if min wasn't found /// /// @returns {Number} - Minimum number from two of them -@function math-min($a, $b, $default) { - $min: $default; - - // - @if ($a == null) { - - // - @if ($b != null) { - $min: $b; - } - } @else if ($b == null) { - $min: $a; - } @else { - - // - @if ($a <= $b) { - $min: $a; - } @else { - $min: $b; - } - } - - @return $min; -} \ No newline at end of file +@function math-min($a, $b, $default: 0) { + $min: $default; + + @if ($a == null) { + @if ($b != null) { + $min: $b; + } + } @else if ($b == null) { + $min: $a; + } @else { + @if ($a <= $b) { + $min: $a; + } @else { + $min: $b; + } + } + + @return $min; +} diff --git a/functions/_splice.scss b/functions/_splice.scss index ec905f5..a72ae91 100644 --- a/functions/_splice.scss +++ b/functions/_splice.scss @@ -11,21 +11,15 @@ /// @returns {List} @function splice($list, $value, $recursive: false) { - $result: (); - - // - @for $i from 1 through length($list) { - - // - @if type-of(nth($list, $i)) == list and $recursive { - $result: append($result, remove(nth($list, $i), $value, $recursive)); - } - - // - @else if nth($list, $i) != $value { - $result: append($result, nth($list, $i)); - } - } - - @return $result; -} \ No newline at end of file + $result: (); + + @for $i from 1 through length($list) { + @if type-of(nth($list, $i)) == list and $recursive { + $result: append($result, remove(nth($list, $i), $value, $recursive)); + } @else if nth($list, $i) != $value { + $result: append($result, nth($list, $i)); + } + } + + @return $result; +} diff --git a/functions/_str-replace.scss b/functions/_str-replace.scss index daf400c..f288c52 100644 --- a/functions/_str-replace.scss +++ b/functions/_str-replace.scss @@ -11,12 +11,11 @@ /// @returns {String} @function str-replace($string, $search, $replace: '') { - $index: str-index($string, $search); - - // - @if $index { - @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); - } - - @return $string; -} \ No newline at end of file + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..16aafc5 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,31 @@ +const gulp = require('gulp'); +const sassdoc = require('sassdoc'); +const mocha = require('gulp-mocha'); + +gulp.task('default', () => + gulp.src('./test/test_sass.js') + .pipe(mocha()) + .once('error', () => { + process.exit(1); + }) + .once('end', () => { + process.exit(); + }) +); + +gulp.task('sassdoc', () => { + return gulp.src(['_config.scss', '_bem.scss', './mixins/**.scss', './helpers/**.scss', './functions/*.scss']) + .pipe(sassdoc({ + dest: 'gh-pages', + verbose: true, + display: { + access: ['public', 'private'], + alias: true, + watermark: true, + }, + groups: { + 'undefined': 'sass-bem' + }, + basePath: 'http://zgabievi.me/sass-bem/', + })) +}); diff --git a/helpers/_block-selector.scss b/helpers/_block-selector.scss index fbd2795..2e6e157 100644 --- a/helpers/_block-selector.scss +++ b/helpers/_block-selector.scss @@ -11,11 +11,11 @@ /// @see {mixin} block @function block-selector($block) { - @return unquote(".#{$block}"); + @return unquote(".#{$block}"); } /// @alias block-selector @function b-selector($block) { - @return block-selector($block); -} \ No newline at end of file + @return block-selector($block); +} diff --git a/helpers/_component-selector.scss b/helpers/_component-selector.scss index 5fc5d68..cd69787 100644 --- a/helpers/_component-selector.scss +++ b/helpers/_component-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} component @function component-selector($component, $namespace) { - @return unquote(".#{$namespace}-#{$component}"); + @return unquote(".#{$namespace}-#{$component}"); } /// @alias component-selector @function c-selector($component) { - @return component-selector($component); -} \ No newline at end of file + @return component-selector($component); +} diff --git a/helpers/_element-selector.scss b/helpers/_element-selector.scss index b103766..335f2af 100644 --- a/helpers/_element-selector.scss +++ b/helpers/_element-selector.scss @@ -12,58 +12,48 @@ /// @see {mixin} element @function element-selector($element, $nested: false) { - $selector: ''; - $parent: unquote("#{&}"); - - // - @if ($nested == true) { - $selector: unquote("&#{$bem-element-separator}#{$element}"); - } - - // - @else { - - // - @if (is-block($parent)) { - $selector: unquote("&#{$bem-element-separator}#{$element}"); - } @else { - $block: get-block($parent); - $selector: unquote("& .#{$block}#{$bem-element-separator}#{$element}"); - } - - // - @if (type-of($element) == 'list') { - $selector: (); - - // - @each $value in $element { - $current: ''; - - // - @if (is-block($parent)) { - $current: unquote("&#{$bem-element-separator}#{$value}"); - } @else { - $block: get-block($parent); - $current: unquote("& .#{$block}#{$bem-element-separator}#{$value}"); - } - - // - $selector: append($selector, $current, comma); - } - } - } - - @return $selector; + $selector: ''; + $parent: unquote("#{&}"); + + @if ($nested == true) { + $selector: unquote("&#{$bem-element-separator}#{$element}"); + } @else { + @if (is-block($parent)) { + $selector: unquote("&#{$bem-element-separator}#{$element}"); + } @else { + $block: get-block($parent); + $selector: unquote("& .#{$block}#{$bem-element-separator}#{$element}"); + } + + @if (type-of($element) == 'list') { + $selector: (); + + @each $value in $element { + $current: ''; + + @if (is-block($parent)) { + $current: unquote("&#{$bem-element-separator}#{$value}"); + } @else { + $block: get-block($parent); + $current: unquote("& .#{$block}#{$bem-element-separator}#{$value}"); + } + + $selector: append($selector, $current, comma); + } + } + } + + @return $selector; } /// @alias element-selector @function e-selector($element) { - @return element-selector($element); + @return element-selector($element); } /// @alias element-selector @function ee-selector($element) { - @return element-selector($element, true); + @return element-selector($element, true); } diff --git a/helpers/_hack-selector.scss b/helpers/_hack-selector.scss index 29d37ac..5a7c12d 100644 --- a/helpers/_hack-selector.scss +++ b/helpers/_hack-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} hack @function hack-selector($hack, $namespace) { - @return unquote(".#{$namespace}#{$hack}"); + @return unquote(".#{$namespace}#{$hack}"); } /// @alias hack-selector @function _-selector($hack) { - @return hack-selector($hack, '_'); -} \ No newline at end of file + @return hack-selector($hack, '_'); +} diff --git a/helpers/_modifier-selector.scss b/helpers/_modifier-selector.scss index d922418..63d6a45 100644 --- a/helpers/_modifier-selector.scss +++ b/helpers/_modifier-selector.scss @@ -11,24 +11,22 @@ /// @see {mixin} modifier @function modifier-selector($modifier) { - $selector: unquote("&#{$bem-modifier-separator}#{$modifier}"); - - // - @if (type-of($modifier) == 'list') { - $selector: (); - - // - @each $value in $modifier { - $current: unquote("&#{$bem-modifier-separator}#{$value}"); - $selector: append($selector, $current, comma); - } - } - - @return $selector; + $selector: unquote("&#{$bem-modifier-separator}#{$modifier}"); + + @if (type-of($modifier) == 'list') { + $selector: (); + + @each $value in $modifier { + $current: unquote("&#{$bem-modifier-separator}#{$value}"); + $selector: append($selector, $current, comma); + } + } + + @return $selector; } /// @alias modifier-selector @function m-selector($modifier) { - @return modifier-selector($modifier); -} \ No newline at end of file + @return modifier-selector($modifier); +} diff --git a/helpers/_object-selector.scss b/helpers/_object-selector.scss index d5acdb8..1e0a943 100644 --- a/helpers/_object-selector.scss +++ b/helpers/_object-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} object @function object-selector($object, $namespace) { - @return unquote(".#{$namespace}-#{$object}"); + @return unquote(".#{$namespace}-#{$object}"); } /// @alias object-selector @function o-selector($object) { - @return object-selector($object); -} \ No newline at end of file + @return object-selector($object); +} diff --git a/helpers/_pseudo-selector.scss b/helpers/_pseudo-selector.scss index 91bc90c..3f1f40b 100644 --- a/helpers/_pseudo-selector.scss +++ b/helpers/_pseudo-selector.scss @@ -9,7 +9,7 @@ /// @see {mixin} first @function first-selector() { - @return unquote("&:first-of-type"); + @return unquote("&:first-of-type"); } /// Pseudo selector with end of last-of-type. @@ -21,7 +21,7 @@ /// @see {mixin} last @function last-selector() { - @return unquote("&:last-of-type"); + @return unquote("&:last-of-type"); } /// Pseudo selector with end of nth-child(even). @@ -33,7 +33,7 @@ /// @see {mixin} even @function even-selector() { - @return unquote("&:nth-child(even)"); + @return unquote("&:nth-child(even)"); } /// Pseudo selector with end of nth-child(odd). @@ -45,7 +45,7 @@ /// @see {mixin} odd @function odd-selector() { - @return unquote("&:nth-child(odd)"); + @return unquote("&:nth-child(odd)"); } /// Pseudo selector with end of before. @@ -57,7 +57,7 @@ /// @see {mixin} before @function before-selector() { - @return unquote("&::before"); + @return unquote("&::before"); } /// Pseudo selector with end of after. @@ -69,5 +69,5 @@ /// @see {mixin} after @function after-selector() { - @return unquote("&::after"); -} \ No newline at end of file + @return unquote("&::after"); +} diff --git a/helpers/_relations-selector.scss b/helpers/_relations-selector.scss index 4d2a5e9..ef5929a 100644 --- a/helpers/_relations-selector.scss +++ b/helpers/_relations-selector.scss @@ -1,17 +1,22 @@ @charset "UTF-8"; -/// Selector of at relationship. +/// Selector(s) of at relationship. /// -/// @param {String} $modifier - Name of modifier that will come after ".[block]--" +/// @param {String} $modifier - List of modifier that will come after ".[block]--" /// /// @returns {String} - .[block]--[modifier] /// /// @see {mixin} at -@function at-selector($modifier) { - $block: get-block(unquote("#{&}")); - - @return unquote(".#{$block}#{$bem-modifier-separator}#{$modifier} &"); +@function at-selector($modifiers...) { + $block: get-block(unquote("#{&}")); + $classes: (); + + @each $modifier in $modifiers { + $classes: append($classes, unquote(".#{$block}#{$bem-modifier-separator}#{$modifier}")); + } + + @return unquote("#{implode($classes)} &"); } /// Selector of adjacent relationship. @@ -23,9 +28,9 @@ /// @see {mixin} next @function next-selector($element) { - $block: get-block(unquote("#{&}")); - - @return unquote("& + .#{$block}#{$bem-element-separator}#{$element}"); + $block: get-block(unquote("#{&}")); + + @return unquote("& + .#{$block}#{$bem-element-separator}#{$element}"); } /// Selector of duo relationship. @@ -34,11 +39,16 @@ /// /// @see {mixin} duo -@function duo-selector() { - $list: explode(unquote("#{&}"), ' '); - $last: nth($list, length($list)); - - @return unquote("& + #{$last}"); +@function duo-selector($debug: false) { + $list: explode(unquote("#{&}"), ' '); + + @if ($debug == true and length($list) == 0) { + $list: ('&'); + } + + $last: nth($list, length($list)); + + @return unquote("& + #{$last}"); } /// Selector of sibling relationship. @@ -50,21 +60,21 @@ /// @see {mixin} with @function with-selector($element) { - $block: get-block(unquote("#{&}")); - - @return unquote("& ~ .#{$block}#{$bem-element-separator}#{$element}"); + $block: get-block(unquote("#{&}")); + + @return unquote("& ~ .#{$block}#{$bem-element-separator}#{$element}"); } -/// Selector of while relationship. +/// Selector(s) of while relationship. /// -/// @param {String} $modifier - Name of modifier that will come after ".[block]--" +/// @param {String} $modifier - List of modifiers that will come after ".[block]--" /// /// @returns {String} - .[block]--[modifier] /// /// @see {mixin} while @function while-selector($modifier) { - $block: get-block(unquote("#{&}")); - - @return unquote("&.#{$block}#{$bem-modifier-separator}#{$modifier}"); + $block: get-block(unquote("#{&}")); + + @return unquote("&.#{$block}#{$bem-modifier-separator}#{$modifier}"); } diff --git a/helpers/_scope-selector.scss b/helpers/_scope-selector.scss index 9df5a8e..22038c3 100644 --- a/helpers/_scope-selector.scss +++ b/helpers/_scope-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} scope @function scope-selector($scope, $namespace) { - @return unquote(".#{$namespace}-#{$scope}"); + @return unquote(".#{$namespace}-#{$scope}"); } /// @alias scope-selector @function s-selector($scope) { - @return scope-selector($scope); -} \ No newline at end of file + @return scope-selector($scope); +} diff --git a/helpers/_state-selector.scss b/helpers/_state-selector.scss index 1c80a5c..569a538 100644 --- a/helpers/_state-selector.scss +++ b/helpers/_state-selector.scss @@ -12,30 +12,30 @@ /// @see {mixin} state @function state-selector($state, $namespace: null) { - $selector: unquote("&.#{$state}"); - - // - @if $namespace != null { - $selector: unquote("&.#{$namespace}-#{$state}"); - } - - @return $selector; + $selector: unquote("&.#{$state}"); + + // + @if $namespace != null { + $selector: unquote("&.#{$namespace}-#{$state}"); + } + + @return $selector; } /// @alias state-selector @function is-selector($state) { - @return state-selector($state, 'is'); + @return state-selector($state, 'is'); } /// @alias state-selector @function has-selector($state) { - @return state-selector($state, 'has'); + @return state-selector($state, 'has'); } /// @alias state-selector @function js-selector($state) { - @return state-selector($state, 'js'); -} \ No newline at end of file + @return state-selector($state, 'js'); +} diff --git a/helpers/_states-selector.scss b/helpers/_states-selector.scss index 1cf7b44..9c2a52d 100644 --- a/helpers/_states-selector.scss +++ b/helpers/_states-selector.scss @@ -9,7 +9,7 @@ /// @see {mixin} hover @function hover-selector() { - @return unquote("&:hover"); + @return unquote("&:hover"); } /// Pseudo selector with end of focus. @@ -21,7 +21,7 @@ /// @see {mixin} focus @function focus-selector() { - @return unquote("&:focus"); + @return unquote("&:focus"); } /// Pseudo selector with end of active. @@ -33,7 +33,7 @@ /// @see {mixin} active @function active-selector() { - @return unquote("&:active"); + @return unquote("&:active"); } /// Pseudo selector with end of link. @@ -45,7 +45,7 @@ /// @see {mixin} link @function link-selector() { - @return unquote("&:link"); + @return unquote("&:link"); } /// Pseudo selector with end of visited. @@ -57,7 +57,7 @@ /// @see {mixin} visited @function visited-selector() { - @return unquote("&:visited"); + @return unquote("&:visited"); } /// Pseudo selector with end of checked. @@ -69,7 +69,7 @@ /// @see {mixin} checked @function checked-selector() { - @return unquote("&:checked"); + @return unquote("&:checked"); } /// Selector with state of disabled. @@ -81,7 +81,7 @@ /// @see {mixin} disabled @function disabled-selector() { - @return unquote("&[disabled]"); + @return unquote("&[disabled]"); } /// Selector with state of readonly. @@ -93,7 +93,7 @@ /// @see {mixin} readonly @function readonly-selector() { - @return unquote("&[readonly]"); + @return unquote("&[readonly]"); } /// Selector with state of contenteditable. @@ -105,12 +105,11 @@ /// @see {mixin} contenteditable @function contenteditable-selector() { - @return unquote("&[contenteditable='true']"); + @return unquote("&[contenteditable='true']"); } - /// @alias contenteditable-selector @function editable-selector() { - @return contenteditable-selector(); + @return contenteditable-selector(); } diff --git a/helpers/_test-selector.scss b/helpers/_test-selector.scss index 153344a..a9575aa 100644 --- a/helpers/_test-selector.scss +++ b/helpers/_test-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} test @function test-selector($test, $namespace) { - @return unquote(".#{$namespace}-#{$test}"); + @return unquote(".#{$namespace}-#{$test}"); } /// @alias test-selector @function qa-selector($test) { - @return test-selector($test); -} \ No newline at end of file + @return test-selector($test); +} diff --git a/helpers/_theme-selector.scss b/helpers/_theme-selector.scss index d29d922..e110497 100644 --- a/helpers/_theme-selector.scss +++ b/helpers/_theme-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} theme @function theme-selector($theme, $namespace) { - @return unquote(".#{$namespace}-#{$theme}"); + @return unquote(".#{$namespace}-#{$theme}"); } /// @alias theme-selector @function t-selector($theme) { - @return theme-selector($theme); -} \ No newline at end of file + @return theme-selector($theme); +} diff --git a/helpers/_utility-selector.scss b/helpers/_utility-selector.scss index 1094362..d9b3f74 100644 --- a/helpers/_utility-selector.scss +++ b/helpers/_utility-selector.scss @@ -12,11 +12,11 @@ /// @see {mixin} utility @function utility-selector($utility, $namespace) { - @return unquote(".#{$namespace}-#{$utility}"); + @return unquote(".#{$namespace}-#{$utility}"); } /// @alias utility-selector @function u-selector($utility) { - @return utility-selector($utility); -} \ No newline at end of file + @return utility-selector($utility); +} diff --git a/mixins/_block.scss b/mixins/_block.scss index 87d9730..65c4503 100644 --- a/mixins/_block.scss +++ b/mixins/_block.scss @@ -23,19 +23,19 @@ /// } @mixin block($block) { - #{block-selector($block)} { - @if $bem-debug == true { - outline: 5px solid #363863; - } - - @content; - } + #{block-selector($block)} { + @if $bem-debug == true { + outline: 5px solid #363863; + } + + @content; + } } /// @alias block @mixin b($block) { - @include block($block) { - @content; - } -} \ No newline at end of file + @include block($block) { + @content; + } +} diff --git a/mixins/_component.scss b/mixins/_component.scss index db849fb..1b66452 100644 --- a/mixins/_component.scss +++ b/mixins/_component.scss @@ -1,7 +1,7 @@ @charset "UTF-8"; /// Signify that something is a Component. This is a concrete, implementation-specific piece of UI. All of the changes you make to its styles should be detectable in the context you’re currently looking at. Modifying these styles should be safe and have no side effects. -/// +/// /// @param {String} $component - Name of component that will come after ".c-" /// @param {String} $namespace [null] - Component element namespace. /// @@ -24,19 +24,19 @@ /// } @mixin component($component, $namespace: $bem-component-namespace) { - #{component-selector($component, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #00b8a9; - } - - @content; - } + #{component-selector($component, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #00b8a9; + } + + @content; + } } /// @alias component @mixin c($component, $namespace: $bem-component-namespace) { - @include component($component, $namespace) { - @content; - } -} \ No newline at end of file + @include component($component, $namespace) { + @content; + } +} diff --git a/mixins/_element.scss b/mixins/_element.scss index a00041f..83e63c6 100644 --- a/mixins/_element.scss +++ b/mixins/_element.scss @@ -18,6 +18,20 @@ /// } /// } /// +/// @include b('list') { +/// @include e('item') { +/// @include ee('link') { +/// color: black; +/// } +/// } +/// } +/// +/// @include b('list') { +/// @include e(('item', 'link')) { +/// color: black; +/// } +/// } +/// /// @example css - Output /// .list__item { /// color: black; @@ -26,31 +40,39 @@ /// .list__item { /// color: black; /// } +/// +/// .list__item__link { +/// color: black; +/// } +/// +/// .list__item, .list__link { +/// color: black; +/// } @mixin element($element, $nested: false) { - @at-root { - #{element-selector($element, $nested)} { - @if $bem-debug == true { - outline: 5px solid #635270; - } - - @content; - } - } + @at-root { + #{element-selector($element, $nested)} { + @if $bem-debug == true { + outline: 5px solid #635270; + } + + @content; + } + } } /// @alias element @mixin e($element, $nested: false) { - @include element($element, $nested) { - @content; - } + @include element($element, $nested) { + @content; + } } /// @alias element @mixin ee($element) { - @include element($element, true) { - @content; - } -} \ No newline at end of file + @include element($element, true) { + @content; + } +} diff --git a/mixins/_hack.scss b/mixins/_hack.scss index 3cfc33a..4a4d1c1 100644 --- a/mixins/_hack.scss +++ b/mixins/_hack.scss @@ -1,7 +1,7 @@ @charset "UTF-8"; /// Signify that this class is the worst of the worst—a hack! Sometimes, although incredibly rarely, we need to add a class in our markup in order to force something to work. If we do this, we need to let others know that this class is less than ideal, and hopefully temporary (i.e. do not bind onto this). -/// +/// /// @param {String} $hack - Name of hack that will come after "._" /// @param {String} $namespace [null] - Hack element namespace. /// @@ -24,19 +24,19 @@ /// } @mixin hack($hack, $namespace: $bem-hack-namespace) { - #{hack-selector($hack, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #f33535; - } - - @content; - } + #{hack-selector($hack, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #f33535; + } + + @content; + } } /// @alias hack @mixin _($hack, $namespace: $bem-hack-namespace) { - @include hack($hack, $namespace) { - @content; - } -} \ No newline at end of file + @include hack($hack, $namespace) { + @content; + } +} diff --git a/mixins/_modifier.scss b/mixins/_modifier.scss index fe1d4b3..062c508 100644 --- a/mixins/_modifier.scss +++ b/mixins/_modifier.scss @@ -1,6 +1,6 @@ @charset "UTF-8"; -/// Modifier selector, that is generated from parent block +/// Modifier selector, that is generated from parent block. /// /// @param {String} $modifier - Name of modifier that will come after ".[block]--" /// @@ -17,6 +17,12 @@ /// } /// } /// +/// @include b('list') { +/// @include m(('inline', 'ordered')) { +/// color: black; +/// } +/// } +/// /// @example css - Output /// .list--inline { /// color: black; @@ -25,6 +31,10 @@ /// .list--inline { /// color: black; /// } +/// +/// .list--inline, .list--ordered { +/// color: black; +/// } @mixin modifier($modifier) { @at-root { @@ -44,4 +54,4 @@ @include modifier($modifier) { @content; } -} \ No newline at end of file +} diff --git a/mixins/_object.scss b/mixins/_object.scss index ba35652..5343d1f 100644 --- a/mixins/_object.scss +++ b/mixins/_object.scss @@ -24,19 +24,19 @@ /// } @mixin object($object, $namespace: $bem-object-namespace) { - #{object-selector($object, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #9bcb3c; - } - - @content; - } + #{object-selector($object, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #9bcb3c; + } + + @content; + } } /// @alias object @mixin o($object, $namespace: $bem-object-namespace) { - @include object($object, $namespace) { - @content; - } -} \ No newline at end of file + @include object($object, $namespace) { + @content; + } +} diff --git a/mixins/_parse.scss b/mixins/_parse.scss index 8fe70ce..ab00daf 100644 --- a/mixins/_parse.scss +++ b/mixins/_parse.scss @@ -19,105 +19,65 @@ /// @throws Mixin doesn't exist @mixin parse($selectors...) { - $parent: unquote("#{&}"); - $collection: (); - - // - @each $selector in $selectors { - - // - @if (map-get($bem-shortcodes, $selector)) { - $selectors: splice($selectors, $selector); - - // - @each $mixin in map-get($bem-shortcodes, $selector) { - $selectors: append($selectors, $mixin); - } - } - } - - // - @each $selector in $selectors { - - // - $parts: explode($selector, ':'); - - // something like ":hover" - @if (str-length(nth($parts, 1)) == 0) { - - // - $selector: unquote("#{$parent}:#{nth($parts, 2)}"); - } - - // something like "before" or "&" - @else if(length($parts) == 1) { - $item: nth($parts, 1); - - // - @if (str-index(quote($item), quote('&'))) { - $selector: unquote("#{str-replace(quote($item), quote('&'), quote($parent))}"); - } - - // - @else { - - // - @if mixin-exists(nth($parts, 1)) { - - // - $selector: call(unquote("#{$item}-selector")); - } - - // - @else { - - // - $selector: unquote("#{$parent}#{$item}"); - } - } - } - - // something like "m:inline" - @else { - $item: implode($parts, ':'); - - // - @if (str-index(quote($item), quote('&'))) { - $selector: unquote("#{str-replace(quote($item), quote('&'), quote($parent))}"); - } - - // - @else { - - // - @if mixin-exists(nth($parts, 1)) { - $function: unquote("#{nth($parts, 1)}-selector"); - $selector: call($function, nth($parts, 2)); - } - - // - @else { - @error "Mixin #{nth($parts, 1)} doesn't exists!"; - } - } - } - - // - $collection: append($collection, $selector); - } - - // - @at-root { - #{implode($collection, ', ')} { - @content; - } - } + $parent: unquote("#{&}"); + $collection: (); + + @each $selector in $selectors { + @if (map-get($bem-shortcodes, $selector)) { + $selectors: splice($selectors, $selector); + + @each $mixin in map-get($bem-shortcodes, $selector) { + $selectors: append($selectors, $mixin); + } + } + } + + @each $selector in $selectors { + $parts: explode($selector, ':'); + + @if (str-length(nth($parts, 1)) == 0) { + $selector: unquote("#{$parent}:#{nth($parts, 2)}"); + } @else if (length($parts) == 1) { + $item: nth($parts, 1); + + @if (str-index(quote($item), quote('&'))) { + $selector: unquote("#{str-replace(quote($item), quote('&'), quote($parent))}"); + } @else { + @if mixin-exists(nth($parts, 1)) { + $selector: call(unquote("#{$item}-selector")); + } @else { + $selector: unquote("#{$parent}#{$item}"); + } + } + } @else { + $item: implode($parts, ':'); + + @if (str-index(quote($item), quote('&'))) { + $selector: unquote("#{str-replace(quote($item), quote('&'), quote($parent))}"); + } @else { + @if mixin-exists(nth($parts, 1)) { + $function: unquote("#{nth($parts, 1)}-selector"); + $selector: call($function, nth($parts, 2)); + } @else { + @error "Mixin #{nth($parts, 1)} doesn't exists!"; + } + } + } + + $collection: append($collection, $selector); + } + + @at-root { + #{implode($collection, ', ')} { + @content; + } + } } /// @alias parse @mixin p($selectors...) { - @include parse($selectors...) { - @content; - } -} \ No newline at end of file + @include parse($selectors...) { + @content; + } +} diff --git a/mixins/_pseudo.scss b/mixins/_pseudo.scss index 93ac214..c264231 100644 --- a/mixins/_pseudo.scss +++ b/mixins/_pseudo.scss @@ -15,9 +15,9 @@ /// } @mixin first { - &:first-of-type { - @content; - } + &:first-of-type { + @content; + } } /// Pseudo selector with end of last-of-type. @@ -35,9 +35,9 @@ /// } @mixin last { - &:last-of-type { - @content; - } + &:last-of-type { + @content; + } } /// Pseudo selector with end of nth-child(even). @@ -55,9 +55,9 @@ /// } @mixin even { - &:nth-child(even) { - @content; - } + &:nth-child(even) { + @content; + } } /// Pseudo selector with end of nth-child(odd). @@ -75,9 +75,9 @@ /// } @mixin odd { - &:nth-child(odd) { - @content; - } + &:nth-child(odd) { + @content; + } } /// Pseudo selector with end of before. @@ -95,9 +95,9 @@ /// } @mixin before { - &::before { - @content; - } + &::before { + @content; + } } /// Pseudo selector with end of after. @@ -115,7 +115,7 @@ /// } @mixin after { - &::after { - @content; - } -} \ No newline at end of file + &::after { + @content; + } +} diff --git a/mixins/_relations.scss b/mixins/_relations.scss index c630207..e59a79b 100644 --- a/mixins/_relations.scss +++ b/mixins/_relations.scss @@ -1,13 +1,21 @@ @charset "UTF-8"; -/// Relationship of parent element with current modifier +/// Relationship of parent element with current modifiers. /// -/// @param {String} $modifier - Name of modifier that will make parent element child. +/// @param {String} $modifiers - List of modifiers that will make parent element child. /// /// @example scss - Usage /// @include b('list') { /// @include e('item') { -/// @include m('inline') { +/// @include at('inline') { +/// color: black; +/// } +/// } +/// } +/// +/// @include b('list') { +/// @include e('item') { +/// @include at('inline', 'inverse') { /// color: black; /// } /// } @@ -17,14 +25,18 @@ /// .list--inline .list__item { /// color: black; /// } +/// +/// .list--inline.list--inverse .list__item { +/// color: black; +/// } -@mixin at($modifier) { - #{at-selector($modifier)} { - @content; - } +@mixin at($modifiers...) { + #{at-selector($modifiers...)} { + @content; + } } -/// Element with next element separated by plus sign +/// Element with next element separated by plus sign. /// /// @param {String} $element - Name of element that will be styled with parent element. /// @@ -43,12 +55,12 @@ /// } @mixin next($element) { - #{next-selector($element)} { - @content; - } + #{next-selector($element)} { + @content; + } } -/// Element with same element separated by plus sign +/// Element with same element separated by plus sign. /// /// @example scss - Usage /// @include b('list') { @@ -65,12 +77,12 @@ /// } @mixin duo { - #{duo-selector()} { - @content; - } + #{duo-selector()} { + @content; + } } -/// Element with sibling elements separated by equivalency sign +/// Element with sibling elements separated by equivalency sign. /// /// @param {String} $element - Name of element that will be styled with parent element. /// @@ -89,14 +101,14 @@ /// } @mixin with($element) { - #{with-selector($element)} { - @content; - } + #{with-selector($element)} { + @content; + } } -/// While two selectors are on same element +/// While two selectors are on same modifier. /// -/// @param {String} $modifier - Name of modifier that will follow parent modifier. +/// @param {String} $modifier - Name modifier that will follow parent modifier. /// /// @example scss - Usage /// @include b('list') { @@ -113,7 +125,7 @@ /// } @mixin while($modifier) { - #{while-selector($modifier)} { - @content; - } + #{while-selector($modifier)} { + @content; + } } diff --git a/mixins/_scope.scss b/mixins/_scope.scss index 6e57900..dd3a152 100644 --- a/mixins/_scope.scss +++ b/mixins/_scope.scss @@ -24,19 +24,19 @@ /// } @mixin scope($scope, $namespace: $bem-scope-namespace) { - #{scope-selector($scope, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #a2453d; - } - - @content; - } + #{scope-selector($scope, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #a2453d; + } + + @content; + } } /// @alias scope @mixin s($scope, $namespace: $bem-scope-namespace) { - @include scope($scope, $namespace) { - @content; - } -} \ No newline at end of file + @include scope($scope, $namespace) { + @content; + } +} diff --git a/mixins/_state.scss b/mixins/_state.scss index d27147d..8c471c3 100644 --- a/mixins/_state.scss +++ b/mixins/_state.scss @@ -18,31 +18,31 @@ /// } @mixin state($state, $namespace: null) { - @at-root { - #{state-selector($state, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #66a96b; - } - - @content; - } - } + @at-root { + #{state-selector($state, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #66a96b; + } + + @content; + } + } } /// @alias state @mixin is($state) { - @include state($state, 'is') { - @content; - } + @include state($state, 'is') { + @content; + } } /// @alias state @mixin has($state) { - @include state($state, 'has') { - @content; - } + @include state($state, 'has') { + @content; + } } /// Signify that this piece of the DOM has some behaviour acting upon it, and that JavaScript binds onto it to provide that behaviour. If you’re not a developer working with JavaScript, leave these well alone. @@ -50,7 +50,7 @@ /// @alias state @mixin js($state) { - @include state($state, 'js') { - @content; - } -} \ No newline at end of file + @include state($state, 'js') { + @content; + } +} diff --git a/mixins/_states.scss b/mixins/_states.scss index 891a7fe..d5745c1 100644 --- a/mixins/_states.scss +++ b/mixins/_states.scss @@ -13,9 +13,9 @@ /// } @mixin hover { - &:hover { - @content; - } + &:hover { + @content; + } } /// Pseudo selector with end of focus. @@ -33,9 +33,9 @@ /// } @mixin focus { - &:focus { - @content; - } + &:focus { + @content; + } } /// Pseudo selector with end of active. @@ -53,9 +53,9 @@ /// } @mixin active { - &:active { - @content; - } + &:active { + @content; + } } /// Pseudo selector with end of link. @@ -73,9 +73,9 @@ /// } @mixin link { - &:link { - @content; - } + &:link { + @content; + } } /// Pseudo selector with end of visited. @@ -93,9 +93,9 @@ /// } @mixin visited { - &:visited { - @content; - } + &:visited { + @content; + } } /// Pseudo selector with end of checked. @@ -113,9 +113,9 @@ /// } @mixin checked { - &:checked { - @content; - } + &:checked { + @content; + } } /// Selector with state of disabled. @@ -133,9 +133,9 @@ /// } @mixin disabled { - &[disabled] { - @content; - } + &[disabled] { + @content; + } } /// Selector with state of readonly. @@ -153,9 +153,9 @@ /// } @mixin readonly { - &[readonly] { - @content; - } + &[readonly] { + @content; + } } /// Selector with state of contenteditable. @@ -173,15 +173,15 @@ /// } @mixin contenteditable { - &[contenteditable="true"] { - @content; - } + &[contenteditable="true"] { + @content; + } } /// @alias contenteditable @mixin editable { - @include contenteditable { - @content; - } + @include contenteditable { + @content; + } } diff --git a/mixins/_test.scss b/mixins/_test.scss index 3b532d7..3944046 100644 --- a/mixins/_test.scss +++ b/mixins/_test.scss @@ -24,19 +24,19 @@ /// } @mixin test($test, $namespace: $bem-test-namespace) { - #{test-selector($test, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #f8e796; - } - - @content; - } + #{test-selector($test, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #f8e796; + } + + @content; + } } /// @alias test @mixin qa($test, $namespace: $bem-test-namespace) { - @include test($test, $namespace) { - @content; - } -} \ No newline at end of file + @include test($test, $namespace) { + @content; + } +} diff --git a/mixins/_theme.scss b/mixins/_theme.scss index 9606f87..fc1c505 100644 --- a/mixins/_theme.scss +++ b/mixins/_theme.scss @@ -24,19 +24,19 @@ /// } @mixin theme($theme, $namespace: $bem-theme-namespace) { - #{theme-selector($theme, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #60316e; - } - - @content; - } + #{theme-selector($theme, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #60316e; + } + + @content; + } } /// @alias theme @mixin t($theme, $namespace: $bem-theme-namespace) { - @include theme($theme, $namespace) { - @content; - } -} \ No newline at end of file + @include theme($theme, $namespace) { + @content; + } +} diff --git a/mixins/_utility.scss b/mixins/_utility.scss index 82edbd2..f8e6079 100644 --- a/mixins/_utility.scss +++ b/mixins/_utility.scss @@ -24,19 +24,19 @@ /// } @mixin utility($utility, $namespace: $bem-utility-namespace) { - #{utility-selector($utility, $namespace)} { - @if $bem-debug == true { - outline: 5px solid #635270; - } - - @content; - } + #{utility-selector($utility, $namespace)} { + @if $bem-debug == true { + outline: 5px solid #635270; + } + + @content; + } } /// @alias utility @mixin u($utility, $namespace: $bem-utility-namespace) { - @include utility($utility, $namespace) { - @content; - } -} \ No newline at end of file + @include utility($utility, $namespace) { + @content; + } +} diff --git a/package.json b/package.json index 2e3975b..816e4d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sass-bem", - "version": "2.5.3", + "version": "2.6.0", "description": "Amazing package for sass to write bem classes, with namespaces and more advanced features.", "main": "_bem.scss", "repository": { @@ -27,5 +27,19 @@ "bower.json", "test", "tests" - ] + ], + "scripts": { + "test": "./node_modules/.bin/mocha --reporter spec", + "sass": "./node_modules/.bin/node-sass style.scss style.css", + "sassdoc": "./node_modules/.bin/node-sass style.scss style.css" + }, + "devDependencies": { + "gulp": "^3.9.1", + "gulp-mocha": "^3.0.1", + "mocha": "^3.2.0", + "node-sass": "^3.13.0", + "path": "^0.12.7", + "sass-true": "^2.1.3", + "sassdoc": "^2.1.20" + } } diff --git a/test/_functions.scss b/test/_functions.scss new file mode 100644 index 0000000..80d1f31 --- /dev/null +++ b/test/_functions.scss @@ -0,0 +1,108 @@ +@include test-module('Functions') { + @include test('bem-index [function]') { + @include assert-equal(bem-index('.list'), 0, 'Get index of separator #1.'); + @include assert-equal(bem-index('.list__item'), 6, 'Get index of separator #2.'); + @include assert-equal(bem-index('.list--inline'), 6, 'Get index of separator #3.'); + @include assert-equal(bem-index('.list__item--inline'), 6, 'Get index of separator #4.'); + @include assert-equal(bem-index('.is-active'), 1, 'Get index of separator #5.'); + @include assert-equal(bem-index('.js-carousel'), 1, 'Get index of separator #6.'); + @include assert-equal(bem-index('.has-child'), 1, 'Get index of separator #7.'); + @include assert-equal(bem-index('.list::before'), 6, 'Get index of separator #8.'); + } + + @include test('is-modifier [function]') { + @include assert-false(is-modifier('.list'), 'Check if selector is modifier #1.'); + @include assert-false(is-modifier('.list__item'), 'Check if selector is modifier #2.'); + @include assert-true(is-modifier('.list--inline'), 'Check if selector is modifier #3.'); + @include assert-true(is-modifier('.list__item--inline'), 'Check if selector is modifier #4.'); + @include assert-false(is-modifier('.is-active'), 'Check if selector is modifier #5.'); + @include assert-false(is-modifier('.js-carousel'), 'Check if selector is modifier #6.'); + @include assert-false(is-modifier('.has-child'), 'Check if selector is modifier #7.'); + @include assert-false(is-modifier('.list::before'), 'Check if selector is modifier #8.'); + } + + @include test('is-element [function]') { + @include assert-false(is-element('.list'), 'Check if selector is element #1.'); + @include assert-true(is-element('.list__item'), 'Check if selector is element #2.'); + @include assert-false(is-element('.list--inline'), 'Check if selector is element #3.'); + @include assert-true(is-element('.list__item--inline'), 'Check if selector is element #4.'); + @include assert-false(is-element('.is-active'), 'Check if selector is element #5.'); + @include assert-false(is-element('.js-carousel'), 'Check if selector is element #6.'); + @include assert-false(is-element('.has-child'), 'Check if selector is element #7.'); + @include assert-false(is-element('.list::before'), 'Check if selector is element #8.'); + } + + @include test('has-state [function]') { + @include assert-false(has-state('.list'), 'Check if selector contains state #1.'); + @include assert-false(has-state('.list__item'), 'Check if selector contains state #2.'); + @include assert-false(has-state('.list--inline'), 'Check if selector contains state #3.'); + @include assert-false(has-state('.list__item--inline'), 'Check if selector contains state #4.'); + @include assert-true(has-state('.is-active'), 'Check if selector contains state #5.'); + @include assert-true(has-state('.js-carousel'), 'Check if selector contains state #6.'); + @include assert-true(has-state('.has-child'), 'Check if selector contains state #7.'); + @include assert-false(has-state('.list::before'), 'Check if selector contains state #8.'); + } + + @include test('has-pseudo [function]') { + @include assert-false(has-pseudo('.list'), 'Check if selector contains pseudo element #1.'); + @include assert-false(has-pseudo('.list__item'), 'Check if selector contains pseudo element #2.'); + @include assert-false(has-pseudo('.list--inline'), 'Check if selector contains pseudo element #3.'); + @include assert-false(has-pseudo('.list__item--inline'), 'Check if selector contains pseudo element #4.'); + @include assert-false(has-pseudo('.is-active'), 'Check if selector contains pseudo element #5.'); + @include assert-false(has-pseudo('.js-carousel'), 'Check if selector contains pseudo element #6.'); + @include assert-false(has-pseudo('.has-child'), 'Check if selector contains pseudo element #7.'); + @include assert-true(has-pseudo('.list::before'), 'Check if selector contains pseudo element #8.'); + } + + @include test('is-block [function]') { + @include assert-true(is-block('.list'), 'Check if selector is block #1.'); + @include assert-false(is-block('.list__item'), 'Check if selector is block #2.'); + @include assert-false(is-block('.list--inline'), 'Check if selector is block #3.'); + @include assert-false(is-block('.list__item--inline'), 'Check if selector is block #4.'); + @include assert-false(is-block('.is-active'), 'Check if selector is block #5.'); + @include assert-false(is-block('.js-carousel'), 'Check if selector is block #6.'); + @include assert-false(is-block('.has-child'), 'Check if selector is block #7.'); + @include assert-false(is-block('.list::before'), 'Check if selector is block #8.'); + } + + @include test('get-block [function]') { + @include assert-equal(get-block('.list'), 'list', 'Get block element from selector #1.'); + @include assert-equal(get-block('.list__item'), 'list', 'Get block element from selector #2.'); + @include assert-equal(get-block('.list--inline'), 'list', 'Get block element from selector #3.'); + @include assert-equal(get-block('.list__item--inline'), 'list', 'Get block element from selector #4.'); + @include assert-unequal(get-block('.is-active'), 'list', 'Get block element from selector #5.'); + @include assert-unequal(get-block('.js-carousel'), 'list', 'Get block element from selector #6.'); + @include assert-unequal(get-block('.has-child'), 'list', 'Get block element from selector #7.'); + @include assert-equal(get-block('.list::before'), 'list', 'Get block element from selector #8.'); + } + + @include test('str-replace [function]') { + @include assert-equal(str-replace('foobar', 'f'), 'oobar', 'Replace string with another string #1.'); + @include assert-equal(str-replace('foobar', 'oo'), 'fbar', 'Replace string with another string #2.'); + @include assert-equal(str-replace('foobar', 'r'), 'fooba', 'Replace string with another string #3.'); + } + + @include test('math-min [function]') { + @include assert-equal(math-min(1, 2), 1, 'Get minimum number from two of them, or get default #1.'); + @include assert-unequal(math-min(2, 3), 3, 'Get minimum number from two of them, or get default #2.'); + @include assert-equal(math-min(3, 3, 4), 3, 'Get minimum number from two of them, or get default #3.'); + @include assert-equal(math-min(null, 3, 4), 3, 'Get minimum number from two of them, or get default #4.'); + @include assert-equal(math-min(null, 4, 5), 4, 'Get minimum number from two of them, or get default #5.'); + } + + @include test('explode [function]') { + @include assert-equal(explode('foo-bar-baz', '-'), ('foo' 'bar' 'baz'), 'Explode string to get list of strings #1.'); + @include assert-equal(explode('foo.bar', '.'), ('foo' 'bar'), 'Explode string to get list of strings #2.'); + } + + @include test('implode [function]') { + @include assert-equal(implode(('foo' 'bar' 'baz'), '-', true), 'foo-bar-baz-', 'Implode list to get string #1.'); + @include assert-equal(implode(('foo' 'bar' 'baz'), '-'), 'foo-bar-baz', 'Implode list to get string #2.'); + @include assert-equal(implode(('foo' 'bar'), '.'), 'foo.bar', 'Implode list to get string #3.'); + } + + @include test('splice [function]') { + @include assert-equal(splice(('foo' 'bar' 'baz'), 'bar', true), ('foo' 'baz'), 'Unset item from list #1.'); + @include assert-equal(splice(('foo' 'bar' 'baz'), 'bar'), ('foo' 'baz'), 'Unset item from list #2.'); + } +} diff --git a/test/_helpers.scss b/test/_helpers.scss new file mode 100644 index 0000000..64db6d0 --- /dev/null +++ b/test/_helpers.scss @@ -0,0 +1,45 @@ +@include test-module('Helpers') { + @include test('block-selector [function]') { + @include assert-equal(block-selector('list'), '.list', 'Selector of block.'); + } + + @include test('b-selector [function]') { + @include assert-equal(b-selector('list'), '.list', 'Selector of block.'); + } + + @include test('element-selector [function]') { + @include assert-equal(element-selector('item'), '&__item', 'Selector of element.'); + } + + @include test('e-selector [function]') { + @include assert-equal(e-selector('item'), '&__item', 'Selector of element.'); + } + + @include test('modifier-selector [function]') { + @include assert-equal(modifier-selector('inline'), '&--inline', 'Selector of modifier.'); + } + + @include test('m-selector [function]') { + @include assert-equal(m-selector('inline'), '&--inline', 'Selector of modifier.'); + } + + @include test('at-selector [function]') { + @include assert-equal(at-selector('inline'), '.--inline &', 'Selector of at relationship.'); + } + + @include test('next-selector [function]') { + @include assert-equal(next-selector('item'), '& + .__item', 'Selector of adjacent relationship.'); + } + + @include test('duo-selector [function]') { + @include assert-equal(duo-selector(true), '& + &', 'Selector of duo relationship.'); + } + + @include test('with-selector [function]') { + @include assert-equal(with-selector('item'), '& ~ .__item', 'Selector of sibling relationship.'); + } + + @include test('while-selector [function]') { + @include assert-equal(while-selector('inline'), '&.--inline', 'Selector of while relationship.'); + } +} diff --git a/test/_mixins.scss b/test/_mixins.scss new file mode 100644 index 0000000..d828d78 --- /dev/null +++ b/test/_mixins.scss @@ -0,0 +1,737 @@ +@include test-module('Mixins') { + @include test('block [mixin]') { + @include assert('Block selector that will be parent of some elements, modifiers, states...') { + @include output { + @include block('list') { + color: black; + } + } + + @include expect { + .list { + color: black; + } + } + } + } + + @include test('b [mixin]') { + @include assert('Block selector that will be parent of some elements, modifiers, states...') { + @include output { + @include b('list') { + color: black; + } + } + + @include expect { + .list { + color: black; + } + } + } + } + + @include test('element [mixin]') { + @include assert('Element selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include element('item') { + color: black; + } + } + } + + @include expect { + .list__item { + color: black; + } + } + } + } + + @include test('e [mixin]') { + @include assert('Element selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include e('item') { + color: black; + } + } + } + + @include expect { + .list__item { + color: black; + } + } + } + } + + @include test('e [mixin]') { + @include assert('Element selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include e(('item', 'link')) { + color: black; + } + } + } + + @include expect { + .list__item, .list__link { + color: black; + } + } + } + } + + @include test('ee [mixin]') { + @include assert('Element selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include e('item') { + @include ee('link') { + color: black; + } + } + } + } + + @include expect { + .list__item__link { + color: black; + } + } + } + } + + @include test('modifier [mixin]') { + @include assert('Modifier selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include modifier('inline') { + color: black; + } + } + } + + @include expect { + .list--inline { + color: black; + } + } + } + } + + @include test('m [mixin]') { + @include assert('Modifier selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include m('inline') { + color: black; + } + } + } + + @include expect { + .list--inline { + color: black; + } + } + } + } + + @include test('m [mixin]') { + @include assert('Modifier selector, that is generated from parent block.') { + @include output { + @include block('list') { + @include m(('inline', 'ordered')) { + color: black; + } + } + } + + @include expect { + .list--inline, .list--ordered { + color: black; + } + } + } + } + + @include test('at [mixin]') { + @include assert('Relationship of parent element with current modifier.') { + @include output { + @include block('list') { + @include e('item') { + @include at('inline') { + color: black; + } + } + } + } + + @include expect { + .list--inline .test-output .list__item { + color: black; + } + } + } + } + + @include test('at [mixin]') { + @include assert('Relationship of parent element with current modifiers.') { + @include output { + @include block('list') { + @include e('item') { + @include at('inline', 'inverse') { + color: black; + } + } + } + } + + @include expect { + .list--inline.test-output .list--inverse .test-output .list__item { + color: black; + } + } + } + } + + @include test('next [mixin]') { + @include assert('Element with next element separated by plus sign.') { + @include output { + @include block('list') { + @include e('item') { + @include next('title') { + color: black; + } + } + } + } + + @include expect { + .list__item + .test-output .list__title { + color: black; + } + } + } + } + + @include test('duo [mixin]') { + @include assert('Element with same element separated by plus sign.') { + @include output { + @include block('list') { + @include e('item') { + @include duo { + color: black; + } + } + } + } + + @include expect { + .list__item + .list__item { + color: black; + } + } + } + } + + @include test('with [mixin]') { + @include assert('Element with sibling elements separated by equivalency sign.') { + @include output { + @include block('list') { + @include e('item') { + @include with('title') { + color: black; + } + } + } + } + + @include expect { + .list__item ~ .test-output .list__title { + color: black; + } + } + } + } + + @include test('while [mixin]') { + @include assert('While two selectors are on same modifier.') { + @include output { + @include block('list') { + @include m('inline') { + @include while('ordered') { + color: black; + } + } + } + } + + @include expect { + .list--inline.test-output .list--ordered { + color: black; + } + } + } + } + + @include test('hover [mixin]') { + @include assert('Pseudo selector with end of hover.') { + @include output { + @include block('list') { + @include hover { + color: black; + } + } + } + + @include expect { + .list:hover { + color: black; + } + } + } + } + + @include test('focus [mixin]') { + @include assert('Pseudo selector with end of focus.') { + @include output { + @include block('list') { + @include focus { + color: black; + } + } + } + + @include expect { + .list:focus { + color: black; + } + } + } + } + + @include test('active [mixin]') { + @include assert('Pseudo selector with end of active.') { + @include output { + @include block('list') { + @include active { + color: black; + } + } + } + + @include expect { + .list:active { + color: black; + } + } + } + } + + @include test('link [mixin]') { + @include assert('Pseudo selector with end of link.') { + @include output { + @include block('list') { + @include link { + color: black; + } + } + } + + @include expect { + .list:link { + color: black; + } + } + } + } + + @include test('visited [mixin]') { + @include assert('Pseudo selector with end of visited.') { + @include output { + @include block('list') { + @include visited { + color: black; + } + } + } + + @include expect { + .list:visited { + color: black; + } + } + } + } + + @include test('checked [mixin]') { + @include assert('Pseudo selector with end of checked.') { + @include output { + @include block('list') { + @include checked { + color: black; + } + } + } + + @include expect { + .list:checked { + color: black; + } + } + } + } + + @include test('disabled [mixin]') { + @include assert('Selector with state of disabled.') { + @include output { + @include block('list') { + @include disabled { + color: black; + } + } + } + + @include expect { + .list[disabled] { + color: black; + } + } + } + } + + @include test('readonly [mixin]') { + @include assert('Selector with state of readonly.') { + @include output { + @include block('list') { + @include readonly { + color: black; + } + } + } + + @include expect { + .list[readonly] { + color: black; + } + } + } + } + + @include test('contenteditable [mixin]') { + @include assert('Selector with state of contenteditable.') { + @include output { + @include block('list') { + @include contenteditable { + color: black; + } + } + } + + @include expect { + .list[contenteditable="true"] { + color: black; + } + } + } + } + + @include test('editable [mixin]') { + @include assert('Selector with state of contenteditable.') { + @include output { + @include block('list') { + @include editable { + color: black; + } + } + } + + @include expect { + .list[contenteditable="true"] { + color: black; + } + } + } + } + + @include test('parse [mixin]') { + @include assert('Parse multiple mixins, pseudo elements and other states.') { + @include output { + @include block('list') { + @include parse('&', 'm:inline', ':hover', '[disabled]') { + color: black; + } + } + } + + @include expect { + .list, .list--inline, .list:hover, .list[disabled] { + color: black; + } + } + } + } + + @include test('p [mixin]') { + @include assert('Parse multiple mixins, pseudo elements and other states.') { + @include output { + @include block('list') { + @include p('&', 'm:inline', ':hover', '[disabled]') { + color: black; + } + } + } + + @include expect { + .list, .list--inline, .list:hover, .list[disabled] { + color: black; + } + } + } + } + + @include test('object [mixin]') { + @include assert('Signify that something is an Object, and that it may be used in any number of unrelated contexts to the one you can currently see it in. Making modifications to these types of class could potentially have knock-on effects in a lot of other unrelated places. Tread carefully.') { + @include output { + @include object('list') { + color: black; + } + } + + @include expect { + .o-list { + color: black; + } + } + } + } + + @include test('o [mixin]') { + @include assert('Signify that something is an Object, and that it may be used in any number of unrelated contexts to the one you can currently see it in. Making modifications to these types of class could potentially have knock-on effects in a lot of other unrelated places. Tread carefully.') { + @include output { + @include o('list') { + color: black; + } + } + + @include expect { + .o-list { + color: black; + } + } + } + } + + @include test('component [mixin]') { + @include assert('Signify that something is a Component. This is a concrete, implementation-specific piece of UI. All of the changes you make to its styles should be detectable in the context you’re currently looking at. Modifying these styles should be safe and have no side effects.') { + @include output { + @include component('list') { + color: black; + } + } + + @include expect { + .c-list { + color: black; + } + } + } + } + + @include test('c [mixin]') { + @include assert('Signify that something is a Component. This is a concrete, implementation-specific piece of UI. All of the changes you make to its styles should be detectable in the context you’re currently looking at. Modifying these styles should be safe and have no side effects.') { + @include output { + @include c('list') { + color: black; + } + } + + @include expect { + .c-list { + color: black; + } + } + } + } + + @include test('utility [mixin]') { + @include assert('Signify that this class is a Utility class. It has a very specific role (often providing only one declaration) and should not be bound onto or changed. It can be reused and is not tied to any specific piece of UI. You will probably recognise this namespace from libraries and methodologies like SUIT.') { + @include output { + @include utility('hidden') { + color: black; + } + } + + @include expect { + .u-hidden { + color: black; + } + } + } + } + + @include test('u [mixin]') { + @include assert('Signify that this class is a Utility class. It has a very specific role (often providing only one declaration) and should not be bound onto or changed. It can be reused and is not tied to any specific piece of UI. You will probably recognise this namespace from libraries and methodologies like SUIT.') { + @include output { + @include u('hidden') { + color: black; + } + } + + @include expect { + .u-hidden { + color: black; + } + } + } + } + + @include test('theme [mixin]') { + @include assert('Signify that a class is responsible for adding a Theme to a view. It lets us know that UI Components’ current cosmetic appearance may be due to the presence of a theme.') { + @include output { + @include theme('dark') { + color: black; + } + } + + @include expect { + .t-dark { + color: black; + } + } + } + } + + @include test('t [mixin]') { + @include assert('Signify that a class is responsible for adding a Theme to a view. It lets us know that UI Components’ current cosmetic appearance may be due to the presence of a theme.') { + @include output { + @include t('dark') { + color: black; + } + } + + @include expect { + .t-dark { + color: black; + } + } + } + } + + @include test('scope [mixin]') { + @include assert('Signify that a class creates a new styling context or Scope. Similar to a Theme, but not necessarily cosmetic, these should be used sparingly—they can be open to abuse and lead to poor CSS if not used wisely.') { + @include output { + @include scope('paper') { + color: black; + } + } + + @include expect { + .s-paper { + color: black; + } + } + } + } + + @include test('s [mixin]') { + @include assert('Signify that a class creates a new styling context or Scope. Similar to a Theme, but not necessarily cosmetic, these should be used sparingly—they can be open to abuse and lead to poor CSS if not used wisely.') { + @include output { + @include s('paper') { + color: black; + } + } + + @include expect { + .s-paper { + color: black; + } + } + } + } + + @include test('is [mixin]') { + @include assert('Signify that the piece of UI in question is currently styled a certain way because of a state or condition. This stateful namespace is gorgeous, and comes from SMACSS. It tells us that the DOM currently has a temporary, optional, or short-lived style applied to it due to a certain state being invoked.') { + @include output { + @include is('active') { + color: black; + } + } + + @include expect { + &.is-active { + color: black; + } + } + } + } + + @include test('has [mixin]') { + @include assert('Signify that the piece of UI in question is currently styled a certain way because of a state or condition. This stateful namespace is gorgeous, and comes from SMACSS. It tells us that the DOM currently has a temporary, optional, or short-lived style applied to it due to a certain state being invoked.') { + @include output { + @include has('child') { + color: black; + } + } + + @include expect { + &.has-child { + color: black; + } + } + } + } + + @include test('js [mixin]') { + @include assert('Signify that this piece of the DOM has some behaviour acting upon it, and that JavaScript binds onto it to provide that behaviour. If you’re not a developer working with JavaScript, leave these well alone.') { + @include output { + @include js('carousel') { + color: black; + } + } + + @include expect { + &.js-carousel { + color: black; + } + } + } + } + + @include test('hack [mixin]') { + @include assert('Signify that this class is the worst of the worst—a hack! Sometimes, although incredibly rarely, we need to add a class in our markup in order to force something to work. If we do this, we need to let others know that this class is less than ideal, and hopefully temporary (i.e. do not bind onto this).') { + @include output { + @include hack('clearfix') { + color: black; + } + } + + @include expect { + ._clearfix { + color: black; + } + } + } + } + + @include test('_ [mixin]') { + @include assert('Signify that this class is the worst of the worst—a hack! Sometimes, although incredibly rarely, we need to add a class in our markup in order to force something to work. If we do this, we need to let others know that this class is less than ideal, and hopefully temporary (i.e. do not bind onto this).') { + @include output { + @include _('clearfix') { + color: black; + } + } + + @include expect { + ._clearfix { + color: black; + } + } + } + } +} diff --git a/test/test.scss b/test/test.scss new file mode 100644 index 0000000..a8337c8 --- /dev/null +++ b/test/test.scss @@ -0,0 +1,10 @@ +@import "../bem"; +@import "true"; + +$true-terminal-output: true; + +@import "functions"; +@import "helpers"; +@import "mixins"; + +@include report; diff --git a/test/test_sass.js b/test/test_sass.js new file mode 100644 index 0000000..dc77b76 --- /dev/null +++ b/test/test_sass.js @@ -0,0 +1,5 @@ +const path = require('path'); +const sass_true = require('sass-true'); + +const sassFile = path.join(__dirname, 'test.scss'); +sass_true.runSass({file: sassFile}, describe, it); diff --git a/test/true.yml b/test/true.yml new file mode 100644 index 0000000..ee67a33 --- /dev/null +++ b/test/true.yml @@ -0,0 +1,2 @@ +options: + color: true \ No newline at end of file