clava 0.5.0 → 0.6.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 +45 -3
- package/README.md +55 -19
- package/dist/index.d.ts +188 -5
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +83 -8
- package/src/types.ts +111 -6
- package/tests/component-api.test.ts +6 -6
- package/tests/extend.test.ts +1 -1
- package/tests/language-service.test.ts +12 -1
- package/tests/refine.test.ts +135 -179
- package/tests/variants-inference.test.ts +69 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# clava
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Computed default variant parameters
|
|
6
|
+
|
|
7
|
+
**BREAKING** if you're using computed `defaultVariants` functions in [`cv`](https://clava.style/docs/reference/cv).
|
|
8
|
+
|
|
9
|
+
Computed `defaultVariants` functions now receive `defaultValue` and `variants` as separate parameters instead of a context object.
|
|
10
|
+
|
|
11
|
+
Before:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
const button = cv({
|
|
15
|
+
variants: {
|
|
16
|
+
size: { sm: "sm", lg: "lg" },
|
|
17
|
+
intent: { neutral: "neutral", brand: "brand" },
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
intent: ({ defaultValue, variants }) =>
|
|
21
|
+
variants.size === "lg" ? "neutral" : defaultValue,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
After:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
const button = cv({
|
|
30
|
+
variants: {
|
|
31
|
+
size: { sm: "sm", lg: "lg" },
|
|
32
|
+
intent: { neutral: "neutral", brand: "brand" },
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
intent: (defaultValue, variants) =>
|
|
36
|
+
variants.size === "lg" ? "neutral" : defaultValue,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Other updates
|
|
42
|
+
|
|
43
|
+
- Documented Clava's public TypeScript helper declarations with inline examples.
|
|
44
|
+
|
|
3
45
|
## 0.5.0
|
|
4
46
|
|
|
5
47
|
### Computed default variants
|
|
@@ -18,7 +60,7 @@ const button = cv({
|
|
|
18
60
|
size: { sm: "sm", lg: "lg" },
|
|
19
61
|
intent: { neutral: "neutral", brand: "brand" },
|
|
20
62
|
},
|
|
21
|
-
refine
|
|
63
|
+
refine({ variants, setDefaultVariants }) {
|
|
22
64
|
if (variants.size === "lg") {
|
|
23
65
|
setDefaultVariants({ intent: "neutral" });
|
|
24
66
|
}
|
|
@@ -111,7 +153,7 @@ Before:
|
|
|
111
153
|
```ts
|
|
112
154
|
const button = cv({
|
|
113
155
|
variants: { size: { sm: "sm", lg: "lg" } },
|
|
114
|
-
computed
|
|
156
|
+
computed({ variants, addClass }) {
|
|
115
157
|
if (variants.size === "lg") {
|
|
116
158
|
addClass("is-large");
|
|
117
159
|
}
|
|
@@ -124,7 +166,7 @@ After:
|
|
|
124
166
|
```ts
|
|
125
167
|
const button = cv({
|
|
126
168
|
variants: { size: { sm: "sm", lg: "lg" } },
|
|
127
|
-
refine
|
|
169
|
+
refine({ variants, addClass }) {
|
|
128
170
|
if (variants.size === "lg") {
|
|
129
171
|
addClass("is-large");
|
|
130
172
|
}
|
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ import type { Variant, VariantProps } from "clava";
|
|
|
24
24
|
- [Solid](#solid)
|
|
25
25
|
- [`create()` And `cx()`](#create-and-cx)
|
|
26
26
|
- [Type Helpers](#type-helpers)
|
|
27
|
+
- [Comparison](#comparison)
|
|
27
28
|
- [API Summary](#api-summary)
|
|
28
29
|
|
|
29
30
|
## Install
|
|
@@ -230,17 +231,19 @@ Variant values can be class values, arrays, `{ class, style }` objects, or [func
|
|
|
230
231
|
|
|
231
232
|
## Function Variants
|
|
232
233
|
|
|
233
|
-
Add a function as a variant value when the prop should generate class/style output dynamically. The function's parameter type defines the prop type.
|
|
234
|
+
Add a function as a variant value when the prop should generate class/style output dynamically. The function's parameter type defines the prop type. Method syntax works well for multi-line callbacks; compact one-line callbacks can stay as arrow-function property values.
|
|
234
235
|
|
|
235
236
|
```ts
|
|
236
237
|
const grid = cv({
|
|
237
238
|
class: "grid",
|
|
238
239
|
variants: {
|
|
239
|
-
columns
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
columns(value: number) {
|
|
241
|
+
return {
|
|
242
|
+
class: `grid-cols-${value}`,
|
|
243
|
+
style: { "--grid-columns": `${value}` },
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
color(value: string | null) {
|
|
244
247
|
return value ? `text-${value}` : "text-current";
|
|
245
248
|
},
|
|
246
249
|
},
|
|
@@ -316,7 +319,7 @@ You can extend any component mode, including `baseButton.jsx`, `baseButton.html`
|
|
|
316
319
|
|
|
317
320
|
## Refine
|
|
318
321
|
|
|
319
|
-
Use computed `defaultVariants` for dependent defaults. A function entry receives the current default value for that key
|
|
322
|
+
Use computed `defaultVariants` for dependent defaults. A function entry receives the current default value for that key as the first parameter and the resolved variants snapshot as the second parameter, then returns the next default value.
|
|
320
323
|
|
|
321
324
|
Use `refine` for final variant overrides and class/style adjustments. It receives the resolved variant values for the component and can return class/style output.
|
|
322
325
|
|
|
@@ -331,10 +334,10 @@ const toolbarButton = cv({
|
|
|
331
334
|
loading: "toolbar-button-loading",
|
|
332
335
|
},
|
|
333
336
|
defaultVariants: {
|
|
334
|
-
intent: (
|
|
337
|
+
intent: (defaultValue, variants) =>
|
|
335
338
|
variants.size === "lg" ? "neutral" : defaultValue,
|
|
336
339
|
},
|
|
337
|
-
refine
|
|
340
|
+
refine({ variants, setVariants, addClass, addStyle }) {
|
|
338
341
|
if (variants.loading) {
|
|
339
342
|
setVariants({ pressed: false });
|
|
340
343
|
}
|
|
@@ -384,17 +387,18 @@ const button = cv({
|
|
|
384
387
|
lg: "button-lg",
|
|
385
388
|
},
|
|
386
389
|
},
|
|
387
|
-
})
|
|
390
|
+
});
|
|
388
391
|
|
|
389
|
-
|
|
392
|
+
interface ButtonProps
|
|
393
|
+
extends ComponentProps<"button">, VariantProps<typeof button> {}
|
|
390
394
|
|
|
391
395
|
function Button(props: ButtonProps) {
|
|
392
396
|
const [variantProps, buttonProps] = splitProps(props, button);
|
|
393
|
-
return <button {...buttonProps} {...button(variantProps)} />;
|
|
397
|
+
return <button {...buttonProps} {...button.jsx(variantProps)} />;
|
|
394
398
|
}
|
|
395
399
|
```
|
|
396
400
|
|
|
397
|
-
The first component source claims variant props plus styling props
|
|
401
|
+
The first component source claims variant props plus the styling props exposed by that component's `propKeys`. The base component claims `class`, `className`, and `style`; mode-specific components claim their own styling props. Later component sources receive only their variant props. Array sources receive exactly the listed keys and do not claim styling props.
|
|
398
402
|
|
|
399
403
|
```ts
|
|
400
404
|
const [buttonProps, fieldProps, rest] = splitProps(props, button, field);
|
|
@@ -431,14 +435,14 @@ const button = cv({
|
|
|
431
435
|
md: "button-md",
|
|
432
436
|
},
|
|
433
437
|
},
|
|
434
|
-
})
|
|
438
|
+
});
|
|
435
439
|
|
|
436
440
|
interface ButtonProps
|
|
437
441
|
extends ComponentProps<"button">, VariantProps<typeof button> {}
|
|
438
442
|
|
|
439
443
|
function Button(props: ButtonProps) {
|
|
440
444
|
const [variantProps, buttonProps] = splitProps(props, button);
|
|
441
|
-
return <button {...buttonProps} {...button(variantProps)} />;
|
|
445
|
+
return <button {...buttonProps} {...button.jsx(variantProps)} />;
|
|
442
446
|
}
|
|
443
447
|
```
|
|
444
448
|
|
|
@@ -459,13 +463,14 @@ const button = cv({
|
|
|
459
463
|
md: "button-md",
|
|
460
464
|
},
|
|
461
465
|
},
|
|
462
|
-
})
|
|
466
|
+
});
|
|
463
467
|
|
|
464
|
-
|
|
468
|
+
interface ButtonProps
|
|
469
|
+
extends ComponentProps<"button">, VariantProps<typeof button> {}
|
|
465
470
|
|
|
466
471
|
function Button(props: ButtonProps) {
|
|
467
472
|
const [variantProps, buttonProps] = splitProps(props, button);
|
|
468
|
-
return <button {...buttonProps} {...button(variantProps)} />;
|
|
473
|
+
return <button {...buttonProps} {...button.htmlObj(variantProps)} />;
|
|
469
474
|
}
|
|
470
475
|
```
|
|
471
476
|
|
|
@@ -504,7 +509,8 @@ Use `VariantProps<typeof component>` to add a Clava component's variant props to
|
|
|
504
509
|
import type { ComponentProps } from "react";
|
|
505
510
|
import type { VariantProps } from "clava";
|
|
506
511
|
|
|
507
|
-
|
|
512
|
+
interface ButtonProps
|
|
513
|
+
extends ComponentProps<"button">, VariantProps<typeof button> {}
|
|
508
514
|
```
|
|
509
515
|
|
|
510
516
|
Use `Variant<typeof component, "key">` to constrain a new variant map to the same values as another component's variant.
|
|
@@ -534,6 +540,36 @@ const icon = cv({
|
|
|
534
540
|
|
|
535
541
|
The package also exports `ClassValue`, `StyleValue`, `StyleClassProps`, `StyleClassValue`, `JSXProps`, `HTMLProps`, `HTMLObjProps`, `CVComponent`, and `CVConfig`.
|
|
536
542
|
|
|
543
|
+
## Comparison
|
|
544
|
+
|
|
545
|
+
This table compares Clava with the packages used by the repository's alternative benchmark: `class-variance-authority@0.7.1`, `cva@1.0.0-beta.4`, `tailwind-variants/lite@3.2.2`, and `tailwind-variants@3.2.2`.
|
|
546
|
+
|
|
547
|
+
| Feature | Clava | CVA v0 | CVA v1 beta | TV Lite | TV |
|
|
548
|
+
| ---------------------------------------------------- | -------------- | ------------------ | ------------------ | ------------------ | ------------------ |
|
|
549
|
+
| Typed variants and default variants | Yes | Yes | Yes | Yes | Yes |
|
|
550
|
+
| Boolean shorthand variants | Yes | No | No | No | No |
|
|
551
|
+
| Component extension or composition | `extend` | No helper | `compose()` | `extend` | `extend` |
|
|
552
|
+
| Cross-variant conditions | `refine()` | `compoundVariants` | `compoundVariants` | `compoundVariants` | `compoundVariants` |
|
|
553
|
+
| Function variant values | Yes | No | No | No | No |
|
|
554
|
+
| Computed default variants | Yes | No | No | No | No |
|
|
555
|
+
| Class and style prop output | Yes | Classes only | Classes only | Classes only | Classes only |
|
|
556
|
+
| JSX, HTML string, and hyphenated-object output modes | Yes | No | No | No | No |
|
|
557
|
+
| Built-in prop splitting for framework props | `splitProps()` | No | No | No | No |
|
|
558
|
+
| Dedicated slots API | No | No | No | Yes | Yes |
|
|
559
|
+
| Built-in Tailwind conflict merging | No | No | No | No | Yes |
|
|
560
|
+
|
|
561
|
+
The `pnpm perf-alternatives` benchmark resolves a composed Tailwind-style button with inherited variants, defaults, and cross-variant conditions. On Node v24.14.1, Vitest reported these results, where higher ops/sec is better:
|
|
562
|
+
|
|
563
|
+
| Package | Ops/sec | Relative to Clava |
|
|
564
|
+
| -------------------------------- | --------: | ----------------: |
|
|
565
|
+
| `clava@0.5.0` | 1,040,314 | 1.00x |
|
|
566
|
+
| `class-variance-authority@0.7.1` | 426,132 | 2.44x slower |
|
|
567
|
+
| `tailwind-variants/lite@3.2.2` | 369,732 | 2.81x slower |
|
|
568
|
+
| `tailwind-variants@3.2.2` | 273,503 | 3.80x slower |
|
|
569
|
+
| `cva@1.0.0-beta.4` | 211,474 | 4.92x slower |
|
|
570
|
+
|
|
571
|
+
Benchmark results vary by runtime and hardware, so treat them as a reproducible snapshot of this repository's composed-variant case rather than a universal ranking.
|
|
572
|
+
|
|
537
573
|
## API Summary
|
|
538
574
|
|
|
539
575
|
`cv(config?)` creates a typed Clava component. Supported config keys are `extend`, `class`, `style`, `variants`, `defaultVariants`, and `refine`.
|
package/dist/index.d.ts
CHANGED
|
@@ -2,22 +2,84 @@ import { ClassValue as ClassValue$1 } from "clsx";
|
|
|
2
2
|
import * as CSS from "csstype";
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* A class value accepted by Clava. It supports strings, numbers, booleans,
|
|
7
|
+
* nullish values, and nested arrays.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import type { ClassValue } from "clava";
|
|
12
|
+
*
|
|
13
|
+
* const className: ClassValue = [
|
|
14
|
+
* "button",
|
|
15
|
+
* false && "button-hidden",
|
|
16
|
+
* ["button-primary"],
|
|
17
|
+
* ];
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
5
20
|
type ClassValue = string | number | boolean | null | undefined | void | ClassValue[];
|
|
6
21
|
type JSXCSSProperties = CSS.Properties<string | number>;
|
|
7
22
|
type HTMLCSSProperties = CSS.PropertiesHyphen<string | number>;
|
|
8
23
|
type StyleProperty = JSXCSSProperties | HTMLCSSProperties | string;
|
|
24
|
+
/**
|
|
25
|
+
* The prop object returned by a component's `.jsx()` mode.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { type JSXProps, cv } from "clava";
|
|
30
|
+
*
|
|
31
|
+
* const button = cv({ class: "button" });
|
|
32
|
+
* const props: JSXProps = button.jsx();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
9
35
|
interface JSXProps {
|
|
10
36
|
className: string;
|
|
11
37
|
style: JSXCSSProperties;
|
|
12
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* The prop object returned by a component's `.html()` mode. The `style` value
|
|
41
|
+
* is serialized as an HTML style string.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { type HTMLProps, cv } from "clava";
|
|
46
|
+
*
|
|
47
|
+
* const button = cv({ style: { color: "red" } });
|
|
48
|
+
* const props: HTMLProps = button.html();
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
13
51
|
interface HTMLProps {
|
|
14
52
|
class: string;
|
|
15
53
|
style: string;
|
|
16
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* The prop object returned by a component's `.htmlObj()` mode. The `style`
|
|
57
|
+
* value uses hyphenated CSS property names.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* import { type HTMLObjProps, cv } from "clava";
|
|
62
|
+
*
|
|
63
|
+
* const button = cv({ style: { fontSize: "16px" } });
|
|
64
|
+
* const props: HTMLObjProps = button.htmlObj();
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
17
67
|
interface HTMLObjProps {
|
|
18
68
|
class: string;
|
|
19
69
|
style: HTMLCSSProperties;
|
|
20
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* The default prop object returned by a Clava component. It uses `class`
|
|
73
|
+
* rather than `className` and keeps styles as a normalized object.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* import { type StyleClassProps, cv } from "clava";
|
|
78
|
+
*
|
|
79
|
+
* const button = cv({ class: "button" });
|
|
80
|
+
* const props: StyleClassProps = button();
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
21
83
|
interface StyleClassProps {
|
|
22
84
|
class: string;
|
|
23
85
|
style: StyleValue;
|
|
@@ -61,6 +123,25 @@ interface ModalComponent<V, R extends ComponentResult> {
|
|
|
61
123
|
variantKeys: (keyof V)[];
|
|
62
124
|
propKeys: (keyof V | ComponentPropKey<R>)[];
|
|
63
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* A callable Clava component returned by `cv()`. It includes the default
|
|
128
|
+
* output mode plus `.jsx()`, `.html()`, and `.htmlObj()` mode helpers.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* import { type CVComponent, cv } from "clava";
|
|
133
|
+
*
|
|
134
|
+
* const button: CVComponent<{
|
|
135
|
+
* size: { sm: string; lg: string };
|
|
136
|
+
* }> = cv({
|
|
137
|
+
* variants: {
|
|
138
|
+
* size: { sm: "button-sm", lg: "button-lg" },
|
|
139
|
+
* },
|
|
140
|
+
* });
|
|
141
|
+
*
|
|
142
|
+
* button.jsx({ size: "lg" });
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
64
145
|
interface CVComponent<V extends Variants = {}, E extends AnyComponent[] = [], R extends ComponentResult = StyleClassProps> extends ModalComponent<MergeVariants<V, E>, R> {
|
|
65
146
|
jsx: ModalComponent<MergeVariants<V, E>, JSXProps>;
|
|
66
147
|
html: ModalComponent<MergeVariants<V, E>, HTMLProps>;
|
|
@@ -77,17 +158,41 @@ type VariantValue = ClassValue | StyleClassValue;
|
|
|
77
158
|
type NonNullKeys<T> = { [K in keyof T]: T[K] extends null ? never : K }[keyof T];
|
|
78
159
|
type ExtractVariantValue<T> = T extends null ? never : T extends ((value: infer V) => any) ? V : T extends readonly unknown[] ? boolean : T extends Record<string, any> ? StringToBoolean<NonNullKeys<T>> : T extends ClassValue ? boolean : never;
|
|
79
160
|
type VariantValues<V> = { [K in keyof V]?: ExtractVariantValue<V[K]> | undefined };
|
|
80
|
-
|
|
81
|
-
defaultValue: ExtractVariantValue<V[K]> | undefined;
|
|
82
|
-
variants: Readonly<VariantValues<V>>;
|
|
83
|
-
}
|
|
84
|
-
type ComputedDefaultVariant<V, K extends keyof V> = (context: DefaultVariantContext<V, K>) => ExtractVariantValue<V[K]> | undefined;
|
|
161
|
+
type ComputedDefaultVariant<V, K extends keyof V> = (defaultValue: ExtractVariantValue<V[K]> | undefined, variants: Readonly<VariantValues<V>>) => ExtractVariantValue<V[K]> | undefined;
|
|
85
162
|
type NonFunctionVariantValue<T> = Exclude<T, (...args: any[]) => any>;
|
|
86
163
|
type DefaultVariantValue<V, K extends keyof V> = [NonFunctionVariantValue<ExtractVariantValue<V[K]>>] extends [never] ? ComputedDefaultVariant<V, K> : NonFunctionVariantValue<ExtractVariantValue<V[K]>> | ComputedDefaultVariant<V, K>;
|
|
87
164
|
type DefaultVariants<V> = { [K in keyof V]?: DefaultVariantValue<V, K> | undefined };
|
|
165
|
+
/**
|
|
166
|
+
* A normalized style object accepted by Clava config, variant, and refine
|
|
167
|
+
* style entries. CSS custom properties are supported with string values.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* import type { StyleValue } from "clava";
|
|
172
|
+
*
|
|
173
|
+
* const style: StyleValue = {
|
|
174
|
+
* color: "red",
|
|
175
|
+
* "--button-accent": "oklch(62% 0.2 250)",
|
|
176
|
+
* };
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
88
179
|
type StyleValue = CSS.Properties & {
|
|
89
180
|
[key: `--${string}`]: string;
|
|
90
181
|
};
|
|
182
|
+
/**
|
|
183
|
+
* A value that contributes both class and style output from a base config,
|
|
184
|
+
* variant value, function variant, or refine callback.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* import type { StyleClassValue } from "clava";
|
|
189
|
+
*
|
|
190
|
+
* const tone: StyleClassValue = {
|
|
191
|
+
* class: "button-primary",
|
|
192
|
+
* style: { color: "white" },
|
|
193
|
+
* };
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
91
196
|
interface StyleClassValue {
|
|
92
197
|
style?: StyleValue;
|
|
93
198
|
class?: ClassValue;
|
|
@@ -105,9 +210,87 @@ type NullablePartial<T> = T extends Record<string, any> ? { [K in keyof T]?: T[K
|
|
|
105
210
|
type ExtendableVariants<V extends Variants, E extends AnyComponent[]> = V & { [K in keyof MergeExtendedVariants<E>]?: NullablePartial<MergeExtendedVariants<E>[K]> | Variant$1 };
|
|
106
211
|
//#endregion
|
|
107
212
|
//#region src/index.d.ts
|
|
213
|
+
/**
|
|
214
|
+
* Extracts the variant props inferred for a Clava component. Use it to add a
|
|
215
|
+
* component's variant props to framework component props.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* import { type VariantProps, cv } from "clava";
|
|
220
|
+
* import type { ComponentProps } from "react";
|
|
221
|
+
*
|
|
222
|
+
* const button = cv({
|
|
223
|
+
* variants: {
|
|
224
|
+
* size: { sm: "button-sm", lg: "button-lg" },
|
|
225
|
+
* disabled: { true: "button-disabled", false: "" },
|
|
226
|
+
* },
|
|
227
|
+
* });
|
|
228
|
+
*
|
|
229
|
+
* interface ButtonProps
|
|
230
|
+
* extends ComponentProps<"button">,
|
|
231
|
+
* VariantProps<typeof button> {}
|
|
232
|
+
*
|
|
233
|
+
* const props: ButtonProps = {
|
|
234
|
+
* size: "lg",
|
|
235
|
+
* disabled: true,
|
|
236
|
+
* };
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
108
239
|
type VariantProps<T extends Pick<AnyComponent, "getVariants">> = ReturnType<T["getVariants"]>;
|
|
109
240
|
type VariantKey<T> = T extends boolean ? "true" | "false" : Extract<T, string>;
|
|
241
|
+
/**
|
|
242
|
+
* Constrains a variant map to the same value keys as a variant on another
|
|
243
|
+
* component. Boolean variants are represented with `"true"` and `"false"`
|
|
244
|
+
* object keys.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* import { type Variant, cv } from "clava";
|
|
249
|
+
*
|
|
250
|
+
* const button = cv({
|
|
251
|
+
* variants: {
|
|
252
|
+
* size: { sm: "button-sm", lg: "button-lg" },
|
|
253
|
+
* },
|
|
254
|
+
* });
|
|
255
|
+
*
|
|
256
|
+
* const icon = cv({
|
|
257
|
+
* extend: [button],
|
|
258
|
+
* variants: {
|
|
259
|
+
* size: {
|
|
260
|
+
* sm: "icon-sm",
|
|
261
|
+
* lg: "icon-lg",
|
|
262
|
+
* } satisfies Variant<typeof button, "size">,
|
|
263
|
+
* },
|
|
264
|
+
* });
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
110
267
|
type Variant<T extends Pick<AnyComponent, "getVariants">, K extends keyof VariantProps<T>> = Record<VariantKey<NonNullable<VariantProps<T>[K]>>, ClassValue | StyleClassValue>;
|
|
268
|
+
/**
|
|
269
|
+
* The configuration object accepted by `cv()`. It defines base class/style
|
|
270
|
+
* output, variants, default variants, component extensions, and refinement
|
|
271
|
+
* logic.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```ts
|
|
275
|
+
* import { type CVConfig, cv } from "clava";
|
|
276
|
+
*
|
|
277
|
+
* const config: CVConfig<{
|
|
278
|
+
* tone: { info: string; danger: string };
|
|
279
|
+
* }> = {
|
|
280
|
+
* variants: {
|
|
281
|
+
* tone: {
|
|
282
|
+
* info: "alert-info",
|
|
283
|
+
* danger: "alert-danger",
|
|
284
|
+
* },
|
|
285
|
+
* },
|
|
286
|
+
* defaultVariants: {
|
|
287
|
+
* tone: "info",
|
|
288
|
+
* },
|
|
289
|
+
* };
|
|
290
|
+
*
|
|
291
|
+
* const alert = cv(config);
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
111
294
|
interface CVConfig<V extends Variants = {}, E extends AnyComponent[] = []> {
|
|
112
295
|
extend?: E;
|
|
113
296
|
class?: ClassValue;
|
package/dist/index.js
CHANGED
|
@@ -816,10 +816,7 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
816
816
|
if (protectedVariantKeys?.has(key)) continue;
|
|
817
817
|
const variantSnapshot = getOwnVariants();
|
|
818
818
|
const defaultValue = inheritedComputedDefaultKeys.has(key) ? variantSnapshot[key] : defaultResolved[key];
|
|
819
|
-
const value = computedDefaultFns[i](
|
|
820
|
-
defaultValue,
|
|
821
|
-
variants: variantSnapshot
|
|
822
|
-
});
|
|
819
|
+
const value = computedDefaultFns[i](defaultValue, variantSnapshot);
|
|
823
820
|
if (hasAnyDisabled) {
|
|
824
821
|
if (disabledVariantKeys.has(key)) continue;
|
|
825
822
|
const valueKey = getVariantValueKey(value);
|