//// /// @group BEM /// /// @access public //// @use '../functions'; @use '../contexts'; @use './block'; @use './element'; @use './modifier'; @use './state'; @use './suffix'; @use './theme'; @use './vars'; /// /// Generate multiple entities (BEM or not) at once. /// /// NOTE: This mixin does not generate perfectly optimized selectors in order to keep track of contexts. /// /// @param {string | list} $first - First selector. Either a string for a manual selector, or a list with the first items standing for a BEM selector function (optionally suffixed by a colon) and other items being passed as arguments to said function. /// @param {string | list} $others - Other selectors. Either a string for a manual selector, or a list with the first items standing for a BEM selector function (optionally suffixed by a colon) and other items being passed as arguments to said function. /// /// @content /// /// @example scss - Creating multiple elements, a modifier and an anchor /// @include object('buttonstrip') { /// display: none; /// /// @include multi('modifier' 'mod', 'elem' 'button' 'separator', '> a') { /// display: block; /// } /// } /// /// // Generates: /// /// .o-buttonstrip { /// display: none; /// } /// /// .o-buttonstrip--mod { /// display: block; /// } /// /// .o-buttonstrip__button, { /// .o-buttonstrip__separator { /// display: block; /// } /// /// .o-buttonstrip > a { /// display: block; /// } /// /// @example scss - Creating multiple elements, a modifier and an anchor - optional colons included /// @include object('buttonstrip') { /// display: none; /// /// @include multi('modifier:' 'mod', 'elem:' 'button' 'separator', '> a') { /// display: block; /// } /// } /// /// // Generates: /// /// .o-buttonstrip { /// display: none; /// } /// /// .o-buttonstrip--mod { /// display: block; /// } /// /// .o-buttonstrip__button, { /// .o-buttonstrip__separator { /// display: block; /// } /// /// .o-buttonstrip > a { /// display: block; /// } /// @mixin multi($first, $others...) { @include contexts.assert-stack-count(vars.$context-id, vars.$max-depth); @each $entity in functions.list-prepend($others, $first) { $is-manual-selector: false; @if type-of($entity) == string { @if find-bem-function($entity) == null { $is-manual-selector: true; } } @if $is-manual-selector { $sel: if(&, selector-nest(&, $entity), selector-parse($entity)); @at-root #{$sel} { @content; } } @else { $entity-func-id: null; @if type-of($entity) == list { $entity-func-id: nth($entity, 1); $entity: functions.list-slice($entity, 2); } @else { $entity-func-id: $entity; $entity: (); } @if str-slice($entity-func-id, str-length($entity-func-id)) == ':' { $entity-func-id: unquote(str-slice($entity-func-id, 1, str-length($entity-func-id) - 1)); } $sel-func: find-bem-function($entity-func-id); @if $sel-func == null { @error 'Function "#{inspect($entity-func-id)}" was not found.'; } $entity-result: call($sel-func, $entity...); $entity-result-selector: nth($entity-result, 1); $entity-result-context: nth($entity-result, 2); @if $entity-result-context != null { @include contexts.push(vars.$context-id, $entity-result-context...); } @at-root #{$entity-result-selector} { @content; } @if $entity-result-context != null { @include contexts.pop(vars.$context-id); } } } } @function find-bem-function($name) { @each $module in (block element modifier state suffix theme) { @if function-exists($name, $module) { @return get-function($name, $module: $module); } } @return null; }