Skip to content

Commit fdaa48e

Browse files
author
Andrii Kirmas
committed
#39 Remove b-e notation split in favor of base
1 parent 7929976 commit fdaa48e

File tree

9 files changed

+200
-149
lines changed

9 files changed

+200
-149
lines changed

README.md

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -231,32 +231,16 @@ Table of output logic:
231231
232232
> Tests @ [./src/bem.core.test.ts:13](https://github.com/askirmas/react-classnaming/blob/main/src/bem.core.test.ts#L13-L35)
233233
234-
| Returned `className` | Query argument |
235-
| --------------------------------- | ------------------------------------------------------------ |
236-
| `""` | `{block: false}`<br />`{block: {el: false}}` |
237-
| <hr> | <hr> |
238-
| `"block"` | `{block: true}`<br />`{block: {$: boolean \| {} \| {[mod]: false} }}` |
239-
| `"block__el"` | `{block: {el: true \| {} \| {[mod]: false} }}` |
240-
| <hr> | <hr> |
241-
| `"block block--mod"` | `{block: "mod"}`<br/>`{block: {$: "mod" \| {mod: true} }}` |
242-
| `"block__el block__el--mod"` | `{block: {el: "mod" \| {mod: true} }}` |
243-
| <hr> | <hr> |
244-
| `"block block--mod--val"` | `{block: {$: {mod: "val"}}}` |
245-
| `"block__el block__el--mod--val"` | `{block: {el: {mod: "val"}}}` |
246-
247-
Mixins are deep merge of single possibilities in table
248-
249234
![](./images/classbeming.gif)
250235
251236
---
252237
253-
#### Setting options
238+
### Setting options
254239
255240
Default options BEM naming:
256241
257-
- Element's separator is a double underscore `"__"`
258242
- Modifier's and value's separator is a double hyphen `"--"`
259-
- Key for block modifiers is `"$"`
243+
- [#30](https://github.com/askirmas/react-classnaming/issues/30) ~~Element's separator is a double underscore `"__"`~~
260244
261245
It is required to change this options twice, both on JS (`setOpts(...)`) and TS `namespace ReactClassNaming { interface BemOptions {...} }`) levels
262246

__recipes__/index.test.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ type CssModule = Record<
2424
ClassHash
2525
>
2626

27-
it("go", () => {
27+
describe("go", () => {
2828
const bem = classBeming<ClassNamesProperty<CssModule> & ClassNamed>()
29-
expect(bem(true, {
30-
"block": {
31-
"&": "m",
32-
"el": {"m": "X"}
33-
}
34-
})).toStrictEqual({
35-
className: "block block-m block_el block_el-m-X"
29+
, classNamed = bem(true, {
30+
block: "m",
31+
block_el: {"m": "X"}
3632
})
33+
it("TBD", () => expect(classNamed).not.toStrictEqual({
34+
className: "block block-m block_el block_el_m-X"
35+
}))
36+
it("Now", () => expect(classNamed).toStrictEqual({
37+
className: "block block-m block_el_m block_el_m-X"
38+
}))
3739
})

__sandbox__/bem--old.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Can be used on #30
2+
3+
import type { Ever0, Extends, PartDeep, Strip } from "src/ts-swiss.types"
4+
import type {ReactClassNaming} from "../src"
5+
6+
export type BemQuery<
7+
classes extends string,
8+
delE extends string = "elementDelimiter" extends keyof ReactClassNaming.BemOptions
9+
? ReactClassNaming.BemOptions["elementDelimiter"]
10+
: ReactClassNaming.BemOptions["$default"]["elementDelimiter"],
11+
delM extends string = "modDelimiter" extends keyof ReactClassNaming.BemOptions
12+
? ReactClassNaming.BemOptions["modDelimiter"]
13+
: ReactClassNaming.BemOptions["$default"]["modDelimiter"],
14+
bModKey extends string = "blockModKey" extends keyof ReactClassNaming.BemOptions
15+
? ReactClassNaming.BemOptions["blockModKey"]
16+
: ReactClassNaming.BemOptions["$default"]["blockModKey"],
17+
> = string extends classes ? BemInGeneral : PartDeep<{
18+
[b in Strip<Strip<classes, delM>, delE>]: boolean
19+
| Exclude<MVs<classes, b, bModKey>, `${string}${delM}${string}`>
20+
| (
21+
Extends<classes, `${b}${delE | delM}${string}`,
22+
{
23+
[e in Elements<classes, b>]: boolean
24+
| Exclude<MVs<classes, b, e>, `${string}${delM}${string}`>
25+
| (
26+
{[m in Strip<MVs<classes, b, e>, delM>]:
27+
false | (
28+
Ever0<
29+
classes extends `${b}${
30+
e extends bModKey ? "" : `${delE}${e}`
31+
}${delM}${m}${delM}${infer V}`
32+
? V : never,
33+
true
34+
>
35+
)
36+
}
37+
)
38+
}
39+
>
40+
)
41+
}>
42+
43+
type Elements<
44+
classes extends string,
45+
b extends string,
46+
delE extends string = "elementDelimiter" extends keyof ReactClassNaming.BemOptions
47+
? ReactClassNaming.BemOptions["elementDelimiter"]
48+
: ReactClassNaming.BemOptions["$default"]["elementDelimiter"],
49+
delM extends string = "modDelimiter" extends keyof ReactClassNaming.BemOptions
50+
? ReactClassNaming.BemOptions["modDelimiter"]
51+
: ReactClassNaming.BemOptions["$default"]["modDelimiter"],
52+
bModKey extends string = "blockModKey" extends keyof ReactClassNaming.BemOptions
53+
? ReactClassNaming.BemOptions["blockModKey"]
54+
: ReactClassNaming.BemOptions["$default"]["blockModKey"],
55+
> = classes extends `${b}${delE}${infer E}`
56+
? Strip<E, delM>
57+
: classes extends `${b}${delM}${string}`
58+
? bModKey
59+
: never
60+
61+
type MVs<
62+
classes extends string,
63+
b extends string,
64+
e extends string,
65+
delE extends string = "elementDelimiter" extends keyof ReactClassNaming.BemOptions
66+
? ReactClassNaming.BemOptions["elementDelimiter"]
67+
: ReactClassNaming.BemOptions["$default"]["elementDelimiter"],
68+
delM extends string = "modDelimiter" extends keyof ReactClassNaming.BemOptions
69+
? ReactClassNaming.BemOptions["modDelimiter"]
70+
: ReactClassNaming.BemOptions["$default"]["modDelimiter"],
71+
bModKey extends string = "blockModKey" extends keyof ReactClassNaming.BemOptions
72+
? ReactClassNaming.BemOptions["blockModKey"]
73+
: ReactClassNaming.BemOptions["$default"]["blockModKey"],
74+
> = classes extends `${b}${
75+
e extends bModKey ? "" : `${delE}${e}`
76+
}${delM}${infer MV}` ? MV : never
77+
78+
export type BemInGeneral = {
79+
[block: string]: undefined | boolean | string | {
80+
[el: string]: undefined | boolean | string
81+
| {
82+
[mod: string]: undefined | boolean | string
83+
}
84+
}
85+
}

__tests__/readme.spec.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ it("Using ClassHash", () => {
161161
</>)
162162
})
163163

164-
it("bem", () => {
164+
describe("bem", () => {
165165
type MyClassNames = ClassNamed & ClassNamesProperty<{
166166
form__item: ClassHash
167167
button: ClassHash
@@ -176,13 +176,11 @@ it("bem", () => {
176176
const bem = classBeming(props)
177177
expectRender(
178178
<div {...bem(true, {
179-
form: {item: true},
180-
button: {
181-
$: {status: "danger"},
182-
icon: {hover: true}
183-
}
179+
form__item: true,
180+
button: {status: "danger"},
181+
button__icon: {hover: true}
184182
})}/>
185-
).toSame(
183+
).not.toSame(
186184
<div className="${props.className} form__item button button--status--danger button__icon button__icon--hover" />
187185
)
188186
})

expect-to-same-render.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ export default expectRender
77
function expectRender(
88
...elements: RElement[]
99
) {
10+
const input = toStatic(elements)
11+
1012
return {
11-
toSame: (...expectations: RElement[]) =>
12-
expect(
13-
elements.map(renderToStaticMarkup).join("")
14-
).toBe(
15-
expectations.map(renderToStaticMarkup).join("")
16-
)
13+
toSame: (...expectations: RElement[]) => expect(input).toBe(toStatic(expectations)),
14+
not: {
15+
toSame: (...expectations: RElement[]) => expect(input).not.toBe(toStatic(expectations)),
16+
}
1717
}
1818
}
19+
20+
function toStatic(els: RElement[]) {
21+
return els.map(renderToStaticMarkup).join("")
22+
}

src/bem.core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { BemInGeneral } from "./bem.types"
22

3-
let elementDelimiter = "__"
4-
, modDelimiter = "--"
3+
let modDelimiter = "--"
4+
, elementDelimiter = "__"
55
, blockModKey = "$"
66

77
export type BemOptions = {

src/bem.test.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ describe("contexting", () => {
77
const bem = classBeming()
88

99
it("1", () => expect(bem({
10-
"block1": true,
11-
"block2": { "el": true }
10+
block1: true,
11+
block2: { el: true }
1212
})).toStrictEqual({
1313
className: "block1 block2__el"
1414
}))
@@ -18,14 +18,14 @@ describe("contexting", () => {
1818
const bem = classBeming({
1919
className: "propagated",
2020
classnames: {
21-
"block1": "hash1",
22-
"block2__el": "hash2"
21+
block1: "hash1",
22+
block2__el: "hash2"
2323
}
2424
})
2525

2626
it("1", () => expect(bem(true, {
27-
"block1": true,
28-
"block2": { "el": true }
27+
block1: true,
28+
block2__el: true
2929
})).toStrictEqual({
3030
className: "propagated hash1 hash2"
3131
}))
@@ -45,11 +45,9 @@ it("TS UX", () => {
4545

4646
const bem = classBeming<ClassProps>()
4747
, check = {
48-
"1": bem(true, {
49-
"block1": {
50-
$: {"m2": "v1"},
51-
"el1": {"m1": true}
52-
},
48+
1: bem(true, {
49+
block1: {m2: "v1"},
50+
block1__el1: "m1",
5351
})
5452
}
5553

src/bem.types.test.ts

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ describe("BemQuery", () => {
1616
const checks: Record<string, BemQuery<"block__el">> = {
1717
//@ts-expect-error
1818
"number": {block: 1},
19+
//@ts-expect-error
1920
"true": {block: true},
21+
//@ts-expect-error
2022
"{}": {block: {}},
2123
//@ts-expect-error
2224
"el=1": {block: {el: {}}},
23-
"el": {block: {el: true}}
25+
//@ts-expect-error
26+
"el": {block: {el: true}},
27+
"block__el": {block__el: true}
2428
}
2529
expect(checks).toBeInstanceOf(Object)
2630
})
@@ -29,14 +33,31 @@ describe("BemQuery", () => {
2933
const checks: Record<string, BemQuery<"block__el--mod">> = {
3034
//@ts-expect-error
3135
"number": {block: 1},
36+
//@ts-expect-error
3237
"true": {block: true},
38+
//@ts-expect-error
3339
"{}": {block: {}},
3440
//@ts-expect-error
3541
"el=1": {block: {el: 1}},
42+
//@ts-expect-error`
3643
"el": {block: {el: true}},
44+
//@ts-expect-error
3745
"el: mod": {block: {el: "mod"}},
46+
//@ts-expect-error
47+
"el: [mod]": {block: {el: ["mod"]}},
48+
//@ts-expect-error
3849
"el: -mod": {block: {el: {mod: false}}},
39-
"el: +mod": {block: {el: {mod: true}}}
50+
//@ts-expect-error
51+
"el: +mod": {block: {el: {mod: true}}},
52+
53+
//@ts-expect-error
54+
"block__el=1": {block__el: 1},
55+
"block__el": {block__el: true},
56+
"block__el: mod": {block__el: "mod"},
57+
//@ts-expect-error //TODO #40
58+
"block__el: [mod]": {block__el: ["mod"]},
59+
"block__el: -mod": {block__el: {mod: false}},
60+
"block__el: +mod": {block__el: {mod: true}}
4061
}
4162
expect(checks).toBeInstanceOf(Object)
4263
})
@@ -45,17 +66,21 @@ describe("BemQuery", () => {
4566
const checks: Record<string, BemQuery<"block__el--mod--val">> = {
4667
//@ts-expect-error
4768
"number": {block: 1},
69+
//@ts-expect-error
4870
"true": {block: true},
71+
//@ts-expect-error
4972
"{}": {block: {}},
5073
//@ts-expect-error
51-
"el=1": {block: {el: 1}},
52-
"el": {block: {el: true}},
74+
"el=1": {block__el: 1},
75+
"el": {block__el: true},
5376
//@ts-expect-error
54-
"el: mod": {block: {el: "mod"}},
55-
"el: -mod": {block: {el: {mod: false}}},
77+
"el: mod": {block__el: "mod"},
5678
//@ts-expect-error
57-
"el: +mod": {block: {el: {mod: true}}},
58-
"el: mod=val": {block: {el: {mod: "val"}}}
79+
"el: mod": {block__el: ["mod"]},
80+
"el: -mod": {block__el: {mod: false}},
81+
//@ts-expect-error
82+
"el: +mod": {block__el: {mod: true}},
83+
"el: mod=val": {block__el: {mod: "val"}},
5984
}
6085
expect(checks).toBeInstanceOf(Object)
6186
})
@@ -69,9 +94,13 @@ describe("BemQuery", () => {
6994
"{}": {block: {}},
7095
//@ts-expect-error
7196
"el": {block: {el: true}},
97+
//@ts-expect-error
7298
"$": {block: {$: true}},
99+
//@ts-expect-error
73100
"$: mod": {block: {$: "mod"}},
101+
//@ts-expect-error
74102
"$: +mod": {block: {$: {mod: true}}},
103+
//@ts-expect-error
75104
"$: -mod": {block: {$: {mod: false}}},
76105
}
77106
expect(checks).toBeInstanceOf(Object)
@@ -87,6 +116,13 @@ describe("BemQuery", () => {
87116
"{}": {block: {}},
88117
//@ts-expect-error
89118
"el": {block: {el: true}},
119+
//@ts-expect-error
120+
"mod---val": {block: "mod--val"},
121+
//@ts-expect-error,
122+
"mod+": {block: {"mod": true}},
123+
"mod-": {block: {"mod": false}},
124+
"mod:val": {block: {"mod": "val"}},
125+
//@ts-expect-error
90126
"$": {block: {$: true}},
91127
//@ts-expect-error
92128
"$: mod": {block: {$: "mod"}},
@@ -96,9 +132,11 @@ describe("BemQuery", () => {
96132
"$: +mod--val": {block: {$: {"mod--val": true}}},
97133
//@ts-expect-error
98134
"$: -mod--val": {block: {$: {"mod--val": false}}},
135+
//@ts-expect-error
99136
"$: -mod": {block: {$: {mod: false}}},
100137
//@ts-expect-error
101138
"$: +mod": {block: {$: {mod: true}}},
139+
//@ts-expect-error
102140
"$: mod=val": {block: {$: {mod: "val"}}},
103141
}
104142
expect(checks).toBeInstanceOf(Object)
@@ -109,12 +147,10 @@ describe("BemQuery", () => {
109147
`${"block" | "block__el"}--${"mod1"|"mod2--val1"|"mod2--val2"}`
110148
>> = {
111149
"exact": {
112-
block: {
113-
$: "mod1",
114-
el: {
115-
mod1: false,
116-
mod2: "val1"
117-
}
150+
block: "mod1",
151+
block__el: {
152+
mod1: false,
153+
mod2: "val1"
118154
}
119155
}
120156
}

0 commit comments

Comments
 (0)