Skip to content

Instantly share code, notes, and snippets.

@brookjordan
Created July 7, 2020 11:30
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save brookjordan/7db9bdbf20c7c9756e9262659c7da86f to your computer and use it in GitHub Desktop.
BEM-style class name builder
/**
* Used like:
* const cls = buildBEMBuilder("block-name");
*
* let blockClass = cls();
* // => "block-name"
*
* let modifiedBlockClass = cls({
* goodModifier: true,
* badModifier: false,
* });
* // => "block-name block-name--good-modifier"
*
* let elementClass = cls('an-element');
* // => "block-name__an-element"
*
* let modifiedElementClass = cls('an-element', {
* aModifier: true,
* anotherModifier: true,
* });
* // => "block-name__an-element block-name__an-element--a-modifier block-name__an-element--another-modifier"
**/
type Modifier = { [key: string]: boolean };
const FALSY_CHECKS = {
true<T>(condition: T) { return typeof condition !== 'boolean' || condition === false },
truthy<T>(condition: T) { return !condition },
nullish<T>(condition: T) { return (typeof condition === 'boolean' && condition === false) || condition == null },
};
type FalsyCheckName = keyof typeof FALSY_CHECKS;
let [ modifierCheckStyle ]: FalsyCheckName[] = (Object.keys(FALSY_CHECKS) as FalsyCheckName[]);
function dasherize(str: string) {
return str
.replace(/_/g, "-")
.replace(/[A-Z]/g, char => `-${char.toLowerCase()}`)
.replace(/^-+/g, "");
}
function buildBEMBuilder(_blockName: string) {
const blockName = dasherize(_blockName);
return function combineWithElementAndModifiers(element: (string | Modifier), modifiers: Modifier = {}) {
const falseCheck = FALSY_CHECKS[modifierCheckStyle];
if (!element) { return blockName; }
let elementClass = blockName;
if (typeof element === "string") {
elementClass += `__${dasherize(element)}`;
}
if (typeof element === "object") {
modifiers = element;
}
if (!modifiers) { return elementClass; }
return [
elementClass,
...Object.keys(modifiers)
.filter((modifier) => !falseCheck(modifiers[modifier]))
.map((modifier) => {
return `${elementClass}--${dasherize(modifier)}`;
}),
].join(' ');
}
}
Object.defineProperty(buildBEMBuilder, "modifierCheckStyle", {
get() {
return modifierCheckStyle;
},
set(requestedCheckStyle: FalsyCheckName) {
modifierCheckStyle = requestedCheckStyle;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment