Created
July 7, 2020 11:30
Star
You must be signed in to star a gist
BEM-style class name builder
This file contains 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
/** | |
* 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