Last active
September 21, 2018 23:52
-
-
Save SidOfc/05121807f89a35571ebfa626fa9c1f0d to your computer and use it in GitHub Desktop.
BEM helper V2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const isObject = subject => subject !== null && typeof subject === 'object'; | |
const b = block => { | |
return { | |
// store values in underscored variable names since | |
// normal names will be used for functions | |
__block: block, | |
__element: null, | |
__modifiers: [], | |
// clear element and modifier cache | |
clear() { | |
this.__element = null; | |
this.__modifiers = []; | |
}, | |
// set BEM element | |
element(element) { | |
if (element) this.__element = element; | |
return this; | |
}, | |
// set BEM modifiers | |
// if any of the arguments is an object, it will | |
// iterate over the entries and add the key as a | |
// modifier when its value is truthy | |
modifiers(...modifiers) { | |
this.__modifiers = modifiers.reduce((mods, modifier) => { | |
if (isObject(modifier)) { | |
Object.entries(modifier).forEach(([mod, accept]) => { | |
if (accept && !mods.includes(mod)) mods.push(mod); | |
}); | |
} else if (Array.isArray(modifier)) { | |
modifier.forEach(mod => mods.push(mod)); | |
} else if (!mods.includes(modifier)) { | |
mods.push(modifier); | |
} | |
return mods; | |
}, []); | |
return this; | |
}, | |
// overwrite toString to output CSS class string | |
toString() { | |
let str = this.__block; | |
if (this.__element) { | |
str = `${str}__${this.__element.toString()}`; | |
} | |
if (this.__modifiers.length > 0) { | |
str = this.__modifiers.reduce((classes, modifier) => { | |
if (modifier) classes.push(`${str}--${modifier}`); | |
return classes; | |
}, [str]).join(' '); | |
} | |
this.clear(); | |
return str; | |
}, | |
// create some short aliasses for short `b(...).e(...).m(...)` notation | |
e(...args) { return this.element(...args); }, | |
m(...args) { return this.modifiers(...args); } | |
}; | |
}; | |
const bem = name => { | |
const block = b(name); | |
const parser = (...args) => { | |
if (typeof args[0] === 'string') { | |
return block.element(args[0]).modifiers(...args.slice(1)); | |
} else { | |
return block.modifiers(...args); | |
} | |
}; | |
// check Proxy support (cough IE11) before usage | |
if (typeof Proxy) { | |
return new Proxy(parser, { | |
get(target, property) { | |
if (property === Symbol.toPrimitive) return () => block.toString(); | |
return (...args) => parser(property, ...args); | |
}, | |
apply(target, thisArg, args) { | |
return parser(...args); | |
} | |
}); | |
} | |
return parser; | |
}; | |
const [large, focussed] = [true, true]; | |
const cn = bem('search'); | |
// always supported | |
console.log(`${b('search').e('bar').m({large, focussed}, 'milk')}`); | |
console.log(`${cn('bar', {large, focussed}, 'milk')}`); | |
console.log(`${cn({large, focussed})}`); | |
console.log(`${cn({large, focussed}, 'yoyo')}`); | |
// only possible with Proxy support | |
console.log(`${cn.bar({large, focussed})}`); | |
console.log(`${cn.button({large, red: true})}`); | |
console.log(`${cn}`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment