slot-variants 1.1.0 → 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/AGENTS.md +38 -9
- package/README.md +220 -14
- package/dist/index.cjs +43 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +43 -3
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -10,6 +10,30 @@
|
|
|
10
10
|
import { sv, cn, type VariantProps } from 'slot-variants';
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
`sv()` is a drop-in replacement for CVA (`cva` → `sv`) and covers the core feature set of tailwind-variants (`tv`) with a simpler API. Slots return strings directly (not functions like in `tv`). Features not in CVA/TV: `requiredVariants`, `presets`, `cacheSize`, `postProcess`, function-based `defaultVariants`, and variadic base args.
|
|
14
|
+
|
|
15
|
+
## Calling Conventions
|
|
16
|
+
|
|
17
|
+
`sv()` supports three calling conventions:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// 1. Config-only (like tailwind-variants' tv())
|
|
21
|
+
const button = sv({
|
|
22
|
+
base: 'btn font-medium',
|
|
23
|
+
variants: { size: { sm: 'text-sm', lg: 'text-lg' } }
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// 2. Base + config (like CVA's cva())
|
|
27
|
+
const button = sv('btn font-medium', {
|
|
28
|
+
variants: { size: { sm: 'text-sm', lg: 'text-lg' } }
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// 3. Class name merging (like cn())
|
|
32
|
+
sv('flex', 'items-center', 'gap-2'); // 'flex items-center gap-2'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The `base` config field merges with base arguments and `slots.base`: `cn(baseArgs..., config.base, slots.base)`.
|
|
36
|
+
|
|
13
37
|
## Best Practices
|
|
14
38
|
|
|
15
39
|
### 1. Keep CSS Classes Mutually Exclusive
|
|
@@ -243,14 +267,16 @@ const button = sv('btn', {
|
|
|
243
267
|
}
|
|
244
268
|
});
|
|
245
269
|
|
|
246
|
-
button.variantKeys;
|
|
247
|
-
button.variants;
|
|
248
|
-
button.slotKeys;
|
|
249
|
-
button.slots;
|
|
250
|
-
button.defaultVariants;
|
|
251
|
-
button.requiredVariants;
|
|
252
|
-
button.presetKeys;
|
|
253
|
-
button.presets;
|
|
270
|
+
button.variantKeys; // ['size', 'intent']
|
|
271
|
+
button.variants; // { size: { sm: 'text-sm', lg: 'text-lg' }, intent: { ... } }
|
|
272
|
+
button.slotKeys; // ['base', 'icon']
|
|
273
|
+
button.slots; // { icon: 'w-4 h-4' }
|
|
274
|
+
button.defaultVariants; // { size: 'sm' }
|
|
275
|
+
button.requiredVariants; // ['intent']
|
|
276
|
+
button.presetKeys; // ['cta']
|
|
277
|
+
button.presets; // { cta: { size: 'lg', intent: 'primary' } }
|
|
278
|
+
button.getVariantValues('size'); // ['sm', 'lg']
|
|
279
|
+
button.getVariantValues('intent'); // ['primary', 'danger']
|
|
254
280
|
```
|
|
255
281
|
|
|
256
282
|
Use introspection to share variant/slot definitions with other parts of your codebase:
|
|
@@ -376,6 +402,7 @@ export const Card = (props: CardProps) => {
|
|
|
376
402
|
|
|
377
403
|
| Option | Type | Description |
|
|
378
404
|
| ------------------ | -------------------------------- | --------------------------------- |
|
|
405
|
+
| `base` | `ClassValue` | Additional base classes |
|
|
379
406
|
| `variants` | `Record<string, VariantConfig>` | Variant definitions |
|
|
380
407
|
| `slots` | `Record<string, ClassValue>` | Named slot definitions |
|
|
381
408
|
| `compoundVariants` | `CompoundVariant[]` | Conditional class combinations |
|
|
@@ -390,6 +417,8 @@ export const Card = (props: CardProps) => {
|
|
|
390
417
|
|
|
391
418
|
- `ClassValue` - Valid input for `cn()` (string, array, object, boolean, null, undefined)
|
|
392
419
|
- `VariantProps<T, E>` - Extract variant props from an `sv()` return, optionally excluding keys
|
|
420
|
+
- `VariantValue<T, K>` - Extract the value union for a single variant key, without `undefined`
|
|
421
|
+
- `SlotClassProps<T>` - Extract the per-slot class injection shape from an `sv()` return type
|
|
393
422
|
|
|
394
423
|
## Imports
|
|
395
424
|
|
|
@@ -398,7 +427,7 @@ export const Card = (props: CardProps) => {
|
|
|
398
427
|
import { sv, cn } from 'slot-variants';
|
|
399
428
|
|
|
400
429
|
// Types only
|
|
401
|
-
import type { VariantProps, ClassValue } from 'slot-variants';
|
|
430
|
+
import type { VariantProps, VariantValue, SlotClassProps, ClassValue } from 'slot-variants';
|
|
402
431
|
```
|
|
403
432
|
|
|
404
433
|
## Performance Notes
|
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ npm install slot-variants
|
|
|
17
17
|
- **`sv()`** - creates variant-based class name generators with optional slots
|
|
18
18
|
- **`cn()`** - a utility for conditionally merging class names
|
|
19
19
|
|
|
20
|
+
`sv()` is a drop-in replacement for [CVA](https://cva.style/) (just rename `cva` to `sv`) and covers the core feature set of [tailwind-variants](https://www.tailwind-variants.org/) (`tv`) with a simpler API. See [Migrating from CVA / tailwind-variants](#migrating-from-cva--tailwind-variants) for details.
|
|
21
|
+
|
|
20
22
|
## Quick Start
|
|
21
23
|
|
|
22
24
|
```typescript
|
|
@@ -84,14 +86,67 @@ cn('foo', null, undefined, false, 'bar'); // 'foo bar'
|
|
|
84
86
|
|
|
85
87
|
## `sv()` - Slot Variants
|
|
86
88
|
|
|
87
|
-
|
|
89
|
+
`sv()` supports three calling conventions:
|
|
90
|
+
|
|
91
|
+
### Class Name Merging (No Config)
|
|
92
|
+
|
|
93
|
+
When called without a config object, `sv()` works like `cn()` — it accepts any number of `ClassValue` arguments and returns a merged class string:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
sv('btn btn-primary'); // 'btn btn-primary'
|
|
97
|
+
sv('flex', 'items-center', 'gap-2'); // 'flex items-center gap-2'
|
|
98
|
+
sv(['btn', 'btn-primary']); // 'btn btn-primary'
|
|
99
|
+
sv({ btn: true, disabled: false }); // 'btn'
|
|
100
|
+
sv('flex', ['items-center'], { gap: true }); // 'flex items-center gap'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Config-Only Call
|
|
104
|
+
|
|
105
|
+
When called with a single config object (no separate base argument), `sv()` returns a variant function. Use the `base` field inside the config:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const button = sv({
|
|
109
|
+
base: 'btn font-medium',
|
|
110
|
+
variants: {
|
|
111
|
+
size: {
|
|
112
|
+
sm: 'text-sm',
|
|
113
|
+
lg: 'text-lg'
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
button({ size: 'sm' }); // 'btn font-medium text-sm'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Base + Config Call
|
|
122
|
+
|
|
123
|
+
When the last argument is a config object preceded by one or more `ClassValue` arguments, the leading arguments are merged as the base:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
const button = sv('btn font-medium', {
|
|
127
|
+
variants: {
|
|
128
|
+
size: {
|
|
129
|
+
sm: 'text-sm',
|
|
130
|
+
lg: 'text-lg'
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
```
|
|
88
135
|
|
|
89
|
-
|
|
136
|
+
The `base` field in the config is merged with the base arguments: `cn(baseArgs..., config.base, slots.base)`:
|
|
90
137
|
|
|
91
138
|
```typescript
|
|
92
|
-
sv('btn
|
|
93
|
-
|
|
94
|
-
|
|
139
|
+
const button = sv('btn', {
|
|
140
|
+
base: 'font-medium',
|
|
141
|
+
variants: {
|
|
142
|
+
size: {
|
|
143
|
+
sm: 'text-sm',
|
|
144
|
+
lg: 'text-lg'
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
button({ size: 'sm' }); // 'btn font-medium text-sm'
|
|
95
150
|
```
|
|
96
151
|
|
|
97
152
|
### Variants
|
|
@@ -659,14 +714,16 @@ const button = sv('btn', {
|
|
|
659
714
|
}
|
|
660
715
|
});
|
|
661
716
|
|
|
662
|
-
button.variantKeys;
|
|
663
|
-
button.variants;
|
|
664
|
-
button.slotKeys;
|
|
665
|
-
button.slots;
|
|
666
|
-
button.defaultVariants;
|
|
667
|
-
button.requiredVariants;
|
|
668
|
-
button.presetKeys;
|
|
669
|
-
button.presets;
|
|
717
|
+
button.variantKeys; // ['size', 'intent']
|
|
718
|
+
button.variants; // { size: { sm: 'text-sm', lg: 'text-lg' }, intent: { ... } }
|
|
719
|
+
button.slotKeys; // ['base', 'icon']
|
|
720
|
+
button.slots; // { icon: 'w-4 h-4' }
|
|
721
|
+
button.defaultVariants; // { size: 'sm' }
|
|
722
|
+
button.requiredVariants; // ['intent']
|
|
723
|
+
button.presetKeys; // ['cta']
|
|
724
|
+
button.presets; // { cta: { size: 'lg', intent: 'primary' } }
|
|
725
|
+
button.getVariantValues('size'); // ['sm', 'lg']
|
|
726
|
+
button.getVariantValues('intent'); // ['primary', 'danger']
|
|
670
727
|
```
|
|
671
728
|
|
|
672
729
|
## TypeScript
|
|
@@ -728,12 +785,84 @@ type ButtonProps = VariantProps<typeof button, 'internalState' | 'intent'>;
|
|
|
728
785
|
// { size?: 'sm' | 'lg' | undefined }
|
|
729
786
|
```
|
|
730
787
|
|
|
788
|
+
### Extracting a Single Variant's Values
|
|
789
|
+
|
|
790
|
+
`VariantValue` extracts the value union for a specific variant key. Unlike indexing into `VariantProps`, it always returns a clean union without `undefined`:
|
|
791
|
+
|
|
792
|
+
```typescript
|
|
793
|
+
import { sv, type VariantValue } from 'slot-variants';
|
|
794
|
+
|
|
795
|
+
const button = sv('btn', {
|
|
796
|
+
variants: {
|
|
797
|
+
size: {
|
|
798
|
+
sm: 'text-sm',
|
|
799
|
+
md: 'text-base',
|
|
800
|
+
lg: 'text-lg'
|
|
801
|
+
},
|
|
802
|
+
intent: {
|
|
803
|
+
primary: 'bg-blue-500',
|
|
804
|
+
danger: 'bg-red-500'
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
requiredVariants: ['intent']
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
type SizeValue = VariantValue<typeof button, 'size'>;
|
|
811
|
+
// 'sm' | 'md' | 'lg' (no undefined, even though size is optional)
|
|
812
|
+
|
|
813
|
+
type IntentValue = VariantValue<typeof button, 'intent'>;
|
|
814
|
+
// 'primary' | 'danger'
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
This is useful when a component only needs to forward a single variant as a typed prop:
|
|
818
|
+
|
|
819
|
+
```typescript
|
|
820
|
+
type ButtonGroupProps = {
|
|
821
|
+
size?: VariantValue<typeof button, 'size'>;
|
|
822
|
+
};
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### Slot Class Injection Props
|
|
826
|
+
|
|
827
|
+
`SlotClassProps<T>` extracts the per-slot class injection shape from an `sv()` return type. This is useful when building wrapper components that expose a typed prop for consumers to pass additional classes into specific slots:
|
|
828
|
+
|
|
829
|
+
```typescript
|
|
830
|
+
import { sv, type SlotClassProps, type VariantProps } from 'slot-variants';
|
|
831
|
+
|
|
832
|
+
const card = sv('border rounded-lg', {
|
|
833
|
+
slots: {
|
|
834
|
+
header: 'font-bold',
|
|
835
|
+
body: 'py-4',
|
|
836
|
+
footer: 'border-t'
|
|
837
|
+
},
|
|
838
|
+
variants: {
|
|
839
|
+
size: { sm: 'text-sm', lg: 'text-lg' }
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
type CardClassProps = SlotClassProps<typeof card>;
|
|
844
|
+
// { base?: ClassValue; header?: ClassValue; body?: ClassValue; footer?: ClassValue }
|
|
845
|
+
|
|
846
|
+
type CardProps = VariantProps<typeof card> & {
|
|
847
|
+
classNames?: SlotClassProps<typeof card>;
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
function Card({ classNames, ...variants }: CardProps) {
|
|
851
|
+
const { base, header, body, footer } = card({ ...variants, class: classNames });
|
|
852
|
+
// ...
|
|
853
|
+
}
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
When used on an `sv()` definition without slots, `SlotClassProps` resolves to `{ base?: ClassValue }`.
|
|
857
|
+
|
|
731
858
|
### Exported Types
|
|
732
859
|
|
|
733
860
|
| Type | Description |
|
|
734
861
|
| --- | --- |
|
|
735
862
|
| `ClassValue` | Valid input types for `cn()` |
|
|
736
863
|
| `VariantProps<T, E>` | Extracts variant props from an `sv()` return type, optionally excluding keys in `E` |
|
|
864
|
+
| `VariantValue<T, K>` | Extracts the value union for a single variant key `K`, without `undefined` |
|
|
865
|
+
| `SlotClassProps<T>` | Extracts the per-slot class injection shape from an `sv()` return type |
|
|
737
866
|
|
|
738
867
|
### Return Type
|
|
739
868
|
|
|
@@ -744,6 +873,7 @@ type ButtonProps = VariantProps<typeof button, 'internalState' | 'intent'>;
|
|
|
744
873
|
|
|
745
874
|
| Option | Type | Description |
|
|
746
875
|
| --- | --- | --- |
|
|
876
|
+
| `base` | `ClassValue` | Additional base classes merged with the base argument and `slots.base` |
|
|
747
877
|
| `variants` | `SVVariants` | Variant definitions mapping variant names to their possible values |
|
|
748
878
|
| `slots` | `SVSlots` | Named slot definitions for multi-element components |
|
|
749
879
|
| `compoundVariants` | `Array` | Additional classes applied when multiple variant conditions match |
|
|
@@ -752,4 +882,80 @@ type ButtonProps = VariantProps<typeof button, 'internalState' | 'intent'>;
|
|
|
752
882
|
| `requiredVariants` | `string[]` | Variant names that must be provided at call time |
|
|
753
883
|
| `presets` | `Record<string, Partial<VariantProps>>` | Named combinations of variant values selectable via `preset` prop |
|
|
754
884
|
| `postProcess` | `(className: string) => string` | Custom transformation applied to final class strings |
|
|
755
|
-
| `cacheSize` | `number` | Maximum number of cached results (default: `256`) |
|
|
885
|
+
| `cacheSize` | `number` | Maximum number of cached results (default: `256`) |
|
|
886
|
+
|
|
887
|
+
## Migrating from CVA / tailwind-variants
|
|
888
|
+
|
|
889
|
+
### From CVA
|
|
890
|
+
|
|
891
|
+
`sv()` is a drop-in replacement for CVA. Rename `cva` to `sv` and `VariantProps` import source:
|
|
892
|
+
|
|
893
|
+
```diff
|
|
894
|
+
- import { cva, type VariantProps } from 'class-variance-authority';
|
|
895
|
+
+ import { sv, type VariantProps } from 'slot-variants';
|
|
896
|
+
|
|
897
|
+
- const button = cva('btn font-medium', {
|
|
898
|
+
+ const button = sv('btn font-medium', {
|
|
899
|
+
variants: {
|
|
900
|
+
size: { sm: 'text-sm', lg: 'text-lg' },
|
|
901
|
+
intent: { primary: 'bg-blue-500', danger: 'bg-red-500' }
|
|
902
|
+
},
|
|
903
|
+
defaultVariants: { size: 'md' },
|
|
904
|
+
compoundVariants: [
|
|
905
|
+
{ size: 'lg', intent: 'primary', class: 'uppercase' }
|
|
906
|
+
]
|
|
907
|
+
});
|
|
908
|
+
```
|
|
909
|
+
|
|
910
|
+
Everything else works identically — the config shape, `class`/`className` override, `VariantProps` extraction, and variant prop handling are all compatible.
|
|
911
|
+
|
|
912
|
+
### From tailwind-variants
|
|
913
|
+
|
|
914
|
+
`sv()` covers the core feature set of tailwind-variants with a simpler API. The config-only calling convention matches `tv()`:
|
|
915
|
+
|
|
916
|
+
```diff
|
|
917
|
+
- import { tv, type VariantProps } from 'tailwind-variants';
|
|
918
|
+
+ import { sv, type VariantProps } from 'slot-variants';
|
|
919
|
+
|
|
920
|
+
- const button = tv({
|
|
921
|
+
+ const button = sv({
|
|
922
|
+
base: 'btn font-medium',
|
|
923
|
+
variants: {
|
|
924
|
+
size: { sm: 'text-sm', lg: 'text-lg' }
|
|
925
|
+
},
|
|
926
|
+
defaultVariants: { size: 'md' }
|
|
927
|
+
});
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
Key differences to be aware of:
|
|
931
|
+
|
|
932
|
+
| Feature | tailwind-variants | slot-variants |
|
|
933
|
+
| --- | --- | --- |
|
|
934
|
+
| Slot return type | Functions: `slot({ class: '...' })` | Strings: `slot` is already a `string` |
|
|
935
|
+
| `extend` (composition) | Supported | Not supported |
|
|
936
|
+
| Built-in `twMerge` | Enabled by default | Use `postProcess: twMerge` |
|
|
937
|
+
|
|
938
|
+
**Slot return type** is the most significant difference. In `tv()`, each slot returns a function that can accept additional props. In `sv()`, slots resolve to strings directly — use the `class` prop with a slot object for per-slot overrides:
|
|
939
|
+
|
|
940
|
+
```typescript
|
|
941
|
+
// tailwind-variants
|
|
942
|
+
const { base, icon } = component({ size: 'sm' });
|
|
943
|
+
base({ class: 'extra' }); // slot is a function
|
|
944
|
+
|
|
945
|
+
// slot-variants
|
|
946
|
+
const { base, icon } = component({ size: 'sm', class: { base: 'extra' } });
|
|
947
|
+
base; // slot is a string
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
**tailwind-merge** is not built-in but can be added via `postProcess`:
|
|
951
|
+
|
|
952
|
+
```typescript
|
|
953
|
+
import { sv } from 'slot-variants';
|
|
954
|
+
import { twMerge } from 'tailwind-merge';
|
|
955
|
+
|
|
956
|
+
const button = sv({
|
|
957
|
+
base: 'px-4 py-2',
|
|
958
|
+
variants: { size: { sm: 'px-2 py-1' } },
|
|
959
|
+
postProcess: twMerge
|
|
960
|
+
});
|
|
961
|
+
```
|
package/dist/index.cjs
CHANGED
|
@@ -56,6 +56,19 @@ function cn(...args) {
|
|
|
56
56
|
// src/sv.ts
|
|
57
57
|
var { isArray: isArray2 } = Array;
|
|
58
58
|
var { assign, entries, keys: keys2 } = Object;
|
|
59
|
+
var configKeys = /* @__PURE__ */ new Set([
|
|
60
|
+
"base",
|
|
61
|
+
"variants",
|
|
62
|
+
"slots",
|
|
63
|
+
"compoundVariants",
|
|
64
|
+
"compoundSlots",
|
|
65
|
+
"defaultVariants",
|
|
66
|
+
"requiredVariants",
|
|
67
|
+
"presets",
|
|
68
|
+
"cacheSize",
|
|
69
|
+
"postProcess"
|
|
70
|
+
]);
|
|
71
|
+
var isConfig = (value) => !!value && typeof value === "object" && !isArray2(value) && keys2(value).every((key) => configKeys.has(key));
|
|
59
72
|
var looseEquals = (first, second) => first === second || `${first}` === `${second}`;
|
|
60
73
|
var matchesCompound = (props, compound) => {
|
|
61
74
|
for (const compoundKey of keys2(compound)) {
|
|
@@ -74,11 +87,24 @@ var matchesCompound = (props, compound) => {
|
|
|
74
87
|
}
|
|
75
88
|
return true;
|
|
76
89
|
};
|
|
77
|
-
function sv(
|
|
90
|
+
function sv(...args) {
|
|
91
|
+
const lastArg = args[args.length - 1];
|
|
92
|
+
let base;
|
|
93
|
+
let config;
|
|
94
|
+
if (args.length >= 2 && isConfig(lastArg)) {
|
|
95
|
+
config = lastArg;
|
|
96
|
+
base = args.length > 2 ? args.slice(0, -1) : args[0];
|
|
97
|
+
} else if (args.length === 1 && isConfig(lastArg)) {
|
|
98
|
+
config = lastArg;
|
|
99
|
+
base = void 0;
|
|
100
|
+
} else {
|
|
101
|
+
base = args;
|
|
102
|
+
}
|
|
78
103
|
if (!config) {
|
|
79
|
-
return cn(
|
|
104
|
+
return cn(...args);
|
|
80
105
|
}
|
|
81
106
|
const {
|
|
107
|
+
base: configBase,
|
|
82
108
|
variants = {},
|
|
83
109
|
slots = {},
|
|
84
110
|
compoundVariants = [],
|
|
@@ -103,7 +129,8 @@ function sv(base, config) {
|
|
|
103
129
|
return value;
|
|
104
130
|
};
|
|
105
131
|
const { base: baseSlot, ...otherSlots } = slots;
|
|
106
|
-
const
|
|
132
|
+
const baseArgs = isArray2(base) ? base : [base];
|
|
133
|
+
const baseClassValue = cn(...baseArgs, configBase, baseSlot);
|
|
107
134
|
const slotKeys = new Set(keys2(otherSlots));
|
|
108
135
|
const normalizedVariants = {};
|
|
109
136
|
for (const [variantKey, variantValue] of entries(variants)) {
|
|
@@ -263,6 +290,18 @@ function sv(base, config) {
|
|
|
263
290
|
}
|
|
264
291
|
return cacheReturn(cacheKey, result);
|
|
265
292
|
};
|
|
293
|
+
const getVariantValues = (key) => keys2(normalizedVariants[key] ?? {}).map((value) => {
|
|
294
|
+
if (value === "true") {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
if (value === "false") {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
if (value !== "" && !Number.isNaN(Number(value))) {
|
|
301
|
+
return Number(value);
|
|
302
|
+
}
|
|
303
|
+
return value;
|
|
304
|
+
});
|
|
266
305
|
return assign(variantFn, {
|
|
267
306
|
variants,
|
|
268
307
|
variantKeys: keys2(variants),
|
|
@@ -272,6 +311,7 @@ function sv(base, config) {
|
|
|
272
311
|
requiredVariants,
|
|
273
312
|
presets,
|
|
274
313
|
presetKeys: keys2(presets),
|
|
314
|
+
getVariantValues,
|
|
275
315
|
clearCache: () => cache.clear(),
|
|
276
316
|
getCacheSize: () => cache.size
|
|
277
317
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ type PresetProp<P extends Record<string, unknown> | undefined> = P extends Recor
|
|
|
53
53
|
} : unknown;
|
|
54
54
|
type SVProps<S extends SVSlots | undefined, V extends SVVariants<S> | undefined, RV extends StringKeyof<V>[], P extends SVPresets<S, V> | undefined> = V extends undefined ? ClassProp<S> : P extends Record<string, unknown> ? Prettify<PartialUndefined<SVVariantProps<S, V>>> & ClassProp<S> & PresetProp<P> : Prettify<Pick<SVVariantProps<S, V>, RV[number]> & Omit<PartialUndefined<SVVariantProps<S, V>>, RV[number]>> & ClassProp<S>;
|
|
55
55
|
type SVConfig<S extends SVSlots | undefined, V extends SVVariants<S> | undefined, RV extends StringKeyof<V>[], P extends SVPresets<S, V> | undefined> = {
|
|
56
|
+
base?: ClassValue | undefined;
|
|
56
57
|
variants?: V | undefined;
|
|
57
58
|
slots?: S | undefined;
|
|
58
59
|
compoundVariants?: SVCompoundVariants<S, V> | undefined;
|
|
@@ -74,15 +75,19 @@ type SVReturnType<S extends SVSlots | undefined, V extends SVVariants<S> | undef
|
|
|
74
75
|
requiredVariants: RV;
|
|
75
76
|
presets: P;
|
|
76
77
|
presetKeys: P extends Record<string, unknown> ? StringKeyof<P>[] : [];
|
|
78
|
+
getVariantValues: V extends SVVariants<S> ? <K extends StringKeyof<V>>(key: K) => SVVariantPropType<V[K], S>[] : (key: never) => never[];
|
|
77
79
|
clearCache: () => void;
|
|
78
80
|
getCacheSize: () => number;
|
|
79
81
|
};
|
|
80
82
|
type VariantProps<T extends (...args: any[]) => unknown, E extends string = never> = Prettify<Omit<Exclude<Parameters<T>[0], undefined>, 'class' | 'className' | 'preset' | E>>;
|
|
83
|
+
type VariantValue<T extends (...args: any[]) => unknown, K extends keyof VariantProps<T>> = NonNullable<VariantProps<T>[K]>;
|
|
84
|
+
type SlotClassProps<T extends (...args: any[]) => unknown> = ReturnType<T> extends string ? Partial<Record<'base', ClassValue>> : Prettify<Partial<Record<Extract<keyof ReturnType<T>, string>, ClassValue>>>;
|
|
81
85
|
/**
|
|
82
86
|
* Creates variant-based class name generator with optional slots support.
|
|
83
87
|
* Inspired by CVA and tailwind-variants.
|
|
84
88
|
*/
|
|
85
|
-
declare function sv(
|
|
86
|
-
declare function sv<S extends SVSlots | undefined = undefined, V extends SVVariants<S> | undefined = undefined, RV extends StringKeyof<V>[] | [] = [], P extends SVPresets<S, V> | undefined = undefined>(
|
|
89
|
+
declare function sv<S extends SVSlots | undefined = undefined, V extends SVVariants<S> | undefined = undefined, RV extends StringKeyof<V>[] | [] = [], P extends SVPresets<S, V> | undefined = undefined>(config: SVConfig<S, V, RV, P>): SVReturnType<S, V, RV, P>;
|
|
90
|
+
declare function sv<S extends SVSlots | undefined = undefined, V extends SVVariants<S> | undefined = undefined, RV extends StringKeyof<V>[] | [] = [], P extends SVPresets<S, V> | undefined = undefined>(...args: [...ClassValue[], SVConfig<S, V, RV, P>]): SVReturnType<S, V, RV, P>;
|
|
91
|
+
declare function sv(...args: ClassValue[]): string;
|
|
87
92
|
|
|
88
|
-
export { type ClassValue, type VariantProps, cn, sv };
|
|
93
|
+
export { type ClassValue, type SlotClassProps, type VariantProps, type VariantValue, cn, sv };
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,19 @@ function cn(...args) {
|
|
|
29
29
|
// src/sv.ts
|
|
30
30
|
var { isArray: isArray2 } = Array;
|
|
31
31
|
var { assign, entries, keys: keys2 } = Object;
|
|
32
|
+
var configKeys = /* @__PURE__ */ new Set([
|
|
33
|
+
"base",
|
|
34
|
+
"variants",
|
|
35
|
+
"slots",
|
|
36
|
+
"compoundVariants",
|
|
37
|
+
"compoundSlots",
|
|
38
|
+
"defaultVariants",
|
|
39
|
+
"requiredVariants",
|
|
40
|
+
"presets",
|
|
41
|
+
"cacheSize",
|
|
42
|
+
"postProcess"
|
|
43
|
+
]);
|
|
44
|
+
var isConfig = (value) => !!value && typeof value === "object" && !isArray2(value) && keys2(value).every((key) => configKeys.has(key));
|
|
32
45
|
var looseEquals = (first, second) => first === second || `${first}` === `${second}`;
|
|
33
46
|
var matchesCompound = (props, compound) => {
|
|
34
47
|
for (const compoundKey of keys2(compound)) {
|
|
@@ -47,11 +60,24 @@ var matchesCompound = (props, compound) => {
|
|
|
47
60
|
}
|
|
48
61
|
return true;
|
|
49
62
|
};
|
|
50
|
-
function sv(
|
|
63
|
+
function sv(...args) {
|
|
64
|
+
const lastArg = args[args.length - 1];
|
|
65
|
+
let base;
|
|
66
|
+
let config;
|
|
67
|
+
if (args.length >= 2 && isConfig(lastArg)) {
|
|
68
|
+
config = lastArg;
|
|
69
|
+
base = args.length > 2 ? args.slice(0, -1) : args[0];
|
|
70
|
+
} else if (args.length === 1 && isConfig(lastArg)) {
|
|
71
|
+
config = lastArg;
|
|
72
|
+
base = void 0;
|
|
73
|
+
} else {
|
|
74
|
+
base = args;
|
|
75
|
+
}
|
|
51
76
|
if (!config) {
|
|
52
|
-
return cn(
|
|
77
|
+
return cn(...args);
|
|
53
78
|
}
|
|
54
79
|
const {
|
|
80
|
+
base: configBase,
|
|
55
81
|
variants = {},
|
|
56
82
|
slots = {},
|
|
57
83
|
compoundVariants = [],
|
|
@@ -76,7 +102,8 @@ function sv(base, config) {
|
|
|
76
102
|
return value;
|
|
77
103
|
};
|
|
78
104
|
const { base: baseSlot, ...otherSlots } = slots;
|
|
79
|
-
const
|
|
105
|
+
const baseArgs = isArray2(base) ? base : [base];
|
|
106
|
+
const baseClassValue = cn(...baseArgs, configBase, baseSlot);
|
|
80
107
|
const slotKeys = new Set(keys2(otherSlots));
|
|
81
108
|
const normalizedVariants = {};
|
|
82
109
|
for (const [variantKey, variantValue] of entries(variants)) {
|
|
@@ -236,6 +263,18 @@ function sv(base, config) {
|
|
|
236
263
|
}
|
|
237
264
|
return cacheReturn(cacheKey, result);
|
|
238
265
|
};
|
|
266
|
+
const getVariantValues = (key) => keys2(normalizedVariants[key] ?? {}).map((value) => {
|
|
267
|
+
if (value === "true") {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
if (value === "false") {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
if (value !== "" && !Number.isNaN(Number(value))) {
|
|
274
|
+
return Number(value);
|
|
275
|
+
}
|
|
276
|
+
return value;
|
|
277
|
+
});
|
|
239
278
|
return assign(variantFn, {
|
|
240
279
|
variants,
|
|
241
280
|
variantKeys: keys2(variants),
|
|
@@ -245,6 +284,7 @@ function sv(base, config) {
|
|
|
245
284
|
requiredVariants,
|
|
246
285
|
presets,
|
|
247
286
|
presetKeys: keys2(presets),
|
|
287
|
+
getVariantValues,
|
|
248
288
|
clearCache: () => cache.clear(),
|
|
249
289
|
getCacheSize: () => cache.size
|
|
250
290
|
});
|