classname-variants 1.2.1 → 1.3.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 +34 -8
- package/example.tsx +3 -0
- package/lib/react.d.ts +14 -3
- package/lib/react.js +4 -1
- package/package.json +1 -1
- package/src/react.ts +18 -14
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@ 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/) or [CSS Modules](https://github.com/css-modules/css-modules) in
|
|
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
|
|
|
9
9
|
[](https://codesandbox.io/s/classname-variants-react-3bzjl?fontsize=14&hidenavigation=1&theme=dark)
|
|
10
10
|
|
|
11
11
|
# Basics
|
|
12
12
|
|
|
13
|
-
Let's
|
|
13
|
+
Let's assume we want to build a button component with Tailwind CSS that comes in different sizes and colors.
|
|
14
14
|
|
|
15
15
|
It consists of some _base classes_ that are always present as well as some optional classes that need to be added depending on the desired _variants_.
|
|
16
16
|
|
|
@@ -135,10 +135,10 @@ const buttonProps = variantProps({
|
|
|
135
135
|
});
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
This way a
|
|
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
139
|
|
|
140
140
|
```tsx
|
|
141
|
-
type Props =
|
|
141
|
+
type Props = JSX.IntrinsicElements["button"] &
|
|
142
142
|
VariantPropsOf<typeof buttonProps>;
|
|
143
143
|
|
|
144
144
|
function Button(props: Props) {
|
|
@@ -154,9 +154,9 @@ function App() {
|
|
|
154
154
|
}
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
# Bonus: styled-components, but
|
|
157
|
+
# Bonus: styled-components, but for static CSS 💅
|
|
158
158
|
|
|
159
|
-
Things can be taken even a step further, resulting in a _styled-components_ like way of defining reusable components:
|
|
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
161
|
```tsx
|
|
162
162
|
import { styled } from "classname-variants/react";
|
|
@@ -171,7 +171,7 @@ const Button = styled("button", {
|
|
|
171
171
|
});
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
Again, this is not limited to tailwind, so you could do the same with CSS modules:
|
|
175
175
|
|
|
176
176
|
```tsx
|
|
177
177
|
import { styled } from "classname-variants/react";
|
|
@@ -187,7 +187,33 @@ const Button = styled("button", {
|
|
|
187
187
|
});
|
|
188
188
|
```
|
|
189
189
|
|
|
190
|
-
You can also style other custom React components as long as
|
|
190
|
+
**NOTE:** You can also style other custom React components as long as they accept a `className` prop.
|
|
191
|
+
|
|
192
|
+
## Polymorphic components with "as"
|
|
193
|
+
|
|
194
|
+
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:
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { styled } from "classname-variants/react";
|
|
198
|
+
import styles from "./styles.module.css";
|
|
199
|
+
|
|
200
|
+
const Button = styled("button", {
|
|
201
|
+
variants: {
|
|
202
|
+
//...
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
function App() {
|
|
207
|
+
return (
|
|
208
|
+
<div>
|
|
209
|
+
<Button>I'm a button</Button>
|
|
210
|
+
<Button as="a" href="/">
|
|
211
|
+
I'm a link!
|
|
212
|
+
</Button>
|
|
213
|
+
</div>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
191
217
|
|
|
192
218
|
# Tailwind IntelliSense
|
|
193
219
|
|
package/example.tsx
CHANGED
package/lib/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentProps, ElementType,
|
|
1
|
+
import { ComponentProps, ElementType, ReactElement } from "react";
|
|
2
2
|
import { Variants, VariantsConfig, VariantOptions, Simplify } from "./index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Utility type to infer the first argument of a variantProps function.
|
|
@@ -13,7 +13,18 @@ declare type VariantProps<C extends VariantsConfig<V>, V extends Variants = C["v
|
|
|
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
|
-
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
16
|
declare type VariantsOf<T> = T extends VariantsConfig<infer V> ? V : {};
|
|
18
|
-
|
|
17
|
+
declare type AsProps<T extends ElementType = ElementType> = {
|
|
18
|
+
as?: T;
|
|
19
|
+
};
|
|
20
|
+
declare 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>>(type: T, config: string | Simplify<C>): <As extends ElementType<any> = T>(props: AsProps<As> & Omit<ComponentProps<As>, "as"> & { [K in keyof C["variants"] as K extends keyof { [K_1 in keyof C["variants"] as C["variants"][K_1] extends {
|
|
22
|
+
true: any;
|
|
23
|
+
} | {
|
|
24
|
+
false: any;
|
|
25
|
+
} ? K_1 : never]: C["variants"][K_1]; } | keyof { [K_2 in keyof C["variants"] as K_2 extends keyof C["defaultVariants"] ? K_2 : never]: C["variants"][K_2]; } ? never : K]: { [K_3 in keyof C["variants"]]: keyof C["variants"][K_3] extends "true" | "false" ? boolean : keyof C["variants"][K_3]; }[K]; } & { [K_4 in keyof C["variants"] as K_4 extends keyof { [K_1 in keyof C["variants"] as C["variants"][K_1] extends {
|
|
26
|
+
true: any;
|
|
27
|
+
} | {
|
|
28
|
+
false: any;
|
|
29
|
+
} ? K_1 : never]: C["variants"][K_1]; } | keyof { [K_2 in keyof C["variants"] as K_2 extends keyof C["defaultVariants"] ? K_2 : never]: C["variants"][K_2]; } ? K_4 : never]?: { [K_3 in keyof C["variants"]]: keyof C["variants"][K_3] extends "true" | "false" ? boolean : keyof C["variants"][K_3]; }[K_4] | undefined; }) => ReactElement | null;
|
|
19
30
|
export {};
|
package/lib/react.js
CHANGED
|
@@ -21,5 +21,8 @@ export function styled(type, config) {
|
|
|
21
21
|
const styledProps = typeof config === "string"
|
|
22
22
|
? variantProps({ base: config, variants: {} })
|
|
23
23
|
: variantProps(config);
|
|
24
|
-
|
|
24
|
+
const Component = forwardRef(({ as, ...props }, ref) => {
|
|
25
|
+
return createElement(as !== null && as !== void 0 ? as : type, { ...styledProps(props), ref });
|
|
26
|
+
});
|
|
27
|
+
return Component;
|
|
25
28
|
}
|
package/package.json
CHANGED
package/src/react.ts
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
createElement,
|
|
4
4
|
ElementType,
|
|
5
5
|
forwardRef,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
ReactElement,
|
|
7
|
+
Ref,
|
|
8
8
|
} from "react";
|
|
9
9
|
|
|
10
10
|
import {
|
|
@@ -52,27 +52,31 @@ export function variantProps<
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
type StyledComponent<
|
|
56
|
-
T extends ElementType,
|
|
57
|
-
C extends VariantsConfig<V>,
|
|
58
|
-
V extends Variants = C["variants"]
|
|
59
|
-
> = ForwardRefExoticComponent<
|
|
60
|
-
PropsWithoutRef<ComponentProps<T> & VariantOptions<C>> &
|
|
61
|
-
React.RefAttributes<T>
|
|
62
|
-
>;
|
|
63
|
-
|
|
64
55
|
type VariantsOf<T> = T extends VariantsConfig<infer V> ? V : {};
|
|
65
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
|
+
|
|
66
64
|
export function styled<
|
|
67
65
|
T extends ElementType,
|
|
68
66
|
C extends VariantsConfig<V>,
|
|
69
67
|
V extends Variants = VariantsOf<C>
|
|
70
|
-
>(type: T, config: string | Simplify<C>)
|
|
68
|
+
>(type: T, config: string | Simplify<C>) {
|
|
71
69
|
const styledProps =
|
|
72
70
|
typeof config === "string"
|
|
73
71
|
? variantProps({ base: config, variants: {} })
|
|
74
72
|
: variantProps(config);
|
|
75
|
-
|
|
76
|
-
|
|
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
|
+
}
|
|
77
80
|
);
|
|
81
|
+
return Component;
|
|
78
82
|
}
|