clava 0.1.19 → 0.2.1

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/src/test.ts DELETED
@@ -1,2873 +0,0 @@
1
- import { describe, expect, expectTypeOf, test } from "vitest";
2
- import {
3
- type Variant,
4
- type VariantProps,
5
- create,
6
- cv as cvBase,
7
- splitProps,
8
- } from "./index.ts";
9
- import type {
10
- AnyComponent,
11
- CVComponent,
12
- ComponentResult,
13
- ComputedVariants,
14
- HTMLCSSProperties,
15
- JSXCSSProperties,
16
- StyleProperty,
17
- Variants,
18
- } from "./types.ts";
19
- import {
20
- htmlObjStyleToStyleValue,
21
- htmlStyleToStyleValue,
22
- isHTMLObjStyle,
23
- jsxStyleToStyleValue,
24
- } from "./utils.ts";
25
-
26
- const MODES = ["jsx", "html", "htmlObj"] as const;
27
- type Mode = (typeof MODES)[number] | null;
28
-
29
- type HTMLProperties<T extends AnyComponent> = VariantProps<T> & {
30
- id?: string;
31
- class?: string;
32
- className?: string;
33
- style?: StyleProperty;
34
- };
35
-
36
- type ConfigParams = NonNullable<Parameters<typeof create>[0]>;
37
-
38
- interface Config {
39
- mode: Mode;
40
- defaultMode: Mode;
41
- transformClass?: ConfigParams["transformClass"];
42
- }
43
-
44
- type ConfigMode<T extends Config> = NonNullable<T["mode"] | T["defaultMode"]>;
45
-
46
- const transformClass = {
47
- uppercase: (className) => className.toUpperCase(),
48
- } satisfies Record<string, Config["transformClass"]>;
49
-
50
- const CONFIGS = {
51
- default: { mode: null, defaultMode: null },
52
- jsx: { mode: "jsx", defaultMode: null },
53
- html: { mode: "html", defaultMode: null },
54
- htmlObj: { mode: "htmlObj", defaultMode: null },
55
- htmlDefault: { mode: null, defaultMode: "html" },
56
- htmlObjDefault: { mode: null, defaultMode: "htmlObj" },
57
- uppercase: {
58
- mode: null,
59
- defaultMode: null,
60
- transformClass: transformClass.uppercase,
61
- },
62
- } satisfies Record<string, Config>;
63
-
64
- function getConfigMode<T extends Config>(config: T): T["mode"] {
65
- if (!("mode" in config)) return null;
66
- return config.mode;
67
- }
68
-
69
- function getConfigDefaultMode<T extends Config>(config: T): T["defaultMode"] {
70
- if (!("defaultMode" in config)) return null;
71
- return config.defaultMode;
72
- }
73
-
74
- function getConfigTransformClass(config: Config) {
75
- if (!("transformClass" in config) || !config.transformClass) {
76
- return (className: string) => className;
77
- }
78
- return config.transformClass;
79
- }
80
-
81
- function getConfigDescription(config: Config) {
82
- for (const [name, cfg] of Object.entries(CONFIGS)) {
83
- if (cfg !== config) continue;
84
- return name;
85
- }
86
- return "custom";
87
- }
88
-
89
- function createCVFromConfig<T extends Config>(
90
- config: T,
91
- ): T["defaultMode"] & T["transformClass"] extends never
92
- ? typeof cvBase
93
- : ReturnType<typeof create>["cv"] {
94
- const defaultMode = getConfigDefaultMode(config);
95
- const transformClass = getConfigTransformClass(config);
96
- const hasTransform = "transformClass" in config && config.transformClass;
97
- if (!defaultMode && !hasTransform) {
98
- return cvBase;
99
- }
100
- const { cv } = create({ defaultMode: defaultMode ?? "jsx", transformClass });
101
- return cv as any;
102
- }
103
-
104
- function getModalComponent<
105
- M extends Mode,
106
- V extends Variants = {},
107
- CV extends ComputedVariants = {},
108
- const E extends AnyComponent[] = [],
109
- >(mode: M, component: CVComponent<V, CV, E>) {
110
- if (!mode) return component;
111
- return component[mode];
112
- }
113
-
114
- function getClass(props: ComponentResult) {
115
- if ("class" in props) return props.class;
116
- return props.className;
117
- }
118
-
119
- function getClassPropertyName(config: Config) {
120
- const mode = config.mode ?? config.defaultMode;
121
- // null defaults to jsx mode
122
- if (mode === "jsx" || mode === null) return "className";
123
- return "class";
124
- }
125
-
126
- function assertClassProperty<T extends Config>(
127
- config: T,
128
- props: ComponentResult,
129
- ): asserts props is ConfigMode<T> extends "html" | "htmlObj"
130
- ? Extract<ComponentResult, { class: string }>
131
- : Extract<ComponentResult, { className: string }> {
132
- const mode = config.mode ?? config.defaultMode;
133
- if (mode === "html" || mode === "htmlObj") {
134
- if (!("class" in props)) {
135
- expect.fail(`Expected ${mode} props to have class`);
136
- }
137
- } else {
138
- if (!("className" in props)) {
139
- expect.fail(`Expected ${mode ?? "jsx"} props to have className`);
140
- }
141
- }
142
- }
143
-
144
- function assertStyleProperty<T extends Config>(
145
- config: T,
146
- props: ComponentResult,
147
- ): asserts props is ConfigMode<T> extends "html"
148
- ? Extract<ComponentResult, { style: string }>
149
- : ConfigMode<T> extends "htmlObj"
150
- ? Extract<ComponentResult, { style: HTMLCSSProperties }>
151
- : Extract<ComponentResult, { style: JSXCSSProperties }> {
152
- if (!("style" in props)) {
153
- const mode = config.mode ?? config.defaultMode;
154
- expect.fail(`Expected ${mode ?? "jsx"} props to have style`);
155
- }
156
- }
157
-
158
- function getStyle(props: Pick<ComponentResult, "style">) {
159
- if (typeof props.style === "string") {
160
- return htmlStyleToStyleValue(props.style);
161
- }
162
- if (typeof props.style === "object") {
163
- if (isHTMLObjStyle(props.style)) {
164
- return htmlObjStyleToStyleValue(props.style);
165
- }
166
- return jsxStyleToStyleValue(props.style);
167
- }
168
- return {};
169
- }
170
-
171
- function getStyleClass(props: ComponentResult): Record<string, unknown> {
172
- return {
173
- ...getStyle(props),
174
- class: getClass(props),
175
- };
176
- }
177
-
178
- for (const config of [CONFIGS.default, CONFIGS.jsx, CONFIGS.uppercase]) {
179
- const mode = getConfigMode(config);
180
- const cv = createCVFromConfig(config);
181
- const cls = getConfigTransformClass(config);
182
-
183
- describe(getConfigDescription(config), () => {
184
- test("style has correct shape for mode", () => {
185
- const component = getModalComponent(
186
- mode,
187
- cv({ class: "base", style: { backgroundColor: "red" } }),
188
- );
189
- const props = component();
190
- assertClassProperty(config, props);
191
- expect(props).not.toHaveProperty("class");
192
- expect(props.className).toBe(cls("base"));
193
- expect(props.style.backgroundColor).toBe("red");
194
- expectTypeOf(props.style).toEqualTypeOf<JSXCSSProperties>();
195
- });
196
-
197
- test("no argument still returns jsx shape", () => {
198
- const component = getModalComponent(mode, cv());
199
- const props = component();
200
- assertClassProperty(config, props);
201
- expect(props).not.toHaveProperty("class");
202
- expect(props.className).toBe("");
203
- expect(props.style).toEqual({});
204
- expectTypeOf(props.style).toEqualTypeOf<JSXCSSProperties>();
205
- });
206
- });
207
- }
208
-
209
- for (const config of [CONFIGS.html, CONFIGS.htmlDefault]) {
210
- const mode = getConfigMode(config);
211
- const cv = createCVFromConfig(config);
212
- const cls = getConfigTransformClass(config);
213
-
214
- describe(getConfigDescription(config), () => {
215
- test("style has correct shape for mode", () => {
216
- const component = getModalComponent(
217
- mode,
218
- cv({ class: "base", style: { backgroundColor: "red" } }),
219
- );
220
- const props = component();
221
- assertClassProperty(config, props);
222
- expect(props).not.toHaveProperty("className");
223
- expect(props.class).toBe(cls("base"));
224
- expect(props.style).toBe("background-color: red;");
225
- });
226
-
227
- test("no argument still returns html shape", () => {
228
- const component = getModalComponent(mode, cv());
229
- const props = component();
230
- assertClassProperty(config, props);
231
- expect(props).not.toHaveProperty("className");
232
- expect(props.class).toBe("");
233
- expect(props.style).toBe("");
234
- });
235
- });
236
- }
237
-
238
- for (const config of [CONFIGS.htmlObj, CONFIGS.htmlObjDefault]) {
239
- const mode = getConfigMode(config);
240
- const cv = createCVFromConfig(config);
241
- const cls = getConfigTransformClass(config);
242
-
243
- describe(getConfigDescription(config), () => {
244
- test("style has correct shape for mode", () => {
245
- const component = getModalComponent(
246
- mode,
247
- cv({ class: "base", style: { backgroundColor: "red" } }),
248
- );
249
- const props = component();
250
- assertClassProperty(config, props);
251
- assertStyleProperty(config, props);
252
- expect(props).not.toHaveProperty("className");
253
- expect(props.class).toBe(cls("base"));
254
- expect(props.style["background-color"]).toBe("red");
255
- expectTypeOf(props.style).toEqualTypeOf<HTMLCSSProperties>();
256
- });
257
-
258
- test("no argument still returns htmlObj shape", () => {
259
- const component = getModalComponent(mode, cv());
260
- const props = component();
261
- assertClassProperty(config, props);
262
- assertStyleProperty(config, props);
263
- expect(props).not.toHaveProperty("className");
264
- expect(props.class).toBe("");
265
- expect(props.style).toEqual({});
266
- expectTypeOf(props.style).toEqualTypeOf<HTMLCSSProperties>();
267
- });
268
- });
269
- }
270
-
271
- for (const config of Object.values(CONFIGS)) {
272
- const mode = getConfigMode(config);
273
- const cv = createCVFromConfig(config);
274
- const cls = getConfigTransformClass(config);
275
-
276
- describe(getConfigDescription(config), () => {
277
- test("no argument", () => {
278
- const component = getModalComponent(mode, cv());
279
- const props = component();
280
- expect(getStyleClass(props)).toEqual({ class: "" });
281
- });
282
-
283
- test("null class", () => {
284
- const component = getModalComponent(mode, cv({ class: null }));
285
- const props = component();
286
- expect(getStyleClass(props)).toEqual({ class: "" });
287
- });
288
-
289
- test("empty array class", () => {
290
- const component = getModalComponent(mode, cv({ class: [] }));
291
- const props = component();
292
- expect(getStyleClass(props)).toEqual({ class: "" });
293
- });
294
-
295
- test("string class", () => {
296
- const component = getModalComponent(mode, cv({ class: "foo bar" }));
297
- const props = component();
298
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar") });
299
- });
300
-
301
- test("nested array class", () => {
302
- const component = getModalComponent(
303
- mode,
304
- cv({ class: ["foo", ["bar", ["baz"]]] }),
305
- );
306
- const props = component();
307
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar baz") });
308
- });
309
-
310
- test("nested array class with falsy values", () => {
311
- const component = getModalComponent(
312
- mode,
313
- cv({ class: ["foo", null, ["bar", false, ["baz", 0]]] }),
314
- );
315
- const props = component();
316
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar baz") });
317
- });
318
-
319
- test("merge class from props", () => {
320
- const component = getModalComponent(mode, cv({ class: "foo bar" }));
321
- const props = component({ class: "baz qux" });
322
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar baz qux") });
323
- });
324
-
325
- test("merge className from props", () => {
326
- const component = getModalComponent(mode, cv({ class: "foo bar" }));
327
- const props = component({ className: "baz qux" });
328
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar baz qux") });
329
- });
330
-
331
- test("merge class and className from props", () => {
332
- const component = getModalComponent(mode, cv({ class: "foo bar" }));
333
- const props = component({ class: "baz qux", className: "quux corge" });
334
- expect(getStyleClass(props)).toEqual({
335
- class: cls("foo bar baz qux quux corge"),
336
- });
337
- });
338
-
339
- test("merge null class from props", () => {
340
- const component = getModalComponent(mode, cv({ class: "foo bar" }));
341
- const props = component({ class: null });
342
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar") });
343
- });
344
-
345
- test("merge null className from props", () => {
346
- const component = getModalComponent(mode, cv({ class: "foo bar" }));
347
- const props = component({ className: null });
348
- expect(getStyleClass(props)).toEqual({ class: cls("foo bar") });
349
- });
350
-
351
- test("empty style", () => {
352
- const component = getModalComponent(mode, cv({ style: {} }));
353
- const props = component();
354
- expect(getStyleClass(props)).toEqual({ class: "" });
355
- });
356
-
357
- test("style with properties", () => {
358
- const component = getModalComponent(
359
- mode,
360
- cv({ style: { backgroundColor: "red", fontSize: "16px" } }),
361
- );
362
- const props = component();
363
- expect(getStyleClass(props)).toEqual({
364
- class: "",
365
- backgroundColor: "red",
366
- fontSize: "16px",
367
- });
368
- });
369
-
370
- test("style does not accept numbers", () => {
371
- const component = getModalComponent(
372
- mode,
373
- cv({
374
- style: {
375
- backgroundColor: "red",
376
- // @ts-expect-error
377
- fontSize: 16,
378
- },
379
- }),
380
- );
381
- const props = component();
382
- expect(getStyleClass(props)).toEqual({
383
- class: "",
384
- backgroundColor: "red",
385
- fontSize: expect.toBeOneOf(["16", "16px"]),
386
- });
387
- });
388
-
389
- test("style with custom property", () => {
390
- const component = getModalComponent(
391
- mode,
392
- cv({ style: { backgroundColor: "red", "--custom-var": "value" } }),
393
- );
394
- const props = component();
395
- expect(getStyleClass(props)).toEqual({
396
- class: "",
397
- backgroundColor: "red",
398
- "--custom-var": "value",
399
- });
400
- });
401
-
402
- test("merge style from props", () => {
403
- const component = getModalComponent(
404
- mode,
405
- cv({ style: { backgroundColor: "red" } }),
406
- );
407
- const props = component({ style: { fontSize: "16px" } });
408
- expect(getStyleClass(props)).toEqual({
409
- class: "",
410
- backgroundColor: "red",
411
- fontSize: "16px",
412
- });
413
- });
414
-
415
- test("merge jsx style from props", () => {
416
- const component = getModalComponent(
417
- mode,
418
- cv({ style: { backgroundColor: "red" } }),
419
- );
420
- const props = component({ style: { fontSize: 16 } });
421
- expect(getStyleClass(props)).toEqual({
422
- class: "",
423
- backgroundColor: "red",
424
- fontSize: "16px",
425
- });
426
- });
427
-
428
- test("merge html style from props", () => {
429
- const component = getModalComponent(
430
- mode,
431
- cv({ style: { backgroundColor: "red" } }),
432
- );
433
- const props = component({ style: "font-size: 16px" });
434
- expect(getStyleClass(props)).toEqual({
435
- class: "",
436
- backgroundColor: "red",
437
- fontSize: "16px",
438
- });
439
- });
440
-
441
- test("merge htmlObj style from props", () => {
442
- const component = getModalComponent(
443
- mode,
444
- cv({ style: { backgroundColor: "red" } }),
445
- );
446
- const props = component({ style: { "font-size": 16 } });
447
- expect(getStyleClass(props)).toEqual({
448
- class: "",
449
- backgroundColor: "red",
450
- fontSize: "16px",
451
- });
452
- });
453
-
454
- test("merge null style from props", () => {
455
- const component = getModalComponent(
456
- mode,
457
- cv({ style: { backgroundColor: "red" } }),
458
- );
459
- const props = component({ style: null });
460
- expect(getStyleClass(props)).toEqual({
461
- class: "",
462
- backgroundColor: "red",
463
- });
464
- });
465
-
466
- test("variant no value empty class", () => {
467
- const component = getModalComponent(
468
- mode,
469
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
470
- );
471
- const props = component();
472
- expect(getStyleClass(props)).toEqual({ class: "" });
473
- });
474
-
475
- test("variant no value with class", () => {
476
- const component = getModalComponent(
477
- mode,
478
- cv({ class: "foo", variants: { size: { sm: "sm", lg: "lg" } } }),
479
- );
480
- const props = component();
481
- expect(getStyleClass(props)).toEqual({ class: cls("foo") });
482
- });
483
-
484
- test("variant with value", () => {
485
- const component = getModalComponent(
486
- mode,
487
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
488
- );
489
- const props = component({ size: "lg" });
490
- expect(getStyleClass(props)).toEqual({ class: cls("lg") });
491
- });
492
-
493
- test("variant with value and class", () => {
494
- const component = getModalComponent(
495
- mode,
496
- cv({ class: "foo", variants: { size: { sm: "sm", lg: "lg" } } }),
497
- );
498
- const props = component({ size: "lg" });
499
- expect(getStyleClass(props)).toEqual({ class: cls("foo lg") });
500
- });
501
-
502
- test("variant with style value", () => {
503
- const component = getModalComponent(
504
- mode,
505
- cv({
506
- variants: {
507
- color: {
508
- red: { style: { backgroundColor: "red" } },
509
- blue: { style: { backgroundColor: "blue" } },
510
- },
511
- },
512
- }),
513
- );
514
- const props = component({ color: "red" });
515
- expect(getStyleClass(props)).toEqual({
516
- class: "",
517
- backgroundColor: "red",
518
- });
519
- });
520
-
521
- test("rejects inline style object without style wrapper", () => {
522
- const component = getModalComponent(
523
- mode,
524
- cv({
525
- variants: {
526
- color: {
527
- // @ts-expect-error old shape requires `style` wrapper
528
- red: { backgroundColor: "red" },
529
- },
530
- },
531
- }),
532
- );
533
- const props = component({ color: "red" });
534
- expect(getStyleClass(props)).toEqual({
535
- class: "",
536
- });
537
- });
538
-
539
- test("variant with class and style value", () => {
540
- const component = getModalComponent(
541
- mode,
542
- cv({
543
- variants: {
544
- color: {
545
- red: { class: "text-red", style: { backgroundColor: "red" } },
546
- blue: { class: "text-blue", style: { backgroundColor: "blue" } },
547
- },
548
- },
549
- }),
550
- );
551
- const props = component({ color: "red" });
552
- expect(getStyleClass(props)).toEqual({
553
- class: cls("text-red"),
554
- backgroundColor: "red",
555
- });
556
- });
557
-
558
- test("multiple variants", () => {
559
- const component = getModalComponent(
560
- mode,
561
- cv({
562
- variants: {
563
- size: { sm: "sm", lg: "lg" },
564
- color: { red: "red", blue: "blue" },
565
- },
566
- }),
567
- );
568
- const props = component({ size: "lg", color: "red" });
569
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
570
- });
571
-
572
- test("boolean variant true", () => {
573
- const component = getModalComponent(
574
- mode,
575
- cv({ variants: { disabled: { true: "disabled", false: "enabled" } } }),
576
- );
577
- const props = component({ disabled: true });
578
- expect(getStyleClass(props)).toEqual({ class: cls("disabled") });
579
- });
580
-
581
- test("boolean variant false", () => {
582
- const component = getModalComponent(
583
- mode,
584
- cv({ variants: { disabled: { true: "disabled", false: "enabled" } } }),
585
- );
586
- const props = component({ disabled: false });
587
- expect(getStyleClass(props)).toEqual({ class: cls("enabled") });
588
- });
589
-
590
- test("boolean variant true only false", () => {
591
- const component = getModalComponent(
592
- mode,
593
- cv({ variants: { disabled: { true: "disabled" } } }),
594
- );
595
- const props = component({ disabled: false });
596
- expect(getStyleClass(props)).toEqual({ class: "" });
597
- });
598
-
599
- test("boolean variant true only true", () => {
600
- const component = getModalComponent(
601
- mode,
602
- cv({ variants: { disabled: { true: "disabled" } } }),
603
- );
604
- const props = component({ disabled: true });
605
- expect(getStyleClass(props)).toEqual({ class: cls("disabled") });
606
- });
607
-
608
- test("boolean variant no value applies false", () => {
609
- const component = getModalComponent(
610
- mode,
611
- cv({ variants: { disabled: { true: "disabled", false: "enabled" } } }),
612
- );
613
- const props = component();
614
- expect(getStyleClass(props)).toEqual({ class: cls("enabled") });
615
- });
616
-
617
- test("boolean variant false only", () => {
618
- const component = getModalComponent(
619
- mode,
620
- cv({ variants: { disabled: { false: "enabled" } } }),
621
- );
622
- const props = component();
623
- expect(getStyleClass(props)).toEqual({ class: cls("enabled") });
624
- });
625
-
626
- test("boolean variant false only false", () => {
627
- const component = getModalComponent(
628
- mode,
629
- cv({ variants: { disabled: { false: "enabled" } } }),
630
- );
631
- const props = component({ disabled: false });
632
- expect(getStyleClass(props)).toEqual({ class: cls("enabled") });
633
- });
634
-
635
- test("boolean variant false only true", () => {
636
- const component = getModalComponent(
637
- mode,
638
- cv({ variants: { disabled: { false: "enabled" } } }),
639
- );
640
- const props = component({ disabled: true });
641
- expect(getStyleClass(props)).toEqual({ class: "" });
642
- });
643
-
644
- test("boolean variant shorthand true", () => {
645
- const component = getModalComponent(
646
- mode,
647
- cv({ variants: { disabled: "disabled" } }),
648
- );
649
- const props = component({ disabled: true });
650
- expect(getStyleClass(props)).toEqual({ class: cls("disabled") });
651
- });
652
-
653
- test("boolean variant shorthand false", () => {
654
- const component = getModalComponent(
655
- mode,
656
- cv({ variants: { disabled: "disabled" } }),
657
- );
658
- const props = component({ disabled: false });
659
- expect(getStyleClass(props)).toEqual({ class: "" });
660
- });
661
-
662
- test("variant style does not accept numbers", () => {
663
- const component = getModalComponent(
664
- mode,
665
- cv({
666
- variants: {
667
- // @ts-expect-error
668
- size: {
669
- sm: {
670
- class: "sm",
671
- style: { fontSize: 12 },
672
- },
673
- lg: { class: "lg", style: { fontSize: "16px" } },
674
- },
675
- },
676
- }),
677
- );
678
- const props = component({ size: "sm" });
679
- expect(getStyleClass(props)).toEqual({
680
- class: cls("sm"),
681
- fontSize: expect.toBeOneOf(["12", "12px"]),
682
- });
683
- });
684
-
685
- test("variant props do not accept invalid values", () => {
686
- const component = getModalComponent(
687
- mode,
688
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
689
- );
690
- const props = component({
691
- // @ts-expect-error invalid value
692
- size:
693
- // no error
694
- "invalid",
695
- });
696
- expect(getStyleClass(props)).toEqual({ class: "" });
697
- });
698
-
699
- test("variant props do not accept invalid keys", () => {
700
- const component = getModalComponent(
701
- mode,
702
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
703
- );
704
- const props = component({
705
- // @ts-expect-error
706
- invalidKey: "value",
707
- });
708
- expect(getStyleClass(props)).toEqual({ class: "" });
709
- });
710
-
711
- test("defaultVariants", () => {
712
- const component = getModalComponent(
713
- mode,
714
- cv({
715
- variants: { size: { sm: "sm", lg: "lg" } },
716
- defaultVariants: { size: "sm" },
717
- }),
718
- );
719
- const props = component();
720
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
721
- });
722
-
723
- test("defaultVariants overridden by props", () => {
724
- const component = getModalComponent(
725
- mode,
726
- cv({
727
- variants: { size: { sm: "sm", lg: "lg" } },
728
- defaultVariants: { size: "sm" },
729
- }),
730
- );
731
- const props = component({ size: "lg" });
732
- expect(getStyleClass(props)).toEqual({ class: cls("lg") });
733
- });
734
-
735
- test("defaultVariants boolean false", () => {
736
- const component = getModalComponent(
737
- mode,
738
- cv({
739
- variants: { disabled: { true: "disabled", false: "enabled" } },
740
- defaultVariants: { disabled: false },
741
- }),
742
- );
743
- const props = component();
744
- expect(getStyleClass(props)).toEqual({ class: cls("enabled") });
745
- });
746
-
747
- test("defaultVariants boolean true", () => {
748
- const component = getModalComponent(
749
- mode,
750
- cv({
751
- variants: { disabled: { true: "disabled", false: "enabled" } },
752
- defaultVariants: { disabled: true },
753
- }),
754
- );
755
- const props = component();
756
- expect(getStyleClass(props)).toEqual({ class: cls("disabled") });
757
- });
758
-
759
- test("defaultVariants boolean shorthand", () => {
760
- const component = getModalComponent(
761
- mode,
762
- cv({
763
- variants: { disabled: "disabled" },
764
- defaultVariants: { disabled: true },
765
- }),
766
- );
767
- const props = component();
768
- expect(getStyleClass(props)).toEqual({ class: cls("disabled") });
769
- });
770
-
771
- test("defaultVariants does not accept invalid keys", () => {
772
- const component = getModalComponent(
773
- mode,
774
- cv({
775
- variants: { size: { sm: "sm", lg: "lg" } },
776
- defaultVariants: {
777
- size: "sm",
778
- // @ts-expect-error
779
- invalidKey: "value",
780
- },
781
- }),
782
- );
783
- const props = component();
784
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
785
- });
786
-
787
- test("defaultVariants does not accept invalid values", () => {
788
- const component = getModalComponent(
789
- mode,
790
- cv({
791
- variants: { size: { sm: "sm", lg: "lg" } },
792
- defaultVariants: {
793
- // @ts-expect-error invalid value
794
- size:
795
- // no error
796
- "invalid",
797
- },
798
- }),
799
- );
800
- const props = component();
801
- expect(getStyleClass(props)).toEqual({ class: "" });
802
- });
803
-
804
- test("defaultVariants when explicitly passing undefined", () => {
805
- const component = getModalComponent(
806
- mode,
807
- cv({
808
- variants: { size: { sm: "sm", lg: "lg" } },
809
- defaultVariants: { size: "sm" },
810
- }),
811
- );
812
- const props = component({ size: undefined });
813
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
814
- });
815
-
816
- test("defaultVariants boolean when explicitly passing undefined", () => {
817
- const component = getModalComponent(
818
- mode,
819
- cv({
820
- variants: { disabled: { true: "disabled", false: "enabled" } },
821
- defaultVariants: { disabled: true },
822
- }),
823
- );
824
- const props = component({ disabled: undefined });
825
- expect(getStyleClass(props)).toEqual({ class: cls("disabled") });
826
- });
827
-
828
- test("computedVariants", () => {
829
- const component = getModalComponent(
830
- mode,
831
- cv({
832
- computedVariants: {
833
- size: (value: "sm" | "lg") => (value === "sm" ? "small" : "large"),
834
- },
835
- }),
836
- );
837
- const props = component({ size: "lg" });
838
- expect(getStyleClass(props)).toEqual({ class: cls("large") });
839
- });
840
-
841
- test("computedVariants with style", () => {
842
- const component = getModalComponent(
843
- mode,
844
- cv({
845
- computedVariants: {
846
- size: (value: "sm" | "lg") => ({
847
- class: value === "sm" ? "small" : "large",
848
- style: { fontSize: value === "sm" ? "12px" : "16px" },
849
- }),
850
- },
851
- }),
852
- );
853
- const props = component({ size: "lg" });
854
- expect(getStyleClass(props)).toEqual({
855
- class: cls("large"),
856
- fontSize: "16px",
857
- });
858
- });
859
-
860
- test("computedVariants overrides extended object variants", () => {
861
- const base = cv({
862
- variants: {
863
- size: {
864
- sm: { class: "base-sm", style: { fontSize: "12px" } },
865
- lg: { class: "base-lg", style: { fontSize: "16px" } },
866
- },
867
- },
868
- });
869
- const component = getModalComponent(
870
- mode,
871
- cv({
872
- extend: [base],
873
- computedVariants: {
874
- size: (value: "sm" | "lg") => ({
875
- class: value === "sm" ? "extended-sm" : "extended-lg",
876
- style: {
877
- backgroundColor: value === "sm" ? "lightgray" : "gray",
878
- },
879
- }),
880
- },
881
- }),
882
- );
883
- const props = component({ size: "lg" });
884
- expect(getStyleClass(props)).toEqual({
885
- class: cls("extended-lg"),
886
- backgroundColor: "gray",
887
- });
888
- });
889
-
890
- test("computedVariants overrides extended computedVariants", () => {
891
- const base = cv({
892
- computedVariants: {
893
- size: (value: "sm" | "lg") => ({
894
- class: value === "sm" ? "base-sm" : "base-lg",
895
- style: { fontSize: value === "sm" ? "12px" : "16px" },
896
- }),
897
- },
898
- });
899
- const component = getModalComponent(
900
- mode,
901
- cv({
902
- extend: [base],
903
- computedVariants: {
904
- size: (value: "sm" | "lg") => ({
905
- class: value === "sm" ? "extended-sm" : "extended-lg",
906
- style: {
907
- backgroundColor: value === "sm" ? "lightgray" : "gray",
908
- },
909
- }),
910
- },
911
- }),
912
- );
913
- const props = component({ size: "lg" });
914
- expect(getStyleClass(props)).toEqual({
915
- class: cls("extended-lg"),
916
- backgroundColor: "gray",
917
- });
918
- });
919
-
920
- test("computedVariants style does not accept numbers", () => {
921
- const component = getModalComponent(
922
- mode,
923
- cv({
924
- computedVariants: {
925
- // @ts-expect-error
926
- size: (value: "sm" | "lg") => ({
927
- class: value === "sm" ? "small" : "large",
928
- style: { fontSize: value === "sm" ? 12 : 16 },
929
- }),
930
- },
931
- }),
932
- );
933
- const props = component({ size: "lg" });
934
- expect(getStyleClass(props)).toEqual({
935
- class: cls("large"),
936
- fontSize: expect.toBeOneOf(["16", "16px"]),
937
- });
938
- });
939
-
940
- test("computedVariants changes extended boolean variant to string", () => {
941
- const base = cv({
942
- variants: { disabled: { true: "disabled", false: "enabled" } },
943
- });
944
- const component = getModalComponent(
945
- mode,
946
- cv({
947
- extend: [base],
948
- computedVariants: {
949
- disabled: (value: "yes" | "no" | "maybe") => {
950
- if (value === "yes") return "state-disabled";
951
- if (value === "no") return "state-enabled";
952
- return "state-pending";
953
- },
954
- },
955
- }),
956
- );
957
- component({
958
- // @ts-expect-error
959
- disabled: true,
960
- });
961
- const props = component({ disabled: "maybe" });
962
- expect(getStyleClass(props)).toEqual({ class: cls("state-pending") });
963
- });
964
-
965
- test("computedVariants changes extended string variant to boolean", () => {
966
- const base = cv({ variants: { size: { sm: "sm", md: "md", lg: "lg" } } });
967
- const component = getModalComponent(
968
- mode,
969
- cv({
970
- extend: [base],
971
- computedVariants: {
972
- size: (value: boolean) => (value ? "size-large" : "size-small"),
973
- },
974
- }),
975
- );
976
- component({
977
- // @ts-expect-error
978
- size: "sm",
979
- });
980
- const propsTrue = component({ size: true });
981
- expect(getStyleClass(propsTrue)).toEqual({ class: cls("size-large") });
982
- const propsFalse = component({ size: false });
983
- expect(getStyleClass(propsFalse)).toEqual({ class: cls("size-small") });
984
- });
985
-
986
- test("computedVariants with number type", () => {
987
- const component = getModalComponent(
988
- mode,
989
- cv({
990
- computedVariants: {
991
- columns: (value: number) => ({
992
- class: `grid-cols-${value}`,
993
- style: { "--grid-columns": `${value}` },
994
- }),
995
- },
996
- }),
997
- );
998
- const props = component({ columns: 3 });
999
- expect(getStyleClass(props)).toEqual({
1000
- class: cls("grid-cols-3"),
1001
- "--grid-columns": "3",
1002
- });
1003
- });
1004
-
1005
- test("computedVariants with number type returns dynamic styles", () => {
1006
- const component = getModalComponent(
1007
- mode,
1008
- cv({
1009
- computedVariants: {
1010
- gap: (value: number) => ({
1011
- style: { "--gap": `${value * 4}px` },
1012
- }),
1013
- padding: (value: number) => ({
1014
- style: {
1015
- "--padding-x": `${value}px`,
1016
- "--padding-y": `${value * 0.5}px`,
1017
- },
1018
- }),
1019
- },
1020
- }),
1021
- );
1022
- const props = component({ gap: 4, padding: 16 });
1023
- expect(getStyleClass(props)).toEqual({
1024
- class: "",
1025
- "--gap": "16px",
1026
- "--padding-x": "16px",
1027
- "--padding-y": "8px",
1028
- });
1029
- });
1030
-
1031
- test("computedVariants with nullable type", () => {
1032
- const component = getModalComponent(
1033
- mode,
1034
- cv({
1035
- computedVariants: {
1036
- color: (value: string | null) => ({
1037
- class: value ? `color-${value}` : "color-default",
1038
- style: { "--color": value ?? "inherit" },
1039
- }),
1040
- },
1041
- }),
1042
- );
1043
- const propsWithValue = component({ color: "red" });
1044
- expect(getStyleClass(propsWithValue)).toEqual({
1045
- class: cls("color-red"),
1046
- "--color": "red",
1047
- });
1048
- const propsWithNull = component({ color: null });
1049
- expect(getStyleClass(propsWithNull)).toEqual({
1050
- class: cls("color-default"),
1051
- "--color": "inherit",
1052
- });
1053
- });
1054
-
1055
- test("computedVariants changes extended variant from string to number", () => {
1056
- const base = cv({
1057
- variants: { size: { sm: "text-sm", md: "text-md", lg: "text-lg" } },
1058
- });
1059
- const component = getModalComponent(
1060
- mode,
1061
- cv({
1062
- extend: [base],
1063
- computedVariants: {
1064
- size: (value: number) => ({
1065
- class: "text-custom",
1066
- style: { fontSize: `${value}px` },
1067
- }),
1068
- },
1069
- }),
1070
- );
1071
- component({
1072
- // @ts-expect-error
1073
- size: "sm",
1074
- });
1075
- const props = component({ size: 18 });
1076
- expect(getStyleClass(props)).toEqual({
1077
- class: cls("text-custom"),
1078
- fontSize: "18px",
1079
- });
1080
- });
1081
-
1082
- test("computed", () => {
1083
- const component = getModalComponent(
1084
- mode,
1085
- cv({
1086
- variants: { size: { sm: "sm", lg: "lg" } },
1087
- computed: ({ variants }) =>
1088
- variants.size === "lg" ? "computed-lg" : null,
1089
- }),
1090
- );
1091
- const props = component({ size: "lg" });
1092
- expect(getStyleClass(props)).toEqual({ class: cls("lg computed-lg") });
1093
- });
1094
-
1095
- test("computed with setVariants", () => {
1096
- const component = getModalComponent(
1097
- mode,
1098
- cv({
1099
- variants: {
1100
- size: { sm: "sm", lg: "lg" },
1101
- color: { red: "red", blue: "blue" },
1102
- },
1103
- computed: ({ variants, setVariants }) => {
1104
- if (variants.size === "lg") {
1105
- setVariants({ color: "red" });
1106
- }
1107
- },
1108
- }),
1109
- );
1110
- const props = component({ size: "lg" });
1111
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1112
- });
1113
-
1114
- test("computed with setDefaultVariants", () => {
1115
- const component = getModalComponent(
1116
- mode,
1117
- cv({
1118
- variants: {
1119
- size: { sm: "sm", lg: "lg" },
1120
- color: { red: "red", blue: "blue" },
1121
- },
1122
- computed: ({ variants, setDefaultVariants }) => {
1123
- if (variants.size === "lg") {
1124
- setDefaultVariants({ color: "red" });
1125
- }
1126
- },
1127
- }),
1128
- );
1129
- const props = component({ size: "lg" });
1130
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1131
- });
1132
-
1133
- test("computed setDefaultVariants does not override props", () => {
1134
- const component = getModalComponent(
1135
- mode,
1136
- cv({
1137
- variants: {
1138
- size: { sm: "sm", lg: "lg" },
1139
- color: { red: "red", blue: "blue" },
1140
- },
1141
- computed: ({ setDefaultVariants }) => {
1142
- setDefaultVariants({ color: "red" });
1143
- },
1144
- }),
1145
- );
1146
- const props = component({ size: "lg", color: "blue" });
1147
- expect(getStyleClass(props)).toEqual({ class: cls("lg blue") });
1148
- });
1149
-
1150
- test("computed setDefaultVariants overrides defaultVariants", () => {
1151
- const component = getModalComponent(
1152
- mode,
1153
- cv({
1154
- variants: {
1155
- size: { sm: "sm", lg: "lg" },
1156
- color: { red: "red", blue: "blue" },
1157
- },
1158
- defaultVariants: { size: "sm", color: "red" },
1159
- computed: ({ setDefaultVariants }) => {
1160
- setDefaultVariants({ color: "blue" });
1161
- },
1162
- }),
1163
- );
1164
- const props = component();
1165
- expect(getStyleClass(props)).toEqual({ class: cls("sm blue") });
1166
- });
1167
-
1168
- test("computed setDefaultVariants overrides extended defaultVariants", () => {
1169
- const base = cv({
1170
- variants: { color: { red: "red", blue: "blue" } },
1171
- defaultVariants: { color: "red" },
1172
- });
1173
- const component = getModalComponent(
1174
- mode,
1175
- cv({
1176
- extend: [base],
1177
- variants: { size: { sm: "sm", lg: "lg" } },
1178
- defaultVariants: { size: "sm" },
1179
- computed: ({ setDefaultVariants }) => {
1180
- setDefaultVariants({ color: "blue" });
1181
- },
1182
- }),
1183
- );
1184
- const props = component();
1185
- expect(getStyleClass(props)).toEqual({ class: cls("blue sm") });
1186
- });
1187
-
1188
- test("computed setDefaultVariants overrides child defaultVariants", () => {
1189
- const base = cv({
1190
- variants: { size: { sm: "sm", lg: "lg" } },
1191
- });
1192
- const component = getModalComponent(
1193
- mode,
1194
- cv({
1195
- extend: [base],
1196
- variants: { color: { red: "red", blue: "blue" } },
1197
- defaultVariants: { size: "sm", color: "red" },
1198
- computed: ({ setDefaultVariants }) => {
1199
- setDefaultVariants({ size: "lg" });
1200
- },
1201
- }),
1202
- );
1203
- const props = component();
1204
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1205
- });
1206
-
1207
- test("computed setDefaultVariants from parent overrides child defaultVariants", () => {
1208
- const base = cv({
1209
- variants: { size: { sm: "sm", lg: "lg" } },
1210
- defaultVariants: { size: "sm" },
1211
- computed: ({ setDefaultVariants }) => {
1212
- setDefaultVariants({ size: "lg" });
1213
- },
1214
- });
1215
- const component = getModalComponent(
1216
- mode,
1217
- cv({
1218
- extend: [base],
1219
- variants: { color: { red: "red", blue: "blue" } },
1220
- defaultVariants: { size: "sm", color: "red" },
1221
- }),
1222
- );
1223
- const props = component();
1224
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1225
- });
1226
-
1227
- test("computed setDefaultVariants from parent overrides child defaultVariants based on props", () => {
1228
- const base = cv({
1229
- variants: { size: { sm: "sm", lg: "lg" }, enabled: "" },
1230
- defaultVariants: { size: "sm" },
1231
- computed: ({ variants, setDefaultVariants }) => {
1232
- if (!variants.enabled) return;
1233
- setDefaultVariants({ size: "lg" });
1234
- },
1235
- });
1236
- const component = getModalComponent(
1237
- mode,
1238
- cv({
1239
- extend: [base],
1240
- variants: { color: { red: "red", blue: "blue" } },
1241
- defaultVariants: { size: "sm", color: "red" },
1242
- }),
1243
- );
1244
- const props = component({ enabled: true });
1245
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1246
- });
1247
-
1248
- test("computed receives default variants from child", () => {
1249
- const base = cv({
1250
- variants: { size: { sm: "sm", lg: "lg" }, large: "" },
1251
- defaultVariants: { size: "sm" },
1252
- computed: ({ variants, setDefaultVariants }) => {
1253
- if (variants.large) {
1254
- setDefaultVariants({ size: "lg" });
1255
- }
1256
- },
1257
- });
1258
- const component = getModalComponent(
1259
- mode,
1260
- cv({
1261
- extend: [base],
1262
- variants: { color: { red: "red", blue: "blue" } },
1263
- defaultVariants: { size: "sm", color: "red", large: true },
1264
- }),
1265
- );
1266
- const props = component();
1267
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1268
- });
1269
-
1270
- test("computed receives default variants from grandchild", () => {
1271
- const base = cv({
1272
- variants: { size: { sm: "sm", lg: "lg" }, large: "" },
1273
- defaultVariants: { size: "sm" },
1274
- computed: ({ variants, setDefaultVariants }) => {
1275
- if (variants.large) {
1276
- setDefaultVariants({ size: "lg" });
1277
- }
1278
- },
1279
- });
1280
- const base2 = cv({ extend: [base] });
1281
- const component = getModalComponent(
1282
- mode,
1283
- cv({
1284
- extend: [base2],
1285
- variants: { color: { red: "red", blue: "blue" } },
1286
- defaultVariants: { size: "sm", color: "red", large: true },
1287
- }),
1288
- );
1289
- const props = component();
1290
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1291
- });
1292
-
1293
- test("computed receives default variants from intermediate component", () => {
1294
- const parent = cv({
1295
- variants: { size: { sm: "sm", lg: "lg" } },
1296
- computed: ({ variants, setDefaultVariants }) => {
1297
- if (!variants.size) {
1298
- setDefaultVariants({ size: "lg" });
1299
- }
1300
- },
1301
- });
1302
- const child = cv({ extend: [parent], defaultVariants: { size: "sm" } });
1303
- const component = getModalComponent(mode, cv({ extend: [child] }));
1304
- const props = component();
1305
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
1306
- });
1307
-
1308
- test("child computed setDefaultVariants overrides parent computed setDefaultVariants", () => {
1309
- const base = cv({
1310
- variants: { size: { sm: "sm", lg: "lg" } },
1311
- defaultVariants: { size: "sm" },
1312
- computed: ({ setDefaultVariants }) => {
1313
- setDefaultVariants({ size: "lg" });
1314
- },
1315
- });
1316
- const component = getModalComponent(
1317
- mode,
1318
- cv({
1319
- extend: [base],
1320
- variants: { color: { red: "red", blue: "blue" } },
1321
- defaultVariants: { size: "sm", color: "red" },
1322
- computed: ({ setDefaultVariants }) => {
1323
- setDefaultVariants({ size: "sm" });
1324
- },
1325
- }),
1326
- );
1327
- const props = component();
1328
- // Order: parent defaultVariants (sm) -> child defaultVariants (sm)
1329
- // -> parent computed.setDefaultVariants (lg)
1330
- // -> child computed.setDefaultVariants (sm)
1331
- expect(getStyleClass(props)).toEqual({ class: cls("sm red") });
1332
- });
1333
-
1334
- test("child setDefaultVariants receives computed variants from parent", () => {
1335
- const base = cv({
1336
- variants: { size: { sm: "sm", lg: "lg" }, small: "" },
1337
- computed: ({ setDefaultVariants }) => {
1338
- setDefaultVariants({ small: true });
1339
- },
1340
- });
1341
- const component = getModalComponent(
1342
- mode,
1343
- cv({
1344
- extend: [base],
1345
- variants: { color: { red: "red", blue: "blue" } },
1346
- defaultVariants: { size: "lg", color: "red" },
1347
- computed: ({ variants, setDefaultVariants }) => {
1348
- if (variants.small) {
1349
- setDefaultVariants({ size: "sm" });
1350
- }
1351
- },
1352
- }),
1353
- );
1354
- const props = component();
1355
- expect(getStyleClass(props)).toEqual({ class: cls("sm red") });
1356
- });
1357
-
1358
- test("computed setDefaultVariants when explicitly passing undefined", () => {
1359
- const component = getModalComponent(
1360
- mode,
1361
- cv({
1362
- variants: {
1363
- size: { sm: "sm", lg: "lg" },
1364
- color: { red: "red", blue: "blue" },
1365
- },
1366
- computed: ({ setDefaultVariants }) => {
1367
- setDefaultVariants({ color: "red" });
1368
- },
1369
- }),
1370
- );
1371
- const props = component({ size: "lg", color: undefined });
1372
- expect(getStyleClass(props)).toEqual({ class: cls("lg red") });
1373
- });
1374
-
1375
- test("computed with defaultVariants", () => {
1376
- const component = getModalComponent(
1377
- mode,
1378
- cv({
1379
- variants: {
1380
- size: { sm: "sm", lg: "lg" },
1381
- color: { red: "red", blue: "blue" },
1382
- },
1383
- defaultVariants: { size: "lg" },
1384
- computed: ({ variants }) =>
1385
- variants.size === "lg" ? "computed-lg" : null,
1386
- }),
1387
- );
1388
- const props = component();
1389
- expect(getStyleClass(props)).toEqual({ class: cls("lg computed-lg") });
1390
- });
1391
-
1392
- test("computed with defaultVariants from extended", () => {
1393
- const base = cv({
1394
- variants: { size: { sm: "sm", lg: "lg" } },
1395
- defaultVariants: { size: "lg" },
1396
- });
1397
- const component = getModalComponent(
1398
- mode,
1399
- cv({
1400
- extend: [base],
1401
- computed: ({ variants }) =>
1402
- variants.size === "lg" ? "computed-lg" : null,
1403
- }),
1404
- );
1405
- const props = component();
1406
- expect(getStyleClass(props)).toEqual({ class: cls("lg computed-lg") });
1407
- });
1408
-
1409
- test("computed from parent receives boolean default value from overridden variant in child", () => {
1410
- const base = cv({
1411
- variants: {
1412
- size: { sm: "sm", lg: "lg" },
1413
- border: { default: "default", true: "border", false: "" },
1414
- },
1415
- defaultVariants: { size: "lg" },
1416
- computed: ({ variants, setVariants }) => {
1417
- expect(variants.border).toBe(false);
1418
- if (!variants.border) {
1419
- setVariants({ size: "sm" });
1420
- }
1421
- },
1422
- });
1423
- const component = getModalComponent(
1424
- mode,
1425
- cv({
1426
- extend: [base],
1427
- computedVariants: {
1428
- border: (_: boolean) => {},
1429
- },
1430
- defaultVariants: { border: false },
1431
- }),
1432
- );
1433
- const props = component();
1434
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
1435
- });
1436
-
1437
- test("computed from parent receives boolean default value from overridden variant in grandchild", () => {
1438
- const base = cv({
1439
- variants: {
1440
- size: { sm: "sm", lg: "lg" },
1441
- border: { default: "default", true: "border", false: "" },
1442
- },
1443
- defaultVariants: { size: "lg" },
1444
- computed: ({ variants, setVariants }) => {
1445
- expect(variants.border).toBe(false);
1446
- if (!variants.border) {
1447
- setVariants({ size: "sm" });
1448
- }
1449
- },
1450
- });
1451
- const base2 = cv({ extend: [base] });
1452
- const component = getModalComponent(
1453
- mode,
1454
- cv({
1455
- extend: [base2],
1456
- computedVariants: {
1457
- border: (_: boolean) => {},
1458
- },
1459
- defaultVariants: { border: false },
1460
- }),
1461
- );
1462
- const props = component();
1463
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
1464
- });
1465
-
1466
- test("computed from parent receives false prop from overridden variant in child", () => {
1467
- const base = cv({
1468
- variants: {
1469
- size: { sm: "sm", lg: "lg" },
1470
- border: { default: "default", true: "border", false: "" },
1471
- },
1472
- defaultVariants: { size: "lg" },
1473
- computed: ({ variants, setVariants }) => {
1474
- expect(variants.border).toBe(false);
1475
- if (!variants.border) {
1476
- setVariants({ size: "sm" });
1477
- }
1478
- },
1479
- });
1480
- const component = getModalComponent(
1481
- mode,
1482
- cv({
1483
- extend: [base],
1484
- computedVariants: {
1485
- border: (_: boolean) => {},
1486
- },
1487
- }),
1488
- );
1489
- const props = component({ border: false });
1490
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
1491
- });
1492
-
1493
- test("computed from parent receives true prop from overridden variant in child", () => {
1494
- const base = cv({
1495
- variants: {
1496
- size: { sm: "sm", lg: "lg" },
1497
- border: { default: "default", true: "border", false: "" },
1498
- },
1499
- defaultVariants: { size: "lg" },
1500
- computed: ({ variants, setVariants }) => {
1501
- expect(variants.border).toBe(true);
1502
- if (variants.border) {
1503
- setVariants({ size: "sm" });
1504
- }
1505
- },
1506
- });
1507
- const component = getModalComponent(
1508
- mode,
1509
- cv({
1510
- extend: [base],
1511
- computedVariants: {
1512
- border: (_: boolean) => {},
1513
- },
1514
- }),
1515
- );
1516
- const props = component({ border: true });
1517
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
1518
- });
1519
-
1520
- test("computed from parent receives true prop from overridden variant in grandchild", () => {
1521
- const base = cv({
1522
- variants: {
1523
- size: { sm: "sm", lg: "lg" },
1524
- border: { default: "default", true: "border", false: "" },
1525
- },
1526
- defaultVariants: { size: "lg" },
1527
- computed: ({ variants, setVariants }) => {
1528
- expect(variants.border).toBe(true);
1529
- if (variants.border) {
1530
- setVariants({ size: "sm" });
1531
- }
1532
- },
1533
- });
1534
- const base2 = cv({ extend: [base] });
1535
- const component = getModalComponent(
1536
- mode,
1537
- cv({
1538
- extend: [base2],
1539
- computedVariants: {
1540
- border: (_: boolean) => {},
1541
- },
1542
- }),
1543
- );
1544
- const props = component({ border: true });
1545
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
1546
- });
1547
-
1548
- test("computed with style", () => {
1549
- const component = getModalComponent(
1550
- mode,
1551
- cv({
1552
- variants: { size: { sm: "sm", lg: "lg" } },
1553
- computed: ({ variants }) =>
1554
- variants.size === "lg" ? { style: { fontSize: "20px" } } : null,
1555
- }),
1556
- );
1557
- const props = component({ size: "lg" });
1558
- expect(getStyleClass(props)).toEqual({
1559
- class: cls("lg"),
1560
- fontSize: "20px",
1561
- });
1562
- });
1563
-
1564
- test("computed with class and style", () => {
1565
- const component = getModalComponent(
1566
- mode,
1567
- cv({
1568
- variants: { size: { sm: "sm", lg: "lg" } },
1569
- computed: ({ variants }) =>
1570
- variants.size === "lg"
1571
- ? { class: "computed-lg", style: { fontSize: "20px" } }
1572
- : null,
1573
- }),
1574
- );
1575
- const props = component({ size: "lg" });
1576
- expect(getStyleClass(props)).toEqual({
1577
- class: cls("lg computed-lg"),
1578
- fontSize: "20px",
1579
- });
1580
- });
1581
-
1582
- test("computed style does not accept numbers", () => {
1583
- const component = getModalComponent(
1584
- mode,
1585
- cv({
1586
- variants: { size: { sm: "sm", lg: "lg" } },
1587
- // @ts-expect-error
1588
- computed: ({ variants }) =>
1589
- variants.size === "lg"
1590
- ? {
1591
- class: "computed-lg",
1592
- style: { fontSize: 20 },
1593
- }
1594
- : null,
1595
- }),
1596
- );
1597
- const props = component({ size: "lg" });
1598
- expect(getStyleClass(props)).toEqual({
1599
- class: cls("lg computed-lg"),
1600
- fontSize: expect.toBeOneOf(["20", "20px"]),
1601
- });
1602
- });
1603
-
1604
- test("computed setVariants does not accept invalid keys", () => {
1605
- const component = getModalComponent(
1606
- mode,
1607
- cv({
1608
- variants: { size: { sm: "sm", lg: "lg" } },
1609
- computed: ({ setVariants }) => {
1610
- setVariants({
1611
- // @ts-expect-error
1612
- invalidKey: "value",
1613
- });
1614
- },
1615
- }),
1616
- );
1617
- const props = component({ size: "lg" });
1618
- expect(getStyleClass(props)).toEqual({ class: cls("lg") });
1619
- });
1620
-
1621
- test("computed setVariants does not accept invalid values", () => {
1622
- const component = getModalComponent(
1623
- mode,
1624
- cv({
1625
- variants: { size: { sm: "sm", lg: "lg" } },
1626
- computed: ({ setVariants }) => {
1627
- setVariants({
1628
- // @ts-expect-error invalid value
1629
- size:
1630
- // no error
1631
- "invalid",
1632
- });
1633
- },
1634
- }),
1635
- );
1636
- const props = component({ size: "lg" });
1637
- // Invalid value overrides the valid one, resulting in no match
1638
- expect(getStyleClass(props)).toEqual({ class: "" });
1639
- });
1640
-
1641
- test("computed addClass with string", () => {
1642
- const component = getModalComponent(
1643
- mode,
1644
- cv({
1645
- variants: { size: { sm: "sm", lg: "lg" } },
1646
- computed: ({ variants, addClass }) => {
1647
- if (variants.size === "lg") {
1648
- addClass("added-lg");
1649
- }
1650
- },
1651
- }),
1652
- );
1653
- const props = component({ size: "lg" });
1654
- expect(getStyleClass(props)).toEqual({ class: cls("lg added-lg") });
1655
- });
1656
-
1657
- test("computed addClass with array", () => {
1658
- const component = getModalComponent(
1659
- mode,
1660
- cv({
1661
- variants: { size: { sm: "sm", lg: "lg" } },
1662
- computed: ({ variants, addClass }) => {
1663
- if (variants.size === "lg") {
1664
- addClass(["added-lg", "extra-class"]);
1665
- }
1666
- },
1667
- }),
1668
- );
1669
- const props = component({ size: "lg" });
1670
- expect(getStyleClass(props)).toEqual({
1671
- class: cls("lg added-lg extra-class"),
1672
- });
1673
- });
1674
-
1675
- test("computed addStyle", () => {
1676
- const component = getModalComponent(
1677
- mode,
1678
- cv({
1679
- variants: { size: { sm: "sm", lg: "lg" } },
1680
- computed: ({ variants, addStyle }) => {
1681
- if (variants.size === "lg") {
1682
- addStyle({ fontSize: "20px" });
1683
- }
1684
- },
1685
- }),
1686
- );
1687
- const props = component({ size: "lg" });
1688
- expect(getStyleClass(props)).toEqual({
1689
- class: cls("lg"),
1690
- fontSize: "20px",
1691
- });
1692
- });
1693
-
1694
- test("computed addClass combined with return value", () => {
1695
- const component = getModalComponent(
1696
- mode,
1697
- cv({
1698
- variants: { size: { sm: "sm", lg: "lg" } },
1699
- computed: ({ variants, addClass }) => {
1700
- if (variants.size === "lg") {
1701
- addClass("added-class");
1702
- }
1703
- return "returned-class";
1704
- },
1705
- }),
1706
- );
1707
- const props = component({ size: "lg" });
1708
- expect(getStyleClass(props)).toEqual({
1709
- class: cls("lg added-class returned-class"),
1710
- });
1711
- });
1712
-
1713
- test("computed addStyle combined with return value", () => {
1714
- const component = getModalComponent(
1715
- mode,
1716
- cv({
1717
- variants: { size: { sm: "sm", lg: "lg" } },
1718
- computed: ({ variants, addStyle }) => {
1719
- if (variants.size === "lg") {
1720
- addStyle({ fontSize: "20px" });
1721
- }
1722
- return { style: { backgroundColor: "red" } };
1723
- },
1724
- }),
1725
- );
1726
- const props = component({ size: "lg" });
1727
- expect(getStyleClass(props)).toEqual({
1728
- class: cls("lg"),
1729
- fontSize: "20px",
1730
- backgroundColor: "red",
1731
- });
1732
- });
1733
-
1734
- test("computed addClass and addStyle together", () => {
1735
- const component = getModalComponent(
1736
- mode,
1737
- cv({
1738
- variants: { size: { sm: "sm", lg: "lg" } },
1739
- computed: ({ variants, addClass, addStyle }) => {
1740
- if (variants.size === "lg") {
1741
- addClass("added-lg");
1742
- addStyle({ fontSize: "20px" });
1743
- }
1744
- },
1745
- }),
1746
- );
1747
- const props = component({ size: "lg" });
1748
- expect(getStyleClass(props)).toEqual({
1749
- class: cls("lg added-lg"),
1750
- fontSize: "20px",
1751
- });
1752
- });
1753
-
1754
- test("computed addClass and addStyle with return value", () => {
1755
- const component = getModalComponent(
1756
- mode,
1757
- cv({
1758
- variants: { size: { sm: "sm", lg: "lg" } },
1759
- computed: ({ variants, addClass, addStyle }) => {
1760
- if (variants.size === "lg") {
1761
- addClass("added-lg");
1762
- addStyle({ fontSize: "20px" });
1763
- }
1764
- return {
1765
- class: "returned-class",
1766
- style: { backgroundColor: "red" },
1767
- };
1768
- },
1769
- }),
1770
- );
1771
- const props = component({ size: "lg" });
1772
- expect(getStyleClass(props)).toEqual({
1773
- class: cls("lg added-lg returned-class"),
1774
- fontSize: "20px",
1775
- backgroundColor: "red",
1776
- });
1777
- });
1778
-
1779
- test("computed addClass multiple calls", () => {
1780
- const component = getModalComponent(
1781
- mode,
1782
- cv({
1783
- variants: { size: { sm: "sm", lg: "lg" } },
1784
- computed: ({ variants, addClass }) => {
1785
- if (variants.size === "lg") {
1786
- addClass("first");
1787
- addClass("second");
1788
- addClass("third");
1789
- }
1790
- },
1791
- }),
1792
- );
1793
- const props = component({ size: "lg" });
1794
- expect(getStyleClass(props)).toEqual({
1795
- class: cls("lg first second third"),
1796
- });
1797
- });
1798
-
1799
- test("computed addStyle multiple calls merges styles", () => {
1800
- const component = getModalComponent(
1801
- mode,
1802
- cv({
1803
- variants: { size: { sm: "sm", lg: "lg" } },
1804
- computed: ({ variants, addStyle }) => {
1805
- if (variants.size === "lg") {
1806
- addStyle({ fontSize: "20px" });
1807
- addStyle({ backgroundColor: "red" });
1808
- addStyle({ color: "blue" });
1809
- }
1810
- },
1811
- }),
1812
- );
1813
- const props = component({ size: "lg" });
1814
- expect(getStyleClass(props)).toEqual({
1815
- class: cls("lg"),
1816
- fontSize: "20px",
1817
- backgroundColor: "red",
1818
- color: "blue",
1819
- });
1820
- });
1821
-
1822
- test("computed addStyle later call overrides earlier", () => {
1823
- const component = getModalComponent(
1824
- mode,
1825
- cv({
1826
- variants: { size: { sm: "sm", lg: "lg" } },
1827
- computed: ({ variants, addStyle }) => {
1828
- if (variants.size === "lg") {
1829
- addStyle({ fontSize: "16px" });
1830
- addStyle({ fontSize: "20px" });
1831
- }
1832
- },
1833
- }),
1834
- );
1835
- const props = component({ size: "lg" });
1836
- expect(getStyleClass(props)).toEqual({
1837
- class: cls("lg"),
1838
- fontSize: "20px",
1839
- });
1840
- });
1841
-
1842
- test("computed addStyle does not accept numbers", () => {
1843
- const component = getModalComponent(
1844
- mode,
1845
- cv({
1846
- variants: { size: { sm: "sm", lg: "lg" } },
1847
- computed: ({ variants, addStyle }) => {
1848
- if (variants.size === "lg") {
1849
- addStyle({
1850
- // @ts-expect-error
1851
- fontSize: 20,
1852
- });
1853
- }
1854
- },
1855
- }),
1856
- );
1857
- const props = component({ size: "lg" });
1858
- expect(getStyleClass(props)).toEqual({
1859
- class: cls("lg"),
1860
- fontSize: expect.toBeOneOf(["20", "20px"]),
1861
- });
1862
- });
1863
-
1864
- test("extend single component", () => {
1865
- const base = cv({ class: "base", variants: { size: { sm: "sm" } } });
1866
- const component = getModalComponent(
1867
- mode,
1868
- cv({ extend: [base], class: "extended" }),
1869
- );
1870
- const props = component({ size: "sm" });
1871
- expect(getStyleClass(props)).toEqual({ class: cls("base extended sm") });
1872
- });
1873
-
1874
- test("extend multiple components", () => {
1875
- const base1 = cv({ class: "base1" });
1876
- const base2 = cv({ class: "base2" });
1877
- const component = getModalComponent(
1878
- mode,
1879
- cv({ extend: [base1, base2], class: "extended" }),
1880
- );
1881
- const props = component();
1882
- expect(getStyleClass(props)).toEqual({
1883
- class: cls("base1 base2 extended"),
1884
- });
1885
- });
1886
-
1887
- test("extend with variant merging", () => {
1888
- const base = cv({ variants: { size: { sm: "base-sm", lg: "base-lg" } } });
1889
- const component = getModalComponent(
1890
- mode,
1891
- cv({ extend: [base], variants: { size: { sm: "extended-sm" } } }),
1892
- );
1893
- const props = component({ size: "sm" });
1894
- expect(getStyleClass(props)).toEqual({
1895
- class: cls("base-sm extended-sm"),
1896
- });
1897
- });
1898
-
1899
- test("extend with variant merging setting base variant", () => {
1900
- const base = cv({ variants: { size: { sm: "base-sm", lg: "base-lg" } } });
1901
- const component = getModalComponent(
1902
- mode,
1903
- cv({
1904
- extend: [base],
1905
- variants: { size: { sm: "extended-sm" } },
1906
- }),
1907
- );
1908
- const props = component({ size: "lg" });
1909
- expect(getStyleClass(props)).toEqual({ class: cls("base-lg") });
1910
- });
1911
-
1912
- test("extend can disable whole variant with null", () => {
1913
- const base = cv({
1914
- variants: { size: { sm: "base-sm", lg: "base-lg" } },
1915
- defaultVariants: { size: "sm" },
1916
- });
1917
- const component = getModalComponent(
1918
- mode,
1919
- cv({
1920
- extend: [base],
1921
- variants: { size: null },
1922
- defaultVariants: {
1923
- // @ts-expect-error disabled variant cannot be set
1924
- size:
1925
- // no error
1926
- "lg",
1927
- },
1928
- }),
1929
- );
1930
- const props = component({
1931
- // @ts-expect-error disabled variant cannot be set
1932
- size:
1933
- // no error
1934
- "lg",
1935
- });
1936
- expect(getStyleClass(props)).toEqual({ class: "" });
1937
- });
1938
-
1939
- test("extend can disable variant value with null", () => {
1940
- const base = cv({
1941
- variants: { size: { sm: "base-sm", lg: "base-lg" } },
1942
- defaultVariants: { size: "sm" },
1943
- });
1944
- const component = getModalComponent(
1945
- mode,
1946
- cv({
1947
- extend: [base],
1948
- variants: { size: { sm: null } },
1949
- defaultVariants: {
1950
- // @ts-expect-error disabled variant value cannot be set
1951
- size:
1952
- // no error
1953
- "sm",
1954
- },
1955
- }),
1956
- );
1957
- const disabledProps = component({
1958
- // @ts-expect-error disabled variant value cannot be set
1959
- size:
1960
- // no error
1961
- "sm",
1962
- });
1963
- expect(getStyleClass(disabledProps)).toEqual({ class: "" });
1964
- const enabledProps = component({ size: "lg" });
1965
- expect(getStyleClass(enabledProps)).toEqual({ class: cls("base-lg") });
1966
- });
1967
-
1968
- test("extend disabled variant value accepts valid defaultVariants", () => {
1969
- const base = cv({
1970
- variants: {
1971
- size: {
1972
- sm: { class: "base-sm", style: { fontSize: "12px" } },
1973
- lg: { class: "base-lg", style: { fontSize: "16px" } },
1974
- },
1975
- },
1976
- });
1977
- const component = getModalComponent(
1978
- mode,
1979
- cv({
1980
- extend: [base],
1981
- variants: { size: { sm: null } },
1982
- defaultVariants: { size: "lg" },
1983
- }),
1984
- );
1985
- const props = component();
1986
- expect(getStyleClass(props)).toEqual({
1987
- class: cls("base-lg"),
1988
- fontSize: "16px",
1989
- });
1990
- });
1991
-
1992
- test("extend disabled variant value with computed setDefaultVariants", () => {
1993
- const base = cv({
1994
- variants: {
1995
- size: {
1996
- sm: { class: "base-sm", style: { fontSize: "12px" } },
1997
- lg: { class: "base-lg", style: { fontSize: "16px" } },
1998
- },
1999
- },
2000
- });
2001
- const validComponent = getModalComponent(
2002
- mode,
2003
- cv({
2004
- extend: [base],
2005
- variants: { size: { sm: null } },
2006
- computed: ({ setDefaultVariants }) => {
2007
- setDefaultVariants({ size: "lg" });
2008
- },
2009
- }),
2010
- );
2011
- expect(getStyleClass(validComponent())).toEqual({
2012
- class: cls("base-lg"),
2013
- fontSize: "16px",
2014
- });
2015
-
2016
- const invalidComponent = getModalComponent(
2017
- mode,
2018
- cv({
2019
- extend: [base],
2020
- variants: { size: { sm: null } },
2021
- computed: ({ setDefaultVariants }) => {
2022
- setDefaultVariants({
2023
- // @ts-expect-error disabled variant value cannot be set
2024
- size:
2025
- // no error
2026
- "sm",
2027
- });
2028
- },
2029
- }),
2030
- );
2031
- expect(getStyleClass(invalidComponent())).toEqual({ class: "" });
2032
- });
2033
-
2034
- test("extend disabled variant value with computed setVariants", () => {
2035
- const base = cv({
2036
- variants: {
2037
- size: {
2038
- sm: { class: "base-sm", style: { fontSize: "12px" } },
2039
- lg: { class: "base-lg", style: { fontSize: "16px" } },
2040
- },
2041
- },
2042
- });
2043
- const validComponent = getModalComponent(
2044
- mode,
2045
- cv({
2046
- extend: [base],
2047
- variants: { size: { sm: null } },
2048
- computed: ({ setVariants }) => {
2049
- setVariants({ size: "lg" });
2050
- },
2051
- }),
2052
- );
2053
- expect(getStyleClass(validComponent())).toEqual({
2054
- class: cls("base-lg"),
2055
- fontSize: "16px",
2056
- });
2057
-
2058
- const invalidComponent = getModalComponent(
2059
- mode,
2060
- cv({
2061
- extend: [base],
2062
- variants: { size: { sm: null } },
2063
- computed: ({ setVariants }) => {
2064
- setVariants({
2065
- // @ts-expect-error disabled variant value cannot be set
2066
- size:
2067
- // no error
2068
- "sm",
2069
- });
2070
- },
2071
- }),
2072
- );
2073
- expect(getStyleClass(invalidComponent())).toEqual({ class: "" });
2074
- });
2075
-
2076
- test("extend inherits defaultVariants", () => {
2077
- const base = cv({
2078
- variants: { size: { sm: "sm", lg: "lg" } },
2079
- defaultVariants: { size: "sm" },
2080
- });
2081
- const component = getModalComponent(mode, cv({ extend: [base] }));
2082
- const props = component();
2083
- expect(getStyleClass(props)).toEqual({ class: cls("sm") });
2084
- });
2085
-
2086
- test("extend override defaultVariants", () => {
2087
- const base = cv({
2088
- variants: { size: { sm: "sm", lg: "lg" } },
2089
- defaultVariants: { size: "sm" },
2090
- });
2091
- const component = getModalComponent(
2092
- mode,
2093
- cv({ extend: [base], defaultVariants: { size: "lg" } }),
2094
- );
2095
- const props = component();
2096
- expect(getStyleClass(props)).toEqual({ class: cls("lg") });
2097
- });
2098
-
2099
- test("class method", () => {
2100
- const component = getModalComponent(
2101
- mode,
2102
- cv({ class: "foo", variants: { size: { sm: "sm", lg: "lg" } } }),
2103
- );
2104
- const className = component.class({ size: "lg" });
2105
- expect(className).toBe(cls("foo lg"));
2106
- });
2107
-
2108
- test("style method", () => {
2109
- const component = getModalComponent(
2110
- mode,
2111
- cv({ style: { backgroundColor: "red" } }),
2112
- );
2113
- const style = component.style();
2114
- expect(getStyle({ style })).toEqual({ backgroundColor: "red" });
2115
- });
2116
-
2117
- test("getVariants returns variant values", () => {
2118
- const component = getModalComponent(
2119
- mode,
2120
- cv({
2121
- variants: { size: { sm: "sm", lg: "lg" } },
2122
- defaultVariants: { size: "sm" },
2123
- }),
2124
- );
2125
- const variants = component.getVariants({ size: "lg" });
2126
- expect(variants).toEqual({ size: "lg" });
2127
- });
2128
-
2129
- test("getVariants returns default variants", () => {
2130
- const component = getModalComponent(
2131
- mode,
2132
- cv({
2133
- variants: { size: { sm: "sm", lg: "lg" } },
2134
- defaultVariants: { size: "sm" },
2135
- }),
2136
- );
2137
- const variants = component.getVariants();
2138
- expect(variants).toEqual({ size: "sm" });
2139
- });
2140
-
2141
- test("getVariants returns variants set by computed setVariants", () => {
2142
- const component = getModalComponent(
2143
- mode,
2144
- cv({
2145
- variants: {
2146
- size: { sm: "sm", lg: "lg" },
2147
- color: { red: "red", blue: "blue" },
2148
- },
2149
- computed: ({ variants, setVariants }) => {
2150
- if (variants.size === "lg") {
2151
- setVariants({ color: "red" });
2152
- }
2153
- },
2154
- }),
2155
- );
2156
- const variants = component.getVariants({ size: "lg" });
2157
- expect(variants).toEqual({ size: "lg", color: "red" });
2158
- });
2159
-
2160
- test("getVariants returns variants set by computed setDefaultVariants", () => {
2161
- const component = getModalComponent(
2162
- mode,
2163
- cv({
2164
- variants: {
2165
- size: { sm: "sm", lg: "lg" },
2166
- color: { red: "red", blue: "blue" },
2167
- },
2168
- computed: ({ variants, setDefaultVariants }) => {
2169
- if (variants.size === "lg") {
2170
- setDefaultVariants({ color: "blue" });
2171
- }
2172
- },
2173
- }),
2174
- );
2175
- const variants = component.getVariants({ size: "lg" });
2176
- expect(variants).toEqual({ size: "lg", color: "blue" });
2177
- });
2178
-
2179
- test("getVariants setDefaultVariants does not override props", () => {
2180
- const component = getModalComponent(
2181
- mode,
2182
- cv({
2183
- variants: {
2184
- size: { sm: "sm", lg: "lg" },
2185
- color: { red: "red", blue: "blue" },
2186
- },
2187
- computed: ({ setDefaultVariants }) => {
2188
- setDefaultVariants({ color: "blue" });
2189
- },
2190
- }),
2191
- );
2192
- const variants = component.getVariants({ color: "red" });
2193
- expect(variants).toEqual({ color: "red" });
2194
- });
2195
-
2196
- test("getVariants setVariants overrides props", () => {
2197
- const component = getModalComponent(
2198
- mode,
2199
- cv({
2200
- variants: {
2201
- size: { sm: "sm", lg: "lg" },
2202
- color: { red: "red", blue: "blue" },
2203
- },
2204
- computed: ({ setVariants }) => {
2205
- setVariants({ color: "blue" });
2206
- },
2207
- }),
2208
- );
2209
- const variants = component.getVariants({ color: "red" });
2210
- expect(variants).toEqual({ color: "blue" });
2211
- });
2212
-
2213
- test("keys returns props keys", () => {
2214
- const component = getModalComponent(
2215
- mode,
2216
- cv({ variants: { size: { sm: "sm" }, color: { red: "red" } } }),
2217
- );
2218
- expectTypeOf(component.keys).toExtend<
2219
- ("class" | "className" | "style" | "size" | "color")[]
2220
- >();
2221
- expect(component.keys).toEqual([
2222
- getClassPropertyName(config),
2223
- "style",
2224
- "size",
2225
- "color",
2226
- ]);
2227
- });
2228
-
2229
- test("splitProps separates variant props", () => {
2230
- const component = getModalComponent(
2231
- mode,
2232
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2233
- );
2234
- const classNameProp = getClassPropertyName(config);
2235
- const props: HTMLProperties<typeof component> = {
2236
- id: "test",
2237
- size: "lg",
2238
- style: { color: "red" },
2239
- [classNameProp]: "extra",
2240
- };
2241
- const [variantProps, otherProps] = splitProps(props, component);
2242
- expectTypeOf(variantProps).branded.toEqualTypeOf<
2243
- Pick<typeof props, "size" | "style" | "class" | "className">
2244
- >();
2245
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2246
- expect(variantProps).toEqual({
2247
- size: "lg",
2248
- style: { color: "red" },
2249
- [classNameProp]: "extra",
2250
- });
2251
- expect(otherProps).toEqual({ id: "test" });
2252
- });
2253
-
2254
- test("variantKeys splitProps", () => {
2255
- const component = getModalComponent(
2256
- mode,
2257
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2258
- );
2259
- const classNameProp = getClassPropertyName(config);
2260
- const props: HTMLProperties<typeof component> = {
2261
- size: "lg",
2262
- id: "test",
2263
- style: "color: red;",
2264
- [classNameProp]: "extra",
2265
- };
2266
- const [variantProps, otherProps] = splitProps(
2267
- props,
2268
- component.variantKeys,
2269
- );
2270
- expectTypeOf(variantProps).branded.toEqualTypeOf<{
2271
- size?: "sm" | "lg";
2272
- }>();
2273
- expectTypeOf(otherProps).toEqualTypeOf<
2274
- Pick<typeof props, "id" | "style" | "class" | "className">
2275
- >();
2276
- expect(variantProps).toEqual({ size: "lg" });
2277
- expect(otherProps).toEqual({
2278
- id: "test",
2279
- style: "color: red;",
2280
- [classNameProp]: "extra",
2281
- });
2282
- });
2283
-
2284
- test("variantKeys property", () => {
2285
- const component = getModalComponent(
2286
- mode,
2287
- cv({
2288
- variants: { size: { sm: "sm" }, color: { red: "red" } },
2289
- }),
2290
- );
2291
- expectTypeOf(component.variantKeys).toEqualTypeOf<("size" | "color")[]>();
2292
- expect(component.variantKeys).toEqual(["size", "color"]);
2293
- });
2294
-
2295
- test("propKeys property", () => {
2296
- const component = getModalComponent(
2297
- mode,
2298
- cv({ variants: { size: { sm: "sm" }, color: { red: "red" } } }),
2299
- );
2300
- const classNameProp = getClassPropertyName(config);
2301
- expectTypeOf(component.propKeys).toExtend<
2302
- ("class" | "className" | "style" | "size" | "color")[]
2303
- >();
2304
- expect(component.propKeys).toEqual([
2305
- classNameProp,
2306
- "style",
2307
- "size",
2308
- "color",
2309
- ]);
2310
- });
2311
-
2312
- test("propKeys on different modes", () => {
2313
- const component = getModalComponent(
2314
- mode,
2315
- cv({ variants: { size: { sm: "sm" } } }),
2316
- );
2317
- const classNameProp = getClassPropertyName(config);
2318
- expect(component.propKeys).toEqual([classNameProp, "style", "size"]);
2319
- });
2320
-
2321
- test("splitProps does not include defaultVariants", () => {
2322
- const component = getModalComponent(
2323
- mode,
2324
- cv({
2325
- variants: { size: { sm: "sm", lg: "lg" }, color: { red: "red" } },
2326
- defaultVariants: { size: "sm", color: "red" },
2327
- }),
2328
- );
2329
- const props: HTMLProperties<typeof component> = {
2330
- id: "test",
2331
- size: "lg",
2332
- };
2333
- const [variantProps, otherProps] = splitProps(props, component);
2334
- expectTypeOf(variantProps).branded.toEqualTypeOf<
2335
- Pick<typeof props, "size" | "color" | "style" | "class" | "className">
2336
- >();
2337
- expect(variantProps).toEqual({
2338
- size: "lg",
2339
- });
2340
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2341
- expect(otherProps).toEqual({ id: "test" });
2342
- });
2343
-
2344
- test("splitProps with key array as second parameter", () => {
2345
- const component = getModalComponent(
2346
- mode,
2347
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2348
- );
2349
- const classNameProp = getClassPropertyName(config);
2350
- const props: HTMLProperties<typeof component> & { disabled?: boolean } = {
2351
- id: "test",
2352
- size: "lg",
2353
- style: { color: "red" },
2354
- [classNameProp]: "extra",
2355
- disabled: true,
2356
- };
2357
- const [variantProps, extraProps, otherProps] = splitProps(
2358
- props,
2359
- component,
2360
- ["disabled"],
2361
- );
2362
- expectTypeOf(variantProps).branded.toEqualTypeOf<
2363
- Pick<typeof props, "size" | "style" | "class" | "className">
2364
- >();
2365
- expect(variantProps).toEqual({
2366
- size: "lg",
2367
- style: { color: "red" },
2368
- [classNameProp]: "extra",
2369
- });
2370
- expectTypeOf(extraProps).branded.toEqualTypeOf<{ disabled?: boolean }>();
2371
- expect(extraProps).toEqual({ disabled: true });
2372
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2373
- expect(otherProps).toEqual({ id: "test" });
2374
- });
2375
-
2376
- test("splitProps with another component as parameter", () => {
2377
- const component1 = getModalComponent(
2378
- mode,
2379
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2380
- );
2381
- const component2 = getModalComponent(
2382
- mode,
2383
- cv({
2384
- variants: { color: { red: "red", blue: "blue" } },
2385
- defaultVariants: { color: "red" },
2386
- }),
2387
- );
2388
- const classNameProp = getClassPropertyName(config);
2389
- const props: HTMLProperties<typeof component1> &
2390
- HTMLProperties<typeof component2> = {
2391
- id: "test",
2392
- size: "lg",
2393
- color: "blue",
2394
- [classNameProp]: "extra",
2395
- };
2396
- const [comp1Props, comp2Props, otherProps] = splitProps(
2397
- props,
2398
- component1,
2399
- component2,
2400
- );
2401
- expectTypeOf(comp1Props).branded.toEqualTypeOf<
2402
- Pick<typeof props, "size" | "style" | "class" | "className">
2403
- >();
2404
- // First component gets class/style props
2405
- expect(comp1Props).toEqual({
2406
- size: "lg",
2407
- [classNameProp]: "extra",
2408
- });
2409
- // Second component only gets variant props (no class/style)
2410
- expectTypeOf(comp2Props).branded.toEqualTypeOf<
2411
- Pick<typeof props, "color">
2412
- >();
2413
- expect(comp2Props).toEqual({
2414
- color: "blue",
2415
- });
2416
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2417
- expect(otherProps).toEqual({ id: "test" });
2418
- });
2419
-
2420
- test("splitProps with component parameter does not include component defaults", () => {
2421
- const component1 = getModalComponent(
2422
- mode,
2423
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2424
- );
2425
- const component2 = getModalComponent(
2426
- mode,
2427
- cv({
2428
- variants: { color: { red: "red", blue: "blue" } },
2429
- defaultVariants: { color: "red" },
2430
- }),
2431
- );
2432
- const props: HTMLProperties<typeof component1> &
2433
- HTMLProperties<typeof component2> = {
2434
- id: "test",
2435
- size: "lg",
2436
- };
2437
- const [comp1Props, comp2Props, otherProps] = splitProps(
2438
- props,
2439
- component1,
2440
- component2,
2441
- );
2442
- // First component gets variant props
2443
- expect(comp1Props).toEqual({ size: "lg" });
2444
- // Second component gets empty object (no defaults applied)
2445
- expect(comp2Props).toEqual({});
2446
- expect(otherProps).toEqual({ id: "test" });
2447
- });
2448
-
2449
- test("splitProps second component excludes class and style", () => {
2450
- const component1 = getModalComponent(
2451
- mode,
2452
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2453
- );
2454
- const component2 = getModalComponent(
2455
- mode,
2456
- cv({ variants: { color: { red: "red", blue: "blue" } } }),
2457
- );
2458
- const classNameProp = getClassPropertyName(config);
2459
- const props: HTMLProperties<typeof component1> &
2460
- HTMLProperties<typeof component2> = {
2461
- id: "test",
2462
- size: "lg",
2463
- color: "blue",
2464
- style: { backgroundColor: "yellow" },
2465
- [classNameProp]: "extra",
2466
- };
2467
- const [comp1Props, comp2Props, otherProps] = splitProps(
2468
- props,
2469
- component1,
2470
- component2,
2471
- );
2472
- expectTypeOf(comp1Props).branded.toEqualTypeOf<
2473
- Pick<typeof props, "size" | "style" | "class" | "className">
2474
- >();
2475
- // First component gets class/style
2476
- expect(comp1Props).toEqual({
2477
- size: "lg",
2478
- style: { backgroundColor: "yellow" },
2479
- [classNameProp]: "extra",
2480
- });
2481
- // Second component only gets variant props
2482
- expectTypeOf(comp2Props).branded.toEqualTypeOf<{
2483
- color?: "red" | "blue";
2484
- }>();
2485
- expect(comp2Props).toEqual({ color: "blue" });
2486
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2487
- expect(otherProps).toEqual({ id: "test" });
2488
- });
2489
-
2490
- test("splitProps with multiple parameters", () => {
2491
- const component1 = getModalComponent(
2492
- mode,
2493
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2494
- );
2495
- const component2 = getModalComponent(
2496
- mode,
2497
- cv({ variants: { color: { red: "red", blue: "blue" } } }),
2498
- );
2499
- const props: HTMLProperties<typeof component1> &
2500
- HTMLProperties<typeof component2> & { disabled?: boolean } = {
2501
- id: "test",
2502
- size: "lg",
2503
- color: "blue",
2504
- disabled: true,
2505
- };
2506
- const [comp1Props, extraProps, comp2Props, otherProps] = splitProps(
2507
- props,
2508
- component1,
2509
- ["disabled"],
2510
- component2,
2511
- );
2512
- expectTypeOf(comp1Props).branded.toEqualTypeOf<
2513
- Pick<typeof props, "size" | "style" | "class" | "className">
2514
- >();
2515
- expectTypeOf(extraProps).branded.toEqualTypeOf<{ disabled?: boolean }>();
2516
- expectTypeOf(comp2Props).branded.toEqualTypeOf<{
2517
- color?: "red" | "blue";
2518
- }>();
2519
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2520
- expect(comp1Props).toEqual({ size: "lg" });
2521
- expect(extraProps).toEqual({ disabled: true });
2522
- expect(comp2Props).toEqual({ color: "blue" });
2523
- expect(otherProps).toEqual({ id: "test" });
2524
- });
2525
-
2526
- test("splitProps with shared keys between components", () => {
2527
- const component1 = getModalComponent(
2528
- mode,
2529
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2530
- );
2531
- const component2 = getModalComponent(
2532
- mode,
2533
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2534
- );
2535
- const props: HTMLProperties<typeof component1> &
2536
- HTMLProperties<typeof component2> = {
2537
- id: "test",
2538
- size: "lg",
2539
- };
2540
- const [comp1Props, comp2Props, otherProps] = splitProps(
2541
- props,
2542
- component1,
2543
- component2,
2544
- );
2545
- expectTypeOf(comp1Props).branded.toEqualTypeOf<
2546
- Pick<typeof props, "size" | "style" | "class" | "className">
2547
- >();
2548
- // First component gets class/style + size
2549
- expect(comp1Props).toEqual({ size: "lg" });
2550
- // Second component only gets variant props (size appears in both)
2551
- expectTypeOf(comp2Props).branded.toEqualTypeOf<{
2552
- size?: "sm" | "lg";
2553
- }>();
2554
- expect(comp2Props).toEqual({ size: "lg" });
2555
- expect(otherProps).toEqual({ id: "test" });
2556
- });
2557
-
2558
- test("splitProps with defaultVariants from multiple components does not include defaults", () => {
2559
- const component1 = getModalComponent(
2560
- mode,
2561
- cv({
2562
- variants: { size: { sm: "sm", lg: "lg" } },
2563
- defaultVariants: { size: "sm" },
2564
- }),
2565
- );
2566
- const component2 = getModalComponent(
2567
- mode,
2568
- cv({
2569
- variants: { color: { red: "red", blue: "blue" } },
2570
- defaultVariants: { color: "red" },
2571
- }),
2572
- );
2573
- const [comp1Props, comp2Props, otherProps] = splitProps(
2574
- { id: "test" },
2575
- component1,
2576
- component2,
2577
- );
2578
- // Neither gets defaults - only props that are actually in the input
2579
- expectTypeOf(comp1Props).branded.toEqualTypeOf<{ size?: "sm" | "lg" }>();
2580
- expect(comp1Props).toEqual({});
2581
- expectTypeOf(comp2Props).branded.toEqualTypeOf<{
2582
- color?: "red" | "blue";
2583
- }>();
2584
- expect(comp2Props).toEqual({});
2585
- expectTypeOf(otherProps).toEqualTypeOf<{ id: string }>();
2586
- expect(otherProps).toEqual({ id: "test" });
2587
- });
2588
-
2589
- test("variantKeys splitProps does not include defaultVariants", () => {
2590
- const component = getModalComponent(
2591
- mode,
2592
- cv({
2593
- variants: { size: { sm: "sm", lg: "lg" }, color: { red: "red" } },
2594
- defaultVariants: { size: "sm", color: "red" },
2595
- }),
2596
- );
2597
- const classNameProp = getClassPropertyName(config);
2598
- const props: HTMLProperties<typeof component> = {
2599
- id: "test",
2600
- size: "lg",
2601
- [classNameProp]: "extra",
2602
- };
2603
- const [variantProps, otherProps] = splitProps(
2604
- props,
2605
- component.variantKeys,
2606
- );
2607
- // variantKeys is just an array, so no defaults are applied
2608
- expect(variantProps).toEqual({
2609
- size: "lg",
2610
- });
2611
- // color is in variantKeys but not in props, so it's not in either result
2612
- expect(otherProps).toEqual({ id: "test", [classNameProp]: "extra" });
2613
- });
2614
-
2615
- test("variantKeys splitProps with key array", () => {
2616
- const component = getModalComponent(
2617
- mode,
2618
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2619
- );
2620
- const classNameProp = getClassPropertyName(config);
2621
- const props: HTMLProperties<typeof component> & { disabled?: boolean } = {
2622
- id: "test",
2623
- size: "lg",
2624
- [classNameProp]: "extra",
2625
- disabled: true,
2626
- };
2627
- const [variantProps, extraProps, otherProps] = splitProps(
2628
- props,
2629
- component.variantKeys,
2630
- ["disabled"],
2631
- );
2632
- expectTypeOf(variantProps).branded.toEqualTypeOf<{
2633
- size?: "sm" | "lg";
2634
- }>();
2635
- expect(variantProps).toEqual({ size: "lg" });
2636
- expectTypeOf(extraProps).branded.toEqualTypeOf<{ disabled?: boolean }>();
2637
- expect(extraProps).toEqual({ disabled: true });
2638
- expectTypeOf(otherProps).toEqualTypeOf<
2639
- Pick<typeof props, "id" | "class" | "className" | "style">
2640
- >();
2641
- expect(otherProps).toEqual({ id: "test", [classNameProp]: "extra" });
2642
- });
2643
-
2644
- test("variantKeys splitProps with component", () => {
2645
- const component1 = getModalComponent(
2646
- mode,
2647
- cv({
2648
- variants: { size: { sm: "sm", lg: "lg" } },
2649
- defaultVariants: { size: "sm" },
2650
- }),
2651
- );
2652
- const component2 = getModalComponent(
2653
- mode,
2654
- cv({
2655
- variants: { color: { red: "red", blue: "blue" } },
2656
- defaultVariants: { color: "red" },
2657
- }),
2658
- );
2659
- const classNameProp = getClassPropertyName(config);
2660
- const props: HTMLProperties<typeof component1> &
2661
- HTMLProperties<typeof component2> = {
2662
- id: "test",
2663
- size: "lg",
2664
- color: "blue",
2665
- [classNameProp]: "extra",
2666
- };
2667
- const [comp1Props, comp2Props, otherProps] = splitProps(
2668
- props,
2669
- component1.variantKeys,
2670
- component2.variantKeys,
2671
- );
2672
- expectTypeOf(comp1Props).branded.toEqualTypeOf<{ size?: "sm" | "lg" }>();
2673
- expect(comp1Props).toEqual({ size: "lg" });
2674
- expectTypeOf(comp2Props).branded.toEqualTypeOf<{
2675
- color?: "red" | "blue";
2676
- }>();
2677
- expect(comp2Props).toEqual({ color: "blue" });
2678
- expectTypeOf(otherProps).toEqualTypeOf<
2679
- Pick<typeof props, "id" | "class" | "className" | "style">
2680
- >();
2681
- expect(otherProps).toEqual({ id: "test", [classNameProp]: "extra" });
2682
- });
2683
-
2684
- test("splitProps with array containing class before component", () => {
2685
- const component = getModalComponent(
2686
- mode,
2687
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2688
- );
2689
- const classNameProp = getClassPropertyName(config);
2690
- const props: HTMLProperties<typeof component> = {
2691
- id: "test",
2692
- size: "lg",
2693
- style: { backgroundColor: "yellow" },
2694
- [classNameProp]: "extra",
2695
- };
2696
- // Array gets class, component still gets class/style (arrays don't claim styling)
2697
- const [arrayProps, compProps, otherProps] = splitProps(
2698
- props,
2699
- [classNameProp],
2700
- component,
2701
- );
2702
- expectTypeOf(arrayProps).branded.toEqualTypeOf<
2703
- Pick<typeof props, "class" | "className">
2704
- >();
2705
- expect(arrayProps).toEqual({ [classNameProp]: "extra" });
2706
- // Component still gets class/style since arrays don't claim them
2707
- expectTypeOf(compProps).branded.toEqualTypeOf<
2708
- Pick<typeof props, "size" | "style" | "class" | "className">
2709
- >();
2710
- expect(compProps).toEqual({
2711
- size: "lg",
2712
- style: { backgroundColor: "yellow" },
2713
- [classNameProp]: "extra",
2714
- });
2715
- expect(otherProps).toEqual({ id: "test" });
2716
- });
2717
-
2718
- test("splitProps with array containing class and style before component", () => {
2719
- const component = getModalComponent(
2720
- mode,
2721
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2722
- );
2723
- const classNameProp = getClassPropertyName(config);
2724
- const props: HTMLProperties<typeof component> = {
2725
- id: "test",
2726
- size: "lg",
2727
- style: { backgroundColor: "yellow" },
2728
- [classNameProp]: "extra",
2729
- };
2730
- // Array gets class and style, component still gets class/style (arrays don't claim styling)
2731
- const [arrayProps, compProps, otherProps] = splitProps(
2732
- props,
2733
- [classNameProp, "style"],
2734
- component,
2735
- );
2736
- expectTypeOf(arrayProps).branded.toEqualTypeOf<
2737
- Pick<typeof props, "class" | "className" | "style">
2738
- >();
2739
- expect(arrayProps).toEqual({
2740
- [classNameProp]: "extra",
2741
- style: { backgroundColor: "yellow" },
2742
- });
2743
- // Component still gets class/style since arrays don't claim them
2744
- expectTypeOf(compProps).branded.toEqualTypeOf<
2745
- Pick<typeof props, "size" | "style" | "class" | "className">
2746
- >();
2747
- expect(compProps).toEqual({
2748
- size: "lg",
2749
- style: { backgroundColor: "yellow" },
2750
- [classNameProp]: "extra",
2751
- });
2752
- expect(otherProps).toEqual({ id: "test" });
2753
- });
2754
-
2755
- test("splitProps with array after component", () => {
2756
- const component = getModalComponent(
2757
- mode,
2758
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2759
- );
2760
- const classNameProp = getClassPropertyName(config);
2761
- const props: HTMLProperties<typeof component> = {
2762
- id: "test",
2763
- size: "lg",
2764
- style: { backgroundColor: "yellow" },
2765
- [classNameProp]: "extra",
2766
- };
2767
- // Component gets class/style first, array also gets them
2768
- const [compProps, arrayProps, otherProps] = splitProps(props, component, [
2769
- classNameProp,
2770
- "style",
2771
- ]);
2772
- expectTypeOf(compProps).branded.toEqualTypeOf<
2773
- Pick<typeof props, "size" | "style" | "class" | "className">
2774
- >();
2775
- expect(compProps).toEqual({
2776
- size: "lg",
2777
- style: { backgroundColor: "yellow" },
2778
- [classNameProp]: "extra",
2779
- });
2780
- expectTypeOf(arrayProps).branded.toEqualTypeOf<
2781
- Pick<typeof props, "class" | "className" | "style">
2782
- >();
2783
- expect(arrayProps).toEqual({
2784
- [classNameProp]: "extra",
2785
- style: { backgroundColor: "yellow" },
2786
- });
2787
- expectTypeOf(otherProps).toEqualTypeOf<{ id?: string }>();
2788
- expect(otherProps).toEqual({ id: "test" });
2789
- });
2790
-
2791
- test("splitProps array before multiple components", () => {
2792
- const component1 = getModalComponent(
2793
- mode,
2794
- cv({ variants: { size: { sm: "sm", lg: "lg" } } }),
2795
- );
2796
- const component2 = getModalComponent(
2797
- mode,
2798
- cv({ variants: { color: { red: "red", blue: "blue" } } }),
2799
- );
2800
- const classNameProp = getClassPropertyName(config);
2801
- const props: HTMLProperties<typeof component1> &
2802
- HTMLProperties<typeof component2> & { disabled?: boolean } = {
2803
- id: "test",
2804
- size: "lg",
2805
- color: "blue",
2806
- disabled: true,
2807
- style: { backgroundColor: "yellow" },
2808
- [classNameProp]: "extra",
2809
- };
2810
- // Array doesn't claim styling, so first component (comp1) gets styling
2811
- const [disabledProps, comp1Props, comp2Props, otherProps] = splitProps(
2812
- props,
2813
- ["disabled"],
2814
- component1,
2815
- component2,
2816
- );
2817
- expectTypeOf(disabledProps).branded.toEqualTypeOf<{
2818
- disabled?: boolean;
2819
- }>();
2820
- expect(disabledProps).toEqual({ disabled: true });
2821
- expectTypeOf(comp1Props).branded.toEqualTypeOf<
2822
- Pick<typeof props, "size" | "style" | "class" | "className">
2823
- >();
2824
- // First component gets class/style
2825
- expect(comp1Props).toEqual({
2826
- size: "lg",
2827
- style: { backgroundColor: "yellow" },
2828
- [classNameProp]: "extra",
2829
- });
2830
- // Second component only gets variant props
2831
- expectTypeOf(comp2Props).branded.toEqualTypeOf<
2832
- Pick<typeof props, "color">
2833
- >();
2834
- expect(comp2Props).toEqual({ color: "blue" });
2835
- expect(otherProps).toEqual({ id: "test" });
2836
- });
2837
- });
2838
- }
2839
-
2840
- describe("Variant utility type", () => {
2841
- test("matches variant keys from another component", () => {
2842
- const base = cvBase({
2843
- variants: { foo: { sm: "foo-sm", lg: "foo-lg" } },
2844
- });
2845
- const component = cvBase({
2846
- extend: [base],
2847
- variants: {
2848
- bar: {
2849
- sm: "bar-sm",
2850
- lg: "bar-lg",
2851
- } satisfies Variant<typeof base, "foo">,
2852
- },
2853
- });
2854
- expect(component({ bar: "sm" }).className).toContain("bar-sm");
2855
- });
2856
-
2857
- test("rejects invalid variant keys", () => {
2858
- const base = cvBase({
2859
- variants: { foo: { sm: "foo-sm", lg: "foo-lg" } },
2860
- });
2861
- cvBase({
2862
- extend: [base],
2863
- variants: {
2864
- bar: {
2865
- sm: "bar-sm",
2866
- lg: "bar-lg",
2867
- // @ts-expect-error
2868
- xl: "bar-xl",
2869
- } satisfies Variant<typeof base, "foo">,
2870
- },
2871
- });
2872
- });
2873
- });