clava 0.2.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.md +552 -0
- package/dist/index.d.ts +22 -30
- package/dist/index.js +356 -171
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/rolldown.config.ts +1 -0
- package/src/index.ts +718 -285
- package/src/types.ts +44 -49
- package/tests/_utils.ts +1 -3
- package/tests/build.test.ts +18 -0
- package/tests/component-api.test.ts +284 -15
- package/tests/extend.test.ts +6 -6
- package/tests/{computed-variants.test.ts → function-variants.test.ts} +105 -25
- package/tests/prototype-pollution.test.ts +6 -6
- package/tests/{computed.test.ts → refine.test.ts} +517 -100
- package/tests/solid.test.ts +30 -0
- package/tests/split-props.test.ts +73 -1
- package/tests/variants-inference.test.ts +252 -0
package/src/types.ts
CHANGED
|
@@ -70,11 +70,15 @@ export type ComponentProps<V = {}> = VariantValues<V> & NullableComponentResult;
|
|
|
70
70
|
|
|
71
71
|
export type GetVariants<V> = (variants?: VariantValues<V>) => VariantValues<V>;
|
|
72
72
|
|
|
73
|
+
type ComponentPropKey<R extends ComponentResult> =
|
|
74
|
+
| keyof R
|
|
75
|
+
| (R extends StyleClassProps ? "className" : never);
|
|
76
|
+
|
|
73
77
|
// Key source types - what can be passed as additional parameters to splitProps
|
|
74
78
|
export type KeySourceArray = readonly string[];
|
|
75
79
|
export type KeySourceComponent = {
|
|
76
|
-
|
|
77
|
-
variantKeys: readonly
|
|
80
|
+
propKeys: readonly string[];
|
|
81
|
+
variantKeys: readonly string[];
|
|
78
82
|
getVariants: () => Record<string, unknown>;
|
|
79
83
|
};
|
|
80
84
|
export type KeySource = KeySourceArray | KeySourceComponent;
|
|
@@ -85,7 +89,7 @@ type IsComponent<S> = S extends { getVariants: () => unknown } ? true : false;
|
|
|
85
89
|
// Extract keys from a source (includes class/style for components)
|
|
86
90
|
type SourceKeys<S> = S extends readonly (infer K)[]
|
|
87
91
|
? K
|
|
88
|
-
: S extends {
|
|
92
|
+
: S extends { propKeys: readonly (infer K)[] }
|
|
89
93
|
? K
|
|
90
94
|
: never;
|
|
91
95
|
|
|
@@ -169,53 +173,52 @@ export interface ModalComponent<V, R extends ComponentResult> {
|
|
|
169
173
|
class: (props?: ComponentProps<V>) => string;
|
|
170
174
|
style: (props?: ComponentProps<V>) => R["style"];
|
|
171
175
|
getVariants: GetVariants<V>;
|
|
172
|
-
keys: (keyof V | keyof NullableComponentResult)[];
|
|
173
176
|
variantKeys: (keyof V)[];
|
|
174
|
-
propKeys: (keyof V |
|
|
177
|
+
propKeys: (keyof V | ComponentPropKey<R>)[];
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
export interface CVComponent<
|
|
178
181
|
V extends Variants = {},
|
|
179
|
-
CV extends ComputedVariants = {},
|
|
180
182
|
E extends AnyComponent[] = [],
|
|
181
183
|
R extends ComponentResult = StyleClassProps,
|
|
182
|
-
> extends ModalComponent<MergeVariants<V,
|
|
183
|
-
jsx: ModalComponent<MergeVariants<V,
|
|
184
|
-
html: ModalComponent<MergeVariants<V,
|
|
185
|
-
htmlObj: ModalComponent<MergeVariants<V,
|
|
184
|
+
> extends ModalComponent<MergeVariants<V, E>, R> {
|
|
185
|
+
jsx: ModalComponent<MergeVariants<V, E>, JSXProps>;
|
|
186
|
+
html: ModalComponent<MergeVariants<V, E>, HTMLProps>;
|
|
187
|
+
htmlObj: ModalComponent<MergeVariants<V, E>, HTMLObjProps>;
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
export type AnyComponent =
|
|
189
|
-
| CVComponent<any, any, any
|
|
191
|
+
| CVComponent<any, any, any>
|
|
190
192
|
| ModalComponent<any, any>;
|
|
191
193
|
|
|
192
194
|
type MergeExtendedVariants<T> = T extends readonly [infer First, ...infer Rest]
|
|
193
195
|
? ExtractVariants<First> & MergeExtendedVariants<Rest>
|
|
194
196
|
: {};
|
|
195
197
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
: {};
|
|
202
|
-
|
|
198
|
+
// Returns a component's effective variants — merged with its own extends —
|
|
199
|
+
// so that a later intermediate component's static variant correctly hides a
|
|
200
|
+
// grandparent's function variant from further descendants. Using a raw
|
|
201
|
+
// intersection here would re-expose the grandparent function through the
|
|
202
|
+
// type chain even after the middle layer replaced it.
|
|
203
203
|
type ExtractVariants<T> =
|
|
204
|
-
T extends CVComponent<infer V,
|
|
205
|
-
? V
|
|
204
|
+
T extends CVComponent<infer V, infer E, any>
|
|
205
|
+
? MergeVariantMaps<V, MergeExtendedVariants<E>>
|
|
206
206
|
: {};
|
|
207
207
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
Child
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
208
|
+
// A function value in `variants` (a function variant) replaces any inherited
|
|
209
|
+
// variant for the same key. An object value merges value-by-value with an
|
|
210
|
+
// inherited object, but replaces an inherited function.
|
|
211
|
+
type MergeVariantDefinition<Child, Parent> = Child extends (
|
|
212
|
+
...args: any[]
|
|
213
|
+
) => any
|
|
214
|
+
? Child
|
|
215
|
+
: Parent extends (...args: any[]) => any
|
|
216
|
+
? Child
|
|
217
|
+
: Child extends Record<string, any>
|
|
218
|
+
? Parent extends Record<string, any>
|
|
219
|
+
? Omit<Parent, keyof Child> & Child
|
|
220
|
+
: Child
|
|
221
|
+
: Child;
|
|
219
222
|
|
|
220
223
|
type MergeVariantMaps<Child, Parent> = Omit<Parent, keyof Child> &
|
|
221
224
|
Child & {
|
|
@@ -225,17 +228,11 @@ type MergeVariantMaps<Child, Parent> = Omit<Parent, keyof Child> &
|
|
|
225
228
|
>;
|
|
226
229
|
};
|
|
227
230
|
|
|
228
|
-
type
|
|
229
|
-
MergeExtendedVariants<E> & MergeExtendedComputedVariants<E>;
|
|
230
|
-
|
|
231
|
-
type MergeBaseVariants<V, E extends AnyComponent[]> = MergeVariantMaps<
|
|
231
|
+
export type MergeVariants<V, E extends AnyComponent[]> = MergeVariantMaps<
|
|
232
232
|
NoInfer<V>,
|
|
233
|
-
|
|
233
|
+
MergeExtendedVariants<E>
|
|
234
234
|
>;
|
|
235
235
|
|
|
236
|
-
export type MergeVariants<V, CV, E extends AnyComponent[]> = NoInfer<CV> &
|
|
237
|
-
Omit<MergeBaseVariants<V, E>, keyof CV>;
|
|
238
|
-
|
|
239
236
|
type StringToBoolean<T> = T extends "true" | "false" ? boolean : T;
|
|
240
237
|
|
|
241
238
|
type VariantValue = ClassValue | StyleClassValue;
|
|
@@ -269,7 +266,7 @@ export interface StyleClassValue {
|
|
|
269
266
|
class?: ClassValue;
|
|
270
267
|
}
|
|
271
268
|
|
|
272
|
-
export interface
|
|
269
|
+
export interface RefineContext<V> {
|
|
273
270
|
variants: VariantValues<V>;
|
|
274
271
|
setVariants: (variants: VariantValues<V>) => void;
|
|
275
272
|
setDefaultVariants: (variants: VariantValues<V>) => void;
|
|
@@ -277,16 +274,14 @@ export interface ComputedContext<V> {
|
|
|
277
274
|
addStyle: (style: StyleValue) => void;
|
|
278
275
|
}
|
|
279
276
|
|
|
280
|
-
export type
|
|
277
|
+
export type Refine<V> = (context: RefineContext<V>) => VariantValue;
|
|
281
278
|
|
|
282
|
-
export type
|
|
283
|
-
|
|
284
|
-
|
|
279
|
+
export type Variant =
|
|
280
|
+
| ClassValue
|
|
281
|
+
| Record<string, VariantValue>
|
|
282
|
+
| ((value: any) => VariantValue);
|
|
285
283
|
export type Variants = Record<string, Variant>;
|
|
286
284
|
|
|
287
|
-
type ExtendedVariants<E extends AnyComponent[]> = MergeExtendedVariants<E> &
|
|
288
|
-
MergeExtendedComputedVariants<E>;
|
|
289
|
-
|
|
290
285
|
type NullablePartial<T> =
|
|
291
286
|
T extends Record<string, any> ? { [K in keyof T]?: T[K] | null } : T | null;
|
|
292
287
|
|
|
@@ -294,7 +289,7 @@ export type ExtendableVariants<
|
|
|
294
289
|
V extends Variants,
|
|
295
290
|
E extends AnyComponent[],
|
|
296
291
|
> = V & {
|
|
297
|
-
[K in keyof
|
|
298
|
-
| NullablePartial<
|
|
292
|
+
[K in keyof MergeExtendedVariants<E>]?:
|
|
293
|
+
| NullablePartial<MergeExtendedVariants<E>[K]>
|
|
299
294
|
| Variant;
|
|
300
295
|
};
|
package/tests/_utils.ts
CHANGED
|
@@ -4,7 +4,6 @@ import type {
|
|
|
4
4
|
AnyComponent,
|
|
5
5
|
CVComponent,
|
|
6
6
|
ComponentResult,
|
|
7
|
-
ComputedVariants,
|
|
8
7
|
HTMLObjProps,
|
|
9
8
|
HTMLProps,
|
|
10
9
|
JSXProps,
|
|
@@ -86,9 +85,8 @@ export function createCVFromConfig(
|
|
|
86
85
|
export function getModeComponent<
|
|
87
86
|
M extends Mode,
|
|
88
87
|
V extends Variants = {},
|
|
89
|
-
CV extends ComputedVariants = {},
|
|
90
88
|
const E extends AnyComponent[] = [],
|
|
91
|
-
>(mode: M, component: CVComponent<V,
|
|
89
|
+
>(mode: M, component: CVComponent<V, E>) {
|
|
92
90
|
if (!mode) return component;
|
|
93
91
|
return component[mode];
|
|
94
92
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { expect, test } from "vitest";
|
|
7
|
+
|
|
8
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const exec = promisify(execFile);
|
|
10
|
+
|
|
11
|
+
test("build preserves the production warning guard for consumers", async () => {
|
|
12
|
+
await exec("pnpm", ["--dir", root, "build"]);
|
|
13
|
+
|
|
14
|
+
const code = await readFile(join(root, "dist/index.js"), "utf8");
|
|
15
|
+
expect(code).toMatch(
|
|
16
|
+
/process\.env\.NODE_ENV !== "production"[\s\S]*?console\.warn\(/,
|
|
17
|
+
);
|
|
18
|
+
}, 60_000);
|
|
@@ -59,7 +59,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
59
59
|
expect(variants).toEqual({ size: "sm" });
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
test("getVariants returns variants set by
|
|
62
|
+
test("getVariants returns variants set by refine setVariants", () => {
|
|
63
63
|
const component = getModeComponent(
|
|
64
64
|
mode,
|
|
65
65
|
cv({
|
|
@@ -67,7 +67,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
67
67
|
size: { sm: "sm", lg: "lg" },
|
|
68
68
|
color: { red: "red", blue: "blue" },
|
|
69
69
|
},
|
|
70
|
-
|
|
70
|
+
refine: ({ variants, setVariants }) => {
|
|
71
71
|
if (variants.size === "lg") {
|
|
72
72
|
setVariants({ color: "red" });
|
|
73
73
|
}
|
|
@@ -78,7 +78,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
78
78
|
expect(variants).toEqual({ size: "lg", color: "red" });
|
|
79
79
|
});
|
|
80
80
|
|
|
81
|
-
test("getVariants
|
|
81
|
+
test("getVariants re-runs when refine changes variants", () => {
|
|
82
82
|
const component = getModeComponent(
|
|
83
83
|
mode,
|
|
84
84
|
cv({
|
|
@@ -86,7 +86,49 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
86
86
|
size: { sm: "sm", lg: "lg" },
|
|
87
87
|
color: { red: "red", blue: "blue" },
|
|
88
88
|
},
|
|
89
|
-
|
|
89
|
+
refine: ({ variants, setVariants }) => {
|
|
90
|
+
if (variants.size === "lg") {
|
|
91
|
+
setVariants({ color: "red" });
|
|
92
|
+
}
|
|
93
|
+
if (variants.color === "red") {
|
|
94
|
+
setVariants({ size: "sm" });
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
const variants = component.getVariants({ size: "lg" });
|
|
100
|
+
expect(variants).toEqual({ size: "sm", color: "red" });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test("getVariants re-runs when setDefaultVariants changes variants", () => {
|
|
104
|
+
const component = getModeComponent(
|
|
105
|
+
mode,
|
|
106
|
+
cv({
|
|
107
|
+
variants: {
|
|
108
|
+
size: { sm: "sm", lg: "lg" },
|
|
109
|
+
color: { red: "red", blue: "blue" },
|
|
110
|
+
},
|
|
111
|
+
refine: ({ variants, setDefaultVariants }) => {
|
|
112
|
+
setDefaultVariants({ color: "red" });
|
|
113
|
+
if (variants.color === "red") {
|
|
114
|
+
setDefaultVariants({ size: "lg" });
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
const variants = component.getVariants();
|
|
120
|
+
expect(variants).toEqual({ size: "lg", color: "red" });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("getVariants returns variants set by refine setDefaultVariants", () => {
|
|
124
|
+
const component = getModeComponent(
|
|
125
|
+
mode,
|
|
126
|
+
cv({
|
|
127
|
+
variants: {
|
|
128
|
+
size: { sm: "sm", lg: "lg" },
|
|
129
|
+
color: { red: "red", blue: "blue" },
|
|
130
|
+
},
|
|
131
|
+
refine: ({ variants, setDefaultVariants }) => {
|
|
90
132
|
if (variants.size === "lg") {
|
|
91
133
|
setDefaultVariants({ color: "blue" });
|
|
92
134
|
}
|
|
@@ -105,7 +147,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
105
147
|
size: { sm: "sm", lg: "lg" },
|
|
106
148
|
color: { red: "red", blue: "blue" },
|
|
107
149
|
},
|
|
108
|
-
|
|
150
|
+
refine: ({ setDefaultVariants }) => {
|
|
109
151
|
setDefaultVariants({ color: "blue" });
|
|
110
152
|
},
|
|
111
153
|
}),
|
|
@@ -122,7 +164,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
122
164
|
size: { sm: "sm", lg: "lg" },
|
|
123
165
|
color: { red: "red", blue: "blue" },
|
|
124
166
|
},
|
|
125
|
-
|
|
167
|
+
refine: ({ setVariants }) => {
|
|
126
168
|
setVariants({ color: "blue" });
|
|
127
169
|
},
|
|
128
170
|
}),
|
|
@@ -134,7 +176,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
134
176
|
test("getVariants picks up setDefaultVariants from extended component", () => {
|
|
135
177
|
const base = cv({
|
|
136
178
|
variants: { size: { sm: "sm", lg: "lg" } },
|
|
137
|
-
|
|
179
|
+
refine: ({ setDefaultVariants }) => {
|
|
138
180
|
setDefaultVariants({ size: "lg" });
|
|
139
181
|
},
|
|
140
182
|
});
|
|
@@ -153,7 +195,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
153
195
|
test("getVariants picks up setDefaultVariants from grandparent component", () => {
|
|
154
196
|
const grandparent = cv({
|
|
155
197
|
variants: { size: { sm: "sm", lg: "lg" } },
|
|
156
|
-
|
|
198
|
+
refine: ({ setDefaultVariants }) => {
|
|
157
199
|
setDefaultVariants({ size: "lg" });
|
|
158
200
|
},
|
|
159
201
|
});
|
|
@@ -170,17 +212,220 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
170
212
|
expect(variants).toEqual({ size: "lg", color: "red" });
|
|
171
213
|
});
|
|
172
214
|
|
|
173
|
-
test("
|
|
215
|
+
test("getVariants re-runs when base component refine changes variants", () => {
|
|
216
|
+
const base = cv({
|
|
217
|
+
variants: { size: { sm: "sm", lg: "lg" }, active: "" },
|
|
218
|
+
defaultVariants: { size: "sm" },
|
|
219
|
+
refine: ({ variants, setVariants }) => {
|
|
220
|
+
if (variants.active) {
|
|
221
|
+
setVariants({ size: "lg" });
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
});
|
|
174
225
|
const component = getModeComponent(
|
|
175
226
|
mode,
|
|
176
|
-
cv({
|
|
227
|
+
cv({
|
|
228
|
+
extend: [base],
|
|
229
|
+
variants: { color: { red: "red", blue: "blue" } },
|
|
230
|
+
refine: ({ variants, setVariants }) => {
|
|
231
|
+
if (variants.size === "lg") {
|
|
232
|
+
setVariants({ color: "red" });
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
}),
|
|
177
236
|
);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
237
|
+
const variants = component.getVariants({ active: true });
|
|
238
|
+
expect(variants).toEqual({ size: "lg", active: true, color: "red" });
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("getVariants preserves base setDefaultVariants after its own setVariants re-run", () => {
|
|
242
|
+
const base = cv({
|
|
243
|
+
variants: {
|
|
244
|
+
size: { sm: "sm", lg: "lg" },
|
|
245
|
+
active: "",
|
|
246
|
+
mode: { on: "on" },
|
|
247
|
+
},
|
|
248
|
+
defaultVariants: { size: "sm" },
|
|
249
|
+
refine: ({ variants, setVariants, setDefaultVariants }) => {
|
|
250
|
+
if (variants.active) {
|
|
251
|
+
setVariants({ mode: "on" });
|
|
252
|
+
}
|
|
253
|
+
if (variants.mode === "on") {
|
|
254
|
+
setDefaultVariants({ size: "lg" });
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
const component = getModeComponent(mode, cv({ extend: [base] }));
|
|
259
|
+
const variants = component.getVariants({ active: true });
|
|
260
|
+
expect(variants).toEqual({ size: "lg", active: true, mode: "on" });
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
test("getVariants setVariants uses the latest pending value", () => {
|
|
264
|
+
const component = getModeComponent(
|
|
265
|
+
mode,
|
|
266
|
+
cv({
|
|
267
|
+
variants: { size: { sm: "sm", lg: "lg" } },
|
|
268
|
+
defaultVariants: { size: "sm" },
|
|
269
|
+
refine: ({ setVariants }) => {
|
|
270
|
+
setVariants({ size: "lg" });
|
|
271
|
+
setVariants({ size: "sm" });
|
|
272
|
+
},
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
const variants = component.getVariants();
|
|
276
|
+
expect(variants).toEqual({ size: "sm" });
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("getVariants child setVariants keeps overriding base setDefaultVariants across re-runs", () => {
|
|
280
|
+
const base = cv({
|
|
281
|
+
variants: { color: { red: "red", blue: "blue" } },
|
|
282
|
+
refine: ({ setDefaultVariants }) => {
|
|
283
|
+
setDefaultVariants({ color: "blue" });
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
const component = getModeComponent(
|
|
287
|
+
mode,
|
|
288
|
+
cv({
|
|
289
|
+
extend: [base],
|
|
290
|
+
variants: { size: { sm: "sm", lg: "lg" } },
|
|
291
|
+
defaultVariants: { size: "sm" },
|
|
292
|
+
refine: ({ variants, setVariants }) => {
|
|
293
|
+
if (variants.size === "sm") {
|
|
294
|
+
setVariants({ color: "red" });
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
}),
|
|
298
|
+
);
|
|
299
|
+
const variants = component.getVariants();
|
|
300
|
+
expect(variants).toEqual({ color: "red", size: "sm" });
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("getVariants setVariants sticks across re-runs", () => {
|
|
304
|
+
const base = cv({
|
|
305
|
+
variants: { color: { red: "red", blue: "blue" } },
|
|
306
|
+
refine: ({ setDefaultVariants }) => {
|
|
307
|
+
setDefaultVariants({ color: "blue" });
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
const component = getModeComponent(
|
|
311
|
+
mode,
|
|
312
|
+
cv({
|
|
313
|
+
extend: [base],
|
|
314
|
+
variants: { color: { red: "red", blue: "blue" }, done: "" },
|
|
315
|
+
refine: ({ variants, setVariants }) => {
|
|
316
|
+
if (!variants.done) {
|
|
317
|
+
setVariants({ color: "red", done: true });
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
}),
|
|
321
|
+
);
|
|
322
|
+
const variants = component.getVariants();
|
|
323
|
+
expect(variants).toEqual({ color: "red", done: true });
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("getVariants base setDefaultVariants can override child static defaults after a re-run", () => {
|
|
327
|
+
const base = cv({
|
|
328
|
+
variants: {
|
|
329
|
+
size: { sm: "sm", lg: "lg" },
|
|
330
|
+
active: "",
|
|
331
|
+
mode: { on: "on" },
|
|
332
|
+
},
|
|
333
|
+
refine: ({ variants, setVariants, setDefaultVariants }) => {
|
|
334
|
+
if (variants.active) {
|
|
335
|
+
setVariants({ mode: "on" });
|
|
336
|
+
}
|
|
337
|
+
if (variants.mode === "on") {
|
|
338
|
+
setDefaultVariants({ size: "lg" });
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
const component = getModeComponent(
|
|
343
|
+
mode,
|
|
344
|
+
cv({ extend: [base], defaultVariants: { size: "sm" } }),
|
|
345
|
+
);
|
|
346
|
+
const variants = component.getVariants({ active: true });
|
|
347
|
+
expect(variants).toEqual({ size: "lg", active: true, mode: "on" });
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test("getVariants setVariants from earlier extends overrides setDefaultVariants from later extends", () => {
|
|
351
|
+
const first = cv({
|
|
352
|
+
variants: { color: { red: "first-red", blue: "first-blue" } },
|
|
353
|
+
refine: ({ setVariants }) => {
|
|
354
|
+
setVariants({ color: "red" });
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
const second = cv({
|
|
358
|
+
variants: { color: { red: "second-red", blue: "second-blue" } },
|
|
359
|
+
refine: ({ setDefaultVariants }) => {
|
|
360
|
+
setDefaultVariants({ color: "blue" });
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
const component = getModeComponent(mode, cv({ extend: [first, second] }));
|
|
364
|
+
const variants = component.getVariants();
|
|
365
|
+
expect(variants).toEqual({ color: "red" });
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test("getVariants setDefaultVariants from later extends overrides setDefaultVariants from earlier extends", () => {
|
|
369
|
+
const first = cv({
|
|
370
|
+
variants: { color: { red: "first-red", blue: "first-blue" } },
|
|
371
|
+
refine: ({ setDefaultVariants }) => {
|
|
372
|
+
setDefaultVariants({ color: "red" });
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
const second = cv({
|
|
376
|
+
variants: { color: { red: "second-red", blue: "second-blue" } },
|
|
377
|
+
refine: ({ setDefaultVariants }) => {
|
|
378
|
+
setDefaultVariants({ color: "blue" });
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
const component = getModeComponent(mode, cv({ extend: [first, second] }));
|
|
382
|
+
const variants = component.getVariants();
|
|
383
|
+
expect(variants).toEqual({ color: "blue" });
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("getVariants setDefaultVariants does not override stable setVariants on later passes", () => {
|
|
387
|
+
const base = cv({
|
|
388
|
+
variants: { color: { red: "base-red", blue: "base-blue" } },
|
|
389
|
+
refine: ({ setVariants }) => {
|
|
390
|
+
setVariants({ color: "red" });
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
const component = getModeComponent(
|
|
394
|
+
mode,
|
|
395
|
+
cv({
|
|
396
|
+
extend: [base],
|
|
397
|
+
variants: { color: { red: "child-red", blue: "child-blue" } },
|
|
398
|
+
refine: ({ variants, setDefaultVariants }) => {
|
|
399
|
+
if (variants.color === "red") {
|
|
400
|
+
setDefaultVariants({ color: "blue" });
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
}),
|
|
183
404
|
);
|
|
405
|
+
const variants = component.getVariants();
|
|
406
|
+
expect(variants).toEqual({ color: "red" });
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
test("getVariants setDefaultVariants does not override setVariants from a previous pass", () => {
|
|
410
|
+
const component = getModeComponent(
|
|
411
|
+
mode,
|
|
412
|
+
cv({
|
|
413
|
+
variants: {
|
|
414
|
+
color: { red: "red", blue: "blue" },
|
|
415
|
+
done: "",
|
|
416
|
+
},
|
|
417
|
+
refine: ({ variants, setVariants, setDefaultVariants }) => {
|
|
418
|
+
if (!variants.done) {
|
|
419
|
+
setVariants({ color: "red", done: true });
|
|
420
|
+
}
|
|
421
|
+
if (variants.done) {
|
|
422
|
+
setDefaultVariants({ color: "blue" });
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
}),
|
|
426
|
+
);
|
|
427
|
+
const variants = component.getVariants();
|
|
428
|
+
expect(variants).toEqual({ color: "red", done: true });
|
|
184
429
|
});
|
|
185
430
|
|
|
186
431
|
test("variantKeys property", () => {
|
|
@@ -217,6 +462,30 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
217
462
|
});
|
|
218
463
|
}
|
|
219
464
|
|
|
465
|
+
test("propKeys are mode-specific", () => {
|
|
466
|
+
const component = cvBase({
|
|
467
|
+
variants: { size: { sm: "sm", md: "md" } },
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
expectTypeOf(component.propKeys).toEqualTypeOf<
|
|
471
|
+
("class" | "className" | "style" | "size")[]
|
|
472
|
+
>();
|
|
473
|
+
expectTypeOf(component.jsx.propKeys).toEqualTypeOf<
|
|
474
|
+
("className" | "style" | "size")[]
|
|
475
|
+
>();
|
|
476
|
+
expectTypeOf(component.html.propKeys).toEqualTypeOf<
|
|
477
|
+
("class" | "style" | "size")[]
|
|
478
|
+
>();
|
|
479
|
+
expectTypeOf(component.htmlObj.propKeys).toEqualTypeOf<
|
|
480
|
+
("class" | "style" | "size")[]
|
|
481
|
+
>();
|
|
482
|
+
|
|
483
|
+
expect(component.propKeys).toEqual(["class", "className", "style", "size"]);
|
|
484
|
+
expect(component.jsx.propKeys).toEqual(["className", "style", "size"]);
|
|
485
|
+
expect(component.html.propKeys).toEqual(["class", "style", "size"]);
|
|
486
|
+
expect(component.htmlObj.propKeys).toEqual(["class", "style", "size"]);
|
|
487
|
+
});
|
|
488
|
+
|
|
220
489
|
describe("Variant utility type", () => {
|
|
221
490
|
test("matches variant keys from another component", () => {
|
|
222
491
|
const base = cvBase({
|
package/tests/extend.test.ts
CHANGED
|
@@ -144,7 +144,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
-
test("extend disabled variant value with
|
|
147
|
+
test("extend disabled variant value with refine setDefaultVariants", () => {
|
|
148
148
|
const base = cv({
|
|
149
149
|
variants: {
|
|
150
150
|
size: {
|
|
@@ -158,7 +158,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
158
158
|
cv({
|
|
159
159
|
extend: [base],
|
|
160
160
|
variants: { size: { sm: null } },
|
|
161
|
-
|
|
161
|
+
refine: ({ setDefaultVariants }) => {
|
|
162
162
|
setDefaultVariants({ size: "lg" });
|
|
163
163
|
},
|
|
164
164
|
}),
|
|
@@ -173,7 +173,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
173
173
|
cv({
|
|
174
174
|
extend: [base],
|
|
175
175
|
variants: { size: { sm: null } },
|
|
176
|
-
|
|
176
|
+
refine: ({ setDefaultVariants }) => {
|
|
177
177
|
setDefaultVariants({
|
|
178
178
|
// @ts-expect-error disabled variant value cannot be set
|
|
179
179
|
size:
|
|
@@ -186,7 +186,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
186
186
|
expect(getStyleClass(invalidComponent())).toEqual({ class: "" });
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
-
test("extend disabled variant value with
|
|
189
|
+
test("extend disabled variant value with refine setVariants", () => {
|
|
190
190
|
const base = cv({
|
|
191
191
|
variants: {
|
|
192
192
|
size: {
|
|
@@ -200,7 +200,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
200
200
|
cv({
|
|
201
201
|
extend: [base],
|
|
202
202
|
variants: { size: { sm: null } },
|
|
203
|
-
|
|
203
|
+
refine: ({ setVariants }) => {
|
|
204
204
|
setVariants({ size: "lg" });
|
|
205
205
|
},
|
|
206
206
|
}),
|
|
@@ -215,7 +215,7 @@ for (const config of Object.values(CONFIGS)) {
|
|
|
215
215
|
cv({
|
|
216
216
|
extend: [base],
|
|
217
217
|
variants: { size: { sm: null } },
|
|
218
|
-
|
|
218
|
+
refine: ({ setVariants }) => {
|
|
219
219
|
setVariants({
|
|
220
220
|
// @ts-expect-error disabled variant value cannot be set
|
|
221
221
|
size:
|