css-variants 2.0.6 â 2.0.8
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 +231 -338
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-

|
|
2
|
-
|
|
3
1
|
[](https://github.com/timphandev/css-variants/actions/workflows/ci.yml)
|
|
4
2
|
[](https://github.com/timphandev/css-variants/blob/main/LICENSE)
|
|
5
3
|
[](https://npmjs.com/package/css-variants)
|
|
@@ -7,470 +5,365 @@
|
|
|
7
5
|
|
|
8
6
|
# css-variants
|
|
9
7
|
|
|
10
|
-
A lightweight, flexible API for managing CSS class variants in JavaScript and TypeScript projects.
|
|
8
|
+
A lightweight, flexible API for managing CSS class variants and inline styles in JavaScript and TypeScript projects.
|
|
11
9
|
|
|
12
10
|
## Features
|
|
13
11
|
|
|
14
|
-
- ðĻ Dynamic class name generation
|
|
15
|
-
-
|
|
16
|
-
- ð§Đ
|
|
12
|
+
- ðĻ Dynamic class name generation with variant support
|
|
13
|
+
- ð
First-class inline styles support alongside class names
|
|
14
|
+
- ð§Đ Powerful slot-based variant system for complex components
|
|
17
15
|
- ðĶ Zero dependencies
|
|
18
16
|
- ð Fully type-safe with TypeScript
|
|
19
17
|
- ð Framework-agnostic
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`css-variants` provides a simple yet powerful way to handle dynamic class names and inline styles based on component props or state. It's designed to work seamlessly with modern JavaScript frameworks and CSS methodologies, offering a type-safe approach to styling your UI components.
|
|
24
|
-
|
|
25
|
-
`css-variants` is heavily inspired by the following excellent packages:
|
|
26
|
-
|
|
27
|
-
- [CVA (Class Variance Authority)](https://github.com/joe-bell/cva): A powerful utility for creating dynamic class names with variants.
|
|
28
|
-
- [Tailwind Variants](https://github.com/nextui-org/tailwind-variants): A flexible and reusable variant system for Tailwind CSS.
|
|
29
|
-
- [Panda CSS](https://github.com/chakra-ui/panda): A CSS-in-JS solution with a focus on developer experience and performance.
|
|
30
|
-
|
|
31
|
-
Thank you to the authors and contributors of these projects for their innovative work.
|
|
32
|
-
|
|
33
|
-
## Table of Contents
|
|
34
|
-
* [Installation](#installation)
|
|
35
|
-
* [Variants](#variants)
|
|
36
|
-
* [Adding variants](#adding-variants)
|
|
37
|
-
* [Multiple variants](#multiple-variants)
|
|
38
|
-
* [Boolean variants](#boolean-variants)
|
|
39
|
-
* [Compound variants](#compound-variants)
|
|
40
|
-
* [Default variants](#default-variants)
|
|
41
|
-
* [Slots](#events)
|
|
42
|
-
* [Basic Usage](#basic-usage)
|
|
43
|
-
* [Slots with variants](#slots-with-variants)
|
|
44
|
-
* [Overriding styles](#overriding-styles)
|
|
45
|
-
* [Overriding styles on a single component](#overriding-styles-on-a-single-component)
|
|
46
|
-
* [Overriding styles on a component with slots](#overriding-styles-on-a-component-with-slots)
|
|
47
|
-
* [Custom function to resolve class names](#custom-function-to-resolve-class-names)
|
|
48
|
-
* [TypeScript](#typeScript)
|
|
49
|
-
* [Contribute](#contribute)
|
|
50
|
-
* [License](#license)
|
|
51
|
-
|
|
18
|
+
- ðŠķ Lightweight (~2KB gzipped)
|
|
19
|
+
- ðĨ Strong tree-shaking support
|
|
20
|
+
- âĄïļ Optimal runtime performance
|
|
52
21
|
|
|
53
22
|
## Installation
|
|
54
23
|
|
|
55
|
-
|
|
24
|
+
```bash
|
|
25
|
+
# npm
|
|
26
|
+
npm install css-variants
|
|
56
27
|
|
|
57
|
-
|
|
28
|
+
# yarn
|
|
58
29
|
yarn add css-variants
|
|
30
|
+
|
|
31
|
+
# pnpm
|
|
32
|
+
pnpm add css-variants
|
|
59
33
|
```
|
|
60
34
|
|
|
61
|
-
##
|
|
35
|
+
## Core Utilities
|
|
62
36
|
|
|
63
|
-
|
|
37
|
+
css-variants provides four main utilities:
|
|
64
38
|
|
|
65
|
-
|
|
39
|
+
- [cv](#class-variants-cv) - Class Variants for managing single component class names
|
|
40
|
+
- [sv](#style-variants-sv) - Style Variants for managing single component inline styles
|
|
41
|
+
- [scv](#slot-class-variants-scv) - Slot Class Variants for managing multiple slot class names
|
|
42
|
+
- [ssv](#slot-style-variants-ssv) - Slot Style Variants for managing multiple slot inline styles
|
|
43
|
+
- [cx](#class-merger-cx) - Utility for composing class names conditionally.
|
|
66
44
|
|
|
67
|
-
|
|
45
|
+
### Class Variants ([cv](./src/cv.ts))
|
|
46
|
+
For managing class names for a single component:
|
|
68
47
|
|
|
69
48
|
```ts
|
|
70
49
|
import { cv } from 'css-variants'
|
|
71
|
-
|
|
50
|
+
|
|
72
51
|
const button = cv({
|
|
73
|
-
base: 'font-bold rounded-
|
|
52
|
+
base: 'font-bold rounded-lg',
|
|
74
53
|
variants: {
|
|
75
54
|
color: {
|
|
76
|
-
primary: 'bg-blue-500
|
|
77
|
-
secondary: 'bg-
|
|
78
|
-
success: 'hover:bg-green-700',
|
|
55
|
+
primary: 'bg-blue-500 text-white',
|
|
56
|
+
secondary: 'bg-gray-500 text-white'
|
|
79
57
|
},
|
|
58
|
+
size: {
|
|
59
|
+
sm: 'text-sm px-2 py-1',
|
|
60
|
+
lg: 'text-lg px-4 py-2'
|
|
61
|
+
}
|
|
80
62
|
},
|
|
63
|
+
compoundVariants: [
|
|
64
|
+
{
|
|
65
|
+
color: 'primary',
|
|
66
|
+
size: 'lg',
|
|
67
|
+
className: 'uppercase'
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
defaultVariants: {
|
|
71
|
+
color: 'primary',
|
|
72
|
+
size: 'sm'
|
|
73
|
+
}
|
|
81
74
|
})
|
|
82
75
|
|
|
83
|
-
|
|
84
|
-
// => 'font-bold rounded-
|
|
76
|
+
// Usage
|
|
77
|
+
button() // => 'font-bold rounded-lg bg-blue-500 text-white text-sm px-2 py-1'
|
|
78
|
+
|
|
79
|
+
button({ size: 'lg' }) // => 'font-bold rounded-lg bg-blue-500 text-white text-lg px-4 py-2 uppercase'
|
|
80
|
+
|
|
81
|
+
button({ size: 'lg', className: 'custom' }) // => 'font-bold rounded-lg bg-blue-500 text-white text-lg px-4 py-2 uppercase custom'
|
|
85
82
|
```
|
|
86
83
|
|
|
84
|
+
### Style Variants ([sv](./src/sv.ts))
|
|
85
|
+
|
|
86
|
+
For managing inline styles:
|
|
87
|
+
|
|
87
88
|
```ts
|
|
88
89
|
import { sv } from 'css-variants'
|
|
89
|
-
|
|
90
|
+
|
|
90
91
|
const button = sv({
|
|
91
92
|
base: {
|
|
92
|
-
fontWeight:
|
|
93
|
+
fontWeight: 'bold',
|
|
94
|
+
borderRadius: '8px'
|
|
93
95
|
},
|
|
94
96
|
variants: {
|
|
95
97
|
color: {
|
|
96
98
|
primary: {
|
|
97
|
-
|
|
99
|
+
backgroundColor: 'blue',
|
|
100
|
+
color: 'white'
|
|
98
101
|
},
|
|
99
102
|
secondary: {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
},
|
|
106
|
-
},
|
|
103
|
+
backgroundColor: 'gray',
|
|
104
|
+
color: 'white'
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
107
108
|
})
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
// Usage
|
|
111
|
+
button({ color: 'primary' })
|
|
112
|
+
// => { fontWeight: 'bold', borderRadius: '8px', backgroundColor: 'blue', color: 'white' }
|
|
113
|
+
|
|
114
|
+
button({
|
|
115
|
+
color: 'secondary',
|
|
116
|
+
style: { padding: '4px' },
|
|
117
|
+
})
|
|
118
|
+
// => { fontWeight: 'bold', borderRadius: '8px', backgroundColor: 'gray', color: 'white', padding: '4px' }
|
|
111
119
|
```
|
|
112
120
|
|
|
113
|
-
###
|
|
121
|
+
### Slot Class Variants ([scv](./src/scv.ts))
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
For managing class names across multiple slots/elements:
|
|
116
124
|
|
|
117
125
|
```ts
|
|
118
|
-
import {
|
|
126
|
+
import { scv } from 'css-variants'
|
|
119
127
|
|
|
120
|
-
const
|
|
121
|
-
|
|
128
|
+
const card = scv({
|
|
129
|
+
slots: ['root', 'title', 'content'],
|
|
130
|
+
base: {
|
|
131
|
+
root: 'rounded-lg shadow',
|
|
132
|
+
title: 'text-xl font-bold',
|
|
133
|
+
content: 'mt-2'
|
|
134
|
+
},
|
|
122
135
|
variants: {
|
|
123
|
-
color: {
|
|
124
|
-
primary: 'bg-blue-500 hover:bg-blue-700',
|
|
125
|
-
secondary: 'bg-purple-500 hover:bg-purple-700',
|
|
126
|
-
success: 'bg-green-500 hover:bg-green-700'
|
|
127
|
-
},
|
|
128
136
|
size: {
|
|
129
|
-
sm:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
sm: {
|
|
138
|
+
root: 'p-4',
|
|
139
|
+
title: 'text-base'
|
|
140
|
+
},
|
|
141
|
+
lg: {
|
|
142
|
+
root: 'p-6',
|
|
143
|
+
title: 'text-2xl'
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
134
147
|
})
|
|
135
148
|
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
// Usage
|
|
150
|
+
card({ size: 'sm' })
|
|
151
|
+
// => {
|
|
152
|
+
// root: 'rounded-lg shadow p-4',
|
|
153
|
+
// title: 'text-xl font-bold text-base',
|
|
154
|
+
// content: 'mt-2'
|
|
155
|
+
// }
|
|
156
|
+
|
|
157
|
+
card({
|
|
158
|
+
size: 'lg',
|
|
159
|
+
classNames: {
|
|
160
|
+
content: 'custom',
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
// => {
|
|
164
|
+
// root: 'rounded-lg shadow p-6',
|
|
165
|
+
// title: 'text-xl font-bold text-2xl',
|
|
166
|
+
// content: 'mt-2 custom'
|
|
167
|
+
// }
|
|
138
168
|
```
|
|
139
169
|
|
|
170
|
+
### Slot Style Variants ([ssv](./src/ssv.ts))
|
|
171
|
+
|
|
172
|
+
For managing inline styles across multiple slots:
|
|
173
|
+
|
|
140
174
|
```ts
|
|
141
|
-
import {
|
|
175
|
+
import { ssv } from 'css-variants'
|
|
142
176
|
|
|
143
|
-
const
|
|
177
|
+
const card = ssv({
|
|
178
|
+
slots: ['root', 'title'],
|
|
144
179
|
base: {
|
|
145
|
-
|
|
180
|
+
root: { padding: '1rem' },
|
|
181
|
+
title: { fontWeight: 'bold' }
|
|
146
182
|
},
|
|
147
183
|
variants: {
|
|
148
184
|
size: {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
185
|
+
sm: {
|
|
186
|
+
root: { maxWidth: '300px' },
|
|
187
|
+
title: { fontSize: '14px' }
|
|
188
|
+
},
|
|
189
|
+
lg: {
|
|
190
|
+
root: { maxWidth: '600px' },
|
|
191
|
+
title: { fontSize: '18px' }
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
157
195
|
})
|
|
158
196
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
You can also add boolean variants to a component. This is useful when you want to add a state variant e.g. `disabled`.
|
|
197
|
+
// Usage
|
|
198
|
+
card({ size: 'sm' })
|
|
199
|
+
// => {
|
|
200
|
+
// root: { padding: '1rem', maxWidth: '300px' },
|
|
201
|
+
// title: { fontWeight: 'bold', fontSize: '14px' }
|
|
202
|
+
// }
|
|
166
203
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
color: {
|
|
173
|
-
primary: 'bg-blue-500 hover:bg-blue-700',
|
|
174
|
-
secondary: 'bg-purple-500 hover:bg-purple-700',
|
|
175
|
-
success: 'bg-green-500 hover:bg-green-700'
|
|
176
|
-
},
|
|
177
|
-
disabled: {
|
|
178
|
-
true: 'opacity-50 pointer-events-none',
|
|
204
|
+
card({
|
|
205
|
+
size: 'lg',
|
|
206
|
+
styles: {
|
|
207
|
+
title: {
|
|
208
|
+
color: 'red',
|
|
179
209
|
},
|
|
180
210
|
},
|
|
181
211
|
})
|
|
212
|
+
// => {
|
|
213
|
+
// root: { padding: '1rem', maxWidth: '600px' },
|
|
214
|
+
// title: { fontWeight: 'bold', fontSize: '18px', color: 'red' }
|
|
215
|
+
// }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Class Merger ([cx](./src/cx.ts))
|
|
182
219
|
|
|
183
|
-
|
|
184
|
-
|
|
220
|
+
Similar to `clsx/classnames` but with better TypeScript support.
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { cx } from 'css-variants'
|
|
224
|
+
|
|
225
|
+
// Basic usage
|
|
226
|
+
cx('foo', 'bar') // => 'foo bar'
|
|
227
|
+
|
|
228
|
+
// With conditions
|
|
229
|
+
cx('foo', {
|
|
230
|
+
'bar': true,
|
|
231
|
+
'baz': false
|
|
232
|
+
}) // => 'foo bar'
|
|
233
|
+
|
|
234
|
+
// With arrays
|
|
235
|
+
cx('foo', ['bar', 'baz']) // => 'foo bar baz'
|
|
236
|
+
|
|
237
|
+
// With nested structures
|
|
238
|
+
cx('foo', {
|
|
239
|
+
bar: true,
|
|
240
|
+
baz: [
|
|
241
|
+
'qux',
|
|
242
|
+
{ quux: true }
|
|
243
|
+
]
|
|
244
|
+
}) // => 'foo bar qux quux'
|
|
245
|
+
|
|
246
|
+
// With falsy values (they're ignored)
|
|
247
|
+
cx('foo', null, undefined, false, 0, '') // => 'foo'
|
|
185
248
|
```
|
|
186
249
|
|
|
187
|
-
|
|
250
|
+
## Advanced Features
|
|
251
|
+
|
|
252
|
+
### Boolean Variants
|
|
188
253
|
|
|
189
|
-
|
|
254
|
+
Support for boolean variants to toggle styles conditionally:
|
|
190
255
|
|
|
191
256
|
```ts
|
|
192
257
|
import { cv } from 'css-variants'
|
|
193
|
-
|
|
258
|
+
|
|
194
259
|
const button = cv({
|
|
195
260
|
variants: {
|
|
196
|
-
size: {
|
|
197
|
-
sm: 'text-sm p-2',
|
|
198
|
-
md: 'text-md p-4',
|
|
199
|
-
lg: 'text-lg',
|
|
200
|
-
},
|
|
201
261
|
disabled: {
|
|
202
|
-
true: 'opacity-50
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
compoundVariants: [
|
|
206
|
-
{
|
|
207
|
-
size: 'lg', // You can also use the values as an array
|
|
208
|
-
disabled: true,
|
|
209
|
-
className: 'uppercase',
|
|
262
|
+
true: 'opacity-50 cursor-not-allowed'
|
|
210
263
|
}
|
|
211
|
-
|
|
264
|
+
}
|
|
212
265
|
})
|
|
213
266
|
|
|
214
|
-
button({
|
|
215
|
-
// => 'text-lg p-6 opacity-50 pointer-events-none uppercase'
|
|
267
|
+
button({ disabled: true }) // => 'opacity-50 cursor-not-allowed'
|
|
216
268
|
```
|
|
217
269
|
|
|
218
|
-
###
|
|
270
|
+
### Compound Variants
|
|
219
271
|
|
|
220
|
-
|
|
272
|
+
Apply styles based on combinations of variants:
|
|
221
273
|
|
|
222
274
|
```ts
|
|
223
275
|
import { cv } from 'css-variants'
|
|
224
|
-
|
|
276
|
+
|
|
225
277
|
const button = cv({
|
|
226
|
-
base: 'font-bold rounded-sm',
|
|
227
278
|
variants: {
|
|
228
279
|
color: {
|
|
229
|
-
primary: 'bg-blue-500
|
|
230
|
-
|
|
231
|
-
success: 'bg-green-500 hover:bg-green-700'
|
|
280
|
+
primary: 'bg-blue-500',
|
|
281
|
+
danger: 'bg-red-500'
|
|
232
282
|
},
|
|
283
|
+
size: {
|
|
284
|
+
sm: 'text-sm',
|
|
285
|
+
lg: 'text-lg'
|
|
286
|
+
}
|
|
233
287
|
},
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
288
|
+
compoundVariants: [
|
|
289
|
+
{
|
|
290
|
+
color: 'danger',
|
|
291
|
+
size: 'lg',
|
|
292
|
+
className: 'animate-pulse'
|
|
293
|
+
}
|
|
294
|
+
]
|
|
237
295
|
})
|
|
238
296
|
|
|
239
|
-
button()
|
|
240
|
-
// => 'font-bold rounded-sm bg-blue-500 hover:bg-blue-700'
|
|
297
|
+
button({ color: 'danger', size: 'lg' }) // => 'bg-red-500 text-lg animate-pulse'
|
|
241
298
|
```
|
|
242
299
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
Slots allows you to separate a component into multiple parts.
|
|
246
|
-
|
|
247
|
-
### Basic Usage
|
|
248
|
-
|
|
249
|
-
You can add `slots` by using the slots key. There's no limit to how many slots you can add.
|
|
250
|
-
|
|
251
|
-
```ts
|
|
252
|
-
import { scv } from 'css-variants'
|
|
253
|
-
|
|
254
|
-
const notification = scv({
|
|
255
|
-
slots: ['root', 'title'],
|
|
256
|
-
base: {
|
|
257
|
-
root: 'root',
|
|
258
|
-
title: 'title',
|
|
259
|
-
},
|
|
260
|
-
})
|
|
300
|
+
### Default Variants
|
|
261
301
|
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Result:
|
|
265
|
-
* {
|
|
266
|
-
* root: 'root',
|
|
267
|
-
* title: 'title',
|
|
268
|
-
* }
|
|
269
|
-
*/
|
|
270
|
-
```
|
|
302
|
+
Specify default variant values:
|
|
271
303
|
|
|
272
304
|
```ts
|
|
273
|
-
import {
|
|
305
|
+
import { cv } from 'css-variants'
|
|
274
306
|
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
},
|
|
281
|
-
title: {
|
|
282
|
-
fontSize: '20px',
|
|
307
|
+
const button = cv({
|
|
308
|
+
variants: {
|
|
309
|
+
size: {
|
|
310
|
+
sm: 'text-sm',
|
|
311
|
+
lg: 'text-lg'
|
|
283
312
|
}
|
|
284
313
|
},
|
|
314
|
+
defaultVariants: {
|
|
315
|
+
size: 'sm'
|
|
316
|
+
}
|
|
285
317
|
})
|
|
286
318
|
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Result:
|
|
290
|
-
* {
|
|
291
|
-
* root: { fontWeight: 'bold' },
|
|
292
|
-
* title: { fontSize: '20px' },
|
|
293
|
-
* }
|
|
294
|
-
*/
|
|
319
|
+
button() // => 'text-sm'
|
|
295
320
|
```
|
|
296
321
|
|
|
297
|
-
###
|
|
322
|
+
### Custom Class Name Resolver
|
|
298
323
|
|
|
299
|
-
|
|
324
|
+
Use your preferred class name utility:
|
|
300
325
|
|
|
301
326
|
```ts
|
|
302
|
-
import {
|
|
327
|
+
import { cv } from 'css-variants'
|
|
328
|
+
import { clsx } from 'clsx'
|
|
303
329
|
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
base: {
|
|
307
|
-
root: 'root',
|
|
308
|
-
title: 'title',
|
|
309
|
-
content: 'content',
|
|
310
|
-
},
|
|
330
|
+
const button = cv({
|
|
331
|
+
base: 'btn',
|
|
311
332
|
variants: {
|
|
312
333
|
color: {
|
|
313
|
-
primary:
|
|
314
|
-
root: 'root-primary',
|
|
315
|
-
title: 'title-primary',
|
|
316
|
-
content: 'content-primary',
|
|
317
|
-
},
|
|
318
|
-
secondary: {
|
|
319
|
-
title: 'title-secondary',
|
|
320
|
-
content: 'content-secondary',
|
|
321
|
-
},
|
|
334
|
+
primary: 'btn-primary'
|
|
322
335
|
}
|
|
323
336
|
},
|
|
337
|
+
classNameResolver: clsx
|
|
324
338
|
})
|
|
325
|
-
|
|
326
|
-
notification({ color: 'primary' })
|
|
327
|
-
/**
|
|
328
|
-
* Result:
|
|
329
|
-
* {
|
|
330
|
-
* root: 'root root-primary',
|
|
331
|
-
* title: 'title title-primary',
|
|
332
|
-
* content: 'content content-primary',
|
|
333
|
-
* }
|
|
334
|
-
*/
|
|
335
|
-
|
|
336
|
-
notification({ color: 'secondary' })
|
|
337
|
-
/**
|
|
338
|
-
* Result:
|
|
339
|
-
* {
|
|
340
|
-
* root: 'root',
|
|
341
|
-
* title: 'title title-secondary',
|
|
342
|
-
* content: 'content content-secondary',
|
|
343
|
-
* }
|
|
344
|
-
*/
|
|
345
339
|
```
|
|
346
340
|
|
|
347
|
-
##
|
|
348
|
-
|
|
349
|
-
`css-variants` allows you to override or extend the styles of your components. This feature is useful when you need to add custom styles or modify existing ones without changing the original component definition.
|
|
341
|
+
## TypeScript Support
|
|
350
342
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
You can override or extend styles for a single component by passing additional `className` and `style` properties when calling the component function. These will be merged with the existing styles.
|
|
343
|
+
Full TypeScript support with automatic type inference:
|
|
354
344
|
|
|
355
345
|
```ts
|
|
356
346
|
import { cv } from 'css-variants'
|
|
357
|
-
|
|
358
|
-
const button = cv({
|
|
359
|
-
base: 'font-semibold',
|
|
360
|
-
variants: {
|
|
361
|
-
color: {
|
|
362
|
-
primary: 'bg-blue-500 hover:bg-blue-700',
|
|
363
|
-
secondary: 'bg-purple-500 hover:bg-purple-700',
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
})
|
|
367
|
-
|
|
368
|
-
button({
|
|
369
|
-
color: 'secondary',
|
|
370
|
-
className: 'border-purple-600',
|
|
371
|
-
})
|
|
372
|
-
// => 'bg-purple-500 hover:bg-purple-700 border-purple-600'
|
|
373
|
-
```
|
|
374
347
|
|
|
375
|
-
```ts
|
|
376
|
-
import { sv } from 'css-variants'
|
|
377
|
-
|
|
378
348
|
const button = cv({
|
|
379
|
-
base: {
|
|
380
|
-
fontWeight: 700,
|
|
381
|
-
},
|
|
382
349
|
variants: {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
},
|
|
387
|
-
secondary: {
|
|
388
|
-
color: 'purple',
|
|
389
|
-
},
|
|
350
|
+
size: {
|
|
351
|
+
sm: 'text-sm',
|
|
352
|
+
lg: 'text-lg'
|
|
390
353
|
}
|
|
391
354
|
}
|
|
392
355
|
})
|
|
393
|
-
|
|
394
|
-
button({
|
|
395
|
-
color: 'secondary',
|
|
396
|
-
style: { color: 'red' },
|
|
397
|
-
})
|
|
398
|
-
// => { fontWeight: 700, color: 'red' }
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### Overriding styles on a component with slots
|
|
402
|
-
|
|
403
|
-
For components with slots, you can override styles using the `classNames` and `styles` properties. These allow you to target specific slots and apply custom classes or inline styles.
|
|
404
|
-
|
|
405
|
-
```ts
|
|
406
|
-
import { csv } from 'css-variants'
|
|
407
|
-
|
|
408
|
-
const notification = cv({
|
|
409
|
-
slots: ['root', 'title'],
|
|
410
|
-
base: {
|
|
411
|
-
root: 'root',
|
|
412
|
-
title: 'title',
|
|
413
|
-
},
|
|
414
|
-
})
|
|
415
|
-
|
|
416
|
-
notification({
|
|
417
|
-
classNames: {
|
|
418
|
-
root: 'root-custom-class',
|
|
419
|
-
},
|
|
420
|
-
})
|
|
421
|
-
/**
|
|
422
|
-
* Result:
|
|
423
|
-
* {
|
|
424
|
-
* root: 'root root-custom-class',
|
|
425
|
-
* title: 'title',
|
|
426
|
-
* }
|
|
427
|
-
*/
|
|
428
356
|
|
|
357
|
+
type ButtonProps = Parameters<typeof button>[0]
|
|
358
|
+
// => { size?: 'sm' | 'lg' | undefined }
|
|
429
359
|
```
|
|
430
360
|
|
|
431
|
-
##
|
|
432
|
-
|
|
433
|
-
Default is the internal 'cx' function. The resolver function should accept multiple class name arguments and return a single concatenated string.
|
|
434
|
-
|
|
435
|
-
You can use this to integrate with class name utilities like clsx, classnames, or your own custom class name resolution logic.
|
|
436
|
-
|
|
437
|
-
```ts
|
|
438
|
-
import { clsx } from 'clsx'
|
|
439
|
-
import { cv as _cv, scv as _scv } from 'css-variants'
|
|
440
|
-
|
|
441
|
-
export const cv: typeof _cv = (config) => {
|
|
442
|
-
return _cv({
|
|
443
|
-
...config,
|
|
444
|
-
classNameResolver: clsx,
|
|
445
|
-
})
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
export const scv: typeof _scv = (config) => {
|
|
449
|
-
return _scv({
|
|
450
|
-
...config,
|
|
451
|
-
classNameResolver: clsx,
|
|
452
|
-
})
|
|
453
|
-
}
|
|
454
|
-
```
|
|
361
|
+
## Inspiration
|
|
455
362
|
|
|
456
|
-
|
|
363
|
+
This library is inspired by several excellent projects:
|
|
457
364
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
```tsx
|
|
461
|
-
import { cv } from 'css-variants'
|
|
462
|
-
|
|
463
|
-
export const button = cv({
|
|
464
|
-
variants: {
|
|
465
|
-
color: {
|
|
466
|
-
primary: 'bg-blue-500 text-white',
|
|
467
|
-
secondary: 'bg-purple-500 text-white',
|
|
468
|
-
},
|
|
469
|
-
},
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
export type ButtonProps = Parameters<typeof button>[0]
|
|
473
|
-
```
|
|
365
|
+
- [CVA (Class Variance Authority)](https://github.com/joe-bell/cva)
|
|
366
|
+
- [Panda CSS](https://github.com/chakra-ui/panda)
|
|
474
367
|
|
|
475
368
|
## Contribute
|
|
476
369
|
|