classname-variants 1.0.1 → 1.0.2
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/README.md +44 -0
- package/example.tsx +20 -14
- package/lib/index.d.ts +99 -12
- package/lib/index.js +16 -8
- package/lib/react.d.ts +5 -5
- package/lib/react.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +145 -26
- package/src/react.ts +23 -12
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@ The library is framework agnostic and can be used with any kind of CSS flavor.
|
|
|
6
6
|
|
|
7
7
|
It is especially useful though if used with [Tailwind](https://tailwindcss.com/) and React, as it provides some [dedicated helpers](#React) and even allows for a _styled-components_ like API, but with [class names instead of styles](#bonus-styled-components-but-with-class-names-)!
|
|
8
8
|
|
|
9
|
+
[](https://codesandbox.io/s/classname-variants-react-3bzjl?fontsize=14&hidenavigation=1&theme=dark)
|
|
10
|
+
|
|
9
11
|
# Basics
|
|
10
12
|
|
|
11
13
|
Let's aussume we want to build a button component with Tailwind CSS that comes in different sizes and colors.
|
|
@@ -168,6 +170,48 @@ const Button = styled("button", {
|
|
|
168
170
|
});
|
|
169
171
|
```
|
|
170
172
|
|
|
173
|
+
# Tailwind IntelliSense
|
|
174
|
+
|
|
175
|
+
In order to get auto-completion for the CSS classes themselves, you can use the [Tailwind CSS IntelliSense](https://github.com/tailwindlabs/tailwindcss-intellisense) plugin for VS Code. In order to make it recognize the strings inside your variants config, you have to somehow mark them and configure the plugin accordingly.
|
|
176
|
+
|
|
177
|
+
One way of doing so is by using tagged template literals:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
const tw = String.raw;
|
|
181
|
+
|
|
182
|
+
const button = variants({
|
|
183
|
+
base: tw`px-5 py-2 text-white`,
|
|
184
|
+
variants: {
|
|
185
|
+
color: {
|
|
186
|
+
neutral: tw`bg-slate-500 hover:bg-slate-400`,
|
|
187
|
+
accent: tw`bg-teal-500 hover:bg-teal-400`,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const tw = String.raw;
|
|
195
|
+
|
|
196
|
+
const button = variants({
|
|
197
|
+
base: tw.px(5).py(2).text.white,
|
|
198
|
+
variants: {
|
|
199
|
+
color: {
|
|
200
|
+
neutral: tw.bg.slate(500).hover(tw.bg.slate.400),
|
|
201
|
+
accent: tw.bg.teal(500).hover(tw.bg.teal(400)),
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
You can then add the following line to your `settings.json`:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
"tailwindCSS.experimental.classRegex": ["tw`(.+?)`"]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
In order to get type coverage even for your Tailwind classes you can use a tool like [tailwind-ts](https://github.com/mathieutu/tailwind-ts).
|
|
214
|
+
|
|
171
215
|
# License
|
|
172
216
|
|
|
173
217
|
MIT
|
package/example.tsx
CHANGED
|
@@ -3,37 +3,43 @@ import ReactDOM from "react-dom";
|
|
|
3
3
|
import { styled } from "./src/react";
|
|
4
4
|
|
|
5
5
|
const Button = styled("button", {
|
|
6
|
-
base: "
|
|
6
|
+
base: "px-5 py-2 text-white disabled:bg-gray-400 disabled:text-gray-300",
|
|
7
7
|
variants: {
|
|
8
8
|
color: {
|
|
9
|
-
neutral: "bg-
|
|
10
|
-
accent: "bg-teal-500",
|
|
9
|
+
neutral: "bg-slate-500 hover:bg-slate-400",
|
|
10
|
+
accent: "bg-teal-500 hover:bg-teal-400",
|
|
11
11
|
},
|
|
12
12
|
outlined: {
|
|
13
13
|
true: "border-2",
|
|
14
14
|
},
|
|
15
|
+
rounded: {
|
|
16
|
+
true: "rounded-full",
|
|
17
|
+
false: "rounded-sm",
|
|
18
|
+
},
|
|
15
19
|
},
|
|
16
20
|
compoundVariants: [
|
|
17
21
|
{
|
|
18
|
-
variants: {
|
|
19
|
-
|
|
20
|
-
outlined: true,
|
|
21
|
-
},
|
|
22
|
-
className: "border-teal-800",
|
|
22
|
+
variants: { color: "accent", outlined: true },
|
|
23
|
+
className: "border-teal-600",
|
|
23
24
|
},
|
|
24
25
|
],
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
color: "neutral",
|
|
28
|
+
},
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
function App() {
|
|
28
32
|
return (
|
|
29
|
-
|
|
30
|
-
<Button
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<Button color="accent" outlined onClick={console.log}>
|
|
33
|
+
<div className="flex justify-center items-center pt-8 gap-4 flex-wrap">
|
|
34
|
+
<Button onClick={console.log}>Accent</Button>
|
|
35
|
+
<Button rounded>Neutral + Rounded</Button>
|
|
36
|
+
<Button color="accent" outlined>
|
|
34
37
|
Accent + Outlined
|
|
35
38
|
</Button>
|
|
36
|
-
|
|
39
|
+
<Button color="accent" disabled>
|
|
40
|
+
Disabled
|
|
41
|
+
</Button>
|
|
42
|
+
</div>
|
|
37
43
|
);
|
|
38
44
|
}
|
|
39
45
|
|
package/lib/index.d.ts
CHANGED
|
@@ -1,18 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Definition of the available variants and their options.
|
|
3
|
+
* @example
|
|
4
|
+
* {
|
|
5
|
+
* color: {
|
|
6
|
+
* white: "bg-white"
|
|
7
|
+
* green: "bg-green-500",
|
|
8
|
+
* },
|
|
9
|
+
* size: {
|
|
10
|
+
* small: "text-xs",
|
|
11
|
+
* large: "text-lg"
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
export declare type Variants = Record<string, Record<string, string>>;
|
|
16
|
+
/**
|
|
17
|
+
* Configuration including defaults and compound variants.
|
|
18
|
+
*/
|
|
19
|
+
export interface VariantsConfig<V extends Variants> {
|
|
4
20
|
base?: string;
|
|
5
|
-
variants
|
|
21
|
+
variants: V;
|
|
6
22
|
compoundVariants?: CompoundVariant<V>[];
|
|
7
|
-
defaultVariants?:
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
23
|
+
defaultVariants?: Partial<OptionsOf<V>>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Rules for class names that are applied for certain variant combinations.
|
|
27
|
+
*/
|
|
28
|
+
export interface CompoundVariant<V extends Variants> {
|
|
29
|
+
variants: Partial<OptionsOf<V>>;
|
|
11
30
|
className: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Only the boolean variants, i.e. ones that have "true" or "false" as options.
|
|
34
|
+
*/
|
|
35
|
+
declare type BooleanVariants<V extends Variants> = {
|
|
36
|
+
[K in keyof V as V[K] extends {
|
|
37
|
+
true: any;
|
|
38
|
+
} | {
|
|
39
|
+
false: any;
|
|
40
|
+
} ? K : never]: V[K];
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Only the variants for which a default options is set.
|
|
44
|
+
*/
|
|
45
|
+
declare type DefaultVariants<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = {
|
|
46
|
+
[K in keyof V as K extends keyof C["defaultVariants"] ? K : never]: C["variants"][K];
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Names of all optional variants, i.e. booleans or ones with default options.
|
|
50
|
+
*/
|
|
51
|
+
declare type OptionalVariantNames<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = keyof BooleanVariants<V> | keyof DefaultVariants<C>;
|
|
52
|
+
/**
|
|
53
|
+
* Possible options for all the optional variants.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* {
|
|
57
|
+
* color?: "white" | "green",
|
|
58
|
+
* rounded?: boolean | undefined
|
|
59
|
+
* }
|
|
60
|
+
*/
|
|
61
|
+
declare type OptionalOptions<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = {
|
|
62
|
+
[K in keyof V as K extends OptionalVariantNames<C> ? K : never]?: OptionsOf<V>[K];
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Possible options for all required variants.
|
|
66
|
+
*
|
|
67
|
+
* @example {
|
|
68
|
+
* size: "small" | "large"
|
|
69
|
+
* }
|
|
70
|
+
*/
|
|
71
|
+
declare type RequiredOptions<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = {
|
|
72
|
+
[K in keyof V as K extends OptionalVariantNames<C> ? never : K]: OptionsOf<V>[K];
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Utility type to extract the possible options.
|
|
76
|
+
* Converts "true" | "false" options into booleans.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* OptionsOf<{
|
|
80
|
+
* size: { small: "text-xs"; large: "text-lg" };
|
|
81
|
+
* rounded: { true: "rounded-full" }
|
|
82
|
+
* }>
|
|
83
|
+
* ==>
|
|
84
|
+
* {
|
|
85
|
+
* size: "text-xs" | "text-lg";
|
|
86
|
+
* rounded: boolean;
|
|
87
|
+
* }
|
|
88
|
+
*/
|
|
89
|
+
declare type OptionsOf<V extends Variants> = {
|
|
90
|
+
[K in keyof V]: keyof V[K] extends "true" | "false" ? boolean : keyof V[K];
|
|
12
91
|
};
|
|
13
|
-
|
|
14
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Extracts the possible options.
|
|
94
|
+
*/
|
|
95
|
+
export declare type VariantOptions<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = RequiredOptions<C> & OptionalOptions<C>;
|
|
96
|
+
/**
|
|
97
|
+
* Without this conversion step, defaultVariants and compoundVariants will
|
|
98
|
+
* allow extra keys, i.e. non-existent variants.
|
|
99
|
+
* See https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts
|
|
100
|
+
*/
|
|
101
|
+
export declare type Simplify<T> = {
|
|
102
|
+
[K in keyof T]: T[K];
|
|
15
103
|
};
|
|
16
|
-
declare
|
|
17
|
-
export declare function variants<V extends Variants>({ base, variants, compoundVariants, defaultVariants, }: VariantsConfig<V>): (props: VariantSelection<V>) => string;
|
|
104
|
+
export declare function variants<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): (props: VariantOptions<C>) => string;
|
|
18
105
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
export function variants(
|
|
1
|
+
export function variants(config) {
|
|
2
|
+
const { base, variants, compoundVariants, defaultVariants } = config;
|
|
3
|
+
const isBooleanVariant = (name) => {
|
|
4
|
+
const v = variants === null || variants === void 0 ? void 0 : variants[name];
|
|
5
|
+
return v && ("false" in v || "true" in v);
|
|
6
|
+
};
|
|
2
7
|
return (props) => {
|
|
8
|
+
var _a;
|
|
3
9
|
const res = [base];
|
|
4
|
-
const getSelected = (name) => {
|
|
10
|
+
const getSelected = (name) => {
|
|
11
|
+
var _a, _b;
|
|
12
|
+
return (_b = (_a = props[name]) !== null && _a !== void 0 ? _a : defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[name]) !== null && _b !== void 0 ? _b : (isBooleanVariant(name) ? false : undefined);
|
|
13
|
+
};
|
|
5
14
|
for (let name in variants) {
|
|
6
15
|
const selected = getSelected(name);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
res.push(options[selected]);
|
|
16
|
+
if (selected !== undefined)
|
|
17
|
+
res.push((_a = variants[name]) === null || _a === void 0 ? void 0 : _a[selected]);
|
|
10
18
|
}
|
|
11
19
|
for (let { variants, className } of compoundVariants !== null && compoundVariants !== void 0 ? compoundVariants : []) {
|
|
12
|
-
const isSelected = (name) => getSelected(name)
|
|
13
|
-
|
|
14
|
-
if (allSelected)
|
|
20
|
+
const isSelected = (name) => getSelected(name) === variants[name];
|
|
21
|
+
if (Object.keys(variants).every(isSelected)) {
|
|
15
22
|
res.push(className);
|
|
23
|
+
}
|
|
16
24
|
}
|
|
17
25
|
return res.filter(Boolean).join(" ");
|
|
18
26
|
};
|
package/lib/react.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ComponentProps, ElementType, ForwardRefExoticComponent, PropsWithoutRef } from "react";
|
|
2
|
-
import { Variants, VariantsConfig,
|
|
2
|
+
import { Variants, VariantsConfig, VariantOptions, Simplify } from ".";
|
|
3
3
|
export declare type VariantProps<T> = T extends (props: infer VariantSelection) => any ? VariantSelection : never;
|
|
4
|
-
export declare function variantProps<V extends Variants>(config:
|
|
4
|
+
export declare function variantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): <T extends VariantOptions<C, C["variants"]>>(props: T) => {
|
|
5
5
|
className: string;
|
|
6
|
-
} & Omit<T, keyof
|
|
7
|
-
declare type StyledComponent<P extends ElementType, V extends Variants> = ForwardRefExoticComponent<PropsWithoutRef<ComponentProps<P> &
|
|
8
|
-
export declare function styled<P extends ElementType, V extends Variants>(type: P, config:
|
|
6
|
+
} & Omit<T, keyof C["variants"]>;
|
|
7
|
+
declare type StyledComponent<P extends ElementType, C extends VariantsConfig<V>, V extends Variants = C["variants"]> = ForwardRefExoticComponent<PropsWithoutRef<ComponentProps<P> & VariantOptions<C>> & React.RefAttributes<P>>;
|
|
8
|
+
export declare function styled<P extends ElementType, C extends VariantsConfig<V>, V extends Variants = C["variants"]>(type: P, config: Simplify<C>): StyledComponent<P, C>;
|
|
9
9
|
export {};
|
package/lib/react.js
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,46 +1,165 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Definition of the available variants and their options.
|
|
3
|
+
* @example
|
|
4
|
+
* {
|
|
5
|
+
* color: {
|
|
6
|
+
* white: "bg-white"
|
|
7
|
+
* green: "bg-green-500",
|
|
8
|
+
* },
|
|
9
|
+
* size: {
|
|
10
|
+
* small: "text-xs",
|
|
11
|
+
* large: "text-lg"
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
export type Variants = Record<string, Record<string, string>>;
|
|
2
16
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Configuration including defaults and compound variants.
|
|
19
|
+
*/
|
|
20
|
+
export interface VariantsConfig<V extends Variants> {
|
|
6
21
|
base?: string;
|
|
7
|
-
variants
|
|
22
|
+
variants: V;
|
|
8
23
|
compoundVariants?: CompoundVariant<V>[];
|
|
9
|
-
defaultVariants?:
|
|
10
|
-
}
|
|
24
|
+
defaultVariants?: Partial<OptionsOf<V>>;
|
|
25
|
+
}
|
|
11
26
|
|
|
12
|
-
|
|
13
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Rules for class names that are applied for certain variant combinations.
|
|
29
|
+
*/
|
|
30
|
+
export interface CompoundVariant<V extends Variants> {
|
|
31
|
+
variants: Partial<OptionsOf<V>>;
|
|
14
32
|
className: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Only the boolean variants, i.e. ones that have "true" or "false" as options.
|
|
37
|
+
*/
|
|
38
|
+
type BooleanVariants<V extends Variants> = {
|
|
39
|
+
[K in keyof V as V[K] extends { true: any } | { false: any }
|
|
40
|
+
? K
|
|
41
|
+
: never]: V[K];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Only the variants for which a default options is set.
|
|
46
|
+
*/
|
|
47
|
+
type DefaultVariants<
|
|
48
|
+
C extends VariantsConfig<V>,
|
|
49
|
+
V extends Variants = C["variants"]
|
|
50
|
+
> = {
|
|
51
|
+
[K in keyof V as K extends keyof C["defaultVariants"]
|
|
52
|
+
? K
|
|
53
|
+
: never]: C["variants"][K];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Names of all optional variants, i.e. booleans or ones with default options.
|
|
58
|
+
*/
|
|
59
|
+
type OptionalVariantNames<
|
|
60
|
+
C extends VariantsConfig<V>,
|
|
61
|
+
V extends Variants = C["variants"]
|
|
62
|
+
> = keyof BooleanVariants<V> | keyof DefaultVariants<C>;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Possible options for all the optional variants.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* {
|
|
69
|
+
* color?: "white" | "green",
|
|
70
|
+
* rounded?: boolean | undefined
|
|
71
|
+
* }
|
|
72
|
+
*/
|
|
73
|
+
type OptionalOptions<
|
|
74
|
+
C extends VariantsConfig<V>,
|
|
75
|
+
V extends Variants = C["variants"]
|
|
76
|
+
> = {
|
|
77
|
+
[K in keyof V as K extends OptionalVariantNames<C>
|
|
78
|
+
? K
|
|
79
|
+
: never]?: OptionsOf<V>[K];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Possible options for all required variants.
|
|
84
|
+
*
|
|
85
|
+
* @example {
|
|
86
|
+
* size: "small" | "large"
|
|
87
|
+
* }
|
|
88
|
+
*/
|
|
89
|
+
type RequiredOptions<
|
|
90
|
+
C extends VariantsConfig<V>,
|
|
91
|
+
V extends Variants = C["variants"]
|
|
92
|
+
> = {
|
|
93
|
+
[K in keyof V as K extends OptionalVariantNames<C>
|
|
94
|
+
? never
|
|
95
|
+
: K]: OptionsOf<V>[K];
|
|
15
96
|
};
|
|
16
97
|
|
|
17
|
-
|
|
18
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Utility type to extract the possible options.
|
|
100
|
+
* Converts "true" | "false" options into booleans.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* OptionsOf<{
|
|
104
|
+
* size: { small: "text-xs"; large: "text-lg" };
|
|
105
|
+
* rounded: { true: "rounded-full" }
|
|
106
|
+
* }>
|
|
107
|
+
* ==>
|
|
108
|
+
* {
|
|
109
|
+
* size: "text-xs" | "text-lg";
|
|
110
|
+
* rounded: boolean;
|
|
111
|
+
* }
|
|
112
|
+
*/
|
|
113
|
+
type OptionsOf<V extends Variants> = {
|
|
114
|
+
[K in keyof V]: keyof V[K] extends "true" | "false" ? boolean : keyof V[K];
|
|
19
115
|
};
|
|
20
116
|
|
|
21
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Extracts the possible options.
|
|
119
|
+
*/
|
|
120
|
+
export type VariantOptions<
|
|
121
|
+
C extends VariantsConfig<V>,
|
|
122
|
+
V extends Variants = C["variants"]
|
|
123
|
+
> = RequiredOptions<C> & OptionalOptions<C>;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Without this conversion step, defaultVariants and compoundVariants will
|
|
127
|
+
* allow extra keys, i.e. non-existent variants.
|
|
128
|
+
* See https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts
|
|
129
|
+
*/
|
|
130
|
+
export type Simplify<T> = {
|
|
131
|
+
[K in keyof T]: T[K];
|
|
132
|
+
};
|
|
22
133
|
|
|
23
|
-
export function variants<
|
|
24
|
-
|
|
25
|
-
variants
|
|
26
|
-
|
|
27
|
-
defaultVariants
|
|
28
|
-
|
|
29
|
-
|
|
134
|
+
export function variants<
|
|
135
|
+
C extends VariantsConfig<V>,
|
|
136
|
+
V extends Variants = C["variants"]
|
|
137
|
+
>(config: Simplify<C>) {
|
|
138
|
+
const { base, variants, compoundVariants, defaultVariants } = config;
|
|
139
|
+
|
|
140
|
+
const isBooleanVariant = (name: keyof V) => {
|
|
141
|
+
const v = variants?.[name];
|
|
142
|
+
return v && ("false" in v || "true" in v);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return (props: VariantOptions<C>) => {
|
|
30
146
|
const res = [base];
|
|
31
147
|
|
|
32
|
-
const getSelected = (name:
|
|
33
|
-
props[name] ??
|
|
148
|
+
const getSelected = (name: keyof V) =>
|
|
149
|
+
(props as any)[name] ??
|
|
150
|
+
defaultVariants?.[name] ??
|
|
151
|
+
(isBooleanVariant(name) ? false : undefined);
|
|
34
152
|
|
|
35
153
|
for (let name in variants) {
|
|
36
154
|
const selected = getSelected(name);
|
|
37
|
-
|
|
38
|
-
if (selected) res.push(options[selected]);
|
|
155
|
+
if (selected !== undefined) res.push(variants[name]?.[selected]);
|
|
39
156
|
}
|
|
157
|
+
|
|
40
158
|
for (let { variants, className } of compoundVariants ?? []) {
|
|
41
|
-
const isSelected = (name: string) => getSelected(name)
|
|
42
|
-
|
|
43
|
-
|
|
159
|
+
const isSelected = (name: string) => getSelected(name) === variants[name];
|
|
160
|
+
if (Object.keys(variants).every(isSelected)) {
|
|
161
|
+
res.push(className);
|
|
162
|
+
}
|
|
44
163
|
}
|
|
45
164
|
return res.filter(Boolean).join(" ");
|
|
46
165
|
};
|
package/src/react.ts
CHANGED
|
@@ -7,15 +7,24 @@ import {
|
|
|
7
7
|
PropsWithoutRef,
|
|
8
8
|
} from "react";
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
Variants,
|
|
12
|
+
variants,
|
|
13
|
+
VariantsConfig,
|
|
14
|
+
VariantOptions,
|
|
15
|
+
Simplify,
|
|
16
|
+
} from ".";
|
|
11
17
|
|
|
12
18
|
export type VariantProps<T> = T extends (props: infer VariantSelection) => any
|
|
13
19
|
? VariantSelection
|
|
14
20
|
: never;
|
|
15
21
|
|
|
16
|
-
export function variantProps<
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
export function variantProps<
|
|
23
|
+
C extends VariantsConfig<V>,
|
|
24
|
+
V extends Variants = C["variants"]
|
|
25
|
+
>(config: Simplify<C>) {
|
|
26
|
+
const mkClass = variants<C>(config);
|
|
27
|
+
return <T extends VariantOptions<C>>(props: T) => {
|
|
19
28
|
const className = mkClass(props);
|
|
20
29
|
const result: any = { className };
|
|
21
30
|
for (let prop in props) {
|
|
@@ -23,24 +32,26 @@ export function variantProps<V extends Variants>(config: VariantsConfig<V>) {
|
|
|
23
32
|
result[prop] = props[prop];
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
|
-
return result as { className: string } & Omit<T, keyof
|
|
35
|
+
return result as { className: string } & Omit<T, keyof C["variants"]>;
|
|
27
36
|
};
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
type StyledComponent<
|
|
31
40
|
P extends ElementType,
|
|
32
|
-
|
|
41
|
+
C extends VariantsConfig<V>,
|
|
42
|
+
V extends Variants = C["variants"]
|
|
33
43
|
> = ForwardRefExoticComponent<
|
|
34
|
-
PropsWithoutRef<ComponentProps<P> &
|
|
44
|
+
PropsWithoutRef<ComponentProps<P> & VariantOptions<C>> &
|
|
35
45
|
React.RefAttributes<P>
|
|
36
46
|
>;
|
|
37
47
|
|
|
38
|
-
export function styled<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
export function styled<
|
|
49
|
+
P extends ElementType,
|
|
50
|
+
C extends VariantsConfig<V>,
|
|
51
|
+
V extends Variants = C["variants"]
|
|
52
|
+
>(type: P, config: Simplify<C>): StyledComponent<P, C> {
|
|
42
53
|
const styledProps = variantProps(config);
|
|
43
|
-
return forwardRef<P, ComponentProps<P> &
|
|
54
|
+
return forwardRef<P, ComponentProps<P> & VariantOptions<C>>((props, ref) =>
|
|
44
55
|
createElement(type, { ...styledProps(props), ref })
|
|
45
56
|
);
|
|
46
57
|
}
|