classname-variants 1.3.0 → 1.3.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 +26 -24
- package/index.html +1 -1
- package/lib/index.d.ts +16 -10
- package/lib/index.js +4 -0
- package/lib/react.d.ts +14 -8
- package/lib/react.js +4 -0
- package/package.json +6 -5
- package/example.tsx +0 -68
- package/lib/example.d.ts +0 -1
- package/lib/example.js +0 -45
- package/lib/src/index.d.ts +0 -105
- package/lib/src/index.js +0 -27
- package/lib/src/react.d.ts +0 -19
- package/lib/src/react.js +0 -25
- package/src/index.ts +0 -166
- package/src/react.ts +0 -82
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Stitches-like [variant API](https://stitches.dev/docs/variants) for plain class names.
|
|
4
4
|
|
|
5
|
-
The library is framework
|
|
5
|
+
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/) or [CSS Modules](https://github.com/css-modules/css-modules) in combination with 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
|
|
|
@@ -158,14 +158,14 @@ function App() {
|
|
|
158
158
|
|
|
159
159
|
Things can be taken even a step further, resulting in a _styled-components_ like way of defining reusable components. Under the hood, this does basically the same as the example above, but also handles _refs_ correctly:
|
|
160
160
|
|
|
161
|
-
```
|
|
162
|
-
import { styled } from "classname-variants/react";
|
|
161
|
+
```ts
|
|
162
|
+
import { styled, tw } from "classname-variants/react";
|
|
163
163
|
|
|
164
164
|
const Button = styled("button", {
|
|
165
165
|
variants: {
|
|
166
166
|
size: {
|
|
167
|
-
small:
|
|
168
|
-
large:
|
|
167
|
+
small: tw`text-xs`,
|
|
168
|
+
large: tw`text-base`,
|
|
169
169
|
},
|
|
170
170
|
},
|
|
171
171
|
});
|
|
@@ -173,7 +173,7 @@ const Button = styled("button", {
|
|
|
173
173
|
|
|
174
174
|
Again, this is not limited to tailwind, so you could do the same with CSS modules:
|
|
175
175
|
|
|
176
|
-
```
|
|
176
|
+
```ts
|
|
177
177
|
import { styled } from "classname-variants/react";
|
|
178
178
|
import styles from "./styles.module.css";
|
|
179
179
|
|
|
@@ -187,7 +187,21 @@ const Button = styled("button", {
|
|
|
187
187
|
});
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
**
|
|
190
|
+
> **Note**
|
|
191
|
+
> You can also style other custom React components as long as they accept a `className` prop.
|
|
192
|
+
|
|
193
|
+
## Styled components without variants
|
|
194
|
+
|
|
195
|
+
You can also use the `styled` function to create styled components without any variants at all:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { styled } from "classname-variants/react";
|
|
199
|
+
|
|
200
|
+
const Button = styled(
|
|
201
|
+
"button",
|
|
202
|
+
"border-none rounded px-3 font-sans bg-green-600 text-white hover:bg-green-500"
|
|
203
|
+
);
|
|
204
|
+
```
|
|
191
205
|
|
|
192
206
|
## Polymorphic components with "as"
|
|
193
207
|
|
|
@@ -195,7 +209,6 @@ If you want to keep all the variants you have defined for a component but want t
|
|
|
195
209
|
|
|
196
210
|
```tsx
|
|
197
211
|
import { styled } from "classname-variants/react";
|
|
198
|
-
import styles from "./styles.module.css";
|
|
199
212
|
|
|
200
213
|
const Button = styled("button", {
|
|
201
214
|
variants: {
|
|
@@ -217,12 +230,12 @@ function App() {
|
|
|
217
230
|
|
|
218
231
|
# Tailwind IntelliSense
|
|
219
232
|
|
|
220
|
-
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
|
|
233
|
+
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.
|
|
221
234
|
|
|
222
235
|
One way of doing so is by using tagged template literals:
|
|
223
236
|
|
|
224
237
|
```ts
|
|
225
|
-
|
|
238
|
+
import { variants, tw } from "classname-variants";
|
|
226
239
|
|
|
227
240
|
const button = variants({
|
|
228
241
|
base: tw`px-5 py-2 text-white`,
|
|
@@ -235,26 +248,15 @@ const button = variants({
|
|
|
235
248
|
});
|
|
236
249
|
```
|
|
237
250
|
|
|
238
|
-
```ts
|
|
239
|
-
const tw = String.raw;
|
|
240
|
-
|
|
241
|
-
const button = variants({
|
|
242
|
-
base: tw.px(5).py(2).text.white,
|
|
243
|
-
variants: {
|
|
244
|
-
color: {
|
|
245
|
-
neutral: tw.bg.slate(500).hover(tw.bg.slate.400),
|
|
246
|
-
accent: tw.bg.teal(500).hover(tw.bg.teal(400)),
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
```
|
|
251
|
-
|
|
252
251
|
You can then add the following line to your `settings.json`:
|
|
253
252
|
|
|
254
253
|
```
|
|
255
254
|
"tailwindCSS.experimental.classRegex": ["tw`(.+?)`"]
|
|
256
255
|
```
|
|
257
256
|
|
|
257
|
+
> **Note**
|
|
258
|
+
> The `tw` helper function is just an alias for [`String.raw`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw).
|
|
259
|
+
|
|
258
260
|
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).
|
|
259
261
|
|
|
260
262
|
# License
|
package/index.html
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
* }
|
|
13
13
|
* }
|
|
14
14
|
*/
|
|
15
|
-
export
|
|
15
|
+
export type Variants = Record<string, Record<string, string>>;
|
|
16
16
|
/**
|
|
17
17
|
* Configuration including defaults and compound variants.
|
|
18
18
|
*/
|
|
19
|
-
export interface VariantsConfig<V extends Variants> {
|
|
19
|
+
export interface VariantsConfig<V extends Variants = {}> {
|
|
20
20
|
base?: string;
|
|
21
21
|
variants: V;
|
|
22
22
|
compoundVariants?: CompoundVariant<V>[];
|
|
@@ -32,7 +32,7 @@ export interface CompoundVariant<V extends Variants> {
|
|
|
32
32
|
/**
|
|
33
33
|
* Only the boolean variants, i.e. ones that have "true" or "false" as options.
|
|
34
34
|
*/
|
|
35
|
-
|
|
35
|
+
type BooleanVariants<V extends Variants> = {
|
|
36
36
|
[K in keyof V as V[K] extends {
|
|
37
37
|
true: any;
|
|
38
38
|
} | {
|
|
@@ -42,13 +42,13 @@ declare type BooleanVariants<V extends Variants> = {
|
|
|
42
42
|
/**
|
|
43
43
|
* Only the variants for which a default options is set.
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
type DefaultVariants<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = {
|
|
46
46
|
[K in keyof V as K extends keyof C["defaultVariants"] ? K : never]: C["variants"][K];
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
49
|
* Names of all optional variants, i.e. booleans or ones with default options.
|
|
50
50
|
*/
|
|
51
|
-
|
|
51
|
+
type OptionalVariantNames<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = keyof BooleanVariants<V> | keyof DefaultVariants<C>;
|
|
52
52
|
/**
|
|
53
53
|
* Possible options for all the optional variants.
|
|
54
54
|
*
|
|
@@ -58,7 +58,7 @@ declare type OptionalVariantNames<C extends VariantsConfig<V>, V extends Variant
|
|
|
58
58
|
* rounded?: boolean | undefined
|
|
59
59
|
* }
|
|
60
60
|
*/
|
|
61
|
-
|
|
61
|
+
type OptionalOptions<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = {
|
|
62
62
|
[K in keyof V as K extends OptionalVariantNames<C> ? K : never]?: OptionsOf<V>[K];
|
|
63
63
|
};
|
|
64
64
|
/**
|
|
@@ -68,7 +68,7 @@ declare type OptionalOptions<C extends VariantsConfig<V>, V extends Variants = C
|
|
|
68
68
|
* size: "small" | "large"
|
|
69
69
|
* }
|
|
70
70
|
*/
|
|
71
|
-
|
|
71
|
+
type RequiredOptions<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = {
|
|
72
72
|
[K in keyof V as K extends OptionalVariantNames<C> ? never : K]: OptionsOf<V>[K];
|
|
73
73
|
};
|
|
74
74
|
/**
|
|
@@ -86,20 +86,26 @@ declare type RequiredOptions<C extends VariantsConfig<V>, V extends Variants = C
|
|
|
86
86
|
* rounded: boolean;
|
|
87
87
|
* }
|
|
88
88
|
*/
|
|
89
|
-
|
|
89
|
+
type OptionsOf<V extends Variants> = {
|
|
90
90
|
[K in keyof V]: keyof V[K] extends "true" | "false" ? boolean : keyof V[K];
|
|
91
91
|
};
|
|
92
92
|
/**
|
|
93
93
|
* Extracts the possible options.
|
|
94
94
|
*/
|
|
95
|
-
export
|
|
95
|
+
export type VariantOptions<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = RequiredOptions<C> & OptionalOptions<C>;
|
|
96
96
|
/**
|
|
97
97
|
* Without this conversion step, defaultVariants and compoundVariants will
|
|
98
98
|
* allow extra keys, i.e. non-existent variants.
|
|
99
99
|
* See https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts
|
|
100
100
|
*/
|
|
101
|
-
export
|
|
101
|
+
export type Simplify<T> = {
|
|
102
102
|
[K in keyof T]: T[K];
|
|
103
103
|
};
|
|
104
104
|
export declare function variants<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): (props: VariantOptions<C>) => string;
|
|
105
|
+
/**
|
|
106
|
+
* No-op function to mark template literals as tailwind strings.
|
|
107
|
+
*/
|
|
108
|
+
export declare const tw: (template: {
|
|
109
|
+
raw: readonly string[] | ArrayLike<string>;
|
|
110
|
+
}, ...substitutions: any[]) => string;
|
|
105
111
|
export {};
|
package/lib/index.js
CHANGED
package/lib/react.d.ts
CHANGED
|
@@ -3,28 +3,34 @@ import { Variants, VariantsConfig, VariantOptions, Simplify } from "./index.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Utility type to infer the first argument of a variantProps function.
|
|
5
5
|
*/
|
|
6
|
-
export
|
|
6
|
+
export type VariantPropsOf<T> = T extends (props: infer P) => any ? P : never;
|
|
7
7
|
/**
|
|
8
8
|
* Type for the variantProps() argument – consists of the VariantOptions and an optional className for chaining.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
type VariantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = VariantOptions<C> & {
|
|
11
11
|
className?: string;
|
|
12
12
|
};
|
|
13
13
|
export declare function variantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): <P extends VariantProps<C, C["variants"]>>(props: P) => {
|
|
14
14
|
className: string;
|
|
15
15
|
} & Omit<P, keyof C["variants"]>;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
type VariantsOf<T, V> = T extends VariantsConfig ? V : {};
|
|
17
|
+
type AsProps<T extends ElementType = ElementType> = {
|
|
18
18
|
as?: T;
|
|
19
19
|
};
|
|
20
|
-
|
|
21
|
-
export declare function styled<T extends ElementType, C extends VariantsConfig<V>, V extends Variants = VariantsOf<C>>(type: T, config: string | Simplify<C>): <As extends ElementType<any> = T>(props: AsProps<As> & Omit<ComponentProps<As>, "as"> & { [K in keyof C["variants"]
|
|
20
|
+
type PolymorphicComponentProps<T extends ElementType> = AsProps<T> & Omit<ComponentProps<T>, "as">;
|
|
21
|
+
export declare function styled<T extends ElementType, C extends VariantsConfig<V>, V extends Variants = VariantsOf<C, C["variants"]>>(type: T, config: string | Simplify<C>): <As extends ElementType<any> = T>(props: AsProps<As> & Omit<ComponentProps<As>, "as"> & (C["variants"] extends infer T_1 extends Variants ? { [K in keyof T_1 as K extends keyof (C["variants"] extends infer T_2 extends Variants ? { [K_1 in keyof T_2 as C["variants"][K_1] extends {
|
|
22
22
|
true: any;
|
|
23
23
|
} | {
|
|
24
24
|
false: any;
|
|
25
|
-
} ? K_1 : never]: C["variants"][K_1]; } | keyof { [K_2 in keyof
|
|
25
|
+
} ? K_1 : never]: C["variants"][K_1]; } : never) | keyof (C["variants"] extends infer T_3 extends Variants ? { [K_2 in keyof T_3 as K_2 extends keyof C["defaultVariants"] ? K_2 : never]: C["variants"][K_2]; } : never) ? never : K]: (C["variants"] extends infer T_4 extends Variants ? { [K_3 in keyof T_4]: keyof C["variants"][K_3] extends "true" | "false" ? boolean : keyof C["variants"][K_3]; } : never)[K]; } : never) & (C["variants"] extends infer T_5 extends Variants ? { [K_4 in keyof T_5 as K_4 extends keyof (C["variants"] extends infer T_2 extends Variants ? { [K_1 in keyof T_2 as C["variants"][K_1] extends {
|
|
26
26
|
true: any;
|
|
27
27
|
} | {
|
|
28
28
|
false: any;
|
|
29
|
-
} ? K_1 : never]: C["variants"][K_1]; } | keyof { [K_2 in keyof
|
|
29
|
+
} ? K_1 : never]: C["variants"][K_1]; } : never) | keyof (C["variants"] extends infer T_3 extends Variants ? { [K_2 in keyof T_3 as K_2 extends keyof C["defaultVariants"] ? K_2 : never]: C["variants"][K_2]; } : never) ? K_4 : never]?: (C["variants"] extends infer T_4 extends Variants ? { [K_3 in keyof T_4]: keyof C["variants"][K_3] extends "true" | "false" ? boolean : keyof C["variants"][K_3]; } : never)[K_4] | undefined; } : never)) => ReactElement | null;
|
|
30
|
+
/**
|
|
31
|
+
* No-op function to mark template literals as tailwind strings.
|
|
32
|
+
*/
|
|
33
|
+
export declare const tw: (template: {
|
|
34
|
+
raw: readonly string[] | ArrayLike<string>;
|
|
35
|
+
}, ...substitutions: any[]) => string;
|
|
30
36
|
export {};
|
package/lib/react.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "classname-variants",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"description": "Variant API for plain class names",
|
|
5
5
|
"author": "Felix Gnass <fgnass@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,9 +41,10 @@
|
|
|
41
41
|
"react"
|
|
42
42
|
],
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/react": "^
|
|
45
|
-
"react": "^
|
|
46
|
-
"react
|
|
47
|
-
"
|
|
44
|
+
"@types/react": "^18.0.26",
|
|
45
|
+
"@types/react-dom": "^18.0.9",
|
|
46
|
+
"react": "^18.2.0",
|
|
47
|
+
"react-dom": "^18.2.0",
|
|
48
|
+
"typescript": "^4.9.4"
|
|
48
49
|
}
|
|
49
50
|
}
|
package/example.tsx
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import ReactDOM from "react-dom";
|
|
3
|
-
import { styled } from "./src/react";
|
|
4
|
-
|
|
5
|
-
function CustomComponent({
|
|
6
|
-
title,
|
|
7
|
-
...props
|
|
8
|
-
}: {
|
|
9
|
-
className?: string;
|
|
10
|
-
title: string;
|
|
11
|
-
}) {
|
|
12
|
-
return <div {...props}>{title}</div>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const Card = styled("div", "bg-white p-4 border-2 rounded-lg");
|
|
16
|
-
|
|
17
|
-
const TitleCard = styled(CustomComponent, "bg-white p-4 border-2 rounded-lg");
|
|
18
|
-
|
|
19
|
-
const Button = styled("button", {
|
|
20
|
-
base: "px-5 py-2 text-white disabled:bg-gray-400 disabled:text-gray-300",
|
|
21
|
-
variants: {
|
|
22
|
-
color: {
|
|
23
|
-
neutral: "bg-slate-500 hover:bg-slate-400",
|
|
24
|
-
accent: "bg-teal-500 hover:bg-teal-400",
|
|
25
|
-
},
|
|
26
|
-
outlined: {
|
|
27
|
-
true: "border-2",
|
|
28
|
-
},
|
|
29
|
-
rounded: {
|
|
30
|
-
true: "rounded-full",
|
|
31
|
-
false: "rounded-sm",
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
compoundVariants: [
|
|
35
|
-
{
|
|
36
|
-
variants: { color: "accent", outlined: true },
|
|
37
|
-
className: "border-teal-600",
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
defaultVariants: {
|
|
41
|
-
color: "neutral",
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
function App() {
|
|
46
|
-
return (
|
|
47
|
-
<div className="flex justify-center items-center pt-8 gap-4 flex-wrap">
|
|
48
|
-
<Button onClick={console.log}>Accent</Button>
|
|
49
|
-
<Button rounded>Neutral + Rounded</Button>
|
|
50
|
-
<Button color="accent" outlined>
|
|
51
|
-
Accent + Outlined
|
|
52
|
-
</Button>
|
|
53
|
-
<Button color="accent" disabled>
|
|
54
|
-
Disabled
|
|
55
|
-
</Button>
|
|
56
|
-
<TitleCard title="Hello" />
|
|
57
|
-
<Card>
|
|
58
|
-
<h1>Hello</h1>
|
|
59
|
-
<p>world</p>
|
|
60
|
-
</Card>
|
|
61
|
-
<Card as="a" href="https://example.com">
|
|
62
|
-
Link
|
|
63
|
-
</Card>
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
ReactDOM.render(<App />, document.getElementById("root"));
|
package/lib/example.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/lib/example.js
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import ReactDOM from "react-dom";
|
|
3
|
-
import { styled } from "./src/react";
|
|
4
|
-
function CustomComponent({ title, ...props }) {
|
|
5
|
-
return React.createElement("div", { ...props }, title);
|
|
6
|
-
}
|
|
7
|
-
const Card = styled("div", "bg-white p-4 border-2 rounded-lg");
|
|
8
|
-
const TitleCard = styled(CustomComponent, "bg-white p-4 border-2 rounded-lg");
|
|
9
|
-
const Button = styled("button", {
|
|
10
|
-
base: "px-5 py-2 text-white disabled:bg-gray-400 disabled:text-gray-300",
|
|
11
|
-
variants: {
|
|
12
|
-
color: {
|
|
13
|
-
neutral: "bg-slate-500 hover:bg-slate-400",
|
|
14
|
-
accent: "bg-teal-500 hover:bg-teal-400",
|
|
15
|
-
},
|
|
16
|
-
outlined: {
|
|
17
|
-
true: "border-2",
|
|
18
|
-
},
|
|
19
|
-
rounded: {
|
|
20
|
-
true: "rounded-full",
|
|
21
|
-
false: "rounded-sm",
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
compoundVariants: [
|
|
25
|
-
{
|
|
26
|
-
variants: { color: "accent", outlined: true },
|
|
27
|
-
className: "border-teal-600",
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
defaultVariants: {
|
|
31
|
-
color: "neutral",
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
function App() {
|
|
35
|
-
return (React.createElement("div", { className: "flex justify-center items-center pt-8 gap-4 flex-wrap" },
|
|
36
|
-
React.createElement(Button, { onClick: console.log }, "Accent"),
|
|
37
|
-
React.createElement(Button, { rounded: true }, "Neutral + Rounded"),
|
|
38
|
-
React.createElement(Button, { color: "accent", outlined: true }, "Accent + Outlined"),
|
|
39
|
-
React.createElement(Button, { color: "accent", disabled: true }, "Disabled"),
|
|
40
|
-
React.createElement(TitleCard, { title: "Hello" }),
|
|
41
|
-
React.createElement(Card, null,
|
|
42
|
-
React.createElement("h1", null, "Hello"),
|
|
43
|
-
React.createElement("p", null, "world"))));
|
|
44
|
-
}
|
|
45
|
-
ReactDOM.render(React.createElement(App, null), document.getElementById("root"));
|
package/lib/src/index.d.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
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> {
|
|
20
|
-
base?: string;
|
|
21
|
-
variants: V;
|
|
22
|
-
compoundVariants?: CompoundVariant<V>[];
|
|
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>>;
|
|
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];
|
|
91
|
-
};
|
|
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];
|
|
103
|
-
};
|
|
104
|
-
export declare function variants<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): (props: VariantOptions<C>) => string;
|
|
105
|
-
export {};
|
package/lib/src/index.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
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
|
-
};
|
|
7
|
-
return (props) => {
|
|
8
|
-
var _a;
|
|
9
|
-
const res = [base];
|
|
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
|
-
};
|
|
14
|
-
for (let name in variants) {
|
|
15
|
-
const selected = getSelected(name);
|
|
16
|
-
if (selected !== undefined)
|
|
17
|
-
res.push((_a = variants[name]) === null || _a === void 0 ? void 0 : _a[selected]);
|
|
18
|
-
}
|
|
19
|
-
for (let { variants, className } of compoundVariants !== null && compoundVariants !== void 0 ? compoundVariants : []) {
|
|
20
|
-
const isSelected = (name) => getSelected(name) === variants[name];
|
|
21
|
-
if (Object.keys(variants).every(isSelected)) {
|
|
22
|
-
res.push(className);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return res.filter(Boolean).join(" ");
|
|
26
|
-
};
|
|
27
|
-
}
|
package/lib/src/react.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { ComponentProps, ElementType, ForwardRefExoticComponent, PropsWithoutRef } from "react";
|
|
2
|
-
import { Variants, VariantsConfig, VariantOptions, Simplify } from "./index.js";
|
|
3
|
-
/**
|
|
4
|
-
* Utility type to infer the first argument of a variantProps function.
|
|
5
|
-
*/
|
|
6
|
-
export declare type VariantPropsOf<T> = T extends (props: infer P) => any ? P : never;
|
|
7
|
-
/**
|
|
8
|
-
* Type for the variantProps() argument – consists of the VariantOptions and an optional className for chaining.
|
|
9
|
-
*/
|
|
10
|
-
declare type VariantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = VariantOptions<C> & {
|
|
11
|
-
className?: string;
|
|
12
|
-
};
|
|
13
|
-
export declare function variantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): <P extends VariantProps<C, C["variants"]>>(props: P) => {
|
|
14
|
-
className: string;
|
|
15
|
-
} & Omit<P, keyof C["variants"]>;
|
|
16
|
-
declare type StyledComponent<T extends ElementType, C extends VariantsConfig<V>, V extends Variants = C["variants"]> = ForwardRefExoticComponent<PropsWithoutRef<ComponentProps<T> & VariantOptions<C>> & React.RefAttributes<T>>;
|
|
17
|
-
declare type Vars<T> = T extends VariantsConfig<infer V> ? V : {};
|
|
18
|
-
export declare function styled<T extends ElementType, C extends VariantsConfig<V>, V extends Variants = Vars<C>>(type: T, config: string | Simplify<C>): StyledComponent<T, C>;
|
|
19
|
-
export {};
|
package/lib/src/react.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createElement, forwardRef, } from "react";
|
|
2
|
-
import { variants, } from "./index.js";
|
|
3
|
-
export function variantProps(config) {
|
|
4
|
-
const variantClassName = variants(config);
|
|
5
|
-
return (props) => {
|
|
6
|
-
const result = {};
|
|
7
|
-
// Pass-through all unrelated props
|
|
8
|
-
for (let prop in props) {
|
|
9
|
-
if (config.variants && !(prop in config.variants)) {
|
|
10
|
-
result[prop] = props[prop];
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
// Add the optionally passed className prop for chaining
|
|
14
|
-
result.className = [props.className, variantClassName(props)]
|
|
15
|
-
.filter(Boolean)
|
|
16
|
-
.join(" ");
|
|
17
|
-
return result;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
export function styled(type, config) {
|
|
21
|
-
const styledProps = typeof config === "string"
|
|
22
|
-
? variantProps({ base: config, variants: {} })
|
|
23
|
-
: variantProps(config);
|
|
24
|
-
return forwardRef((props, ref) => createElement(type, { ...styledProps(props), ref }));
|
|
25
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
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>>;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Configuration including defaults and compound variants.
|
|
19
|
-
*/
|
|
20
|
-
export interface VariantsConfig<V extends Variants> {
|
|
21
|
-
base?: string;
|
|
22
|
-
variants: V;
|
|
23
|
-
compoundVariants?: CompoundVariant<V>[];
|
|
24
|
-
defaultVariants?: Partial<OptionsOf<V>>;
|
|
25
|
-
}
|
|
26
|
-
|
|
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>>;
|
|
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];
|
|
96
|
-
};
|
|
97
|
-
|
|
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];
|
|
115
|
-
};
|
|
116
|
-
|
|
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
|
-
};
|
|
133
|
-
|
|
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>) => {
|
|
146
|
-
const res = [base];
|
|
147
|
-
|
|
148
|
-
const getSelected = (name: keyof V) =>
|
|
149
|
-
(props as any)[name] ??
|
|
150
|
-
defaultVariants?.[name] ??
|
|
151
|
-
(isBooleanVariant(name) ? false : undefined);
|
|
152
|
-
|
|
153
|
-
for (let name in variants) {
|
|
154
|
-
const selected = getSelected(name);
|
|
155
|
-
if (selected !== undefined) res.push(variants[name]?.[selected]);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
for (let { variants, className } of compoundVariants ?? []) {
|
|
159
|
-
const isSelected = (name: string) => getSelected(name) === variants[name];
|
|
160
|
-
if (Object.keys(variants).every(isSelected)) {
|
|
161
|
-
res.push(className);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return res.filter(Boolean).join(" ");
|
|
165
|
-
};
|
|
166
|
-
}
|
package/src/react.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ComponentProps,
|
|
3
|
-
createElement,
|
|
4
|
-
ElementType,
|
|
5
|
-
forwardRef,
|
|
6
|
-
ReactElement,
|
|
7
|
-
Ref,
|
|
8
|
-
} from "react";
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
Variants,
|
|
12
|
-
variants,
|
|
13
|
-
VariantsConfig,
|
|
14
|
-
VariantOptions,
|
|
15
|
-
Simplify,
|
|
16
|
-
} from "./index.js";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Utility type to infer the first argument of a variantProps function.
|
|
20
|
-
*/
|
|
21
|
-
export type VariantPropsOf<T> = T extends (props: infer P) => any ? P : never;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Type for the variantProps() argument – consists of the VariantOptions and an optional className for chaining.
|
|
25
|
-
*/
|
|
26
|
-
type VariantProps<
|
|
27
|
-
C extends VariantsConfig<V>,
|
|
28
|
-
V extends Variants = C["variants"]
|
|
29
|
-
> = VariantOptions<C> & { className?: string };
|
|
30
|
-
|
|
31
|
-
export function variantProps<
|
|
32
|
-
C extends VariantsConfig<V>,
|
|
33
|
-
V extends Variants = C["variants"]
|
|
34
|
-
>(config: Simplify<C>) {
|
|
35
|
-
const variantClassName = variants<C>(config);
|
|
36
|
-
return <P extends VariantProps<C>>(props: P) => {
|
|
37
|
-
const result: any = {};
|
|
38
|
-
|
|
39
|
-
// Pass-through all unrelated props
|
|
40
|
-
for (let prop in props) {
|
|
41
|
-
if (config.variants && !(prop in config.variants)) {
|
|
42
|
-
result[prop] = props[prop];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Add the optionally passed className prop for chaining
|
|
47
|
-
result.className = [props.className, variantClassName(props)]
|
|
48
|
-
.filter(Boolean)
|
|
49
|
-
.join(" ");
|
|
50
|
-
|
|
51
|
-
return result as { className: string } & Omit<P, keyof C["variants"]>;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
type VariantsOf<T> = T extends VariantsConfig<infer V> ? V : {};
|
|
56
|
-
|
|
57
|
-
type AsProps<T extends ElementType = ElementType> = {
|
|
58
|
-
as?: T;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
type PolymorphicComponentProps<T extends ElementType> = AsProps<T> &
|
|
62
|
-
Omit<ComponentProps<T>, "as">;
|
|
63
|
-
|
|
64
|
-
export function styled<
|
|
65
|
-
T extends ElementType,
|
|
66
|
-
C extends VariantsConfig<V>,
|
|
67
|
-
V extends Variants = VariantsOf<C>
|
|
68
|
-
>(type: T, config: string | Simplify<C>) {
|
|
69
|
-
const styledProps =
|
|
70
|
-
typeof config === "string"
|
|
71
|
-
? variantProps({ base: config, variants: {} })
|
|
72
|
-
: variantProps(config);
|
|
73
|
-
|
|
74
|
-
const Component: <As extends ElementType = T>(
|
|
75
|
-
props: PolymorphicComponentProps<As> & VariantOptions<C>
|
|
76
|
-
) => ReactElement | null = forwardRef(
|
|
77
|
-
({ as, ...props }: AsProps, ref: Ref<Element>) => {
|
|
78
|
-
return createElement(as ?? type, { ...styledProps(props), ref });
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
return Component;
|
|
82
|
-
}
|