Skip to content

Instantly share code, notes, and snippets.

@gildniy
Created November 23, 2017 03:16
Show Gist options
  • Save gildniy/e328665cbd14d1c2b8d500d077a7222f to your computer and use it in GitHub Desktop.
Save gildniy/e328665cbd14d1c2b8d500d077a7222f to your computer and use it in GitHub Desktop.
Expressive BEM mixins (for BEM and namespacing) as reference to this post using the same approach for .sass file (https://codepen.io/andersschmidt/post/expressive-bem-with-sass-part-ii-a-first-draft-of-mixins)
// ------------------------------------------------
// Expressive BEM mixins (for BEM and namespacing)
//-------------------------------------------------
//---------------------------------------------
// Creates a new, top-level Block
// --------------------------------------------
// If a type (e.g. component, module, utility)
// is given, it will auto-generate a namespaced
// class that adheres to Harry Roberts' post
// on namespaced BEM classes.
// If given: @include new(product-item, component)
// Produces: .c-product-item
// Remember, the $type is optional.
@mixin new($name, $type: null) {
@at-root {
@if ($type != null) {
$namespace: str-slice($type, 0, 1);
.#{$namespace}-#{$name} {
@content
}
} @else {
.#{$name} {
@content
}
}
}
}
@mixin class($name, $type: null) { /* OOP class alias */
@include new($name, $type: null) {
@content
}
}
@mixin createClass($name, $type: null) { /* React-inspired class alias */
@include new($name, $type: null) {
@content
}
}
/*---------------------------------------------
// Creates an Element
//---------------------------------------------*/
// If given:
// @include new(product-item, component){
// @include has(title)
// }
//
// Produces:
// .c-product-item {}
// .c-product-item__title {}
//
// If given:
// @include new(person){
// @include when(female);
// @include has(hand, person) refers to the parent scope
// }
// }
//
// Produces:
// .person {};
// .person--female {};
// .person--female .person__hand {};
//
@mixin has($name, $childOf: '') {
@if ($childOf != '') {
.#{$childOf}__#{$name} {
@content
}
} @else {
@at-root {
#{&}__#{$name} {
@content
}
}
}
}
//----------------------------------------------
// Creates a Modifier
// ---------------------------------------------
// If given:
// @include new(person){
// @include when(female)
// }
//
// Produces:
// .person {}
// .person--female {}
@mixin when($name) {
@at-root {
#{&}--#{$name} {
@content
}
}
}
//-----------------------------------------------
// Creates a behaviorial State
// -----------------------------------------
// If given:
// @include new(menu, component){
// @include has(item){
// @include if(active)
// }
// }
//
// Produces:
// .c-menu {}
// .c-menu__item {}
// .c-menu__item.is-active {}
@mixin if-its($state) {
&.is-#{$state} {
@content
}
}
@mixin if($state) {
@include if-its($state) {
@content
}
}
//-----------------------------------------------
// Creates an ownership State
//-----------------------------------------------
// If given:
// @include new(menu, component){
// @include has(item){
// @include with(dropdown)
// }
// }
//
// Produces:
// .c-menu {}
// .c-menu__item {}
// .c-menu__item.has-dropdown {}
@mixin got($something) {
&.has-#{$something} {
@content
}
}
@mixin with($something) {
@include got($something) {
@content
}
}
//-----------------------------------------------
// Allows importing Blocks into other Blocks
//-----------------------------------------------
// Uses @extend, so BEWARE. This is experimental,
// may mess up your code, so double-check that the
// output is what you want.
//
// This potentially allows you to create blocks
//(components, modules etc.) seperately and instead
// load them into a parent block / component similar
// to something like React.
//
// As a silly example, let's say you've made
// a List component and your Product
// component should be imported into, rather than
// nested as a @include has:
//
// @include new(product, component){
// color: red;
// height: 50px;
// width: 100px;
// }
//
// @include new(list, component){
// display: block;
// margin: 0;
//
// @include import(c-product)
// }
//
// Note that we're using the generated class name
// as the parameter value in @include import. So just saying
// @include import(product) won't work(unless you wrote
// @include new(product) without setting a type).
@mixin import($something) {
@at-root {
& .#{$something} {
@extend .#{$something};
@content
}
}
}
@mixin fetch($something) {
@include import($something) {
@content
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment