classname-variants 1.0.2 → 1.2.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/README.md +21 -2
- package/example.tsx +13 -0
- package/lib/react.d.ts +15 -6
- package/lib/react.js +11 -5
- package/package.json +3 -2
- package/src/react.ts +35 -16
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Stitches-like [variant API](https://stitches.dev/docs/variants) for plain class
|
|
|
4
4
|
|
|
5
5
|
The library is framework agnostic and can be used with any kind of CSS flavor.
|
|
6
6
|
|
|
7
|
-
It is especially useful though if used with [Tailwind](https://tailwindcss.com/)
|
|
7
|
+
It is especially useful though if used with [Tailwind](https://tailwindcss.com/) or [CSS Modules](https://github.com/css-modules/css-modules) in cobmination 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
|
|
|
9
9
|
[](https://codesandbox.io/s/classname-variants-react-3bzjl?fontsize=14&hidenavigation=1&theme=dark)
|
|
10
10
|
|
|
@@ -138,7 +138,8 @@ const buttonProps = variantProps({
|
|
|
138
138
|
This way a compontents' 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
139
|
|
|
140
140
|
```tsx
|
|
141
|
-
type Props = SX.IntrinsicElements["button"] &
|
|
141
|
+
type Props = SX.IntrinsicElements["button"] &
|
|
142
|
+
VariantPropsOf<typeof buttonProps>;
|
|
142
143
|
|
|
143
144
|
function Button(props: Props) {
|
|
144
145
|
return <button {...buttonProps(props)} />;
|
|
@@ -170,6 +171,24 @@ const Button = styled("button", {
|
|
|
170
171
|
});
|
|
171
172
|
```
|
|
172
173
|
|
|
174
|
+
The same can be done with CSS modules:
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
import { styled } from "classname-variants/react";
|
|
178
|
+
import styles from "./styles.module.css";
|
|
179
|
+
|
|
180
|
+
const Button = styled("button", {
|
|
181
|
+
variants: {
|
|
182
|
+
size: {
|
|
183
|
+
small: styles.small,
|
|
184
|
+
large: styles.large,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
You can also style other custom React components as long as the accept a `className` prop.
|
|
191
|
+
|
|
173
192
|
# Tailwind IntelliSense
|
|
174
193
|
|
|
175
194
|
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.
|
package/example.tsx
CHANGED
|
@@ -2,6 +2,18 @@ import React from "react";
|
|
|
2
2
|
import ReactDOM from "react-dom";
|
|
3
3
|
import { styled } from "./src/react";
|
|
4
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(CustomComponent, "bg-white p-4 border-2 rounded-lg");
|
|
16
|
+
|
|
5
17
|
const Button = styled("button", {
|
|
6
18
|
base: "px-5 py-2 text-white disabled:bg-gray-400 disabled:text-gray-300",
|
|
7
19
|
variants: {
|
|
@@ -39,6 +51,7 @@ function App() {
|
|
|
39
51
|
<Button color="accent" disabled>
|
|
40
52
|
Disabled
|
|
41
53
|
</Button>
|
|
54
|
+
<Card title="Hello" />
|
|
42
55
|
</div>
|
|
43
56
|
);
|
|
44
57
|
}
|
package/lib/react.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { ComponentProps, ElementType, ForwardRefExoticComponent, PropsWithoutRef } from "react";
|
|
2
|
-
import { Variants, VariantsConfig, VariantOptions, Simplify } from ".";
|
|
3
|
-
|
|
4
|
-
|
|
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) => {
|
|
5
14
|
className: string;
|
|
6
|
-
} & Omit<
|
|
7
|
-
declare type StyledComponent<
|
|
8
|
-
export declare function styled<
|
|
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
|
+
export declare function styled<T extends ElementType, C extends VariantsConfig<V>, V extends Variants = C["variants"]>(type: T, config: string | Simplify<C>): StyledComponent<T, C>;
|
|
9
18
|
export {};
|
package/lib/react.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { createElement, forwardRef, } from "react";
|
|
2
|
-
import { variants, } from ".";
|
|
2
|
+
import { variants, } from "./index.js";
|
|
3
3
|
export function variantProps(config) {
|
|
4
|
-
const
|
|
4
|
+
const variantClassName = variants(config);
|
|
5
5
|
return (props) => {
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const result = {};
|
|
7
|
+
// Pass-through all unrelated props
|
|
8
8
|
for (let prop in props) {
|
|
9
9
|
if (config.variants && !(prop in config.variants)) {
|
|
10
10
|
result[prop] = props[prop];
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
// Add the optionally passed className prop for chaining
|
|
14
|
+
result.className = [props.className, variantClassName(props)]
|
|
15
|
+
.filter(Boolean)
|
|
16
|
+
.join(" ");
|
|
13
17
|
return result;
|
|
14
18
|
};
|
|
15
19
|
}
|
|
16
20
|
export function styled(type, config) {
|
|
17
|
-
const styledProps =
|
|
21
|
+
const styledProps = typeof config === "string"
|
|
22
|
+
? variantProps({ base: config, variants: {} })
|
|
23
|
+
: variantProps(config);
|
|
18
24
|
return forwardRef((props, ref) => createElement(type, { ...styledProps(props), ref }));
|
|
19
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "classname-variants",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Variant API for plain class names",
|
|
5
5
|
"author": "Felix Gnass <fgnass@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "tsc",
|
|
33
|
-
"start": "npx vite"
|
|
33
|
+
"start": "npx vite",
|
|
34
|
+
"prepublishOnly": "npm run build"
|
|
34
35
|
},
|
|
35
36
|
"keywords": [
|
|
36
37
|
"tailwind",
|
package/src/react.ts
CHANGED
|
@@ -13,45 +13,64 @@ import {
|
|
|
13
13
|
VariantsConfig,
|
|
14
14
|
VariantOptions,
|
|
15
15
|
Simplify,
|
|
16
|
-
} from ".";
|
|
16
|
+
} from "./index.js";
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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 };
|
|
21
30
|
|
|
22
31
|
export function variantProps<
|
|
23
32
|
C extends VariantsConfig<V>,
|
|
24
33
|
V extends Variants = C["variants"]
|
|
25
34
|
>(config: Simplify<C>) {
|
|
26
|
-
const
|
|
27
|
-
return <
|
|
28
|
-
const
|
|
29
|
-
|
|
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
|
|
30
40
|
for (let prop in props) {
|
|
31
41
|
if (config.variants && !(prop in config.variants)) {
|
|
32
42
|
result[prop] = props[prop];
|
|
33
43
|
}
|
|
34
44
|
}
|
|
35
|
-
|
|
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"]>;
|
|
36
52
|
};
|
|
37
53
|
}
|
|
38
54
|
|
|
39
55
|
type StyledComponent<
|
|
40
|
-
|
|
56
|
+
T extends ElementType,
|
|
41
57
|
C extends VariantsConfig<V>,
|
|
42
58
|
V extends Variants = C["variants"]
|
|
43
59
|
> = ForwardRefExoticComponent<
|
|
44
|
-
PropsWithoutRef<ComponentProps<
|
|
45
|
-
React.RefAttributes<
|
|
60
|
+
PropsWithoutRef<ComponentProps<T> & VariantOptions<C>> &
|
|
61
|
+
React.RefAttributes<T>
|
|
46
62
|
>;
|
|
47
63
|
|
|
48
64
|
export function styled<
|
|
49
|
-
|
|
65
|
+
T extends ElementType,
|
|
50
66
|
C extends VariantsConfig<V>,
|
|
51
67
|
V extends Variants = C["variants"]
|
|
52
|
-
>(type:
|
|
53
|
-
const styledProps =
|
|
54
|
-
|
|
68
|
+
>(type: T, config: string | Simplify<C>): StyledComponent<T, C> {
|
|
69
|
+
const styledProps =
|
|
70
|
+
typeof config === "string"
|
|
71
|
+
? variantProps({ base: config, variants: {} })
|
|
72
|
+
: variantProps(config);
|
|
73
|
+
return forwardRef<T, ComponentProps<T> & VariantOptions<C>>((props, ref) =>
|
|
55
74
|
createElement(type, { ...styledProps(props), ref })
|
|
56
75
|
);
|
|
57
76
|
}
|