css-variants 2.0.6 → 2.0.7

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.
Files changed (2) hide show
  1. package/README.md +163 -339
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -7,470 +7,294 @@
7
7
 
8
8
  # css-variants
9
9
 
10
- A lightweight, flexible API for managing CSS class variants in JavaScript and TypeScript projects.
10
+ A lightweight, flexible API for managing CSS class variants and inline styles in JavaScript and TypeScript projects.
11
11
 
12
12
  ## Features
13
13
 
14
- - ðŸŽĻ Dynamic class name generation based on variants
15
- - 🔧 Support for inline styles alongside class names
16
- - ðŸ§Đ Slot-based variant system for complex components
14
+ - ðŸŽĻ Dynamic class name generation with variant support
15
+ - 💅 First-class inline styles support alongside class names
16
+ - ðŸ§Đ Powerful slot-based variant system for complex components
17
17
  - ðŸ“Ķ Zero dependencies
18
18
  - 🔒 Fully type-safe with TypeScript
19
19
  - 🚀 Framework-agnostic
20
-
21
- ## Overview
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
-
20
+ - ðŸŠķ Lightweight (~2KB gzipped)
21
+ - ðŸ”Ĩ Strong tree-shaking support
22
+ - ⚡ïļ Optimal runtime performance
52
23
 
53
24
  ## Installation
54
25
 
55
- To use `css-variants` in your project, you can install it as a dependency:
26
+ ```bash
27
+ # npm
28
+ npm install css-variants
56
29
 
57
- ```sh
30
+ # yarn
58
31
  yarn add css-variants
32
+
33
+ # pnpm
34
+ pnpm add css-variants
59
35
  ```
60
36
 
61
- ## Variants
37
+ ## Core Utilities
62
38
 
63
- Variants allows you to create multiple versions of the same component.
39
+ css-variants provides four main utilities:
64
40
 
65
- ### Adding variants
41
+ - [cv](./src/cv.ts) - Class Variants for managing single component class names
42
+ - [sv](./src/sv.ts) - Style Variants for managing single component inline styles
43
+ - [scv](./src/scv.ts) - Slot Class Variants for managing multiple slot class names
44
+ - [ssv](./src/ssv.ts) - Slot Style Variants for managing multiple slot inline styles
66
45
 
67
- You can add variants by using the `variants` key. There's no limit to how many variants you can add.
46
+ ### Class Variants (cv)
47
+ For managing class names for a single component:
68
48
 
69
49
  ```ts
70
50
  import { cv } from 'css-variants'
71
-
51
+
72
52
  const button = cv({
73
- base: 'font-bold rounded-sm',
53
+ base: 'font-bold rounded-lg',
74
54
  variants: {
75
55
  color: {
76
- primary: 'bg-blue-500 hover:bg-blue-700',
77
- secondary: 'bg-purple-500 hover:bg-purple-700',
78
- success: 'hover:bg-green-700',
56
+ primary: 'bg-blue-500 text-white',
57
+ secondary: 'bg-gray-500 text-white'
79
58
  },
59
+ size: {
60
+ sm: 'text-sm px-2 py-1',
61
+ lg: 'text-lg px-4 py-2'
62
+ }
80
63
  },
64
+ compoundVariants: [
65
+ {
66
+ color: 'primary',
67
+ size: 'lg',
68
+ className: 'uppercase'
69
+ }
70
+ ],
71
+ defaultVariants: {
72
+ color: 'primary',
73
+ size: 'sm'
74
+ }
81
75
  })
82
76
 
83
- button({ color: 'secondary' })
84
- // => 'font-bold rounded-sm bg-purple-500 hover:bg-purple-700'
77
+ // Usage
78
+ button() // => 'font-bold rounded-lg bg-blue-500 text-white text-sm px-2 py-1'
79
+ button({ size: 'lg' }) // => 'font-bold rounded-lg bg-blue-500 text-white text-lg px-4 py-2 uppercase'
85
80
  ```
86
81
 
82
+ ### Style Variants (sv)
83
+
84
+ For managing inline styles:
85
+
87
86
  ```ts
88
87
  import { sv } from 'css-variants'
89
-
88
+
90
89
  const button = sv({
91
90
  base: {
92
- fontWeight: 700,
91
+ fontWeight: 'bold',
92
+ borderRadius: '8px'
93
93
  },
94
94
  variants: {
95
95
  color: {
96
96
  primary: {
97
- color: 'blue',
97
+ backgroundColor: 'blue',
98
+ color: 'white'
98
99
  },
99
100
  secondary: {
100
- color: 'red',
101
- },
102
- success: {
103
- color: 'green',
104
- },
105
- },
106
- },
101
+ backgroundColor: 'gray',
102
+ color: 'white'
103
+ }
104
+ }
105
+ }
107
106
  })
108
107
 
109
- button({ color: 'secondary' })
110
- // => { fontWeight: 700, color: 'red' }
108
+ button({ color: 'primary' })
109
+ // => { fontWeight: 'bold', borderRadius: '8px', backgroundColor: 'blue', color: 'white' }
111
110
  ```
112
111
 
113
- ### Multiple variants
112
+ ### Slot Class Variants (scv)
114
113
 
115
- You can add multiple variants to a single component.
114
+ For managing class names across multiple slots/elements:
116
115
 
117
116
  ```ts
118
- import { cv } from 'css-variants'
117
+ import { scv } from 'css-variants'
119
118
 
120
- const button = cv({
121
- base: 'font-bold',
119
+ const card = scv({
120
+ slots: ['root', 'title', 'content'],
121
+ base: {
122
+ root: 'rounded-lg shadow',
123
+ title: 'text-xl font-bold',
124
+ content: 'mt-2'
125
+ },
122
126
  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
127
  size: {
129
- sm: 'text-sm p-2',
130
- md: 'text-md p-4',
131
- lg: 'text-lg p-6',
132
- },
133
- },
128
+ sm: {
129
+ root: 'p-4',
130
+ title: 'text-base'
131
+ },
132
+ lg: {
133
+ root: 'p-6',
134
+ title: 'text-2xl'
135
+ }
136
+ }
137
+ }
134
138
  })
135
139
 
136
- button({ color: 'success', size: 'lg' })
137
- // => 'font-bold bg-green-500 hover:bg-green-700 text-lg p-6'
140
+ // Usage
141
+ card({ size: 'sm' })
142
+ // => {
143
+ // root: 'rounded-lg shadow p-4',
144
+ // title: 'text-xl font-bold text-base',
145
+ // content: 'mt-2'
146
+ // }
138
147
  ```
139
148
 
149
+ ### Slot Style Variants (ssv)
150
+
151
+ For managing inline styles across multiple slots:
152
+
140
153
  ```ts
141
- import { sv } from 'css-variants'
154
+ import { ssv } from 'css-variants'
142
155
 
143
- const button = sv({
156
+ const card = ssv({
157
+ slots: ['root', 'title'],
144
158
  base: {
145
- fontWeight: 700,
159
+ root: { padding: '1rem' },
160
+ title: { fontWeight: 'bold' }
146
161
  },
147
162
  variants: {
148
163
  size: {
149
- small: { fontSize: '12px' },
150
- large: { fontSize: '24px' },
151
- },
152
- color: {
153
- red: { color: 'red' },
154
- blue: { color: 'blue' },
155
- },
156
- },
164
+ sm: {
165
+ root: { maxWidth: '300px' },
166
+ title: { fontSize: '14px' }
167
+ },
168
+ lg: {
169
+ root: { maxWidth: '600px' },
170
+ title: { fontSize: '18px' }
171
+ }
172
+ }
173
+ }
157
174
  })
158
175
 
159
- button({ size: 'small', color: 'blue' })
160
- // => { fontWeight: 700, fontSize: '12px', color: 'blue' }
176
+ card({ size: 'sm' })
177
+ // => {
178
+ // root: { padding: '1rem', maxWidth: '300px' },
179
+ // title: { fontWeight: 'bold', fontSize: '14px' }
180
+ // }
161
181
  ```
162
182
 
163
- ### Boolean variants
183
+ ## Advanced Features
184
+
185
+ ### Boolean Variants
164
186
 
165
- You can also add boolean variants to a component. This is useful when you want to add a state variant e.g. `disabled`.
187
+ Support for boolean variants to toggle styles conditionally:
166
188
 
167
189
  ```ts
168
190
  import { cv } from 'css-variants'
169
-
191
+
170
192
  const button = cv({
171
193
  variants: {
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
194
  disabled: {
178
- true: 'opacity-50 pointer-events-none',
179
- },
180
- },
195
+ true: 'opacity-50 cursor-not-allowed'
196
+ }
197
+ }
181
198
  })
182
199
 
183
- button({ disabled: true })
184
- // => 'opacity-50 pointer-events-none'
200
+ button({ disabled: true }) // => 'opacity-50 cursor-not-allowed'
185
201
  ```
186
202
 
187
- ### Compound variants
203
+ ### Compound Variants
188
204
 
189
- Sometimes you might want to add a variant that depends on another variant. This is possible by using the `compoundVariants` key.
205
+ Apply styles based on combinations of variants:
190
206
 
191
207
  ```ts
192
208
  import { cv } from 'css-variants'
193
-
209
+
194
210
  const button = cv({
195
211
  variants: {
196
- size: {
197
- sm: 'text-sm p-2',
198
- md: 'text-md p-4',
199
- lg: 'text-lg',
200
- },
201
- disabled: {
202
- true: 'opacity-50 pointer-events-none',
212
+ color: {
213
+ primary: 'bg-blue-500',
214
+ danger: 'bg-red-500'
203
215
  },
216
+ size: {
217
+ sm: 'text-sm',
218
+ lg: 'text-lg'
219
+ }
204
220
  },
205
221
  compoundVariants: [
206
222
  {
207
- size: 'lg', // You can also use the values as an array
208
- disabled: true,
209
- className: 'uppercase',
223
+ color: 'danger',
224
+ size: 'lg',
225
+ className: 'animate-pulse'
210
226
  }
211
- ],
227
+ ]
212
228
  })
213
-
214
- button({ size: 'lg', disabled: true })
215
- // => 'text-lg p-6 opacity-50 pointer-events-none uppercase'
216
229
  ```
217
230
 
218
- ### Default variants
231
+ ### Default Variants
219
232
 
220
- You can also add a default variant to a component. This is useful when you want to add a predefined variants values to a component.
233
+ Specify default variant values:
221
234
 
222
235
  ```ts
223
236
  import { cv } from 'css-variants'
224
-
237
+
225
238
  const button = cv({
226
- base: 'font-bold rounded-sm',
227
239
  variants: {
228
- color: {
229
- primary: 'bg-blue-500 hover:bg-blue-700',
230
- secondary: 'bg-purple-500 hover:bg-purple-700',
231
- success: 'bg-green-500 hover:bg-green-700'
232
- },
233
- },
234
- defaultVariants: {
235
- color: 'primary',
236
- },
237
- })
238
-
239
- button()
240
- // => 'font-bold rounded-sm bg-blue-500 hover:bg-blue-700'
241
- ```
242
-
243
- ## Slots
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
- })
261
-
262
- notification()
263
- /**
264
- * Result:
265
- * {
266
- * root: 'root',
267
- * title: 'title',
268
- * }
269
- */
270
- ```
271
-
272
- ```ts
273
- import { ssv } from 'css-variants'
274
-
275
- const notification = ssv({
276
- slots: ['root', 'title'],
277
- base: {
278
- root: {
279
- fontWeight: 'bold',
280
- },
281
- title: {
282
- fontSize: '20px',
240
+ size: {
241
+ sm: 'text-sm',
242
+ lg: 'text-lg'
283
243
  }
284
244
  },
245
+ defaultVariants: {
246
+ size: 'sm'
247
+ }
285
248
  })
286
249
 
287
- notification()
288
- /**
289
- * Result:
290
- * {
291
- * root: { fontWeight: 'bold' },
292
- * title: { fontSize: '20px' },
293
- * }
294
- */
250
+ button() // => 'text-sm'
295
251
  ```
296
252
 
297
- ### Slots with variants
253
+ ### Custom Class Name Resolver
298
254
 
299
- You can also change the entire component and its slots by using the variants.
255
+ Use your preferred class name utility:
300
256
 
301
257
  ```ts
302
- import { csv } from 'css-variants'
258
+ import { cv } from 'css-variants'
259
+ import { clsx } from 'clsx'
303
260
 
304
- const notification = cv({
305
- slots: ['root', 'title', 'content'],
306
- base: {
307
- root: 'root',
308
- title: 'title',
309
- content: 'content',
310
- },
261
+ const button = cv({
262
+ base: 'btn',
311
263
  variants: {
312
264
  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
- },
265
+ primary: 'btn-primary'
322
266
  }
323
267
  },
268
+ classNameResolver: clsx
324
269
  })
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
270
  ```
346
271
 
347
- ## Overriding styles
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.
350
-
351
- ### Overriding styles on a single component
272
+ ## TypeScript Support
352
273
 
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.
274
+ Full TypeScript support with automatic type inference:
354
275
 
355
276
  ```ts
356
277
  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
278
 
375
- ```ts
376
- import { sv } from 'css-variants'
377
-
378
279
  const button = cv({
379
- base: {
380
- fontWeight: 700,
381
- },
382
280
  variants: {
383
- color: {
384
- primary: {
385
- color: 'blue',
386
- },
387
- secondary: {
388
- color: 'purple',
389
- },
281
+ size: {
282
+ sm: 'text-sm',
283
+ lg: 'text-lg'
390
284
  }
391
285
  }
392
286
  })
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
287
 
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
-
429
- ```
430
-
431
- ## Custom function to resolve class names
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
- }
288
+ type ButtonProps = Parameters<typeof button>[0]
289
+ // => { size?: 'sm' | 'lg' | undefined }
454
290
  ```
455
291
 
456
- ## TypeScript
457
-
458
- ### Extracting Variant Types
292
+ ## Inspiration
459
293
 
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
- })
294
+ This library is inspired by several excellent projects:
471
295
 
472
- export type ButtonProps = Parameters<typeof button>[0]
473
- ```
296
+ - [CVA (Class Variance Authority)](https://github.com/joe-bell/cva)
297
+ - [Panda CSS](https://github.com/chakra-ui/panda)
474
298
 
475
299
  ## Contribute
476
300
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "css-variants",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "A lightweight, flexible API for managing CSS class variants.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",