/
bem.ts
75 lines (66 loc) · 2.01 KB
/
bem.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
type Block = string;
type Element = string;
type Modifier = Record<string, unknown>;
function modify(base: string, modifier?: Modifier): string {
if (!modifier) {
return base;
}
const hasOwn = Object.prototype.hasOwnProperty;
return Object.keys(modifier).reduce((s, mod) => {
if (hasOwn.call(modifier, mod) && modifier[mod]) {
s = `${s} ${base}--${mod}`;
}
return s;
}, base);
}
type BEMResult = (
elementOrModifier?: Element | Modifier,
modifier?: Modifier
) => string;
/**
* Applies the BEM styled class name to an element.
*
* @see https://en.bem.info/methodology/css/
* @param base - The base class to use
* @returns a function to call that generates the full class name
*/
export function bem(base: Block): BEMResult {
if (process.env.NODE_ENV !== "production") {
if (!base) {
throw new Error(
"bem requires a base block class but none were provided."
);
}
}
/**
* Creates the full class name from the base block name. This can be called
* without any arguments which will just return the base block name (kind of
* worthless), or you can provide a child element name and modifiers.
*
* @param elementOrModifier - This is either the child element name or an
* object of modifiers to apply. This **must** be a string if the second
* argument is provided.
* @param modifier - Any optional modifiers to apply to the block and optional
* element.
* @returns the full class name
*/
return function block(
elementOrModifier?: Element | Modifier,
modifier?: Modifier
): string {
if (process.env.NODE_ENV !== "production") {
if (typeof elementOrModifier !== "string" && modifier) {
throw new TypeError(
"bem does not support having two modifier arguments."
);
}
}
if (!elementOrModifier) {
return base;
}
if (typeof elementOrModifier !== "string") {
return modify(base, elementOrModifier);
}
return modify(`${base}__${elementOrModifier}`, modifier);
};
}