//// /// @group BEM /// /// @access public //// /// /// Generate a new block. /// /// This mixin simply creates a new block with the name {namespace}_{name}, /// where {namespace} is the prefix assigned to $type and {name} is the /// block's name. /// /// @param {string} $name - Block name /// @param {string} $type [null] - BEMIT namespace of the block /// /// @content /// /// @throw If $type is invalid /// @throw If the block is preceded by another block, element, modifier or suffix /// /// @example scss - Creating a new block /// @include iro-bem-block('something', 'component') { /// /* some definitions */ /// } /// /// // Generates: /// /// .c-something { /// /* some definitions */ /// } /// @mixin iro-bem-block($name, $type: null) { $result: iro-bem-block($name, $type); $selector: nth($result, 1); $context: nth($result, 2); @include iro-bem-validate( 'block', (name: $name, type: $type), $selector, $context ); @if $type != null { $iro-bem-blocks: append($iro-bem-blocks, $name + '_' + $type) !global; } @else { $iro-bem-blocks: append($iro-bem-blocks, $name) !global; } @include iro-context-push($iro-bem-context-id, $context...); @at-root #{$selector} { @content; } @include iro-context-pop($iro-bem-context-id); } /// /// Generate a new block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-block /// @function iro-bem-block($name, $type: null) { // // Possible outcomes: // - ({b,e,m,s}) block // $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); $selector: null; $base-selector: null; @if $type != null { $namespace: map-get($iro-bem-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: iro-bem-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; } /// /// Generate a new object block. It's a shorthand for iro-bem-block($name, 'object'). /// /// @param {string} $name - Object block name /// /// @content /// @mixin iro-bem-object($name) { @include iro-bem-block($name, 'object') { @content; } } /// /// Generate a new object block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-object /// @function iro-bem-object($name) { @return iro-bem-block($name, 'object'); } /// /// Generate a new component block. It's a shorthand for iro-bem-block($name, 'component'). /// /// @param {string} $name - Component block name /// /// @content /// @mixin iro-bem-component($name) { @include iro-bem-block($name, 'component') { @content; } } /// /// Generate a new component block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-component /// @function iro-bem-component($name) { @return iro-bem-block($name, 'component'); } /// /// Generate a new layout block. It's a shorthand for iro-bem-block($name, 'layout'). /// /// @param {string} $name - Layout block name /// /// @content /// @mixin iro-bem-layout($name) { @include iro-bem-block($name, 'layout') { @content; } } /// /// Generate a new layout block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-layout /// @function iro-bem-layout($name) { @return iro-bem-block($name, 'layout'); } /// /// Generate a new utility block. It's a shorthand for iro-bem-block($name, 'utility'). /// /// @param {string} $name - Utility block name /// /// @content /// @mixin iro-bem-utility($name) { @include iro-bem-block($name, 'utility') { @content; } } /// /// Generate a new utility block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-utility /// @function iro-bem-utility($name) { @return iro-bem-block($name, 'utility'); } /// /// Generate a new scope block. It's a shorthand for iro-bem-block($name, 'scope'). /// /// @param {string} $name - Scope block name /// /// @content /// @mixin iro-bem-scope($name) { @include iro-bem-block($name, 'scope') { @content; } } /// /// Generate a new scope block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-scope /// @function iro-bem-scope($name) { @return iro-bem-block($name, 'scope'); } /// /// Generate a new theme block. It's a shorthand for iro-bem-block($name, 'theme'). /// /// @param {string} $name - Theme block name /// /// @content /// @mixin iro-bem-theme($name) { @include iro-bem-block($name, 'theme') { @content; } } /// /// Generate a new theme block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-theme /// @function iro-bem-theme($name) { @return iro-bem-block($name, 'theme'); } /// /// Generate a new JS block. It's a shorthand for iro-bem-block($name, 'js'). /// /// @param {string} $name - JS block name /// /// @content /// @mixin iro-bem-js($name) { @include iro-bem-block($name, 'js') { @content; } } /// /// Generate a new JS block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-js /// @function iro-bem-js($name) { @return iro-bem-block($name, 'js'); } /// /// Generate a new QA block. It's a shorthand for iro-bem-block($name, 'qa'). /// /// @param {string} $name - QA block name /// /// @content /// @mixin iro-bem-qa($name) { @include iro-bem-block($name, 'qa') { @content; } } /// /// Generate a new QA block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-qa /// @function iro-bem-qa($name) { @return iro-bem-block($name, 'qa'); } /// /// Generate a new hack block. It's a shorthand for iro-bem-block($name, 'hack'). /// /// @param {string} $name - Hack block name /// /// @content /// @mixin iro-bem-hack($name) { @include iro-bem-block($name, 'hack') { @content; } } /// /// Generate a new hack block. Check the respective mixin documentation for more information. /// /// @return {list} A list with two items: 1. selector, 2. context or `null` /// /// @see {mixin} iro-bem-hack /// @function iro-bem-hack($name) { @return iro-bem-block($name, 'hack'); } /// /// Assert that a block or element is composed of another block. In BEM, such a relationship is referred to /// as a "mix": https://en.bem.info/methodology/key-concepts/#mix /// /// Compilation will fail if the foreign block doesn't exist. This way, you can ensure that blocks are /// defined in the right order so that composed blocks/elements will actually override the foreign /// declarations without having to artificially increase the specificity. /// /// @param {string | list} $block - Either first block name, or list with two items: 1. block name, 2. block type /// @param {string | list} $blocks - Either other block names, or list with two items: 1. block name, 2. block type /// /// @throw If a block type is invalid /// @throw If a block doesn't exist /// /// @example scss - Successful assertion /// @include iro-bem-component('someBlock') { /// /* some definitions */ /// } /// /// @include iro-bem-component('anotherBlock') { /// /* some definitions */ /// /// @include iro-bem-element('elem') { /// @include iro-bem-composed-of('someBlock' 'component'); /// /// /* some definitions */ /// } /// } /// /// // Intended use:
...
/// /// @example scss - Failing assertion /// @include iro-bem-component('anotherBlock') { /// /* some definitions */ /// /// @include iro-bem-element('elem') { /// @include iro-bem-composed-of('someBlock' 'component'); /// /// /* some definitions */ /// } /// } /// /// @include iro-bem-component('someBlock') { /// /* some definitions */ /// } /// /// // Compilation will fail because c-someBlock is defined after c-anotherBlock__elem /// @mixin iro-bem-composed-of($block, $blocks...) { @each $block in iro-list-prepend($blocks, $block) { @if type-of($block) == string { @if not index($iro-bem-blocks, $block) { @error 'Block "#{$block}" does not exist.'; } } @else { $name: nth($block, 1); $type: nth($block, 2); @if not map-get($iro-bem-namespaces, $type) { @error '"#{$type}" is not a valid type.'; } @if not index($iro-bem-blocks, $name + '_' + $type) { @error 'Block "#{$name}" does not exist.'; } } } }