clases 1.0.0 → 1.0.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 ADDED
@@ -0,0 +1,131 @@
1
+ # 🚀 Class Utilities
2
+
3
+ A high-performance, recursive, and type-safe utility for managing CSS classes. Designed specifically for Tailwind CSS users who want to replace messy string concatenations with structured, maintainable objects.
4
+
5
+ ## ✨ Features
6
+
7
+ - 🔄 **Deep Recursion:** Nest variants like `md: { hover: '...' }` to stack prefixes automatically.
8
+ - 🛡️ **Hard Typing:** Full IntelliSense autocomplete for all Tailwind variants and custom plugins.
9
+ - 🔌 **Stackable Plugins:** Merge multiple design systems or custom configurations into a single `cl` function.
10
+ - 🗜️ **Zero Overhead:** Built on top of `tailwind-merge` and `clsx` for optimal performance and conflict resolution.
11
+ - 📦 **Monorepo Ready:** Lightweight, tree-shakable packages.
12
+
13
+ ---
14
+
15
+ ## 📦 Packages
16
+
17
+ | Package | Description |
18
+ | :--- | :--- |
19
+ | **clases** | The recursive engine. Use this to build custom variants or plugins. |
20
+ | **clases-tailwind** | Pre-configured with all Tailwind CSS variants and type definitions. |
21
+
22
+ ---
23
+
24
+ ## 🚀 Quick Start
25
+
26
+ ### 1. Installation
27
+
28
+ ```bash
29
+ pnpm add clases-tailwind clases
30
+ ```
31
+
32
+ ### 2. Basic Usage
33
+
34
+ ```typescript
35
+ import { cl } from 'clases-tailwind';
36
+
37
+ const className = cl({
38
+ base: 'p-4 text-sm transition-all',
39
+ hover: 'bg-blue-500 text-white',
40
+ md: 'text-lg p-8',
41
+ dark: {
42
+ base: 'bg-gray-900',
43
+ hover: 'bg-gray-800'
44
+ }
45
+ });
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 💡 Advanced Use Cases
51
+
52
+ ### 🔄 Recursive Stacking (The "Secret Sauce")
53
+ Stop repeating prefixes. Nesting objects automatically stacks variants in the correct order.
54
+
55
+ ```typescript
56
+ cl({
57
+ md: {
58
+ hover: {
59
+ base: 'scale-105',
60
+ after: 'content-["*"]'
61
+ }
62
+ }
63
+ });
64
+ // Result: "md:hover:scale-105 md:hover:after:content-['*']"
65
+ ```
66
+
67
+
68
+
69
+ ### 🛠️ Custom Plugin Management
70
+ You can stack the Tailwind plugin with your own semantic aliases or project-specific configs.
71
+
72
+ ```typescript
73
+ import { createCl } from 'clases';
74
+ import { tailwind } from 'clases-tailwind';
75
+
76
+ const cl = createCl(
77
+ tailwind,
78
+ {
79
+ hocus: 'hover:focus',
80
+ brand: 'text-indigo-600 dark:text-indigo-400'
81
+ }
82
+ );
83
+
84
+ cl({
85
+ hocus: 'outline-none ring-2',
86
+ brand: 'font-bold'
87
+ });
88
+ ```
89
+
90
+ ### 📂 Clean Multi-line Layouts
91
+ Use backticks and commas to organize large chunks of layout logic without losing readability.
92
+
93
+ ```typescript
94
+ cl({
95
+ base: `
96
+ grid grid-cols-1,
97
+ gap-4 items-center,
98
+ w-full max-w-7xl mx-auto
99
+ `,
100
+ lg: 'grid-cols-3 gap-8'
101
+ });
102
+ ```
103
+
104
+ ---
105
+
106
+ ## ⌨️ Why Objects?
107
+
108
+ | Feature | Standard Tailwind Strings | Class Utilities Objects |
109
+ | :--- | :--- | :--- |
110
+ | **Readability** | ❌ Hard to scan long lines | ✅ Grouped by variant |
111
+ | **Maintenance** | ❌ Easy to forget prefixes | ✅ Automatic stacking |
112
+ | **Logic** | ❌ Messy ternary operators | ✅ Native JS object logic |
113
+ | **Types** | ❌ String-based (no safety) | ✅ Full Autocomplete |
114
+
115
+ ---
116
+
117
+ ## 🛠️ API Reference
118
+
119
+ ### `cl(...inputs)`
120
+ The main utility function. Accepts strings, arrays, objects, or nested structures.
121
+
122
+ ### `createCl(...plugins)`
123
+ Factory function to create a customized `cl` instance. Merges all provided objects into a single type-safe registry.
124
+
125
+ ### `tailwind`
126
+ The raw plugin data containing all Tailwind CSS variants.
127
+
128
+ ---
129
+
130
+ ## 📄 License
131
+ MIT © Mauricio Frías
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":";;;;;;;;;;AAWO,SAAS,YAAuD,OAAA,EAAmB;AAEtF,EAAA,MAAM,QAAA,GAAmC,OAAO,MAAA,CAAO,EAAE,MAAM,MAAA,EAAO,EAAG,GAAG,OAAO,CAAA;AAInF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAA,EAAa,KAAA,KAAuB;AACjD,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAEnB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA,CACF,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,CAC1B,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACjB;AAER,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAE/B,QAAA,MAAM,WAAA,GACF,GAAA,KAAQ,MAAA,GACF,SAAA,GACA,SAAA,KAAc,SACd,GAAA,GACA,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAE7B,QAAA,OAAO,OAAA,CAAQ,aAAa,WAAW,CAAA;AAAA,MAC3C,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAEQ,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA;AAEhC,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,KAAA,CACF,MAAM,UAAU,CAAA,CAChB,OAAO,OAAO,CAAA,CACd,IAAI,CAAC,GAAA,KAAS,WAAW,MAAA,GAAS,GAAA,GAAM,GAAG,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA,CAC3D,KAAK,GAAG,CAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AAEA,EAAA,OAAO,IAAI,MAAA,KAAoF;AAC3F,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACpC,MAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtE,QAAA,OAAO,OAAO,OAAA,CAAQ,KAAK,EACtB,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,MAAO,CAAA,KAAM,IAAA,GAAO,IAAI,OAAA,CAAQ,CAAA,EAAG,CAAC,CAAE,CAAA,CAChD,KAAK,GAAG,CAAA;AAAA,MACjB;AACA,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA;AACD,IAAA,OAAOA,qBAAA,CAAQC,qBAAA,CAAK,SAAS,CAAC,CAAA;AAAA,EAClC,CAAA;AACJ","file":"index.cjs","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\n/**\r\n * Helper type to merge an array of objects into one single type\r\n * This is what gives the user autocomplete for ALL plugins combined.\r\n */\r\ntype MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest]\r\n ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {})\r\n : {};\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n // Core merges all plugins into a single registry automatically\r\n const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);\r\n\r\n type CombinedKeys = keyof MergePlugins<TPlugins>;\r\n\r\n const process = (key: string, value: any): string => {\r\n if (!value) return '';\r\n\r\n if (Array.isArray(value)) {\r\n return value\r\n .map((v) => process(key, v))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\nif (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n // FIX: If the nested key is 'base', it doesn't add to the prefix chain\r\n const combinedKey =\r\n key === 'base'\r\n ? nestedKey\r\n : nestedKey === 'base'\r\n ? key // If nested is base, keep the parent key\r\n : `${key}:${nestedKey}`;\r\n\r\n return process(combinedKey, nestedValue);\r\n })\r\n .join(' ');\r\n}\r\n\r\n const prefix = registry[key] || key;\r\n\r\n if (typeof value === 'string') {\r\n return value\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (prefix === 'base' ? cls : `${prefix}:${cls}`))\r\n .join(' ');\r\n }\r\n return '';\r\n };\r\n\r\n return (...inputs: (ClassValue | { [K in CombinedKeys | 'base' | (string & {})]?: any })[]) => {\r\n const processed = inputs.map((input) => {\r\n if (input !== null && typeof input === 'object' && !Array.isArray(input)) {\r\n return Object.entries(input)\r\n .map(([k, v]) => (v === true ? k : process(k, v)))\r\n .join(' ');\r\n }\r\n return input;\r\n });\r\n return twMerge(clsx(processed));\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":";;;;;;;;;;AAsBO,SAAS,YAAuD,OAAA,EAAmB;AAEtF,EAAA,MAAM,QAAA,GAAmC,OAAO,MAAA,CAAO,EAAE,MAAM,MAAA,EAAO,EAAG,GAAG,OAAO,CAAA;AAOnF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAA,EAAa,KAAA,KAAuB;AACjD,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAEnB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA,CACF,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,CAC1B,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACjB;AAEA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAE/B,QAAA,MAAM,WAAA,GACF,GAAA,KAAQ,MAAA,GACF,SAAA,GACA,SAAA,KAAc,SACd,GAAA,GACA,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAE7B,QAAA,OAAO,OAAA,CAAQ,aAAa,WAAW,CAAA;AAAA,MAC3C,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAEA,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA;AAEhC,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,KAAA,CACF,MAAM,UAAU,CAAA,CAChB,OAAO,OAAO,CAAA,CACd,IAAI,CAAC,GAAA,KAAS,WAAW,MAAA,GAAS,GAAA,GAAM,GAAG,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA,CAC3D,KAAK,GAAG,CAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AASA,EAAA,OAAO,IAAI,MAAA,KAAoF;AAC3F,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACpC,MAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtE,QAAA,OAAO,OAAO,OAAA,CAAQ,KAAK,EACtB,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,MAAO,CAAA,KAAM,IAAA,GAAO,IAAI,OAAA,CAAQ,CAAA,EAAG,CAAC,CAAE,CAAA,CAChD,KAAK,GAAG,CAAA;AAAA,MACjB;AACA,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA;AACD,IAAA,OAAOA,qBAAA,CAAQC,qBAAA,CAAK,SAAS,CAAC,CAAA;AAAA,EAClC,CAAA;AACJ","file":"index.cjs","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\n/**\r\n * Helper type to merge an array of objects into one single type.\r\n * This provides the user with full autocomplete for ALL combined plugins.\r\n */\r\ntype MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest]\r\n ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {})\r\n : {};\r\n\r\n/**\r\n * Creates a customized class utility instance with plugin support.\r\n * * This factory function merges multiple prefix plugins and returns a scoped\r\n * `cl` function that handles recursive prefixing, tailwind-merge, and clsx logic.\r\n * * @param plugins - One or more objects defining prefix maps (e.g., { btn: 'button' }).\r\n * @returns A specialized `cl` function with autocompletion for the provided plugins.\r\n * * @example\r\n * const myCl = createCl({ ui: 'prefix' });\r\n * // Autocomplete will suggest 'ui' or 'base'\r\n * myCl({ ui: { primary: true } }); // 'prefix:primary'\r\n */\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n // Core merges all plugins into a single registry automatically\r\n const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);\r\n\r\n type CombinedKeys = keyof MergePlugins<TPlugins>;\r\n\r\n /**\r\n * Internal processor to handle recursive key chaining and prefix mapping.\r\n */\r\n const process = (key: string, value: any): string => {\r\n if (!value) return '';\r\n\r\n if (Array.isArray(value)) {\r\n return value\r\n .map((v) => process(key, v))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n if (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n // FIX: If the nested key is 'base', it doesn't add to the prefix chain\r\n const combinedKey =\r\n key === 'base'\r\n ? nestedKey\r\n : nestedKey === 'base'\r\n ? key // If nested is base, keep the parent key\r\n : `${key}:${nestedKey}`;\r\n\r\n return process(combinedKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n const prefix = registry[key] || key;\r\n\r\n if (typeof value === 'string') {\r\n return value\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (prefix === 'base' ? cls : `${prefix}:${cls}`))\r\n .join(' ');\r\n }\r\n return '';\r\n };\r\n\r\n /**\r\n * Optimized class utility function.\r\n * * Combines multiple arguments into a single string, resolving Tailwind conflicts\r\n * and applying the plugin prefixing logic defined during creation.\r\n * * @param inputs - Arguments can be strings, objects with plugin keys, or standard ClassValues.\r\n * @returns A merged string of CSS classes.\r\n */\r\n return (...inputs: (ClassValue | { [K in CombinedKeys | 'base' | (string & {})]?: any })[]) => {\r\n const processed = inputs.map((input) => {\r\n if (input !== null && typeof input === 'object' && !Array.isArray(input)) {\r\n return Object.entries(input)\r\n .map(([k, v]) => (v === true ? k : process(k, v)))\r\n .join(' ');\r\n }\r\n return input;\r\n });\r\n return twMerge(clsx(processed));\r\n };\r\n}\r\n"]}
package/dist/index.d.cts CHANGED
@@ -1,10 +1,21 @@
1
1
  import { ClassValue } from 'clsx';
2
2
 
3
3
  /**
4
- * Helper type to merge an array of objects into one single type
5
- * This is what gives the user autocomplete for ALL plugins combined.
4
+ * Helper type to merge an array of objects into one single type.
5
+ * This provides the user with full autocomplete for ALL combined plugins.
6
6
  */
7
7
  type MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest] ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {}) : {};
8
+ /**
9
+ * Creates a customized class utility instance with plugin support.
10
+ * * This factory function merges multiple prefix plugins and returns a scoped
11
+ * `cl` function that handles recursive prefixing, tailwind-merge, and clsx logic.
12
+ * * @param plugins - One or more objects defining prefix maps (e.g., { btn: 'button' }).
13
+ * @returns A specialized `cl` function with autocompletion for the provided plugins.
14
+ * * @example
15
+ * const myCl = createCl({ ui: 'prefix' });
16
+ * // Autocomplete will suggest 'ui' or 'base'
17
+ * myCl({ ui: { primary: true } }); // 'prefix:primary'
18
+ */
8
19
  declare function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins): (...inputs: (ClassValue | { [K in keyof MergePlugins<TPlugins> | "base" | (string & {})]?: any; })[]) => string;
9
20
 
10
21
  export { createCl };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,21 @@
1
1
  import { ClassValue } from 'clsx';
2
2
 
3
3
  /**
4
- * Helper type to merge an array of objects into one single type
5
- * This is what gives the user autocomplete for ALL plugins combined.
4
+ * Helper type to merge an array of objects into one single type.
5
+ * This provides the user with full autocomplete for ALL combined plugins.
6
6
  */
7
7
  type MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest] ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {}) : {};
8
+ /**
9
+ * Creates a customized class utility instance with plugin support.
10
+ * * This factory function merges multiple prefix plugins and returns a scoped
11
+ * `cl` function that handles recursive prefixing, tailwind-merge, and clsx logic.
12
+ * * @param plugins - One or more objects defining prefix maps (e.g., { btn: 'button' }).
13
+ * @returns A specialized `cl` function with autocompletion for the provided plugins.
14
+ * * @example
15
+ * const myCl = createCl({ ui: 'prefix' });
16
+ * // Autocomplete will suggest 'ui' or 'base'
17
+ * myCl({ ui: { primary: true } }); // 'prefix:primary'
18
+ */
8
19
  declare function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins): (...inputs: (ClassValue | { [K in keyof MergePlugins<TPlugins> | "base" | (string & {})]?: any; })[]) => string;
9
20
 
10
21
  export { createCl };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AAWO,SAAS,YAAuD,OAAA,EAAmB;AAEtF,EAAA,MAAM,QAAA,GAAmC,OAAO,MAAA,CAAO,EAAE,MAAM,MAAA,EAAO,EAAG,GAAG,OAAO,CAAA;AAInF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAA,EAAa,KAAA,KAAuB;AACjD,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAEnB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA,CACF,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,CAC1B,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACjB;AAER,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAE/B,QAAA,MAAM,WAAA,GACF,GAAA,KAAQ,MAAA,GACF,SAAA,GACA,SAAA,KAAc,SACd,GAAA,GACA,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAE7B,QAAA,OAAO,OAAA,CAAQ,aAAa,WAAW,CAAA;AAAA,MAC3C,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAEQ,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA;AAEhC,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,KAAA,CACF,MAAM,UAAU,CAAA,CAChB,OAAO,OAAO,CAAA,CACd,IAAI,CAAC,GAAA,KAAS,WAAW,MAAA,GAAS,GAAA,GAAM,GAAG,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA,CAC3D,KAAK,GAAG,CAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AAEA,EAAA,OAAO,IAAI,MAAA,KAAoF;AAC3F,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACpC,MAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtE,QAAA,OAAO,OAAO,OAAA,CAAQ,KAAK,EACtB,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,MAAO,CAAA,KAAM,IAAA,GAAO,IAAI,OAAA,CAAQ,CAAA,EAAG,CAAC,CAAE,CAAA,CAChD,KAAK,GAAG,CAAA;AAAA,MACjB;AACA,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA;AACD,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAC,CAAA;AAAA,EAClC,CAAA;AACJ","file":"index.js","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\n/**\r\n * Helper type to merge an array of objects into one single type\r\n * This is what gives the user autocomplete for ALL plugins combined.\r\n */\r\ntype MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest]\r\n ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {})\r\n : {};\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n // Core merges all plugins into a single registry automatically\r\n const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);\r\n\r\n type CombinedKeys = keyof MergePlugins<TPlugins>;\r\n\r\n const process = (key: string, value: any): string => {\r\n if (!value) return '';\r\n\r\n if (Array.isArray(value)) {\r\n return value\r\n .map((v) => process(key, v))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\nif (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n // FIX: If the nested key is 'base', it doesn't add to the prefix chain\r\n const combinedKey =\r\n key === 'base'\r\n ? nestedKey\r\n : nestedKey === 'base'\r\n ? key // If nested is base, keep the parent key\r\n : `${key}:${nestedKey}`;\r\n\r\n return process(combinedKey, nestedValue);\r\n })\r\n .join(' ');\r\n}\r\n\r\n const prefix = registry[key] || key;\r\n\r\n if (typeof value === 'string') {\r\n return value\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (prefix === 'base' ? cls : `${prefix}:${cls}`))\r\n .join(' ');\r\n }\r\n return '';\r\n };\r\n\r\n return (...inputs: (ClassValue | { [K in CombinedKeys | 'base' | (string & {})]?: any })[]) => {\r\n const processed = inputs.map((input) => {\r\n if (input !== null && typeof input === 'object' && !Array.isArray(input)) {\r\n return Object.entries(input)\r\n .map(([k, v]) => (v === true ? k : process(k, v)))\r\n .join(' ');\r\n }\r\n return input;\r\n });\r\n return twMerge(clsx(processed));\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AAsBO,SAAS,YAAuD,OAAA,EAAmB;AAEtF,EAAA,MAAM,QAAA,GAAmC,OAAO,MAAA,CAAO,EAAE,MAAM,MAAA,EAAO,EAAG,GAAG,OAAO,CAAA;AAOnF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAA,EAAa,KAAA,KAAuB;AACjD,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAEnB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA,CACF,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,CAC1B,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACjB;AAEA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAE/B,QAAA,MAAM,WAAA,GACF,GAAA,KAAQ,MAAA,GACF,SAAA,GACA,SAAA,KAAc,SACd,GAAA,GACA,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAE7B,QAAA,OAAO,OAAA,CAAQ,aAAa,WAAW,CAAA;AAAA,MAC3C,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAEA,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA;AAEhC,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,KAAA,CACF,MAAM,UAAU,CAAA,CAChB,OAAO,OAAO,CAAA,CACd,IAAI,CAAC,GAAA,KAAS,WAAW,MAAA,GAAS,GAAA,GAAM,GAAG,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA,CAC3D,KAAK,GAAG,CAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AASA,EAAA,OAAO,IAAI,MAAA,KAAoF;AAC3F,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AACpC,MAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtE,QAAA,OAAO,OAAO,OAAA,CAAQ,KAAK,EACtB,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,MAAO,CAAA,KAAM,IAAA,GAAO,IAAI,OAAA,CAAQ,CAAA,EAAG,CAAC,CAAE,CAAA,CAChD,KAAK,GAAG,CAAA;AAAA,MACjB;AACA,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA;AACD,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,SAAS,CAAC,CAAA;AAAA,EAClC,CAAA;AACJ","file":"index.js","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\n/**\r\n * Helper type to merge an array of objects into one single type.\r\n * This provides the user with full autocomplete for ALL combined plugins.\r\n */\r\ntype MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest]\r\n ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {})\r\n : {};\r\n\r\n/**\r\n * Creates a customized class utility instance with plugin support.\r\n * * This factory function merges multiple prefix plugins and returns a scoped\r\n * `cl` function that handles recursive prefixing, tailwind-merge, and clsx logic.\r\n * * @param plugins - One or more objects defining prefix maps (e.g., { btn: 'button' }).\r\n * @returns A specialized `cl` function with autocompletion for the provided plugins.\r\n * * @example\r\n * const myCl = createCl({ ui: 'prefix' });\r\n * // Autocomplete will suggest 'ui' or 'base'\r\n * myCl({ ui: { primary: true } }); // 'prefix:primary'\r\n */\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n // Core merges all plugins into a single registry automatically\r\n const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);\r\n\r\n type CombinedKeys = keyof MergePlugins<TPlugins>;\r\n\r\n /**\r\n * Internal processor to handle recursive key chaining and prefix mapping.\r\n */\r\n const process = (key: string, value: any): string => {\r\n if (!value) return '';\r\n\r\n if (Array.isArray(value)) {\r\n return value\r\n .map((v) => process(key, v))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n if (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n // FIX: If the nested key is 'base', it doesn't add to the prefix chain\r\n const combinedKey =\r\n key === 'base'\r\n ? nestedKey\r\n : nestedKey === 'base'\r\n ? key // If nested is base, keep the parent key\r\n : `${key}:${nestedKey}`;\r\n\r\n return process(combinedKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n const prefix = registry[key] || key;\r\n\r\n if (typeof value === 'string') {\r\n return value\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (prefix === 'base' ? cls : `${prefix}:${cls}`))\r\n .join(' ');\r\n }\r\n return '';\r\n };\r\n\r\n /**\r\n * Optimized class utility function.\r\n * * Combines multiple arguments into a single string, resolving Tailwind conflicts\r\n * and applying the plugin prefixing logic defined during creation.\r\n * * @param inputs - Arguments can be strings, objects with plugin keys, or standard ClassValues.\r\n * @returns A merged string of CSS classes.\r\n */\r\n return (...inputs: (ClassValue | { [K in CombinedKeys | 'base' | (string & {})]?: any })[]) => {\r\n const processed = inputs.map((input) => {\r\n if (input !== null && typeof input === 'object' && !Array.isArray(input)) {\r\n return Object.entries(input)\r\n .map(([k, v]) => (v === true ? k : process(k, v)))\r\n .join(' ');\r\n }\r\n return input;\r\n });\r\n return twMerge(clsx(processed));\r\n };\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clases",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/index.ts CHANGED
@@ -2,19 +2,33 @@ import { twMerge } from 'tailwind-merge';
2
2
  import clsx, { type ClassValue } from 'clsx';
3
3
 
4
4
  /**
5
- * Helper type to merge an array of objects into one single type
6
- * This is what gives the user autocomplete for ALL plugins combined.
5
+ * Helper type to merge an array of objects into one single type.
6
+ * This provides the user with full autocomplete for ALL combined plugins.
7
7
  */
8
8
  type MergePlugins<T extends Record<string, string>[]> = T extends [infer First, ...infer Rest]
9
9
  ? First & (Rest extends Record<string, string>[] ? MergePlugins<Rest> : {})
10
10
  : {};
11
11
 
12
+ /**
13
+ * Creates a customized class utility instance with plugin support.
14
+ * * This factory function merges multiple prefix plugins and returns a scoped
15
+ * `cl` function that handles recursive prefixing, tailwind-merge, and clsx logic.
16
+ * * @param plugins - One or more objects defining prefix maps (e.g., { btn: 'button' }).
17
+ * @returns A specialized `cl` function with autocompletion for the provided plugins.
18
+ * * @example
19
+ * const myCl = createCl({ ui: 'prefix' });
20
+ * // Autocomplete will suggest 'ui' or 'base'
21
+ * myCl({ ui: { primary: true } }); // 'prefix:primary'
22
+ */
12
23
  export function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {
13
24
  // Core merges all plugins into a single registry automatically
14
25
  const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);
15
26
 
16
27
  type CombinedKeys = keyof MergePlugins<TPlugins>;
17
28
 
29
+ /**
30
+ * Internal processor to handle recursive key chaining and prefix mapping.
31
+ */
18
32
  const process = (key: string, value: any): string => {
19
33
  if (!value) return '';
20
34
 
@@ -25,21 +39,21 @@ export function createCl<TPlugins extends Record<string, string>[]>(...plugins:
25
39
  .join(' ');
26
40
  }
27
41
 
28
- if (typeof value === 'object') {
29
- return Object.entries(value)
30
- .map(([nestedKey, nestedValue]) => {
31
- // FIX: If the nested key is 'base', it doesn't add to the prefix chain
32
- const combinedKey =
33
- key === 'base'
34
- ? nestedKey
35
- : nestedKey === 'base'
36
- ? key // If nested is base, keep the parent key
37
- : `${key}:${nestedKey}`;
42
+ if (typeof value === 'object') {
43
+ return Object.entries(value)
44
+ .map(([nestedKey, nestedValue]) => {
45
+ // FIX: If the nested key is 'base', it doesn't add to the prefix chain
46
+ const combinedKey =
47
+ key === 'base'
48
+ ? nestedKey
49
+ : nestedKey === 'base'
50
+ ? key // If nested is base, keep the parent key
51
+ : `${key}:${nestedKey}`;
38
52
 
39
- return process(combinedKey, nestedValue);
40
- })
41
- .join(' ');
42
- }
53
+ return process(combinedKey, nestedValue);
54
+ })
55
+ .join(' ');
56
+ }
43
57
 
44
58
  const prefix = registry[key] || key;
45
59
 
@@ -53,6 +67,13 @@ if (typeof value === 'object') {
53
67
  return '';
54
68
  };
55
69
 
70
+ /**
71
+ * Optimized class utility function.
72
+ * * Combines multiple arguments into a single string, resolving Tailwind conflicts
73
+ * and applying the plugin prefixing logic defined during creation.
74
+ * * @param inputs - Arguments can be strings, objects with plugin keys, or standard ClassValues.
75
+ * @returns A merged string of CSS classes.
76
+ */
56
77
  return (...inputs: (ClassValue | { [K in CombinedKeys | 'base' | (string & {})]?: any })[]) => {
57
78
  const processed = inputs.map((input) => {
58
79
  if (input !== null && typeof input === 'object' && !Array.isArray(input)) {