classname-variants 1.3.3 â 1.4.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/README.md +137 -133
- package/index.html +5 -2
- package/lib/example/index.d.ts +1 -0
- package/lib/example/index.js +8 -0
- package/lib/example/preact.d.ts +9 -0
- package/lib/example/preact.js +76 -0
- package/lib/example/react.d.ts +8 -0
- package/lib/example/react.js +76 -0
- package/lib/preact.d.ts +30 -0
- package/lib/preact.js +33 -0
- package/lib/react.d.ts +2 -10
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -1,20 +1,67 @@
|
|
|
1
|
-
# classname-variants
|
|
1
|
+
# classname-variants ð
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Library to create type-safe components that render their class name based on a set of variants.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- âïļ Supports React, Preact and vanilla DOM
|
|
8
|
+
- ðĄïļ Fully type-safe and excellent auto completion support
|
|
9
|
+
- â
Supports both optional and required variants
|
|
10
|
+
- ðŠķ Light-weight without any dependencies
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
# Examples
|
|
15
|
+
|
|
16
|
+
Here is an example that uses React and Tailwind CSS:
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { styled } from "classname-variants/react";
|
|
20
|
+
|
|
21
|
+
const Button = styled("button", {
|
|
22
|
+
variants: {
|
|
23
|
+
size: {
|
|
24
|
+
small: "text-xs",
|
|
25
|
+
large: "text-lg",
|
|
26
|
+
},
|
|
27
|
+
primary: {
|
|
28
|
+
true: "bg-teal-500 text-white",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function UsageExample() {
|
|
34
|
+
return <Button primary size="large" />;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
10
37
|
|
|
11
|
-
|
|
38
|
+
[](https://codesandbox.io/s/classname-variants-react-3bzjl?fontsize=14&hidenavigation=1&theme=dark)
|
|
12
39
|
|
|
13
|
-
|
|
40
|
+
While the library has been designed with tools like Tailwind in mind, it can be also used with custom classes or CSS modules:
|
|
14
41
|
|
|
15
|
-
|
|
42
|
+
## Preact + CSS modules
|
|
16
43
|
|
|
17
44
|
```tsx
|
|
45
|
+
import { styled } from "classname-variants/preact";
|
|
46
|
+
import styles from "./styles.module.css";
|
|
47
|
+
|
|
48
|
+
const Button = styled("button", {
|
|
49
|
+
variants: {
|
|
50
|
+
size: {
|
|
51
|
+
small: styles.small,
|
|
52
|
+
large: styles.large,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Vanilla DOM
|
|
59
|
+
|
|
60
|
+
The core of the library is completely framework-agnostic:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { variants } from "classname-variants";
|
|
64
|
+
|
|
18
65
|
const button = variants({
|
|
19
66
|
base: "rounded text-white",
|
|
20
67
|
variants: {
|
|
@@ -22,50 +69,61 @@ const button = variants({
|
|
|
22
69
|
brand: "bg-sky-500",
|
|
23
70
|
accent: "bg-teal-500",
|
|
24
71
|
},
|
|
25
|
-
size: {
|
|
26
|
-
small: "px-5 py-3 text-xs",
|
|
27
|
-
large: "px-6 py-4 text-base",
|
|
28
|
-
},
|
|
29
72
|
},
|
|
30
73
|
});
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
The result is a function that expects an object which specifies what variants should be selected. When called, it returns a string containing the respective class names:
|
|
34
74
|
|
|
35
|
-
```ts
|
|
36
75
|
document.write(`
|
|
37
|
-
<button class="${button({
|
|
38
|
-
color: "accent",
|
|
39
|
-
size: "large",
|
|
40
|
-
})}">
|
|
76
|
+
<button class="${button({ color: "accent" })}">
|
|
41
77
|
Click Me!
|
|
42
78
|
</button>
|
|
43
79
|
`);
|
|
44
80
|
```
|
|
45
81
|
|
|
46
|
-
#
|
|
82
|
+
# API
|
|
47
83
|
|
|
48
|
-
|
|
84
|
+
### Defining variants
|
|
49
85
|
|
|
50
|
-
|
|
86
|
+
You can add any number of variants by using the `variants` key.
|
|
51
87
|
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
|
|
88
|
+
```ts
|
|
89
|
+
{
|
|
90
|
+
variants: {
|
|
91
|
+
color: {
|
|
92
|
+
primary: "bg-teal",
|
|
93
|
+
secondary: "bg-indigo",
|
|
94
|
+
danger: "bg-red"
|
|
95
|
+
},
|
|
96
|
+
size: {
|
|
97
|
+
small: "text-sm",
|
|
98
|
+
medium: "text-md",
|
|
99
|
+
large: "text-lg",
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Boolean variants
|
|
106
|
+
|
|
107
|
+
Variants can be typed as `boolean` by using `true` / `false` as key:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
{
|
|
55
111
|
variants: {
|
|
56
|
-
|
|
57
|
-
true: "
|
|
112
|
+
primary: {
|
|
113
|
+
true: "bg-teal-500",
|
|
58
114
|
},
|
|
59
115
|
},
|
|
60
|
-
}
|
|
116
|
+
}
|
|
61
117
|
```
|
|
62
118
|
|
|
63
|
-
|
|
119
|
+
```ts
|
|
120
|
+
<Button primary>Click Me!</Button>
|
|
121
|
+
```
|
|
64
122
|
|
|
65
|
-
The `compoundVariants` option can be used to apply class names based on a combination of other variants
|
|
123
|
+
The `compoundVariants` option can be used to apply class names based on a combination of other variants:
|
|
66
124
|
|
|
67
|
-
```
|
|
68
|
-
|
|
125
|
+
```ts
|
|
126
|
+
{
|
|
69
127
|
variants: {
|
|
70
128
|
color: {
|
|
71
129
|
neutral: "bg-gray-200",
|
|
@@ -84,128 +142,71 @@ const button = variants({
|
|
|
84
142
|
className: "border-teal-500",
|
|
85
143
|
},
|
|
86
144
|
],
|
|
87
|
-
}
|
|
145
|
+
}
|
|
88
146
|
```
|
|
89
147
|
|
|
90
|
-
|
|
148
|
+
### Default variants
|
|
91
149
|
|
|
92
|
-
|
|
150
|
+
If you define a variant it becomes a required prop unless you specify a default (or the variant is boolean). You can use the `defaultVariants` property to specify defaults:
|
|
93
151
|
|
|
94
152
|
```ts
|
|
95
|
-
|
|
153
|
+
{
|
|
96
154
|
variants: {
|
|
97
155
|
color: {
|
|
98
|
-
|
|
99
|
-
|
|
156
|
+
primary: "bg-teal-300",
|
|
157
|
+
secondary: "bg-teal-100"
|
|
100
158
|
},
|
|
101
159
|
},
|
|
102
160
|
defaultVariants: {
|
|
103
|
-
color: "
|
|
104
|
-
}
|
|
105
|
-
}
|
|
161
|
+
color: "secondary",
|
|
162
|
+
}
|
|
163
|
+
}
|
|
106
164
|
```
|
|
107
165
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
The library contains utility functions that are useful for writing React components.
|
|
166
|
+
### Base class
|
|
111
167
|
|
|
112
|
-
|
|
168
|
+
Use the `base` property to specify class names that should always be applied:
|
|
113
169
|
|
|
114
170
|
```ts
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const buttonProps = variantProps({
|
|
118
|
-
base: "rounded-md text-white",
|
|
171
|
+
{
|
|
172
|
+
base: "text-black rounded-full px-2",
|
|
119
173
|
variants: {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
accent: "bg-teal-500",
|
|
123
|
-
},
|
|
124
|
-
size: {
|
|
125
|
-
small: "px-5 py-3 text-xs",
|
|
126
|
-
large: "px-6 py-4 text-base",
|
|
127
|
-
},
|
|
128
|
-
rounded: {
|
|
129
|
-
true: "rounded-full",
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
defaultVariants: {
|
|
133
|
-
color: "brand",
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
This way a component's props (or part of them) can be directly spread into the target element. All variant-related props are used to construct the `className` property while all other props are passed through verbatim:
|
|
139
|
-
|
|
140
|
-
```tsx
|
|
141
|
-
type Props = JSX.IntrinsicElements["button"] &
|
|
142
|
-
VariantPropsOf<typeof buttonProps>;
|
|
143
|
-
|
|
144
|
-
function Button(props: Props) {
|
|
145
|
-
return <button {...buttonProps(props)} />;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function App() {
|
|
149
|
-
return (
|
|
150
|
-
<Button size="small" color="accent" onClick={console.log}>
|
|
151
|
-
Click Me!
|
|
152
|
-
</Button>
|
|
153
|
-
);
|
|
174
|
+
// ...
|
|
175
|
+
}
|
|
154
176
|
}
|
|
155
177
|
```
|
|
156
178
|
|
|
157
|
-
|
|
179
|
+
### Components without variants
|
|
158
180
|
|
|
159
|
-
|
|
181
|
+
Sometimes it can be useful to define styled components that
|
|
182
|
+
don't have any variants, which can be done like this:
|
|
160
183
|
|
|
161
|
-
```
|
|
162
|
-
import { styled
|
|
184
|
+
```tsx
|
|
185
|
+
import { styled } from "classname-variants/react";
|
|
163
186
|
|
|
164
|
-
const Button = styled("button",
|
|
165
|
-
variants: {
|
|
166
|
-
size: {
|
|
167
|
-
small: tw`text-xs`,
|
|
168
|
-
large: tw`text-base`,
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
});
|
|
187
|
+
const Button = styled("button", "bg-transparent border p-2");
|
|
172
188
|
```
|
|
173
189
|
|
|
174
|
-
|
|
190
|
+
### Styling custom components
|
|
175
191
|
|
|
176
|
-
|
|
177
|
-
import { styled } from "classname-variants/react";
|
|
178
|
-
import styles from "./styles.module.css";
|
|
192
|
+
You can style any custom React/Preact component as long as they accept a `className` prop (or `class` in case of Preact).
|
|
179
193
|
|
|
180
|
-
|
|
194
|
+
```tsx
|
|
195
|
+
function MyComponent(props) {
|
|
196
|
+
return <div {...props}>I'm a stylable custom component.</div>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const MyStyledComponent = styled(MyComponent, {
|
|
200
|
+
base: "some-class",
|
|
181
201
|
variants: {
|
|
182
|
-
|
|
183
|
-
small: styles.small,
|
|
184
|
-
large: styles.large,
|
|
185
|
-
},
|
|
202
|
+
// ...
|
|
186
203
|
},
|
|
187
204
|
});
|
|
188
205
|
```
|
|
189
206
|
|
|
190
|
-
|
|
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
|
-
```
|
|
205
|
-
|
|
206
|
-
## Polymorphic components with "as"
|
|
207
|
+
### Polymorphic components with "as"
|
|
207
208
|
|
|
208
|
-
If you want to keep all the variants you have defined for a component but want to render a different HTML tag or a different custom component, you can use the
|
|
209
|
+
If you want to keep all the variants you have defined for a component but want to render a different HTML tag or a different custom component, you can use the `as` prop to do so:
|
|
209
210
|
|
|
210
211
|
```tsx
|
|
211
212
|
import { styled } from "classname-variants/react";
|
|
@@ -215,17 +216,20 @@ const Button = styled("button", {
|
|
|
215
216
|
//...
|
|
216
217
|
},
|
|
217
218
|
});
|
|
219
|
+
```
|
|
218
220
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
221
|
+
The component can then be rendered as button or as anchor or even as custom component exposed by some router:
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
<>
|
|
225
|
+
<Button>I'm a button</Button>
|
|
226
|
+
<Button as="a" href="/">
|
|
227
|
+
I'm a link!
|
|
228
|
+
</Button>
|
|
229
|
+
<Button as={Link} to="/">
|
|
230
|
+
I'm a styled Link component
|
|
231
|
+
</Button>
|
|
232
|
+
</>
|
|
229
233
|
```
|
|
230
234
|
|
|
231
235
|
# Tailwind IntelliSense
|
package/index.html
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
|
-
<
|
|
14
|
-
<
|
|
13
|
+
<h1>React</h1>
|
|
14
|
+
<div id="react-root"></div>
|
|
15
|
+
<h1>Preact</h1>
|
|
16
|
+
<div id="preact-root"></div>
|
|
17
|
+
<script type="module" src="./src/example/index.ts"></script>
|
|
15
18
|
</body>
|
|
16
19
|
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createElement } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { render, h } from "preact";
|
|
4
|
+
import { ReactApp } from "./react";
|
|
5
|
+
import { PreactApp } from "./preact";
|
|
6
|
+
const root = createRoot(document.getElementById("react-root"));
|
|
7
|
+
root.render(createElement(ReactApp));
|
|
8
|
+
render(h(PreactApp, {}), document.getElementById("preact-root"));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
import { h } from "preact";
|
|
3
|
+
export declare const ExpectErrors: <As extends keyof h.JSX.IntrinsicElements | import("preact").ComponentType<any> = "div">(props: {
|
|
4
|
+
as?: As | undefined;
|
|
5
|
+
} & Omit<import("preact").ComponentProps<As>, "as" | "color"> & {
|
|
6
|
+
color: "neutral" | "accent";
|
|
7
|
+
} & {}) => import("preact").VNode<{}> | null;
|
|
8
|
+
export declare function WithErrors(): h.JSX.Element;
|
|
9
|
+
export declare function PreactApp(): h.JSX.Element;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
import { styled } from "../preact";
|
|
3
|
+
import { h } from "preact";
|
|
4
|
+
function CustomComponent({ title, ...props }) {
|
|
5
|
+
return h("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
|
+
size: {
|
|
17
|
+
small: "text-sm",
|
|
18
|
+
medium: "text-md",
|
|
19
|
+
},
|
|
20
|
+
outlined: {
|
|
21
|
+
true: "border-2",
|
|
22
|
+
},
|
|
23
|
+
rounded: {
|
|
24
|
+
true: "rounded-full",
|
|
25
|
+
false: "rounded-sm",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
compoundVariants: [
|
|
29
|
+
{
|
|
30
|
+
variants: { color: "accent", outlined: true },
|
|
31
|
+
className: "border-teal-600",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
color: "neutral",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
export const ExpectErrors = styled("div", {
|
|
39
|
+
variants: {
|
|
40
|
+
color: {
|
|
41
|
+
neutral: "grey",
|
|
42
|
+
accent: "hotpink",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
compoundVariants: [
|
|
46
|
+
{
|
|
47
|
+
//@ts-expect-error
|
|
48
|
+
variants: { outlined: true },
|
|
49
|
+
className: "",
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
defaultVariants: {
|
|
53
|
+
//@ts-expect-error
|
|
54
|
+
outlined: true,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
export function WithErrors() {
|
|
58
|
+
return (h("div", null,
|
|
59
|
+
h(Button, { foo: true, size: "medium" }, "unknown property"),
|
|
60
|
+
h(Card, { foo: true }, "Unknown property"),
|
|
61
|
+
h(Button, { size: "medium", color: "foo" }, "Invalid variant"),
|
|
62
|
+
h(Button, null, "Missing size")));
|
|
63
|
+
}
|
|
64
|
+
export function PreactApp() {
|
|
65
|
+
return (h("div", { className: "flex justify-center items-center pt-8 gap-4 flex-wrap" },
|
|
66
|
+
h(Button, { size: "medium", onClick: console.log }, "Accent"),
|
|
67
|
+
h(Button, { size: "medium", rounded: true }, "Neutral + Rounded"),
|
|
68
|
+
h(Button, { size: "medium", color: "accent", outlined: true }, "Accent + Outlined"),
|
|
69
|
+
h(Button, { size: "medium", color: "accent", disabled: true }, "Disabled"),
|
|
70
|
+
h(TitleCard, { title: "Hello" }),
|
|
71
|
+
h(Card, null,
|
|
72
|
+
h("h1", null, "Hello"),
|
|
73
|
+
h("p", null, "world")),
|
|
74
|
+
h(Card, { as: "a", href: "https://example.com" }, "Link"),
|
|
75
|
+
h(Card, { as: CustomComponent, title: "Test" })));
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export declare const ExpectErrors: <As extends React.ElementType<any> = "div">(props: {
|
|
3
|
+
as?: As | undefined;
|
|
4
|
+
} & Omit<React.ComponentProps<As>, "as" | "color"> & {
|
|
5
|
+
color: "neutral" | "accent";
|
|
6
|
+
} & {}) => React.ReactElement<any, string | React.JSXElementConstructor<any>> | null;
|
|
7
|
+
export declare function WithErrors(): JSX.Element;
|
|
8
|
+
export declare function ReactApp(): JSX.Element;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { styled } from "../react";
|
|
3
|
+
function CustomComponent({ title, ...props }) {
|
|
4
|
+
return React.createElement("div", { ...props }, title);
|
|
5
|
+
}
|
|
6
|
+
const Card = styled("div", "bg-white p-4 border-2 rounded-lg");
|
|
7
|
+
const TitleCard = styled(CustomComponent, "bg-white p-4 border-2 rounded-lg");
|
|
8
|
+
const Button = styled("button", {
|
|
9
|
+
base: "px-5 py-2 text-white disabled:bg-gray-400 disabled:text-gray-300",
|
|
10
|
+
variants: {
|
|
11
|
+
color: {
|
|
12
|
+
neutral: "bg-slate-500 hover:bg-slate-400",
|
|
13
|
+
accent: "bg-teal-500 hover:bg-teal-400",
|
|
14
|
+
},
|
|
15
|
+
size: {
|
|
16
|
+
small: "text-sm",
|
|
17
|
+
medium: "text-md",
|
|
18
|
+
},
|
|
19
|
+
outlined: {
|
|
20
|
+
true: "border-2",
|
|
21
|
+
},
|
|
22
|
+
rounded: {
|
|
23
|
+
true: "rounded-full",
|
|
24
|
+
false: "rounded-sm",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
compoundVariants: [
|
|
28
|
+
{
|
|
29
|
+
variants: { color: "accent", outlined: true },
|
|
30
|
+
className: "border-teal-600",
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
defaultVariants: {
|
|
34
|
+
color: "neutral",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
export const ExpectErrors = styled("div", {
|
|
38
|
+
variants: {
|
|
39
|
+
color: {
|
|
40
|
+
neutral: "grey",
|
|
41
|
+
accent: "hotpink",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
compoundVariants: [
|
|
45
|
+
{
|
|
46
|
+
//@ts-expect-error
|
|
47
|
+
variants: { outlined: true },
|
|
48
|
+
className: "",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
defaultVariants: {
|
|
52
|
+
//@ts-expect-error
|
|
53
|
+
outlined: true,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
export function WithErrors() {
|
|
57
|
+
return (React.createElement("div", null,
|
|
58
|
+
React.createElement(Button, { foo: true, size: "medium" }, "unknown property"),
|
|
59
|
+
React.createElement(Card, { foo: true }, "Unknown property"),
|
|
60
|
+
React.createElement(Button, { size: "medium", color: "foo" }, "Invalid variant"),
|
|
61
|
+
React.createElement(Button, null, "Missing size"),
|
|
62
|
+
React.createElement(Card, { as: "b", href: "https://example.com" }, "B tags don't have a href attribute")));
|
|
63
|
+
}
|
|
64
|
+
export function ReactApp() {
|
|
65
|
+
return (React.createElement("div", { className: "flex justify-center items-center pt-8 gap-4 flex-wrap" },
|
|
66
|
+
React.createElement(Button, { size: "medium", onClick: console.log }, "Accent"),
|
|
67
|
+
React.createElement(Button, { size: "medium", rounded: true }, "Neutral + Rounded"),
|
|
68
|
+
React.createElement(Button, { size: "medium", color: "accent", outlined: true }, "Accent + Outlined"),
|
|
69
|
+
React.createElement(Button, { size: "medium", color: "accent", disabled: true }, "Disabled"),
|
|
70
|
+
React.createElement(TitleCard, { title: "Hello" }),
|
|
71
|
+
React.createElement(Card, null,
|
|
72
|
+
React.createElement("h1", null, "Hello"),
|
|
73
|
+
React.createElement("p", null, "world")),
|
|
74
|
+
React.createElement(Card, { as: "a", href: "https://example.com" }, "Link"),
|
|
75
|
+
React.createElement(Card, { as: CustomComponent, title: "Test" })));
|
|
76
|
+
}
|
package/lib/preact.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { JSX, ComponentType, ComponentProps, VNode } from "preact";
|
|
2
|
+
type ElementType<P = any> = keyof JSX.IntrinsicElements | ComponentType<P>;
|
|
3
|
+
import { Variants, VariantsConfig, VariantOptions, Simplify } from "./index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Utility type to infer the first argument of a variantProps function.
|
|
6
|
+
*/
|
|
7
|
+
export type VariantPropsOf<T> = T extends (props: infer P) => any ? P : never;
|
|
8
|
+
/**
|
|
9
|
+
* Type for the variantProps() argument â consists of the VariantOptions and an optional className for chaining.
|
|
10
|
+
*/
|
|
11
|
+
type VariantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]> = VariantOptions<C> & {
|
|
12
|
+
class?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function variantProps<C extends VariantsConfig<V>, V extends Variants = C["variants"]>(config: Simplify<C>): <P extends VariantProps<C, C["variants"]>>(props: P) => {
|
|
16
|
+
class: string;
|
|
17
|
+
} & Omit<P, keyof C["variants"]>;
|
|
18
|
+
type VariantsOf<T, V> = T extends VariantsConfig ? V : {};
|
|
19
|
+
type AsProps<T extends ElementType = ElementType> = {
|
|
20
|
+
as?: T;
|
|
21
|
+
};
|
|
22
|
+
type PolymorphicComponentProps<V, T extends ElementType> = AsProps<T> & Omit<ComponentProps<T>, "as" | keyof V> & V;
|
|
23
|
+
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: PolymorphicComponentProps<VariantOptions<C, C["variants"]>, As>) => VNode | null;
|
|
24
|
+
/**
|
|
25
|
+
* No-op function to mark template literals as tailwind strings.
|
|
26
|
+
*/
|
|
27
|
+
export declare const tw: (template: {
|
|
28
|
+
raw: readonly string[] | ArrayLike<string>;
|
|
29
|
+
}, ...substitutions: any[]) => string;
|
|
30
|
+
export {};
|
package/lib/preact.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { h } from "preact";
|
|
2
|
+
import { forwardRef } from "preact/compat";
|
|
3
|
+
import { variants, } from "./index.js";
|
|
4
|
+
export function variantProps(config) {
|
|
5
|
+
const variantClassName = variants(config);
|
|
6
|
+
return (props) => {
|
|
7
|
+
const result = {};
|
|
8
|
+
// Pass-through all unrelated props
|
|
9
|
+
for (let prop in props) {
|
|
10
|
+
if (config.variants && !(prop in config.variants)) {
|
|
11
|
+
result[prop] = props[prop];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// Add the optionally passed class/className prop for chaining
|
|
15
|
+
result.class = [variantClassName(props), props.class, props.className]
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.join(" ");
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function styled(type, config) {
|
|
22
|
+
const styledProps = typeof config === "string"
|
|
23
|
+
? variantProps({ base: config, variants: {} })
|
|
24
|
+
: variantProps(config);
|
|
25
|
+
const Component = forwardRef(({ as, ...props }, ref) => {
|
|
26
|
+
return h(as !== null && as !== void 0 ? as : type, { ...styledProps(props), ref });
|
|
27
|
+
});
|
|
28
|
+
return Component;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* No-op function to mark template literals as tailwind strings.
|
|
32
|
+
*/
|
|
33
|
+
export const tw = String.raw;
|
package/lib/react.d.ts
CHANGED
|
@@ -17,16 +17,8 @@ type VariantsOf<T, V> = T extends VariantsConfig ? V : {};
|
|
|
17
17
|
type AsProps<T extends ElementType = ElementType> = {
|
|
18
18
|
as?: T;
|
|
19
19
|
};
|
|
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:
|
|
22
|
-
true: any;
|
|
23
|
-
} | {
|
|
24
|
-
false: any;
|
|
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
|
-
true: any;
|
|
27
|
-
} | {
|
|
28
|
-
false: any;
|
|
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;
|
|
20
|
+
type PolymorphicComponentProps<V, T extends ElementType> = AsProps<T> & Omit<ComponentProps<T>, "as" | keyof V> & V;
|
|
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: PolymorphicComponentProps<VariantOptions<C, C["variants"]>, As>) => ReactElement | null;
|
|
30
22
|
/**
|
|
31
23
|
* No-op function to mark template literals as tailwind strings.
|
|
32
24
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "classname-variants",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Variant API for plain class names",
|
|
5
5
|
"author": "Felix Gnass <fgnass@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
"./react": {
|
|
17
17
|
"import": "./lib/react.js",
|
|
18
18
|
"type": "./lib/react.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./preact": {
|
|
21
|
+
"import": "./lib/preact.js",
|
|
22
|
+
"type": "./lib/preact.d.ts"
|
|
19
23
|
}
|
|
20
24
|
},
|
|
21
25
|
"typesVersions": {
|
|
@@ -25,6 +29,9 @@
|
|
|
25
29
|
],
|
|
26
30
|
"react": [
|
|
27
31
|
"./lib/react.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"preact": [
|
|
34
|
+
"./lib/preact.d.ts"
|
|
28
35
|
]
|
|
29
36
|
}
|
|
30
37
|
},
|
|
@@ -38,11 +45,13 @@
|
|
|
38
45
|
"css",
|
|
39
46
|
"classname",
|
|
40
47
|
"variants",
|
|
41
|
-
"react"
|
|
48
|
+
"react",
|
|
49
|
+
"preact"
|
|
42
50
|
],
|
|
43
51
|
"devDependencies": {
|
|
44
52
|
"@types/react": "^18.0.26",
|
|
45
53
|
"@types/react-dom": "^18.0.9",
|
|
54
|
+
"preact": "^10.20.2",
|
|
46
55
|
"react": "^18.2.0",
|
|
47
56
|
"react-dom": "^18.2.0",
|
|
48
57
|
"typescript": "^4.9.4"
|