//// /// @group BEM /// /// @access public //// @use './validators'; @use './vars'; @use './functions' as bemfunctions; @use '../functions'; @use '../contexts'; /// /// 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 block('something', 'component') { /// /* some definitions */ /// } /// /// // Generates: /// /// .c-something { /// /* some definitions */ /// } /// @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} { @content; } @include contexts.pop(vars.$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} 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; } /// /// Generate a new object block. It's a shorthand for block($name, 'object'). /// /// @param {string} $name - Object block name /// /// @content /// @mixin object($name) { @include 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} object /// @function object($name) { @return block($name, 'object'); } /// /// Generate a new component block. It's a shorthand for block($name, 'component'). /// /// @param {string} $name - Component block name /// /// @content /// @mixin component($name) { @include 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} component /// @function component($name) { @return block($name, 'component'); } /// /// Generate a new layout block. It's a shorthand for block($name, 'layout'). /// /// @param {string} $name - Layout block name /// /// @content /// @mixin layout($name) { @include 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} layout /// @function layout($name) { @return block($name, 'layout'); } /// /// Generate a new utility block. It's a shorthand for block($name, 'utility'). /// /// @param {string} $name - Utility block name /// /// @content /// @mixin utility($name) { @include 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} utility /// @function utility($name) { @return block($name, 'utility'); } /// /// Generate a new scope block. It's a shorthand for block($name, 'scope'). /// /// @param {string} $name - Scope block name /// /// @content /// @mixin scope($name) { @include 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} scope /// @function scope($name) { @return block($name, 'scope'); } /// /// Generate a new theme block. It's a shorthand for block($name, 'theme'). /// /// @param {string} $name - Theme block name /// /// @content /// @mixin theme($name) { @include 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} theme /// @function theme($name) { @return block($name, 'theme'); } /// /// Generate a new JS block. It's a shorthand for block($name, 'js'). /// /// @param {string} $name - JS block name /// /// @content /// @mixin js($name) { @include 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} js /// @function js($name) { @return block($name, 'js'); } /// /// Generate a new QA block. It's a shorthand for block($name, 'qa'). /// /// @param {string} $name - QA block name /// /// @content /// @mixin qa($name) { @include 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} qa /// @function qa($name) { @return block($name, 'qa'); } /// /// Generate a new hack block. It's a shorthand for block($name, 'hack'). /// /// @param {string} $name - Hack block name /// /// @content /// @mixin hack($name) { @include 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} hack /// @function hack($name) { @return 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 component('someBlock') { /// /* some definitions */ /// } /// /// @include component('anotherBlock') { /// /* some definitions */ /// /// @include elem('elem') { /// @include composed-of('someBlock' 'component'); /// /// /* some definitions */ /// } /// } /// /// // Intended use: