Skip to content

Instantly share code, notes, and snippets.

@SidOfc
Last active September 21, 2018 23:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SidOfc/05121807f89a35571ebfa626fa9c1f0d to your computer and use it in GitHub Desktop.
Save SidOfc/05121807f89a35571ebfa626fa9c1f0d to your computer and use it in GitHub Desktop.
BEM helper V2
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