tailwind-variants 3.2.1 → 3.2.2

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
@@ -104,6 +104,59 @@ const button = tv({
104
104
  return <button className={button({size: "sm", color: "secondary"})}>Click me</button>;
105
105
  ```
106
106
 
107
+ ## Utility Functions
108
+
109
+ Tailwind Variants provides several utility functions for combining and merging class names:
110
+
111
+ ### `cx` - Simple Concatenation
112
+
113
+ Combines class names without merging conflicting classes (similar to `clsx`):
114
+
115
+ ```js
116
+ import {cx} from "tailwind-variants";
117
+
118
+ cx("text-xl", "font-bold"); // => "text-xl font-bold"
119
+ cx("px-2", "px-4"); // => "px-2 px-4" (no merging)
120
+ ```
121
+
122
+ ### `cn` - Merge with Default Config
123
+
124
+ > **Updated in v3.2.2** - Now returns a string directly (no function call needed)
125
+
126
+ Combines class names and merges conflicting Tailwind CSS classes using the default `tailwind-merge` config. Returns a string directly:
127
+
128
+ ```js
129
+ import {cn} from "tailwind-variants";
130
+
131
+ cn("bg-red-500", "bg-blue-500"); // => "bg-blue-500"
132
+ cn("px-2", "px-4", "py-2"); // => "px-4 py-2"
133
+ ```
134
+
135
+ ### `cnMerge` - Merge with Custom Config
136
+
137
+ > **Available from v3.2.2**
138
+
139
+ Combines class names and merges conflicting Tailwind CSS classes with support for custom `twMerge` configuration via a second function call:
140
+
141
+ ```js
142
+ import {cnMerge} from "tailwind-variants";
143
+
144
+ // Disable merging
145
+ cnMerge("px-2", "px-4")({twMerge: false}) // => "px-2 px-4"
146
+
147
+ // Enable merging explicitly
148
+ cnMerge("bg-red-500", "bg-blue-500")({twMerge: true}) // => "bg-blue-500"
149
+
150
+ // Use custom twMergeConfig
151
+ cnMerge("px-2", "px-4")({twMergeConfig: {...}}) // => merged with custom config
152
+ ```
153
+
154
+ **When to use which:**
155
+
156
+ - Use `cx` when you want simple concatenation without any merging
157
+ - Use `cn` for most cases when you want automatic conflict resolution with default settings
158
+ - Use `cnMerge` when you need to customize the merge behavior (disable merging, custom config, etc.)
159
+
107
160
  ## Acknowledgements
108
161
 
109
162
  - [**cva**](https://github.com/joe-bell/cva) ([Joe Bell](https://github.com/joe-bell))
package/dist/index.cjs CHANGED
@@ -16,44 +16,24 @@ var createTwMerge = (cachedTwMergeConfig) => {
16
16
  }
17
17
  });
18
18
  };
19
+ var executeMerge = (classnames, config) => {
20
+ const base = chunk2JY7EID6_cjs.cx(classnames);
21
+ if (!base || !(config?.twMerge ?? true)) return base;
22
+ if (!chunk52Z2HSI4_cjs.state.cachedTwMerge || chunk52Z2HSI4_cjs.state.didTwMergeConfigChange) {
23
+ chunk52Z2HSI4_cjs.state.didTwMergeConfigChange = false;
24
+ chunk52Z2HSI4_cjs.state.cachedTwMerge = createTwMerge(chunk52Z2HSI4_cjs.state.cachedTwMergeConfig);
25
+ }
26
+ return chunk52Z2HSI4_cjs.state.cachedTwMerge(base) || void 0;
27
+ };
19
28
  var cn = (...classnames) => {
20
- const execute = (config) => {
21
- const base = chunk2JY7EID6_cjs.cx(classnames);
22
- if (!base || !(config?.twMerge ?? true)) return base;
23
- if (!chunk52Z2HSI4_cjs.state.cachedTwMerge || chunk52Z2HSI4_cjs.state.didTwMergeConfigChange) {
24
- chunk52Z2HSI4_cjs.state.didTwMergeConfigChange = false;
25
- chunk52Z2HSI4_cjs.state.cachedTwMerge = createTwMerge(chunk52Z2HSI4_cjs.state.cachedTwMergeConfig);
26
- }
27
- return chunk52Z2HSI4_cjs.state.cachedTwMerge(base) || void 0;
28
- };
29
- const defaultResult = execute({});
30
- const fn = (config) => execute(config);
31
- return new Proxy(fn, {
32
- apply(target, thisArg, args) {
33
- return target(...args);
34
- },
35
- get(target, prop) {
36
- if (prop === Symbol.toPrimitive) {
37
- return (hint) => {
38
- if (hint === "string" || hint === "default") {
39
- return defaultResult ?? "";
40
- }
41
- return defaultResult;
42
- };
43
- }
44
- if (prop === "valueOf") {
45
- return () => defaultResult;
46
- }
47
- if (prop === "toString") {
48
- return () => String(defaultResult ?? "");
49
- }
50
- return target[prop];
51
- }
52
- });
29
+ return executeMerge(classnames, {});
30
+ };
31
+ var cnMerge = (...classnames) => {
32
+ return (config) => executeMerge(classnames, config);
53
33
  };
54
34
 
55
35
  // src/index.js
56
- var { createTV, tv } = chunk52Z2HSI4_cjs.getTailwindVariants(cn);
36
+ var { createTV, tv } = chunk52Z2HSI4_cjs.getTailwindVariants(cnMerge);
57
37
 
58
38
  Object.defineProperty(exports, "defaultConfig", {
59
39
  enumerable: true,
@@ -64,5 +44,6 @@ Object.defineProperty(exports, "cx", {
64
44
  get: function () { return chunk2JY7EID6_cjs.cx; }
65
45
  });
66
46
  exports.cn = cn;
47
+ exports.cnMerge = cnMerge;
67
48
  exports.createTV = createTV;
68
49
  exports.tv = tv;
package/dist/index.d.ts CHANGED
@@ -22,34 +22,40 @@ export type * from "./types.d.ts";
22
22
  export declare const cx: <T extends CnOptions>(...classes: T) => CnReturn;
23
23
 
24
24
  /**
25
- * Type representing a callable function that can also be coerced to a string.
26
- * This allows `cn` to work both as a function and directly in template literals.
25
+ * Combines class names and merges conflicting Tailwind CSS classes using `tailwind-merge`.
26
+ * Uses default twMerge config. For custom config, use `cnMerge` instead.
27
+ * @param classes - Class names to combine (strings, arrays, objects, etc.)
28
+ * @returns A merged class string, or `undefined` if no valid classes are provided
29
+ * @example
30
+ * ```ts
31
+ * // Simple usage with default twMerge config
32
+ * cn('bg-red-500', 'bg-blue-500') // => 'bg-blue-500'
33
+ * cn('px-2', 'px-4', 'py-2') // => 'px-4 py-2'
34
+ *
35
+ * // For custom twMerge config, use cnMerge instead
36
+ * cnMerge('px-2', 'px-4')({twMerge: false}) // => 'px-2 px-4'
37
+ * ```
27
38
  */
28
- type CnCallable = ((config?: TWMConfig) => CnReturn) & {
29
- toString(): string;
30
- valueOf(): CnReturn;
31
- [Symbol.toPrimitive](hint: "string" | "number" | "default"): string | CnReturn;
32
- } & string;
39
+ export declare const cn: <T extends CnOptions>(...classes: T) => CnReturn;
33
40
 
34
41
  /**
35
42
  * Combines class names and merges conflicting Tailwind CSS classes using `tailwind-merge`.
43
+ * Supports custom twMerge config via the second function call.
36
44
  * @param classes - Class names to combine (strings, arrays, objects, etc.)
37
- * @returns A callable function that returns the merged class string. Works directly in template literals (coerces to string) or can be called with optional config.
45
+ * @returns A function that accepts optional twMerge config and returns the merged class string
38
46
  * @example
39
47
  * ```ts
40
- * // twMerge defaults to true - works directly in template literals
41
- * `${cn('bg-red-500', 'bg-blue-500')}` // => 'bg-blue-500'
42
- * String(cn('bg-red-500', 'bg-blue-500')) // => 'bg-blue-500'
43
- *
44
- * // Can still be called with config for explicit control
45
- * cn('bg-red-500', 'bg-blue-500')() // => 'bg-blue-500'
48
+ * // With custom config
49
+ * cnMerge('bg-red-500', 'bg-blue-500')({twMerge: true}) // => 'bg-blue-500'
50
+ * cnMerge('px-2', 'px-4')({twMerge: false}) // => 'px-2 px-4'
46
51
  *
47
- * // Note: If you need simple concatenation without merging, use `cx` instead:
48
- * // Instead of: cn('bg-red-500', 'bg-blue-500')({ twMerge: false })
49
- * // Use: cx('bg-red-500', 'bg-blue-500') // => 'bg-red-500 bg-blue-500'
52
+ * // With twMergeConfig
53
+ * cnMerge('px-2', 'px-4')({twMergeConfig: {...}}) // => merged with custom config
50
54
  * ```
51
55
  */
52
- export declare const cn: <T extends CnOptions>(...classes: T) => CnCallable;
56
+ export declare const cnMerge: <T extends CnOptions>(
57
+ ...classes: T
58
+ ) => (config?: TWMConfig) => CnReturn;
53
59
 
54
60
  /**
55
61
  * Creates a variant-aware component function with Tailwind CSS classes.
package/dist/index.js CHANGED
@@ -16,43 +16,23 @@ var createTwMerge = (cachedTwMergeConfig) => {
16
16
  }
17
17
  });
18
18
  };
19
+ var executeMerge = (classnames, config) => {
20
+ const base = cx(classnames);
21
+ if (!base || !(config?.twMerge ?? true)) return base;
22
+ if (!state.cachedTwMerge || state.didTwMergeConfigChange) {
23
+ state.didTwMergeConfigChange = false;
24
+ state.cachedTwMerge = createTwMerge(state.cachedTwMergeConfig);
25
+ }
26
+ return state.cachedTwMerge(base) || void 0;
27
+ };
19
28
  var cn = (...classnames) => {
20
- const execute = (config) => {
21
- const base = cx(classnames);
22
- if (!base || !(config?.twMerge ?? true)) return base;
23
- if (!state.cachedTwMerge || state.didTwMergeConfigChange) {
24
- state.didTwMergeConfigChange = false;
25
- state.cachedTwMerge = createTwMerge(state.cachedTwMergeConfig);
26
- }
27
- return state.cachedTwMerge(base) || void 0;
28
- };
29
- const defaultResult = execute({});
30
- const fn = (config) => execute(config);
31
- return new Proxy(fn, {
32
- apply(target, thisArg, args) {
33
- return target(...args);
34
- },
35
- get(target, prop) {
36
- if (prop === Symbol.toPrimitive) {
37
- return (hint) => {
38
- if (hint === "string" || hint === "default") {
39
- return defaultResult ?? "";
40
- }
41
- return defaultResult;
42
- };
43
- }
44
- if (prop === "valueOf") {
45
- return () => defaultResult;
46
- }
47
- if (prop === "toString") {
48
- return () => String(defaultResult ?? "");
49
- }
50
- return target[prop];
51
- }
52
- });
29
+ return executeMerge(classnames, {});
30
+ };
31
+ var cnMerge = (...classnames) => {
32
+ return (config) => executeMerge(classnames, config);
53
33
  };
54
34
 
55
35
  // src/index.js
56
- var { createTV, tv } = getTailwindVariants(cn);
36
+ var { createTV, tv } = getTailwindVariants(cnMerge);
57
37
 
58
- export { cn, createTV, tv };
38
+ export { cn, cnMerge, createTV, tv };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwind-variants",
3
- "version": "3.2.1",
3
+ "version": "3.2.2",
4
4
  "description": "🦄 Tailwindcss first-class variant API",
5
5
  "keywords": [
6
6
  "tailwindcss",