Last active
October 21, 2022 00:59
-
-
Save 0x009922/cb0d8763a6e0892e3e2a2be000f59af2 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import { CamelCase, Simplify } from 'type-fest' | |
declare const create: <B extends string>(blockName: B) => BlockBuilder<B> | |
interface BlockBuilder<R extends string, M extends ModifiersArray = [], E extends BuiltElem<any, any>[] = []> { | |
mod: { | |
<B extends AnyBlockBuilder, M extends string>(this: B, name: M): ExtendsBlockModifiers<B, M> | |
<B extends BlockBuilder<any, any>, M extends string, V extends string>( | |
this: B, | |
modName: M, | |
modVal: V, | |
): ExtendsBlockModifiers<B, M, V> | |
} | |
elem: <B extends AnyBlockBuilder, E extends string>(this: B, elemName: E) => ElemBuilder<B, E> | |
finish: <B extends AnyBlockBuilder>(this: B, mode: 'classic') => BuildBEM<B> | |
} | |
type AnyBlockBuilder = BlockBuilder<any, any, any> | |
interface ElemBuilder<B extends BlockBuilder<any, any>, E extends string, M extends ModifiersArray = []> { | |
mod: { | |
<B extends ElemBuilder<any, any, any>, M extends string>(this: B, modName: M): ExtendElemModifiers<B, M> | |
<B extends ElemBuilder<any, any, any>, M extends string, V extends string>( | |
this: B, | |
modName: M, | |
modVal: V, | |
): ExtendElemModifiers<B, M, V> | |
} | |
finish: <B extends ElemBuilder<any, any, any>>(this: B) => FinishElemBuilder<B> | |
} | |
type FinishElemBuilder<B extends ElemBuilder<any, any, any>> = B extends ElemBuilder< | |
BlockBuilder<infer BlockName, infer BlockModifiers, infer BlockElems>, | |
infer ElemName, | |
infer ElemModifiers | |
> | |
? BlockBuilder<BlockName, BlockModifiers, [...BlockElems, BuiltElem<ElemName, ElemModifiers>]> | |
: null | |
interface BuiltElem<N extends string, M extends ModifiersArray> { | |
elemName: N | |
modifiers: M | |
} | |
interface Modifier<M extends string, V extends string> { | |
kind: 'mod' | |
mod: M | |
val: V | |
} | |
interface BoolModifier<M extends string> { | |
kind: 'bool' | |
mod: M | |
} | |
type ExtendElemModifiers<E, M extends string, V extends string | null = null> = E extends ElemBuilder< | |
infer B, | |
infer E, | |
infer Current | |
> | |
? ElemBuilder<B, E, AddModifier<Current, M, V>> | |
: never | |
type ExtendsBlockModifiers<B, M extends string, V extends string | null = null> = B extends BlockBuilder< | |
infer R, | |
infer Current, | |
infer Elems | |
> | |
? BlockBuilder<R, AddModifier<Current, M, V>, Elems> | |
: never | |
type ModifiersArray = Array<Modifier<any, any> | BoolModifier<any>> | |
type AddModifier<Current extends ModifiersArray, M extends string, V extends string | null = null> = [ | |
...Current, | |
V extends string ? Modifier<M, V> : BoolModifier<M>, | |
] | |
type BuildBEM<B> = B extends BlockBuilder<infer R, infer M, infer E> | |
? Simplify<ExpandModifiers<`${CamelCase<R>}_`, M> & ExpandElems<`${CamelCase<R>}__`, E>> | |
: never | |
type ExpandModifiers<Pre extends string, M> = M extends [infer M, ...infer Tail] | |
? (M extends BoolModifier<infer M> | |
? { | |
[K in `${Pre}${CamelCase<M>}`]: `${Pre}_${M}` | |
} | |
: M extends Modifier<infer M, infer V> | |
? { | |
[K in `${Pre}${CamelCase<M>}_${CamelCase<V>}`]: `${Pre}_${M}_${V}` | |
} | |
: never) & | |
ExpandModifiers<Pre, Tail> | |
: {} | |
type ExpandElems<Pre extends string, E> = E extends [BuiltElem<infer E, infer M>, ...infer Tail] | |
? { [K in `${Pre}${CamelCase<E>}`]: string } & ExpandModifiers<`${Pre}${CamelCase<E>}_`, M> & ExpandElems<Pre, Tail> | |
: {} | |
type Test1 = ExpandModifiers<'nya', [BoolModifier<'load'>, Modifier<'a', 'b'>]> | |
type Test2 = ExpandElems<'hoh', []> | |
type Test3 = ExpandElems<'hoh__', [BuiltElem<'yay', [Modifier<'mod', 'val'>]>]> | |
type Test4 = FinishElemBuilder<ElemBuilder<BlockBuilder<'block', [], []>, 'elem', []>> | |
const bem4 = create('block').elem('elem').finish().finish('classic') | |
const bem = create('my-component') | |
.mod('loading') | |
.mod('disabled') | |
.mod('theme', 'light') | |
.mod('theme', 'dark') | |
.elem('input') | |
.finish() | |
.elem('button') | |
.mod('loading') | |
.mod('bg', '1') | |
.mod('bg', '2') | |
.finish() | |
.finish('classic') | |
// type `bem.` |
This file contains hidden or 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
import { Simplify } from 'type-fest' | |
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false | |
type Expect<T extends true> = T | |
declare const defineBem: <B extends string>(blockName: B) => BlockBuilder<B> | |
type BemStyle = 'classic' | 'two-dashes' | |
type ApplyStyleToModifier< | |
style extends BemStyle, | |
m extends ModifierBool<any> | ModifierKeyValue<any, any>, | |
> = m extends ModifierBool<infer k> | |
? k | |
: m extends ModifierKeyValue<infer k, infer v> | |
? style extends 'classic' | |
? `${k}_${v}` | |
: style extends 'two-dashes' | |
? `${k}--${v}` | |
: never | |
: never | |
type ApplyStyleToModifierPrefix<style extends BemStyle, r extends string> = style extends 'classic' | |
? `${r}_` | |
: style extends 'two-dashes' | |
? `${r}--` | |
: never | |
type ApplyStyleToElementPrefix<style extends BemStyle, r extends string> = `${r}__` | |
interface BlockBuilder<r extends string, mm extends ModifiersArray = [], ee extends BuiltElem<any, any>[] = []> { | |
mod: { | |
<m extends string>(key: m): ExtendBlockWithModifier<BlockBuilder<r, mm, ee>, m> | |
<m extends string, v extends string>(key: m, value: v): ExtendBlockWithModifier<BlockBuilder<r, mm, ee>, m, v> | |
} | |
elem: { | |
<n extends string>(name: n): ExtendBlockWithElement<BlockBuilder<r, mm, ee>, BuiltElem<n, []>> | |
<n extends string, e extends ElemBuilder<any>>( | |
name: n, | |
fn: (elementBuilder: ElemBuilder) => e, | |
): ExtendBlockWithElement<BlockBuilder<r, mm, ee>, BuildElement<n, e>> | |
} | |
build: { | |
(): BuildClasses<BlockBuilder<r, mm, ee>, 'classic'> | |
<s extends BemStyle>(style: s): BuildClasses<BlockBuilder<r, mm, ee>, s> | |
} | |
} | |
type AnyBlockBuilder = BlockBuilder<any, any, any> | |
type ExtendBlockWithElement<b extends AnyBlockBuilder, e extends BuiltElem<any, any>> = b extends BlockBuilder< | |
infer r, | |
infer m, | |
infer ee | |
> | |
? BlockBuilder<r, m, [...ee, e]> | |
: never | |
type BuildElement<n extends string, b extends ElemBuilder<any>> = b extends ElemBuilder<infer m> | |
? BuiltElem<n, m> | |
: never | |
interface ElemBuilder<mm extends ModifiersArray = []> { | |
mod: { | |
<k extends string>(key: k): ExtendElemWithModifier<ElemBuilder<mm>, k> | |
<k extends string, v extends string>(key: k, value: v): ExtendElemWithModifier<ElemBuilder<mm>, k, v> | |
} | |
} | |
interface BuiltElem<n extends string, m extends ModifiersArray> { | |
name: n | |
modifiers: m | |
} | |
interface ModifierKeyValue<M extends string, V extends string> { | |
kind: 'modifier-k-v' | |
key: M | |
value: V | |
} | |
interface ModifierBool<M extends string> { | |
kind: 'modifier-bool' | |
key: M | |
} | |
type ExtendElemWithModifier< | |
e extends ElemBuilder<any>, | |
k extends string, | |
v extends string | null = null, | |
> = e extends ElemBuilder<infer m> ? ElemBuilder<AddModifier<m, k, v>> : never | |
type ExtendBlockWithModifier< | |
builder extends AnyBlockBuilder, | |
key extends string, | |
value extends string | null = null, | |
> = builder extends BlockBuilder<infer root, infer modifiers, infer elements> | |
? BlockBuilder<root, AddModifier<modifiers, key, value>, elements> | |
: never | |
type ModifiersArray = Array<ModifierKeyValue<any, any> | ModifierBool<any>> | |
type AddModifier<m extends ModifiersArray, k extends string, v extends string | null = null> = [ | |
...m, | |
v extends string ? ModifierKeyValue<k, v> : ModifierBool<k>, | |
] | |
type test1 = Expect<Equal<AddModifier<[], 'foo'>, [ModifierBool<'foo'>]>> | |
type test2 = Expect<Equal<AddModifier<[], 'foo', 'bar'>, [ModifierKeyValue<'foo', 'bar'>]>> | |
type test3 = Expect< | |
Equal<AddModifier<[ModifierBool<'foo'>], 'foo', 'bar'>, [ModifierBool<'foo'>, ModifierKeyValue<'foo', 'bar'>]> | |
> | |
type BuildClasses<b extends AnyBlockBuilder, style extends BemStyle> = b extends BlockBuilder< | |
infer r, | |
infer mm, | |
infer ee | |
> | |
? Simplify<BuildModifierClasses<r, mm, style> & BuildElementsTupleClasses<r, ee, style>> | |
: never | |
type test11 = Expect< | |
Equal< | |
BuildClasses< | |
BlockBuilder<'ro-ot', [ModifierKeyValue<'ke-y', 'va-lue'>], [BuiltElem<'elem-1', [ModifierBool<'elem-flag'>]>]>, | |
'classic' | |
>, | |
TupleToRecord<['ro-ot_ke-y_va-lue', 'ro-ot__elem-1', 'ro-ot__elem-1_elem-flag']> | |
> | |
> | |
type BuildModifierSuffixes<m extends ModifiersArray, style extends BemStyle> = m extends [ | |
infer h extends ModifierBool<any> | ModifierKeyValue<any, any>, | |
...infer t extends ModifiersArray, | |
] | |
? [ApplyStyleToModifier<style, h>, ...BuildModifierSuffixes<t, style>] | |
: [] | |
type test7 = Expect< | |
Equal< | |
BuildModifierSuffixes<[ModifierBool<'foo'>, ModifierKeyValue<'my-key', 'my-value'>], 'classic'>, | |
['foo', 'my-key_my-value'] | |
> | |
> | |
type ConcatPrefixTuple<t extends string[], p extends string> = t extends [ | |
infer head extends string, | |
...infer tail extends string[], | |
] | |
? [`${p}${head}`, ...ConcatPrefixTuple<tail, p>] | |
: [] | |
type test8 = Expect< | |
Equal< | |
ConcatPrefixTuple<['foo', 'my-key_my-value'], 'my-component_'>, | |
['my-component_foo', 'my-component_my-key_my-value'] | |
> | |
> | |
type TupleToRecordRecur<t extends any[]> = t extends [infer head extends string, ...infer tail] | |
? { [K in head]: K } & TupleToRecordRecur<tail> | |
: {} | |
type TupleToRecord<t extends any[]> = Simplify<TupleToRecordRecur<t>> | |
type test9 = Expect< | |
Equal< | |
TupleToRecord<['a', 'b', 'c']>, | |
{ | |
a: 'a' | |
b: 'b' | |
c: 'c' | |
} | |
> | |
> | |
type BuildModifierClasses<r extends string, m extends ModifiersArray, style extends BemStyle> = TupleToRecord< | |
ConcatPrefixTuple<BuildModifierSuffixes<m, style>, ApplyStyleToModifierPrefix<style, r>> | |
> | |
type test10 = Expect< | |
Equal< | |
BuildModifierClasses<'r-oot', [ModifierBool<'bool'>, ModifierKeyValue<'key', 'value'>], 'classic'>, | |
TupleToRecord<['r-oot_bool', 'r-oot_key_value']> | |
> | |
> | |
type BuildElementClasses<r extends string, e extends BuiltElem<any, any>, style extends BemStyle> = e extends BuiltElem< | |
infer n, | |
infer mm | |
> | |
? `${ApplyStyleToElementPrefix<style, r>}${n}` extends infer elem extends string | |
? TupleToRecord< | |
[elem, ...ConcatPrefixTuple<BuildModifierSuffixes<mm, style>, ApplyStyleToModifierPrefix<style, elem>>] | |
> | |
: never | |
: never | |
type BuildElementsTupleClassesRecur< | |
r extends string, | |
ee extends BuiltElem<any, any>[], | |
style extends BemStyle, | |
> = ee extends [infer head extends BuiltElem<any, any>, ...infer tail extends BuiltElem<any, any>[]] | |
? BuildElementClasses<r, head, style> & BuildElementsTupleClassesRecur<r, tail, style> | |
: {} | |
type BuildElementsTupleClasses<r extends string, ee extends BuiltElem<any, any>[], style extends BemStyle> = Simplify< | |
BuildElementsTupleClassesRecur<r, ee, style> | |
> | |
type test12 = Expect< | |
Equal< | |
BuildElementClasses<'root', BuiltElem<'elem-1', [ModifierKeyValue<'key', 'value'>]>, 'classic'>, | |
TupleToRecord<['root__elem-1', 'root__elem-1_key_value']> | |
> | |
> | |
const bem4 = defineBem('block').elem('elem').build('classic') | |
type test5 = Expect<Equal<typeof bem4, TupleToRecord<['block__elem']>>> | |
const myComponent = defineBem('my-component') | |
.mod('loading') | |
.mod('disabled') | |
.mod('theme', 'light') | |
.mod('theme', 'dark') | |
.elem('input') | |
.elem('button', (b) => b.mod('loading').mod('bg', '1').mod('bg', '2')) | |
const myComponentClassic = myComponent.build() | |
type test6 = Expect< | |
Equal< | |
typeof myComponentClassic, | |
TupleToRecord< | |
[ | |
'my-component_loading', | |
'my-component_disabled', | |
'my-component_theme_light', | |
'my-component_theme_dark', | |
'my-component__input', | |
'my-component__button', | |
'my-component__button_loading', | |
'my-component__button_bg_1', | |
'my-component__button_bg_2', | |
] | |
> | |
> | |
> | |
const myComponentTwoDashes = myComponent.build('two-dashes') | |
type test13 = Expect< | |
Equal< | |
typeof myComponentTwoDashes, | |
TupleToRecord< | |
[ | |
'my-component--loading', | |
'my-component--disabled', | |
'my-component--theme--light', | |
'my-component--theme--dark', | |
'my-component__input', | |
'my-component__button', | |
'my-component__button--loading', | |
'my-component__button--bg--1', | |
'my-component__button--bg--2', | |
] | |
> | |
> | |
> |
This file contains hidden or 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
import { Simplify, CamelCase } from 'type-fest' | |
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false | |
type Expect<T extends true> = T | |
declare const defineBem: <B extends string>(blockName: B) => BlockBuilder<B> | |
type BemStyle = 'classic' | 'two-dashes' | |
type RootBlockKey = 'block' | |
type ApplyStyleToModifier<style extends BemStyle, m extends AnyModifier> = m extends ModifierBool<infer k> | |
? k | |
: m extends ModifierKeyValue<infer k, infer v> | |
? style extends 'classic' | |
? `${k}_${v}` | |
: style extends 'two-dashes' | |
? `${k}--${v}` | |
: never | |
: never | |
type ApplyStyleToModifierPrefix<style extends BemStyle, r extends string> = style extends 'classic' | |
? `${r}_` | |
: style extends 'two-dashes' | |
? `${r}--` | |
: never | |
type ApplyStyleToElementPrefix<style extends BemStyle, r extends string> = `${r}__` | |
interface BlockBuilder<r extends string, mm extends ModifiersArray = [], ee extends BuiltElem<any, any>[] = []> { | |
mod: { | |
<b extends AnyBlockBuilder, m extends string>(this: b, key: m): ExtendBlockWithModifier<b, m> | |
<b extends AnyBlockBuilder, m extends string, v extends string>(this: b, key: m, value: v): ExtendBlockWithModifier< | |
b, | |
m, | |
v | |
> | |
} | |
elem: { | |
<b extends AnyBlockBuilder, n extends string>(this: b, name: n): ExtendBlockWithElement<b, BuiltElem<n, []>> | |
<b extends AnyBlockBuilder, n extends string, e extends ElemBuilder<any>>( | |
this: b, | |
name: n, | |
fn: (elementBuilder: ElemBuilder) => e, | |
): ExtendBlockWithElement<b, BuildElement<n, e>> | |
} | |
build: { | |
(): BuildClasses<BlockBuilder<r, mm, ee>, 'classic'> | |
<s extends BemStyle>(style: s): BuildClasses<BlockBuilder<r, mm, ee>, s> | |
} | |
} | |
type AnyBlockBuilder = BlockBuilder<any, any, any> | |
type ExtendBlockWithElement<b extends AnyBlockBuilder, e extends BuiltElem<any, any>> = b extends BlockBuilder< | |
infer r, | |
infer m, | |
infer ee | |
> | |
? BlockBuilder<r, m, [...ee, e]> | |
: never | |
type BuildElement<n extends string, b extends ElemBuilder<any>> = b extends ElemBuilder<infer m> | |
? BuiltElem<n, m> | |
: never | |
interface ElemBuilder<mm extends ModifiersArray = []> { | |
mod: { | |
<b extends AnyElemBuilder, k extends string>(this: b, key: k): ExtendElemWithModifier<b, k> | |
<b extends AnyElemBuilder, k extends string, v extends string>(this: b, key: k, value: v): ExtendElemWithModifier< | |
b, | |
k, | |
v | |
> | |
} | |
} | |
type AnyElemBuilder = ElemBuilder<any> | |
interface BuiltElem<n extends string, m extends ModifiersArray> { | |
name: n | |
modifiers: m | |
} | |
interface ModifierKeyValue<M extends string, V extends string> { | |
kind: 'modifier-k-v' | |
key: M | |
value: V | |
} | |
interface ModifierBool<M extends string> { | |
kind: 'modifier-bool' | |
key: M | |
} | |
type AnyModifier = ModifierBool<any> | ModifierKeyValue<any, any> | |
type ExtendElemWithModifier< | |
e extends ElemBuilder<any>, | |
k extends string, | |
v extends string | null = null, | |
> = e extends ElemBuilder<infer m> ? ElemBuilder<AddModifier<m, k, v>> : never | |
type ExtendBlockWithModifier< | |
builder extends AnyBlockBuilder, | |
key extends string, | |
value extends string | null = null, | |
> = builder extends BlockBuilder<infer root, infer modifiers, infer elements> | |
? BlockBuilder<root, AddModifier<modifiers, key, value>, elements> | |
: never | |
type ModifiersArray = Array<ModifierKeyValue<any, any> | ModifierBool<any>> | |
type AddModifier<m extends ModifiersArray, k extends string, v extends string | null = null> = [ | |
...m, | |
v extends string ? ModifierKeyValue<k, v> : ModifierBool<k>, | |
] | |
type test1 = Expect<Equal<AddModifier<[], 'foo'>, [ModifierBool<'foo'>]>> | |
type test2 = Expect<Equal<AddModifier<[], 'foo', 'bar'>, [ModifierKeyValue<'foo', 'bar'>]>> | |
type test3 = Expect< | |
Equal<AddModifier<[ModifierBool<'foo'>], 'foo', 'bar'>, [ModifierBool<'foo'>, ModifierKeyValue<'foo', 'bar'>]> | |
> | |
type BuildClasses<b extends AnyBlockBuilder, style extends BemStyle> = b extends BlockBuilder< | |
infer r, | |
infer mm, | |
infer ee | |
> | |
? Simplify<{ [k in RootBlockKey]: r } & BuildModifierClasses<r, mm, style> & BuildElementsTupleClasses<r, ee, style>> | |
: never | |
type test11 = Expect< | |
Equal< | |
BuildClasses< | |
BlockBuilder<'ro-ot', [ModifierKeyValue<'ke-y', 'va-lue'>], [BuiltElem<'elem-1', [ModifierBool<'elem-flag'>]>]>, | |
'classic' | |
>, | |
{ | |
block: 'ro-ot' | |
block_keY_vaLue: 'ro-ot_ke-y_va-lue' | |
block__elem1: 'ro-ot__elem-1' | |
block__elem1_elemFlag: 'ro-ot__elem-1_elem-flag' | |
} | |
> | |
> | |
type BuildModifierSuffixes<m extends ModifiersArray, style extends BemStyle> = m extends [ | |
infer h extends ModifierBool<any> | ModifierKeyValue<any, any>, | |
...infer t extends ModifiersArray, | |
] | |
? [ApplyStyleToModifier<style, h>, ...BuildModifierSuffixes<t, style>] | |
: [] | |
type test7 = Expect< | |
Equal< | |
BuildModifierSuffixes<[ModifierBool<'foo'>, ModifierKeyValue<'my-key', 'my-value'>], 'classic'>, | |
['foo', 'my-key_my-value'] | |
> | |
> | |
type AnyModifierToKeySuffix<t extends AnyModifier> = t extends ModifierBool<infer k> | |
? CamelCase<k> | |
: t extends ModifierKeyValue<infer k, infer v> | |
? `${CamelCase<k>}_${CamelCase<v>}` | |
: never | |
type ModifiersToRecordRecur<r extends string, m extends ModifiersArray, style extends BemStyle> = m extends [ | |
infer head extends AnyModifier, | |
...infer tail extends ModifiersArray, | |
] | |
? { | |
[K in `${RootBlockKey}_${AnyModifierToKeySuffix<head>}`]: `${ApplyStyleToModifierPrefix< | |
style, | |
r | |
>}${ApplyStyleToModifier<style, head>}` | |
} & ModifiersToRecordRecur<r, tail, style> | |
: {} | |
type BuildModifierClasses<r extends string, m extends ModifiersArray, style extends BemStyle> = Simplify< | |
ModifiersToRecordRecur<r, m, style> | |
> | |
type test10 = Expect< | |
Equal< | |
BuildModifierClasses<'s-table', [ModifierBool<'bool'>, ModifierKeyValue<'my-key', 'my-value'>], 'classic'>, | |
{ | |
block_bool: 's-table_bool' | |
block_myKey_myValue: 's-table_my-key_my-value' | |
} | |
> | |
> | |
type BuildSingleElementRecord< | |
style extends BemStyle, | |
r extends string, | |
n extends string, | |
m extends null | AnyModifier = null, | |
> = { | |
[k in `${RootBlockKey}__${CamelCase<n>}${m extends AnyModifier | |
? `_${AnyModifierToKeySuffix<m>}` | |
: ''}`]: `${ApplyStyleToElementPrefix<style, r>}${m extends AnyModifier | |
? `${ApplyStyleToModifierPrefix<style, n>}${ApplyStyleToModifier<style, m>}` | |
: n}` | |
} | |
type BuildElementModifierClassesRecur< | |
r extends string, | |
n extends string, | |
mm extends ModifiersArray, | |
style extends BemStyle, | |
> = mm extends [infer head extends AnyModifier, ...infer tail extends ModifiersArray] | |
? BuildSingleElementRecord<style, r, n, head> & BuildElementModifierClassesRecur<r, n, tail, style> | |
: {} | |
type BuildElementClasses<r extends string, e extends BuiltElem<any, any>, style extends BemStyle> = e extends BuiltElem< | |
infer n, | |
infer mm | |
> | |
? Simplify<BuildSingleElementRecord<style, r, n> & BuildElementModifierClassesRecur<r, n, mm, style>> | |
: never | |
type BuildElementsTupleClassesRecur< | |
r extends string, | |
ee extends BuiltElem<any, any>[], | |
style extends BemStyle, | |
> = ee extends [infer head extends BuiltElem<any, any>, ...infer tail extends BuiltElem<any, any>[]] | |
? BuildElementClasses<r, head, style> & BuildElementsTupleClassesRecur<r, tail, style> | |
: {} | |
type BuildElementsTupleClasses<r extends string, ee extends BuiltElem<any, any>[], style extends BemStyle> = Simplify< | |
BuildElementsTupleClassesRecur<r, ee, style> | |
> | |
type test12 = Expect< | |
Equal< | |
BuildElementClasses<'s-table', BuiltElem<'elem-1', [ModifierKeyValue<'key', 'value'>]>, 'classic'>, | |
{ | |
block__elem1: 's-table__elem-1' | |
block__elem1_key_value: 's-table__elem-1_key_value' | |
} | |
> | |
> | |
const bem4 = defineBem('block').elem('elem').build('classic') | |
type test5 = Expect<Equal<typeof bem4, { block: 'block'; block__elem: 'block__elem' }>> | |
const myComponent = defineBem('my-component') | |
.mod('loading') | |
.mod('disabled') | |
.mod('theme', 'light') | |
.mod('theme', 'dark') | |
.elem('input') | |
.elem('button', (b) => b.mod('loading').mod('bg', '1').mod('bg', '2')) | |
const myComponentClassic = myComponent.build() | |
type test6 = Expect< | |
Equal< | |
typeof myComponentClassic, | |
{ | |
block: 'my-component' | |
block_loading: 'my-component_loading' | |
block_disabled: 'my-component_disabled' | |
block_theme_light: 'my-component_theme_light' | |
block_theme_dark: 'my-component_theme_dark' | |
block__input: 'my-component__input' | |
block__button: 'my-component__button' | |
block__button_loading: 'my-component__button_loading' | |
block__button_bg_1: 'my-component__button_bg_1' | |
block__button_bg_2: 'my-component__button_bg_2' | |
} | |
> | |
> | |
const myComponentTwoDashes = myComponent.build('two-dashes') | |
type test13 = Expect< | |
Equal< | |
typeof myComponentTwoDashes, | |
{ | |
block: 'my-component' | |
block_loading: 'my-component--loading' | |
block_disabled: 'my-component--disabled' | |
block_theme_light: 'my-component--theme--light' | |
block_theme_dark: 'my-component--theme--dark' | |
block__input: 'my-component__input' | |
block__button: 'my-component__button' | |
block__button_loading: 'my-component__button--loading' | |
block__button_bg_1: 'my-component__button--bg--1' | |
block__button_bg_2: 'my-component__button--bg--2' | |
} | |
> | |
> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Intellisense: