Skip to content

Commit ff87656

Browse files
author
Andrii Kirmas
committed
#5 TBD chained toggler. Requires another lambda or options
1 parent ed7d88b commit ff87656

File tree

5 files changed

+116
-67
lines changed

5 files changed

+116
-67
lines changed

src/basic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ function _classNaming(
4444
const className = joinWithLead(propagate, dehash(classes))
4545
, host: ClassNamingCall = classes => _classNaming(classes, className)
4646

47-
return wrapper(className, undefined, host)
47+
return wrapper(host, className)
4848
}
4949

5050
type ClassNamingChain = ClassNamingCall & {

src/core.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@ export {
1414
}
1515

1616
function wrapper<T>(
17-
className: Parameters<typeof joinWithLead>[0],
18-
classKeys: Parameters<typeof joinWithLead>[1],
19-
destination: T
17+
destination: T,
18+
className: undefined | string
2019
) {
2120
//@ts-expect-error
22-
destination[classNameKey]
23-
= joinWithLead(className, classKeys)
21+
destination[classNameKey] = className
2422

2523
return stringifyClassNamed(destination as T & ClassNamed)
2624
}
@@ -59,7 +57,7 @@ function truthyKeys<T>(source: T) {
5957
}
6058

6159
//TODO Consider returning `undefined` on empty string
62-
function joinWithLead(value: Falsy|ClassValue, arr: undefined| readonly string[]) : string {
60+
function joinWithLead(value: Falsy|ClassValue, arr: undefined | readonly string[]) : string {
6361
const str1 = value || ""
6462
if (!(arr && arr.length))
6563
return str1

src/ctx.test.ts

Lines changed: 90 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,92 +9,133 @@ describe(classNamingCtx.name, () => {
99

1010
describe("classnames", () => {
1111
const classes = classNamingCtx({classnames})
12-
it("map", () => expect(classes(
13-
{
12+
it("map", () => expect({
13+
...classes({
1414
class1: true,
1515
class2: false,
1616
class3: "",
1717
//@ts-expect-error Truthy not allowed by TS
1818
class4: 1,
19-
}
20-
)).toStrictEqual({
19+
})
20+
}).toStrictEqual({
2121
className: "class1 hash4"
2222
}))
2323

24-
it("array", () => expect(classes(
25-
true && "class1",
26-
false && "class2",
27-
"" && "class3",
28-
1 && "class4"
29-
)).toStrictEqual({
24+
it("array", () => expect({
25+
...classes(
26+
true && "class1",
27+
false && "class2",
28+
"" && "class3",
29+
1 && "class4"
30+
)
31+
}).toStrictEqual({
3032
className: "class1 hash4"
3133
}))
3234

33-
it("map + array", () => expect(classes(
34-
{
35-
class1: false,
36-
class4: true
37-
},
38-
"class1",
39-
false && "class4"
40-
)).toStrictEqual({
35+
it("map + array", () => expect({
36+
...classes(
37+
{
38+
class1: false,
39+
class4: true
40+
},
41+
"class1",
42+
false && "class4"
43+
)
44+
}).toStrictEqual({
4145
className: "hash4 class1"
4246
}))
4347

44-
it("redundant in map", () => expect(classes({
45-
//@ts-expect-error Object literal may only specify known properties, and 'etc' does not exist
46-
etc: true
47-
})).toStrictEqual({
48+
it("redundant in map", () => expect({
49+
...classes({
50+
//@ts-expect-error Object literal may only specify known properties, and 'etc' does not exist
51+
etc: true
52+
})
53+
}).toStrictEqual({
4854
className: "etc"
4955
}))
5056

51-
it("redundant in array", () => expect(classes(
52-
//@ts-expect-error Argument of type '"etc"' is not assignable
53-
"etc"
54-
)).toStrictEqual({
57+
it("redundant in array", () => expect({
58+
...classes(
59+
//@ts-expect-error Argument of type '"etc"' is not assignable
60+
"etc"
61+
)
62+
}).toStrictEqual({
5563
className: "etc"
5664
}))
5765

5866
//TODO Raise TS error
59-
it("propagate absent className", () => expect(classes(
60-
true,
61-
{class1: true},
62-
"class4"
63-
)).toStrictEqual({
67+
it("propagate absent className", () => expect({
68+
...classes(
69+
true,
70+
{class1: true},
71+
"class4"
72+
)
73+
}).toStrictEqual({
6474
className: "class1 hash4"
6575
}))
6676
})
6777

6878
describe("className + classnames", () => {
6979
const classes = classNamingCtx({className, classnames})
70-
it("only propagated", () => expect(classes(
71-
true
72-
)).toStrictEqual({
73-
className
74-
}))
80+
it("only propagated", () => expect({
81+
...classes(
82+
true
83+
)
84+
}).toStrictEqual({
85+
className
86+
}))
7587

76-
it("without propagation", () => expect(classes(
77-
"class1",
78-
"class4"
79-
)).toStrictEqual({
88+
it("without propagation", () => expect({
89+
...classes(
90+
"class1",
91+
"class4"
92+
)
93+
}).toStrictEqual({
8094
className: "class1 hash4"
8195
}))
8296

83-
it("both", () => expect(classes(
84-
true,
85-
"class1",
86-
"class4"
87-
)).toStrictEqual({
97+
it("both", () => expect({
98+
...classes(
99+
true,
100+
"class1",
101+
"class4"
102+
)
103+
}).toStrictEqual({
88104
className: "App class1 hash4"
89105
}))
90106
})
91107

92-
it("only propagate classnames", () => expect(classNamingCtx(
93-
{classnames},
94-
{withClassNames: true}
95-
)()).toStrictEqual({
108+
it("only propagate classnames", () => expect({
109+
...classNamingCtx(
110+
{classnames},
111+
{withClassNames: true}
112+
)(
113+
)
114+
}).toStrictEqual({
96115
className: "",
97116
classnames
98117
}))
99118

119+
describe("chained", () => {
120+
it("Cur", () => expect({
121+
//@ts-expect-error
122+
...classNamingCtx({classnames})(
123+
{class1: true}
124+
)({class2: true}
125+
)({class1: false}
126+
)({class3: true})
127+
}).not.toStrictEqual({
128+
className: "class3"
129+
}))
130+
it("TBD", () => expect({
131+
//@ts-expect-error
132+
...classNamingCtx({classnames})(
133+
{class1: true}
134+
)({class2: true}
135+
)({class1: false}
136+
)({class3: true})
137+
}).not.toStrictEqual({
138+
className: "class2 class3"
139+
}))
140+
})
100141
})

src/ctx.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type { Falsy, ToggleMap, ClassNamer, ClassNamed, ClassNamesMap, EmptyObject } from "./defs"
2-
import {dehash, truthyKeys, wrapper} from "./core"
2+
import {dehash, joinWithLead, truthyKeys, wrapper} from "./core"
33
import { emptize } from "./utils"
44

5+
56
emptize(classNamer)
67

78
//TODO no `className` - no first `true`
@@ -45,7 +46,7 @@ function classNamingCtx<
4546
{classnames, className}: ClassNamer<ClassKeys>,
4647
options?: ClassNamerOptions<withClassNames>
4748
) {
48-
return classNamer.bind({classnames, className, ...options}) as tClassNaming<ClassKeys, withClassNames>
49+
return classNamer.bind({classnames, className, options}) as tClassNaming<ClassKeys, withClassNames>
4950
}
5051

5152
type ClassNamerOptions<
@@ -59,17 +60,20 @@ function classNamer<
5960
ClassKeys extends string,
6061
withClassNames extends boolean|undefined
6162
>(
62-
this: Partial<ClassNamer<ClassKeys> & ClassNamerOptions<withClassNames>>,
63+
this: Partial<ClassNamer<ClassKeys> & {options: ClassNamerOptions<withClassNames>}>,
6364
arg0?: true | ToggleMap<ClassKeys> | ClassKeys,
6465
arg1?: ToggleMap<ClassKeys> | ClassKeys,
6566
...args: (ClassKeys | Falsy)[]
6667
): ClassNamed & Partial<Pick<typeof this, "classnames">> {
6768
const {
6869
className: propagated,
6970
classnames,
71+
options
72+
} = this
73+
, {
7074
withClassNames,
7175
// withSelf
72-
} = this
76+
} = options ?? {}
7377
, withPropagation = arg0 === true
7478
, allowed: ClassKeys[] = truthyKeys(arg0 === true ? false : arg0)
7579
.concat(truthyKeys(arg1))
@@ -83,10 +87,16 @@ function classNamer<
8387
emptize(classnames)
8488

8589
classnames && dehash(classnames, allowed)
86-
90+
91+
const className = joinWithLead(withPropagation && propagated, allowed)
92+
, host = classNamer.bind({classnames, className, options})
93+
94+
withClassNames && (
95+
//@ts-expect-error
96+
host["classnames"] = classnames
97+
)
8798
return wrapper(
88-
withPropagation && propagated,
89-
allowed,
90-
!withClassNames ? {} : {classnames}
99+
host,
100+
className,
91101
)
92102
}

src/versus-classnames.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ it("css module", () => expect({
4040
// No error on redundant CSS-class
4141
"class1", "class3"
4242
)
43-
}).toStrictEqual(
44-
classNamingCtx({classnames: module_css})(
43+
}).toStrictEqual({
44+
...classNamingCtx({classnames: module_css})(
4545
"class1",
4646
//@ts-expect-error Argument of type '"class3"' is not assignable to parameter
4747
"class3"
4848
)
49-
))
49+
}))
5050

5151
it.todo("Does `classnames` have chainable interface?")

0 commit comments

Comments
 (0)