BemPug
Simple mixins to help you writing code on BEM methodology in pug or jade projects.
You like BEM? Try BemGo — starter kit for developing BEM apps using Gulp and Webpack.
Anchors
Install | Mixins | Examples | Helpers | Changelog
Install
Install from npm:
npm i bempug -D
Then include index
file to your pug or jade project:
include ../../node_modules/bempug/index
Mixins
Block mixin:
+b( name, data, tag )
- name
String
- data
String or Object
- data.m
String
— block modifier - data.p
Boolean
— disable parent mode - data.e
Array or String
— mix block with element - data.b
Array or String
— mix block with another block - data.t
String
— block tag - data.s
String
— block separators
- data.m
- tag
String
If data argument is String it will be a modifier.
Element mixin:
+e( name, data, tag )
- name
String
- data
String or Object
- data.m
String
— element modifier - data.p
String
— parent block - data.e
Array or String
— mix element with another element - data.b
Array or String
— mix element with block - data.t
String
— element tag - data.s
String
— element separators
- data.m
- tag
String
If data argument is String it will be a modifier.
Examples
Block | Element | Modifier | Tag | Mix | Separators
Block
Simple example:
+b( 'block' ) +e( 'element' ) Text
<div class="block"> <div class="block__element">Text</div></div>
You can to disable parent mode and element will ignore this block:
+b( 'header' ) +b( 'grid', {p: false} ) // or short {p:0} +e( 'logo' ) Logo
<div class="header"> <div class="grid"> <div class="header__logo">Logo</div> </div></div>
Element
Element depends on parent block:
+b( 'content' ) +e( 'layout' ) Content
<div class="content"> <div class="content__layout">Content</div></div>
You can set parent block for element directly:
+b( 'content' ) +e( 'layout', {p: 'page'} ) Content
<div class="content"> <div class="page__layout">Content</div></div>
Modifier
Block and element have modifier:
+b( 'alert', 'success' ) +e( 'text', 'bolder' ) Success
<div class="alert alert--success"> <div class="alert__text alert__text--bolder">Success</div></div>
Block and element have more than one modifier:
+b( 'alert', 'success.active' ) +e( 'text', 'bolder.italic' ) Success
<div class="alert alert--success alert--active"> <div class="alert__text alert__text--bolder alert__text--italic">Success</div></div>
Also, you can set modifiers in Object
:
+b( 'alert', {m: 'success.active'} ) Success
<div class="alert alert--success alert--active">Success</div>
Tag
Default tag is div, but you can set it directly:
+b( 'news', {}, 'article' ) +e( 'title', {}, 'h1' ) Title // Or in data Object +b( 'news', {t: 'article'} ) +e( 'title', {t: 'h1'} ) Title
<article class="news"> <h1 class="news__title">Title</h1></article>
Sometimes mixin can be smart and tag depends on parent or attributes:
+b( 'list', {t: 'ul'} ) +e( 'item' ) My item 1 +e( 'item' ) My item 2 +e( 'item' ) My item 3 +b( 'link' )(href='https://www.npmjs.com/package/bempug') +b( 'text' ) My text
<ul class="list"> <li class="list__item">My item 1</li> <li class="list__item">My item 2</li> <li class="list__item">My item 3</li></ul> <a class="link" href="https://www.npmjs.com/package/bempug"> <span class="text">My text</span></a>
Also, you can use tagByName
global option for set default tag by name:
- BEMPUG.tagByName = {list: 'ul', form: 'form', fields: 'fieldset'}; +b( 'list' ) +e( 'item' ) Item +e( 'item' ) Item +b( 'form' ) +e( 'fields' ) Fields
<ul class="list"> <li class="list__item">Item</li> <li class="list__item">Item</li></ul> <form class="form"> <fieldset class="form__fields">Fields</fieldset></form>
Mix
Block is mixed with element:
+b( 'title', {e: 'article'} ) Title
<div class="title article__title">Title</div>
You can set name of element in mix with colon:
+b( 'title', {e: 'article:my-name'} ) Title
<div class="title article__my-name">Title</div>
Block is mixed with two elements:
+b( 'title', {e: ['article', 'content']} ) Title
<div class="title article__title content__title">Title</div>
Also, you can use ampersand &
sign as parent block reference:
+b( 'news' ) +b( 'title', {e: '&'} ) Title +b( 'text', {e: '&:description'} ) Text
<div class="news"> <div class="title news__title">Title</div> <div class="text news__description">Text</div></div>
Block is mixed with element which has modifiers:
+b( 'title', {e: 'news|bolder.size-m'} ) Title
<div class="title news__title news__title--bolder news__title--size-m">Title</div>
Element is mixed with another element:
+b( 'footer' ) +e( 'bottom', {e: 'page'} )
<div class="footer"> <div class="footer__bottom page__bottom"></div></div>
Element is mixed with block:
+b( 'footer' ) +e( 'bottom', {b: 'grid'} )
<div class="footer"> <div class="footer__bottom grid"></div></div>
Block is mixed with another block:
+b( 'article', {b: 'news'} ) Content
<div class="article news">Content</div>
Block is mixed with another block which has modifiers:
+b( 'article', {b: 'news|first'} ) Content
<div class="article news news--first">Content</div>
Block is mixed with two blocks which have modifiers:
+b( 'article', {b: ['news|first','fixed|active']} ) Content
<div class="article news news--first fixed fixed--active">Content</div>
Separators
You can change global separators:
- BEMPUG.modifier = '_';- BEMPUG.element = '__'; +b( 'alert', 'success.active' ) +e( 'text', 'bolder.italic' ) Success
<div class="alert alert_success alert_active"> <div class="alert__text alert__text_bolder alert__text_italic">Success</div></div>
Also, you can set separators for each block and ignore global settings 'modifier|element'
:
+b( 'news', {e: 'content', m: 'first', s: '---|___' } ) +b( 'text', {e: true, m: 'bolder'} ) Text
<div class="news news---first content___news"> <div class="text text---bolder news___text">Text</div></div>
Helpers
Get current block | Get current parent | Callbacks
Get current block
You can get current block name:
+b( 'nav' ) +e( 'item' ) - console.log( BEMPUG.getCurrentBlock() ); // 'nav' +b( 'img' ) - console.log( BEMPUG.getCurrentBlock() ); // 'img'
Get current parent
You can get current parent Object
:
+b( 'html', 'no-js', 'html' )(lang='en') - console.log( BEMPUG.getCurrentParent() );
{ type: 'block', name: 'html', tag: 'html', attributes: { lang: 'en' }, sep: { modifier: '--', element: '__' }, classes: [ 'html', 'html--no-js' ], parent: {}, selfClosing: false }
Callbacks
You can set beforeParse
callback:
- BEMPUG.beforeParse[ 'input' ] = function( block ) { if ( typeof block.data.m === 'undefined' ) block.data.m = 'default';} +b( 'input', {m: 'search'} ) // Have modifier 'search' +b( 'input' ) // No modifier, but we set modifier 'default' by callback
<input class="input input--search"><input class="input input--default">
You can set afterParse
callback:
- BEMPUG.afterParse[ 'page' ] = function( block ) { block.setTag( 'body' ); block.addModifier( 'test' ); block.attributes.itemscope = true; block.attributes.itemtype = 'http://schema.org/WebPage';} +b( 'page' ) My page
<body class="page page--test" itemscope itemtype="http://schema.org/WebPage">My page</body>
Changelog
1.1.1
- Fixed: disable parent mode not work in cb
- Fixed: name of element in mix with another element
1.1.0
- Add: ampersand sign for mix
- Add: mix element with blocks and another elements
1.0.2
- Add: some global helpers
- Add: before / after parse callback
- Fixed: block and element separators work for any descendant
- Fixed: default tag depends on parent tag for any descendant
1.0.1
- Add: disable parent mode for blocks
1.0.0
- Release version
Thanks
Many thanks to Roman Komarov for the original idea.