slot-variants 1.5.0 → 1.6.1

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 CHANGED
@@ -12,10 +12,11 @@ npm install slot-variants
12
12
 
13
13
  ## Overview
14
14
 
15
- `slot-variants` exports two functions:
15
+ `slot-variants` exports three functions:
16
16
 
17
17
  - **`sv()`** - creates variant-based class name generators with optional slots
18
18
  - **`cn()`** - a utility for conditionally merging class names
19
+ - **`createSV()`** - builds a pre-configured `sv()` with shared config defaults
19
20
 
20
21
  `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
22
 
@@ -68,7 +69,7 @@ cn(['foo', ['bar', 'baz']]); // 'foo bar baz'
68
69
  cn({ foo: true, bar: false, baz: true }); // 'foo baz'
69
70
 
70
71
  // Mixed
71
- cn('base', ['responsive'], { active: true }); // 'base active responsive'
72
+ cn('base', ['responsive'], { active: true }); // 'base responsive active'
72
73
 
73
74
  // Falsy values are filtered out
74
75
  cn('foo', null, undefined, false, 'bar'); // 'foo bar'
@@ -733,6 +734,52 @@ const button = sv('px-4 py-2 bg-blue-500', {
733
734
 
734
735
  The `postProcess` function is applied to each slot's final class string independently.
735
736
 
737
+ ### Shared Defaults with `createSV()`
738
+
739
+ `createSV(defaults)` returns a pre-configured `sv()` that merges `defaults` into every config-based call. This avoids repeating the same options — most commonly `postProcess: twMerge` — across every component:
740
+
741
+ ```typescript
742
+ import { createSV } from 'slot-variants';
743
+ import { twMerge } from 'tailwind-merge';
744
+
745
+ export const customSV = createSV({
746
+ postProcess: twMerge,
747
+ cacheSize: 512
748
+ });
749
+
750
+ // twMerge is applied without restating it per component
751
+ const button = customSV('px-4 py-2 bg-blue-500', {
752
+ variants: {
753
+ size: {
754
+ sm: 'px-2 py-1 text-sm',
755
+ lg: 'px-6 py-3 text-lg'
756
+ }
757
+ }
758
+ });
759
+ ```
760
+
761
+ `defaults` accepts **any** config option (`base`, `variants`, `slots`, `compoundVariants`, `cacheSize`, `introspection`, `postProcess`, …). The merge is shallow and **a per-call value always wins** over the matching default — there is no deep merging of variants or compound rules:
762
+
763
+ ```typescript
764
+ const customSV = createSV({ postProcess: twMerge });
765
+
766
+ // This component opts out of twMerge entirely
767
+ const raw = customSV('btn', {
768
+ variants: { size: { sm: 'text-sm' } },
769
+ postProcess: (className) => className // overrides the default
770
+ });
771
+ ```
772
+
773
+ Calls with no config object are forwarded straight to `cn()`-style merging and never see the defaults:
774
+
775
+ ```typescript
776
+ const customSV = createSV({ postProcess: (c) => c.toUpperCase() });
777
+
778
+ customSV('flex', 'items-center'); // 'flex items-center' — defaults are skipped
779
+ ```
780
+
781
+ A factory-level `introspection: true` is reflected in each component's return type, so the [introspection](#introspection) API is available without setting the flag on every config. A per-call `introspection: false` opts an individual component back out.
782
+
736
783
  ### Caching
737
784
 
738
785
  Results are cached automatically for performance. The default cache size is **256** entries.
@@ -945,6 +992,7 @@ When used on an `sv()` definition without slots, `SlotClassProps` resolves to `{
945
992
  | `VariantProps<T, E>` | Extracts variant props from an `sv()` return type, optionally excluding keys in `E` |
946
993
  | `VariantValue<T, K>` | Extracts the value union for a single variant key `K`, without `undefined` |
947
994
  | `SlotClassProps<T>` | Extracts the per-slot class injection shape from an `sv()` return type |
995
+ | `SV<DI>` | The shape of an `sv()` function, with the factory's introspection default `DI`; the return type of `createSV()` |
948
996
 
949
997
  ### Return Type
950
998
 
@@ -986,6 +1034,8 @@ Class values inside the config (`base`, `variants`, `slots`, and `compound*` `cl
986
1034
 
987
1035
  - **`slot-variants/no-shared-tokens`** — flags class tokens that appear in every value of an exhaustively-covered variant, where “exhaustive” means the variant has a statically defined default value, is listed in `requiredVariants`, or `requiredVariants` is `true` (every variant required). Those tokens are constant in the rendered output, so they belong in `base` or the corresponding `slots[slot]` entry rather than being repeated in every variant value. The rule only analyzes `sv()` calls with a config, compares tokens per-slot, skips non-exhaustive variants, single-value variants, boolean shorthand, undefined or dynamic defaults, and dynamic or partially-analyzable variant value records, and reports every repeated occurrence that should be lifted out.
988
1036
 
1037
+ - **`slot-variants/require-top-level-config`** — flags `sv()` calls made with a config object that aren't at the module top level. The config form compiles the variant function and seeds its cache once; nesting it inside a function (a component body, an arrow, an object method, etc.) rebuilds that work — and throws away the variant cache — on every call, so the config form belongs at module scope. The cn-style calling convention of `sv()` (and every `cn()` call) carries no config and is left alone, as are calls inside top-level blocks or conditionals, which still run only at module load.
1038
+
989
1039
  Only calls where `sv` or `cn` is a named import from `'slot-variants'` are analyzed. `no-conflicting-classes` skips dynamic inputs silently to avoid false positives; `no-dynamic-classes` is the opposite — it flags exactly those positions so the static analyzer can fully reason about every call. `no-shared-tokens` sits between them: it needs a fully statically analyzable, exhaustive variant before it can prove a token is constant across every value. `no-empty-classes` and `no-redundant-spaces` are independent and complement the structural rules: they cover empty and badly-shaped literals reachable from a call's arguments, regardless of whether the surrounding call is fully static.
990
1040
 
991
1041
  ### ESLint (flat config)
@@ -1011,7 +1061,8 @@ export default [
1011
1061
  'slot-variants/no-dynamic-classes': 'error',
1012
1062
  'slot-variants/no-empty-classes': 'error',
1013
1063
  'slot-variants/no-redundant-spaces': 'error',
1014
- 'slot-variants/no-shared-tokens': 'error'
1064
+ 'slot-variants/no-shared-tokens': 'error',
1065
+ 'slot-variants/require-top-level-config': 'error'
1015
1066
  }
1016
1067
  }
1017
1068
  ];
@@ -1027,7 +1078,8 @@ export default [
1027
1078
  "slot-variants/no-dynamic-classes": "error",
1028
1079
  "slot-variants/no-empty-classes": "error",
1029
1080
  "slot-variants/no-redundant-spaces": "error",
1030
- "slot-variants/no-shared-tokens": "error"
1081
+ "slot-variants/no-shared-tokens": "error",
1082
+ "slot-variants/require-top-level-config": "error"
1031
1083
  }
1032
1084
  }
1033
1085
  ```
@@ -1193,7 +1245,7 @@ Key differences to be aware of:
1193
1245
  | --- | --- | --- |
1194
1246
  | Slot return type | Always functions: `slot({ class: '...' })` | Strings by default; functions for slots listed in `multiSlots` |
1195
1247
  | `extend` (composition) | Supported | Not supported |
1196
- | Built-in `twMerge` | Enabled by default | Use `postProcess: twMerge` |
1248
+ | Built-in `twMerge` | Enabled by default | Use `postProcess: twMerge`, globally via `createSV` |
1197
1249
 
1198
1250
  **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, or list a slot in [`multiSlots`](#multi-slots) to expose it as a `tv`-style reconfigurable function:
1199
1251
 
@@ -1219,3 +1271,13 @@ const button = sv({
1219
1271
  postProcess: twMerge
1220
1272
  });
1221
1273
  ```
1274
+
1275
+ To enable it globally — the closest equivalent to `tv`'s default `twMerge` — wrap it once with [`createSV()`](#shared-defaults-with-createsv) and import the result everywhere:
1276
+
1277
+ ```typescript
1278
+ // custom-sv.ts
1279
+ import { createSV } from 'slot-variants';
1280
+ import { twMerge } from 'tailwind-merge';
1281
+
1282
+ export const customSV = createSV({ postProcess: twMerge });
1283
+ ```
package/SKILL.md CHANGED
@@ -107,6 +107,15 @@ import { twMerge } from 'tailwind-merge';
107
107
  sv('px-4 py-2', { variants: { size: { lg: 'px-6 py-3' } }, postProcess: twMerge });
108
108
  ```
109
109
 
110
+ To avoid restating `postProcess` (or any config default) per component, wrap `sv` once with `createSV`. Defaults are shallow merged into every config-based call and a per-call value always wins:
111
+
112
+ ```typescript
113
+ import { createSV } from 'slot-variants';
114
+ import { twMerge } from 'tailwind-merge';
115
+
116
+ const customSV = createSV({ postProcess: twMerge, cacheSize: 512 });
117
+ ```
118
+
110
119
  ### 9. Leverage Caching for Performance
111
120
 
112
121
  The library caches results automatically (default 256 entries). Each cache entry is one distinct combination of resolved variant values:
@@ -196,5 +205,6 @@ Class values inside the config (`base`, `variants` values, `slots` values, and `
196
205
  - `VariantProps<T, E>` — Extract variant props from an `sv()` return, optionally excluding keys
197
206
  - `VariantValue<T, K>` — Extract the value union for a single variant key, without `undefined`
198
207
  - `SlotClassProps<T>` — Extract the per-slot class injection shape from an `sv()` return type
208
+ - `SV<DI>` — The shape of an `sv()` function (the return type of `createSV()`), carrying the factory's introspection default `DI`
199
209
 
200
210
  Functions are imported as named values; types via `import type { ... } from 'slot-variants'`.
@@ -1215,12 +1215,47 @@ var noEmptyClasses = {
1215
1215
  });
1216
1216
  }
1217
1217
  };
1218
+ var isInsideFunctionScope = (scope) => {
1219
+ let current = scope;
1220
+ while (current) {
1221
+ if (current.type === "function") {
1222
+ return true;
1223
+ }
1224
+ current = current.upper;
1225
+ }
1226
+ return false;
1227
+ };
1228
+ var requireTopLevelConfig = {
1229
+ meta: {
1230
+ type: "problem",
1231
+ docs: {
1232
+ description: "Require sv() calls with a config object to be at the module top level",
1233
+ recommended: true,
1234
+ url: DOCS_URL
1235
+ },
1236
+ schema: [],
1237
+ messages: {
1238
+ nested: "sv() with a config object must be called at the module top level, not nested inside a function \u2014 otherwise its compiled config and variant cache are rebuilt on every call."
1239
+ }
1240
+ },
1241
+ create(context) {
1242
+ return createTrackedCallListeners(context, (node, call) => {
1243
+ if (!call.config) {
1244
+ return;
1245
+ }
1246
+ if (isInsideFunctionScope(context.sourceCode.getScope(node))) {
1247
+ context.report({ node, messageId: "nested" });
1248
+ }
1249
+ });
1250
+ }
1251
+ };
1218
1252
  var rules = {
1219
1253
  "no-conflicting-classes": noConflictingClasses,
1220
1254
  "no-dynamic-classes": noDynamicClasses,
1221
1255
  "no-empty-classes": noEmptyClasses,
1222
1256
  "no-redundant-spaces": noRedundantSpaces,
1223
- "no-shared-tokens": noSharedTokens
1257
+ "no-shared-tokens": noSharedTokens,
1258
+ "require-top-level-config": requireTopLevelConfig
1224
1259
  };
1225
1260
  var meta = { name: "slot-variants" };
1226
1261
  var recommendedRules = {};
@@ -9,6 +9,7 @@ declare const rules: {
9
9
  'no-empty-classes': Rule.RuleModule;
10
10
  'no-redundant-spaces': Rule.RuleModule;
11
11
  'no-shared-tokens': Rule.RuleModule;
12
+ 'require-top-level-config': Rule.RuleModule;
12
13
  };
13
14
  declare const plugin: {
14
15
  meta: {
@@ -20,6 +21,7 @@ declare const plugin: {
20
21
  'no-empty-classes': Rule.RuleModule;
21
22
  'no-redundant-spaces': Rule.RuleModule;
22
23
  'no-shared-tokens': Rule.RuleModule;
24
+ 'require-top-level-config': Rule.RuleModule;
23
25
  };
24
26
  configs: Record<string, Linter.Config>;
25
27
  };
@@ -1190,12 +1190,47 @@ var noEmptyClasses = {
1190
1190
  });
1191
1191
  }
1192
1192
  };
1193
+ var isInsideFunctionScope = (scope) => {
1194
+ let current = scope;
1195
+ while (current) {
1196
+ if (current.type === "function") {
1197
+ return true;
1198
+ }
1199
+ current = current.upper;
1200
+ }
1201
+ return false;
1202
+ };
1203
+ var requireTopLevelConfig = {
1204
+ meta: {
1205
+ type: "problem",
1206
+ docs: {
1207
+ description: "Require sv() calls with a config object to be at the module top level",
1208
+ recommended: true,
1209
+ url: DOCS_URL
1210
+ },
1211
+ schema: [],
1212
+ messages: {
1213
+ nested: "sv() with a config object must be called at the module top level, not nested inside a function \u2014 otherwise its compiled config and variant cache are rebuilt on every call."
1214
+ }
1215
+ },
1216
+ create(context) {
1217
+ return createTrackedCallListeners(context, (node, call) => {
1218
+ if (!call.config) {
1219
+ return;
1220
+ }
1221
+ if (isInsideFunctionScope(context.sourceCode.getScope(node))) {
1222
+ context.report({ node, messageId: "nested" });
1223
+ }
1224
+ });
1225
+ }
1226
+ };
1193
1227
  var rules = {
1194
1228
  "no-conflicting-classes": noConflictingClasses,
1195
1229
  "no-dynamic-classes": noDynamicClasses,
1196
1230
  "no-empty-classes": noEmptyClasses,
1197
1231
  "no-redundant-spaces": noRedundantSpaces,
1198
- "no-shared-tokens": noSharedTokens
1232
+ "no-shared-tokens": noSharedTokens,
1233
+ "require-top-level-config": requireTopLevelConfig
1199
1234
  };
1200
1235
  var meta = { name: "slot-variants" };
1201
1236
  var recommendedRules = {};
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  cn: () => cn,
24
+ createSV: () => createSV,
24
25
  sv: () => sv
25
26
  });
26
27
  module.exports = __toCommonJS(index_exports);
@@ -34,6 +35,13 @@ var append = (result, value) => {
34
35
  }
35
36
  return `${result} ${value}`;
36
37
  };
38
+ var appendArray = (result, array) => {
39
+ const flattened = cn(...array);
40
+ if (flattened) {
41
+ return append(result, flattened);
42
+ }
43
+ return result;
44
+ };
37
45
  var appendRecord = (result, record) => {
38
46
  let current = result;
39
47
  for (const key of keys(record)) {
@@ -44,11 +52,8 @@ var appendRecord = (result, record) => {
44
52
  return current;
45
53
  };
46
54
  function cn(...args) {
47
- let index = 0;
48
55
  let result = "";
49
- while (index < args.length) {
50
- const item = args[index];
51
- index++;
56
+ for (const item of args) {
52
57
  if (!item) {
53
58
  continue;
54
59
  }
@@ -57,7 +62,7 @@ function cn(...args) {
57
62
  continue;
58
63
  }
59
64
  if (isArray(item)) {
60
- args.push(...item);
65
+ result = appendArray(result, item);
61
66
  continue;
62
67
  }
63
68
  if (typeof item === "object") {
@@ -674,12 +679,15 @@ var runVariantResult = (config, props) => {
674
679
  }
675
680
  return applyMultiSlots(config, props, result);
676
681
  };
677
- function sv(...args) {
682
+ var sv = ((...args) => {
678
683
  const last = args.at(-1);
679
684
  if (!isConfig(last)) {
680
685
  return cn(...args);
681
686
  }
682
687
  const config = compileConfig(args.slice(0, -1), last);
688
+ return createVariantFn(config);
689
+ });
690
+ var createVariantFn = (config) => {
683
691
  const variantFn = (props = {}) => runVariantResult(config, props);
684
692
  if (!config.introspection) {
685
693
  return variantFn;
@@ -701,9 +709,24 @@ function sv(...args) {
701
709
  clearCache: () => config.cache.clear(),
702
710
  getCacheSize: () => config.cache.size
703
711
  });
704
- }
712
+ };
713
+ var createSV = (defaults = {}) => {
714
+ const configuredSv = (...args) => {
715
+ const last = args.at(-1);
716
+ if (!isConfig(last)) {
717
+ return cn(...args);
718
+ }
719
+ const config = compileConfig(args.slice(0, -1), {
720
+ ...defaults,
721
+ ...last
722
+ });
723
+ return createVariantFn(config);
724
+ };
725
+ return configuredSv;
726
+ };
705
727
  // Annotate the CommonJS export names for ESM import in node:
706
728
  0 && (module.exports = {
707
729
  cn,
730
+ createSV,
708
731
  sv
709
732
  });
package/dist/index.d.ts CHANGED
@@ -108,6 +108,18 @@ type VariantFn<S extends MaybeSlots, V extends MaybeVariants<S>, RV extends Requ
108
108
  (...args: [RequiredVariantKeys<V, RV>] extends [never] ? [props?: Prettify<Props<S, V, RV, P>> | undefined] : [props: Prettify<Props<S, V, RV, P>>]): ReturnValue<S, V, MS>;
109
109
  } & (I extends true ? Prettify<IntrospectionValues<S, V, RV, P, MS>> : unknown);
110
110
  type NonConfigClassArg<T> = T extends Record<string, unknown> ? Exclude<StringKeyof<T>, ConfigKey> extends never ? never : T : T;
111
+ /**
112
+ * The shape of an `sv()` function. Mirrors the overloads of the exported `sv`,
113
+ * with the introspection default `DI` baked in by `createSV()` so configs that
114
+ * omit `introspection` inherit the factory default in their return type.
115
+ */
116
+ type SV<DI extends boolean = false> = {
117
+ <S extends MaybeSlots = undefined, V extends MaybeVariants<S> = undefined, RV extends RequiredVariants<V> = false, P extends MaybePresets<S, V> = undefined, MS extends MultiSlots<S> = false, I extends boolean = DI>(config: Config<S, V, RV, P, MS, I>): VariantFn<S, V, RV, P, MS, I>;
118
+ <S extends MaybeSlots = undefined, V extends MaybeVariants<S> = undefined, RV extends RequiredVariants<V> = false, P extends MaybePresets<S, V> = undefined, MS extends MultiSlots<S> = false, I extends boolean = DI>(...args: [...ClassValue[], Config<S, V, RV, P, MS, I>]): VariantFn<S, V, RV, P, MS, I>;
119
+ <const T extends ClassValue[]>(...args: T & {
120
+ [K in keyof T]: NonConfigClassArg<T[K]>;
121
+ }): string;
122
+ };
111
123
  /**
112
124
  * Extracts the variant props object from an `sv()` return type
113
125
  *
@@ -215,10 +227,28 @@ type SlotClassProps<T extends AnyFn> = ReturnType<T> extends string ? Partial<Re
215
227
  * const { base, header, body } = card();
216
228
  * ```
217
229
  */
218
- declare function sv<S extends MaybeSlots = undefined, V extends MaybeVariants<S> = undefined, RV extends RequiredVariants<V> = false, P extends MaybePresets<S, V> = undefined, MS extends MultiSlots<S> = false, I extends boolean = false>(config: Config<S, V, RV, P, MS, I>): VariantFn<S, V, RV, P, MS, I>;
219
- declare function sv<S extends MaybeSlots = undefined, V extends MaybeVariants<S> = undefined, RV extends RequiredVariants<V> = false, P extends MaybePresets<S, V> = undefined, MS extends MultiSlots<S> = false, I extends boolean = false>(...args: [...ClassValue[], Config<S, V, RV, P, MS, I>]): VariantFn<S, V, RV, P, MS, I>;
220
- declare function sv<const T extends ClassValue[]>(...args: T & {
221
- [K in keyof T]: NonConfigClassArg<T[K]>;
222
- }): string;
230
+ declare const sv: SV;
231
+ type RawConfig = Config<MaybeSlots, MaybeVariants<MaybeSlots>, RequiredVariants<MaybeVariants<MaybeSlots>>, MaybePresets<MaybeSlots, MaybeVariants<MaybeSlots>>, MultiSlots<MaybeSlots>, boolean>;
232
+ /**
233
+ * Builds a pre-configured `sv()` function whose `defaults` are applied to every
234
+ * config-based call. The defaults accept any config option and are shallow
235
+ * merged so a per-call value always wins; calls with no config are forwarded
236
+ * to `cn()`-style merging untouched.
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * import { twMerge } from 'tailwind-merge';
241
+ *
242
+ * const customSV = createSV({ postProcess: twMerge, cacheSize: 512 });
243
+ *
244
+ * // twMerge is applied without restating it per component
245
+ * const button = customSV('px-4 py-2', {
246
+ * variants: { size: { sm: 'px-2', lg: 'px-6' } }
247
+ * });
248
+ * ```
249
+ */
250
+ declare const createSV: <I extends boolean = false>(defaults?: RawConfig & {
251
+ introspection?: I | undefined;
252
+ }) => SV<I>;
223
253
 
224
- export { type ClassValue, type SlotClassProps, type VariantProps, type VariantValue, cn, sv };
254
+ export { type ClassValue, type SV, type SlotClassProps, type VariantProps, type VariantValue, cn, createSV, sv };
package/dist/index.js CHANGED
@@ -7,6 +7,13 @@ var append = (result, value) => {
7
7
  }
8
8
  return `${result} ${value}`;
9
9
  };
10
+ var appendArray = (result, array) => {
11
+ const flattened = cn(...array);
12
+ if (flattened) {
13
+ return append(result, flattened);
14
+ }
15
+ return result;
16
+ };
10
17
  var appendRecord = (result, record) => {
11
18
  let current = result;
12
19
  for (const key of keys(record)) {
@@ -17,11 +24,8 @@ var appendRecord = (result, record) => {
17
24
  return current;
18
25
  };
19
26
  function cn(...args) {
20
- let index = 0;
21
27
  let result = "";
22
- while (index < args.length) {
23
- const item = args[index];
24
- index++;
28
+ for (const item of args) {
25
29
  if (!item) {
26
30
  continue;
27
31
  }
@@ -30,7 +34,7 @@ function cn(...args) {
30
34
  continue;
31
35
  }
32
36
  if (isArray(item)) {
33
- args.push(...item);
37
+ result = appendArray(result, item);
34
38
  continue;
35
39
  }
36
40
  if (typeof item === "object") {
@@ -647,12 +651,15 @@ var runVariantResult = (config, props) => {
647
651
  }
648
652
  return applyMultiSlots(config, props, result);
649
653
  };
650
- function sv(...args) {
654
+ var sv = ((...args) => {
651
655
  const last = args.at(-1);
652
656
  if (!isConfig(last)) {
653
657
  return cn(...args);
654
658
  }
655
659
  const config = compileConfig(args.slice(0, -1), last);
660
+ return createVariantFn(config);
661
+ });
662
+ var createVariantFn = (config) => {
656
663
  const variantFn = (props = {}) => runVariantResult(config, props);
657
664
  if (!config.introspection) {
658
665
  return variantFn;
@@ -674,8 +681,23 @@ function sv(...args) {
674
681
  clearCache: () => config.cache.clear(),
675
682
  getCacheSize: () => config.cache.size
676
683
  });
677
- }
684
+ };
685
+ var createSV = (defaults = {}) => {
686
+ const configuredSv = (...args) => {
687
+ const last = args.at(-1);
688
+ if (!isConfig(last)) {
689
+ return cn(...args);
690
+ }
691
+ const config = compileConfig(args.slice(0, -1), {
692
+ ...defaults,
693
+ ...last
694
+ });
695
+ return createVariantFn(config);
696
+ };
697
+ return configuredSv;
698
+ };
678
699
  export {
679
700
  cn,
701
+ createSV,
680
702
  sv
681
703
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slot-variants",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "description": "Type-safe class name variants with slots",
5
5
  "type": "module",
6
6
  "exports": {