Skip to content

Commit 9e88c13

Browse files
committed
WIP: moved cva
1 parent 9d86b2e commit 9e88c13

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

packages/cva/src/cva.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { cva } from './cva';
2+
3+
describe('cva', () => {
4+
it('should work', () => {
5+
expect(cva()).toEqual('cva');
6+
});
7+
});

packages/cva/src/cva.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Adapted from https://github.com/joe-bell/cva/blob/main/packages/class-variance-authority/src/index.ts
2+
// - removed clsx dep
3+
// - removed className prop
4+
// - use Qwik ClassList instead of ClassValue
5+
// - simplified VariantProps + expand props in hover tooltip
6+
// - added VariantPropsFor type
7+
8+
import { type ClassList, type QwikIntrinsicElements } from '@builder.io/qwik';
9+
10+
/** All the props that the variant function adds, including a `class` */
11+
export type VariantProps<VariantFn> = VariantFn extends (p: infer Props) => ClassList
12+
? // Expand the props so they are visible in hover tooltips
13+
{ [p in keyof Props]: Props[p] }
14+
: never;
15+
/** The DOM props of the given element + the variant props */
16+
export type AddVariantPropsTo<El extends keyof QwikIntrinsicElements, VariantFn> = Omit<
17+
QwikIntrinsicElements[El],
18+
'class'
19+
> &
20+
VariantProps<VariantFn>;
21+
22+
type ClassProp = { class?: ClassList };
23+
type StringToBoolean<T> = T extends 'true' | 'false' ? boolean : T;
24+
25+
const falsyToString = <T>(value: T) =>
26+
typeof value === 'boolean' ? `${value}` : value === 0 ? '0' : value;
27+
28+
type ConfigSchema = {
29+
[configOption: string]: { [variant: string]: ClassList };
30+
};
31+
type ConfigVariants<T extends ConfigSchema> = {
32+
[Variant in keyof T]?: StringToBoolean<keyof T[Variant]> | null | undefined;
33+
};
34+
type ConfigVariantsMulti<T extends ConfigSchema> = {
35+
[Variant in keyof T]?:
36+
| StringToBoolean<keyof T[Variant]>
37+
| StringToBoolean<keyof T[Variant]>[]
38+
| undefined;
39+
};
40+
41+
type Config<T> = T extends ConfigSchema
42+
? {
43+
variants?: T;
44+
defaultVariants?: ConfigVariants<T>;
45+
compoundVariants?: (T extends ConfigSchema
46+
? (ConfigVariants<T> | ConfigVariantsMulti<T>) & ClassProp
47+
: ClassProp)[];
48+
}
49+
: never;
50+
51+
type Props<T> = T extends ConfigSchema ? ConfigVariants<T> & ClassProp : ClassProp;
52+
53+
export const cva =
54+
<T>(base?: ClassList, config?: Config<T>): ((props: Props<T>) => ClassList) =>
55+
(props?: Props<T>) => {
56+
if (!config?.variants) return [base, props?.class];
57+
58+
const { variants, defaultVariants } = config;
59+
60+
const getVariantClassNames = Object.keys(variants).map(
61+
(variant: keyof typeof variants) => {
62+
const variantProp = props?.[variant as keyof typeof props];
63+
const defaultVariantProp = defaultVariants?.[variant];
64+
65+
if (variantProp === null) return null;
66+
67+
const variantKey = (falsyToString(variantProp) ||
68+
falsyToString(defaultVariantProp)) as keyof (typeof variants)[typeof variant];
69+
70+
return variants[variant][variantKey];
71+
}
72+
);
73+
74+
let getCompoundVariantClassNames;
75+
if (config?.compoundVariants) {
76+
const combinedProps = props
77+
? Object.entries(props).reduce(
78+
(acc, [key, value]) => {
79+
if (value === undefined) {
80+
return acc;
81+
}
82+
83+
acc[key] = value;
84+
return acc;
85+
},
86+
{ ...defaultVariants } as Record<string, unknown>
87+
)
88+
: defaultVariants;
89+
90+
getCompoundVariantClassNames =
91+
combinedProps &&
92+
config.compoundVariants.reduce(
93+
(acc, { class: cvClass, ...compoundVariantOptions }) =>
94+
Object.entries(compoundVariantOptions).every(([key, value]) => {
95+
const propVal = combinedProps[key];
96+
return Array.isArray(value) ? value.includes(propVal) : propVal === value;
97+
})
98+
? [...acc, cvClass]
99+
: acc,
100+
[] as ClassList[]
101+
);
102+
}
103+
104+
return [base, getVariantClassNames, getCompoundVariantClassNames, props?.class];
105+
};

0 commit comments

Comments
 (0)