1+ import { classNames , isRecord } from '@/css/classnames.js' ;
2+
3+ export interface BlockFn {
4+ ( ...mods : unknown [ ] ) : string ;
5+ }
6+
7+ export interface ElemFn {
8+ ( elem : string , ...mods : unknown [ ] ) : string ;
9+ }
10+
11+ /**
12+ * Applies mods to the specified element.
13+ * @param element - element name.
14+ * @param mod - mod to apply.
15+ */
16+ function applyMods ( element : string , mod : unknown ) : string {
17+ if ( Array . isArray ( mod ) ) {
18+ return classNames ( mod . map ( m => applyMods ( element , m ) ) ) ;
19+ }
20+ if ( isRecord ( mod ) ) {
21+ return classNames (
22+ Object . entries ( mod ) . map ( ( [ mod , v ] ) => v && applyMods ( element , mod ) ) ,
23+ ) ;
24+ }
25+ const v = classNames ( mod ) ;
26+ return v && `${ element } --${ v } ` ;
27+ }
28+
29+ /**
30+ * Computes final classname for the specified element.
31+ * @param element - element name.
32+ * @param mods - mod to apply.
33+ */
34+ function computeClassnames ( element : string , ...mods : unknown [ ] ) : string {
35+ return classNames ( element , applyMods ( element , mods ) ) ;
36+ }
37+
38+ /**
39+ * @returns A tuple, containing two functions. The first one generates classnames list for the
40+ * block, the second one generates classnames for its elements.
41+ * @param block - BEM block name.
42+ */
43+ export function bem ( block : string ) : [ BlockFn , ElemFn ] {
44+ return [
45+ ( ...mods ) => computeClassnames ( block , mods ) ,
46+ ( elem , ...mods ) => computeClassnames ( `${ block } __${ elem } ` , mods ) ,
47+ ] ;
48+ }
0 commit comments