clases 1.1.10 → 1.1.12

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
@@ -4,19 +4,19 @@ A high-performance, recursive, and type-safe utility for managing CSS classes. D
4
4
 
5
5
  ## ✨ Features
6
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.
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
12
 
13
13
  ---
14
14
 
15
15
  ## 📦 Packages
16
16
 
17
- | Package | Description |
18
- | :--- | :--- |
19
- | **clases** | The recursive engine. Use this to build custom variants or plugins. |
17
+ | Package | Description |
18
+ | :------------------ | :------------------------------------------------------------------ |
19
+ | **clases** | The recursive engine. Use this to build custom variants or plugins. |
20
20
  | **clases-tailwind** | Pre-configured with all Tailwind CSS variants and type definitions. |
21
21
 
22
22
  ---
@@ -35,13 +35,13 @@ pnpm add clases-tailwind clases
35
35
  import { cl } from 'clases-tailwind';
36
36
 
37
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
- }
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
45
  });
46
46
  ```
47
47
 
@@ -50,144 +50,86 @@ const className = cl({
50
50
  ## 💡 Advanced Use Cases
51
51
 
52
52
  ### 🔄 Recursive Stacking (The "Secret Sauce")
53
+
53
54
  Stop repeating prefixes. Nesting objects automatically stacks variants in the correct order.
54
55
 
55
56
  ```typescript
56
57
  cl({
57
- md: {
58
- hover: {
59
- base: 'scale-105',
60
- after: 'content-["*"]'
58
+ md: {
59
+ hover: {
60
+ base: 'scale-105',
61
+ after: 'content-["*"]'
62
+ }
61
63
  }
62
- }
63
64
  });
64
65
  // Result: "md:hover:scale-105 md:hover:after:content-['*']"
65
66
  ```
66
- ---
67
-
68
- ## 🌈 Beautiful Syntax & Variants
69
-
70
- The most powerful feature of this utility is **Transparent Logical Nesting**. It allows you to organize your design system using nested objects that represent your business logic (variants, states, or themes) without polluting the final CSS output.
71
-
72
- #### How it Works
73
-
74
- The engine distinguishes between **Registered Prefixes** (modifiers like `md`, `hover`, or `ui`) and **Logical Keys** (your own organizational names like `variants`, `primary`, or `[state]`):
75
-
76
- * **Registered Keys**: Concatenate to form the final CSS prefix.
77
- * **Unregistered Keys**: Act as transparent wrappers. They are ignored in the final string but pass the current prefix down to their children.
78
-
79
- #### Component Variants Example
80
-
81
- This structure allows you to colocate base styles, responsive modifiers, and interaction states within a single logical branch:
82
-
83
- ```typescript
84
- const variant = 'primary';
85
- const theme = 'dark';
86
-
87
- const className = cl({
88
- md: {
89
- // 'variants' is NOT in the registry, so it is transparent
90
- variants: {
91
- // We select the active branch using standard JS
92
- [variant]: {
93
- base: 'rounded-lg px-4 py-2 transition',
94
- // 'dark' is a registered prefix, so it will be mapped
95
- dark: 'border-white text-white',
96
- hover: 'opacity-80'
97
- },
98
- secondary: 'bg-gray-200 text-black'
99
- }[variant]
100
- }
101
- });
102
-
103
- /**
104
- * Output (for variant 'primary'):
105
- * "md:rounded-lg md:px-4 md:py-2 md:transition md:dark:border-white md:dark:text-white md:hover:opacity-80"
106
- */
107
- ```
108
67
 
109
- #### Why this is superior:
110
-
111
- 1. **Clean DOM**: You won't see "ghost" prefixes like `variants:primary:bg-blue-500` in your HTML.
112
- 2. **Zero Boilerplate**: You don't have to repeat `md:dark:...` for every single class; the engine handles the chain automatically.
113
- 3. **Type-Safe Organization**: Use your own naming conventions to group styles while keeping the output perfectly compatible with Tailwind CSS.
114
-
115
- #### Best Practice: Selection Logic
116
-
117
- To keep the output optimized and prevent class collisions, handle the selection at the logical level so the engine only processes the "winning" branch:
118
-
119
- ```typescript
120
- cl({
121
- ui: {
122
- [status]: {
123
- success: 'text-green-600',
124
- error: 'text-red-600',
125
- pending: 'text-yellow-600'
126
- }[status]
127
- }
128
- });
129
- ```
130
68
  ---
131
69
 
132
70
  ### 🛠️ Custom Plugin Management
71
+
133
72
  You can stack the Tailwind plugin with your own semantic aliases or project-specific configs.
134
73
 
135
74
  ```typescript
136
75
  import { createCl } from 'clases';
137
76
  import { tailwind } from 'clases-tailwind';
138
77
 
139
- const cl = createCl(
140
- tailwind,
141
- {
78
+ const cl = createCl(tailwind, {
142
79
  hocus: 'hover:focus',
143
- brand: 'text-indigo-600 dark:text-indigo-400'
144
- }
145
- );
80
+ brand: 'text-indigo-600 dark:text-indigo-400'
81
+ });
146
82
 
147
- cl({
148
- hocus: 'outline-none ring-2',
149
- brand: 'font-bold'
83
+ cl({
84
+ hocus: 'outline-none ring-2',
85
+ brand: 'font-bold'
150
86
  });
151
87
  ```
152
88
 
153
89
  ### 📂 Clean Multi-line Layouts
90
+
154
91
  Use backticks and commas to organize large chunks of layout logic without losing readability.
155
92
 
156
93
  ```typescript
157
94
  cl({
158
- base: `
95
+ base: `
159
96
  grid grid-cols-1,
160
97
  gap-4 items-center,
161
98
  w-full max-w-7xl mx-auto
162
99
  `,
163
- lg: 'grid-cols-3 gap-8'
100
+ lg: 'grid-cols-3 gap-8'
164
101
  });
165
102
  ```
103
+
166
104
  ---
167
105
 
168
106
  ## ⌨️ Why Objects?
169
107
 
170
- | Feature | Standard Tailwind Strings | Class Utilities Objects |
171
- | :--- | :--- | :--- |
172
- | **Readability** | ❌ Hard to scan long lines | ✅ Grouped by variant |
173
- | **Maintenance** | ❌ Easy to forget prefixes | ✅ Automatic stacking |
174
- | **Logic** | ❌ Messy ternary operators | ✅ Native JS object logic |
175
- | **Types** | ❌ String-based (no safety) | ✅ Full Autocomplete |
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 |
176
114
 
177
115
  ---
178
116
 
179
117
  ## 🛠️ API Reference
180
118
 
181
119
  ### `cl(...inputs)`
120
+
182
121
  The main utility function. Accepts strings, arrays, objects, or nested structures.
183
122
 
184
123
  ### `createCl(...plugins)`
124
+
185
125
  Factory function to create a customized `cl` instance. Merges all provided objects into a single type-safe registry.
186
126
 
187
127
  ### `tailwind`
128
+
188
129
  The raw plugin data containing all Tailwind CSS variants.
189
130
 
190
131
  ---
191
132
 
192
133
  ## 📄 License
193
- MIT © Mauricio Frías
134
+
135
+ MIT © Mauricio Frías
package/dist/index.cjs CHANGED
@@ -1,37 +1,63 @@
1
1
  'use strict';
2
2
 
3
3
  var tailwindMerge = require('tailwind-merge');
4
+ var clsx = require('clsx');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var clsx__default = /*#__PURE__*/_interopDefault(clsx);
4
9
 
5
10
  // src/index.ts
6
11
  function createCl(...plugins) {
7
12
  const registry = Object.assign({}, ...plugins);
8
- const process = (accumulatedPrefix, input) => {
9
- if (!input) return "";
13
+ const process = (accumulatedPath, input) => {
14
+ console.log(`[START] Path: "${accumulatedPath}" | Input:`, input);
15
+ if (!input) {
16
+ console.log(`[SKIP] Input is falsy`);
17
+ return "";
18
+ }
10
19
  if (typeof input === "string") {
11
- return input.split(/[,\s\n]+/).filter(Boolean).map((cls) => accumulatedPrefix ? `${accumulatedPrefix}:${cls}` : cls).join(" ");
20
+ const resolvedPrefix = accumulatedPath.split(":").map((part) => {
21
+ if (part === "base" || part === "?") return null;
22
+ return registry[part] || part;
23
+ }).filter(Boolean).join(":");
24
+ const result = input.split(/[,\s\n]+/).filter(Boolean).map((cls) => resolvedPrefix ? `${resolvedPrefix}:${cls}` : cls).join(" ");
25
+ console.log(`[STRING] Resolved: "${resolvedPrefix}" | Out: "${result}"`);
26
+ return result;
12
27
  }
13
28
  if (Array.isArray(input)) {
14
- return input.map((i) => process(accumulatedPrefix, i)).filter(Boolean).join(" ");
29
+ console.log(`[ARRAY] Processing ${input.length} elements...`);
30
+ return input.map((i) => process(accumulatedPath, i)).filter(Boolean).join(" ");
15
31
  }
16
32
  if (typeof input === "object") {
17
- let results = [];
18
- for (const [key, value] of Object.entries(input)) {
19
- if (!value) continue;
20
- const registeredPrefix = registry[key];
21
- if (registeredPrefix) {
22
- const nextPrefix = accumulatedPrefix ? `${accumulatedPrefix}:${registeredPrefix}` : registeredPrefix;
23
- results.push(process(nextPrefix, value));
33
+ console.log(`[OBJECT] Keys:`, Object.keys(input));
34
+ return Object.entries(input).map(([key, value]) => {
35
+ const isTransparent = key === "base" || key === "?";
36
+ const isRegistered = registry[key] !== void 0;
37
+ console.log(
38
+ ` -> Key: "${key}" | Value: ${value} | isPrefix: ${isRegistered} | isTransparent: ${isTransparent}`
39
+ );
40
+ if (!value) {
41
+ console.log(` [SKIP KEY] "${key}" because value is falsy`);
42
+ return "";
43
+ }
44
+ if (isTransparent || isRegistered) {
45
+ const newPath = accumulatedPath ? `${accumulatedPath}:${key}` : key;
46
+ console.log(` [DIVE] Moving to path: "${newPath}"`);
47
+ return process(newPath, value);
24
48
  } else {
25
- results.push(process(accumulatedPrefix, key));
49
+ console.log(
50
+ ` [CLASS] Treating key "${key}" as class under path "${accumulatedPath}"`
51
+ );
52
+ return process(accumulatedPath, key);
26
53
  }
27
- }
28
- return results.join(" ");
54
+ }).filter(Boolean).join(" ");
29
55
  }
30
56
  return "";
31
57
  };
32
58
  return (...inputs) => {
33
59
  const processed = inputs.map((input) => process("", input));
34
- return tailwindMerge.twMerge(processed.filter(Boolean).join(" "));
60
+ return tailwindMerge.twMerge(clsx__default.default(processed));
35
61
  };
36
62
  }
37
63
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["twMerge"],"mappings":";;;;;AAGO,SAAS,YAAuD,OAAA,EAAmB;AACtF,EAAA,MAAM,WAAmC,MAAA,CAAO,MAAA,CAAO,EAAC,EAAG,GAAG,OAAO,CAAA;AAErE,EAAA,MAAM,OAAA,GAAU,CAAC,iBAAA,EAA2B,KAAA,KAAuB;AAC/D,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAGnB,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MACF,KAAA,CAAM,UAAU,EAChB,MAAA,CAAO,OAAO,EACd,GAAA,CAAI,CAAC,QAAS,iBAAA,GAAoB,CAAA,EAAG,iBAAiB,CAAA,CAAA,EAAI,GAAG,KAAK,GAAI,CAAA,CACtE,KAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA,CACF,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,iBAAA,EAAmB,CAAC,CAAC,CAAA,CACxC,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,IAAI,UAAoB,EAAC;AAEzB,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC9C,QAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,QAAA,MAAM,gBAAA,GAAmB,SAAS,GAAG,CAAA;AAErC,QAAA,IAAI,gBAAA,EAAkB;AAElB,UAAA,MAAM,aAAa,iBAAA,GACb,CAAA,EAAG,iBAAiB,CAAA,CAAA,EAAI,gBAAgB,CAAA,CAAA,GACxC,gBAAA;AACN,UAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,KAAK,CAAC,CAAA;AAAA,QAC3C,CAAA,MAAO;AAGH,UAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAC,CAAA;AAAA,QAChD;AAAA,MACJ;AACA,MAAA,OAAO,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAC3B;AAEA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AAEA,EAAA,OAAO,IAAI,MAAA,KAAyB;AAEhC,IAAA,MAAM,SAAA,GAAY,OAAO,GAAA,CAAI,CAAC,UAAU,OAAA,CAAQ,EAAA,EAAI,KAAK,CAAC,CAAA;AAE1D,IAAA,OAAOA,sBAAQ,SAAA,CAAU,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,EACtD,CAAA;AACJ","file":"index.cjs","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n const registry: Record<string, string> = Object.assign({}, ...plugins);\r\n\r\n const process = (accumulatedPrefix: string, input: any): string => {\r\n if (!input) return '';\r\n\r\n // 1. Strings: Aplicar prefijo acumulado\r\n if (typeof input === 'string') {\r\n return input\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (accumulatedPrefix ? `${accumulatedPrefix}:${cls}` : cls))\r\n .join(' ');\r\n }\r\n\r\n // 2. Arrays: Procesar cada elemento\r\n if (Array.isArray(input)) {\r\n return input\r\n .map((i) => process(accumulatedPrefix, i))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // 3. Objetos: El corazón del problema\r\n if (typeof input === 'object') {\r\n let results: string[] = [];\r\n\r\n for (const [key, value] of Object.entries(input)) {\r\n if (!value) continue;\r\n\r\n const registeredPrefix = registry[key];\r\n\r\n if (registeredPrefix) {\r\n // Es un prefijo: acumulamos y bajamos un nivel\r\n const nextPrefix = accumulatedPrefix\r\n ? `${accumulatedPrefix}:${registeredPrefix}`\r\n : registeredPrefix;\r\n results.push(process(nextPrefix, value));\r\n } else {\r\n // NO es prefijo: es lógica { 'clase': true }\r\n // Procesamos la llave 'key' como el contenido, bajo el prefijo actual\r\n results.push(process(accumulatedPrefix, key));\r\n }\r\n }\r\n return results.join(' ');\r\n }\r\n\r\n return '';\r\n };\r\n\r\n return (...inputs: ClassValue[]) => {\r\n // Ejecutamos nuestro motor en cada input\r\n const processed = inputs.map((input) => process('', input));\r\n // twMerge se encarga de limpiar el string final\r\n return twMerge(processed.filter(Boolean).join(' '));\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":"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","file":"index.cjs","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n const registry: Record<string, string> = Object.assign({}, ...plugins);\r\n\r\n const process = (accumulatedPath: string, input: any): string => {\r\n console.log(`[START] Path: \"${accumulatedPath}\" | Input:`, input);\r\n\r\n if (!input) {\r\n console.log(`[SKIP] Input is falsy`);\r\n return '';\r\n }\r\n\r\n // 1. Caso String\r\n if (typeof input === 'string') {\r\n const resolvedPrefix = accumulatedPath\r\n .split(':')\r\n .map((part) => {\r\n if (part === 'base' || part === '?') return null;\r\n return registry[part] || part;\r\n })\r\n .filter(Boolean)\r\n .join(':');\r\n\r\n const result = input\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (resolvedPrefix ? `${resolvedPrefix}:${cls}` : cls))\r\n .join(' ');\r\n\r\n console.log(`[STRING] Resolved: \"${resolvedPrefix}\" | Out: \"${result}\"`);\r\n return result;\r\n }\r\n\r\n // 2. Caso Array\r\n if (Array.isArray(input)) {\r\n console.log(`[ARRAY] Processing ${input.length} elements...`);\r\n return input\r\n .map((i) => process(accumulatedPath, i))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // 3. Caso Objeto\r\n if (typeof input === 'object') {\r\n console.log(`[OBJECT] Keys:`, Object.keys(input));\r\n return Object.entries(input)\r\n .map(([key, value]) => {\r\n const isTransparent = key === 'base' || key === '?';\r\n const isRegistered = registry[key] !== undefined;\r\n\r\n console.log(\r\n ` -> Key: \"${key}\" | Value: ${value} | isPrefix: ${isRegistered} | isTransparent: ${isTransparent}`\r\n );\r\n\r\n if (!value) {\r\n console.log(` [SKIP KEY] \"${key}\" because value is falsy`);\r\n return '';\r\n }\r\n\r\n if (isTransparent || isRegistered) {\r\n const newPath = accumulatedPath ? `${accumulatedPath}:${key}` : key;\r\n console.log(` [DIVE] Moving to path: \"${newPath}\"`);\r\n return process(newPath, value);\r\n } else {\r\n console.log(\r\n ` [CLASS] Treating key \"${key}\" as class under path \"${accumulatedPath}\"`\r\n );\r\n return process(accumulatedPath, key);\r\n }\r\n })\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n return '';\r\n };\r\n\r\n return (...inputs: ClassValue[]) => {\r\n const processed = inputs.map((input) => process('', input));\r\n return twMerge(clsx(processed));\r\n };\r\n}\r\n"]}
package/dist/index.js CHANGED
@@ -1,35 +1,57 @@
1
1
  import { twMerge } from 'tailwind-merge';
2
+ import clsx from 'clsx';
2
3
 
3
4
  // src/index.ts
4
5
  function createCl(...plugins) {
5
6
  const registry = Object.assign({}, ...plugins);
6
- const process = (accumulatedPrefix, input) => {
7
- if (!input) return "";
7
+ const process = (accumulatedPath, input) => {
8
+ console.log(`[START] Path: "${accumulatedPath}" | Input:`, input);
9
+ if (!input) {
10
+ console.log(`[SKIP] Input is falsy`);
11
+ return "";
12
+ }
8
13
  if (typeof input === "string") {
9
- return input.split(/[,\s\n]+/).filter(Boolean).map((cls) => accumulatedPrefix ? `${accumulatedPrefix}:${cls}` : cls).join(" ");
14
+ const resolvedPrefix = accumulatedPath.split(":").map((part) => {
15
+ if (part === "base" || part === "?") return null;
16
+ return registry[part] || part;
17
+ }).filter(Boolean).join(":");
18
+ const result = input.split(/[,\s\n]+/).filter(Boolean).map((cls) => resolvedPrefix ? `${resolvedPrefix}:${cls}` : cls).join(" ");
19
+ console.log(`[STRING] Resolved: "${resolvedPrefix}" | Out: "${result}"`);
20
+ return result;
10
21
  }
11
22
  if (Array.isArray(input)) {
12
- return input.map((i) => process(accumulatedPrefix, i)).filter(Boolean).join(" ");
23
+ console.log(`[ARRAY] Processing ${input.length} elements...`);
24
+ return input.map((i) => process(accumulatedPath, i)).filter(Boolean).join(" ");
13
25
  }
14
26
  if (typeof input === "object") {
15
- let results = [];
16
- for (const [key, value] of Object.entries(input)) {
17
- if (!value) continue;
18
- const registeredPrefix = registry[key];
19
- if (registeredPrefix) {
20
- const nextPrefix = accumulatedPrefix ? `${accumulatedPrefix}:${registeredPrefix}` : registeredPrefix;
21
- results.push(process(nextPrefix, value));
27
+ console.log(`[OBJECT] Keys:`, Object.keys(input));
28
+ return Object.entries(input).map(([key, value]) => {
29
+ const isTransparent = key === "base" || key === "?";
30
+ const isRegistered = registry[key] !== void 0;
31
+ console.log(
32
+ ` -> Key: "${key}" | Value: ${value} | isPrefix: ${isRegistered} | isTransparent: ${isTransparent}`
33
+ );
34
+ if (!value) {
35
+ console.log(` [SKIP KEY] "${key}" because value is falsy`);
36
+ return "";
37
+ }
38
+ if (isTransparent || isRegistered) {
39
+ const newPath = accumulatedPath ? `${accumulatedPath}:${key}` : key;
40
+ console.log(` [DIVE] Moving to path: "${newPath}"`);
41
+ return process(newPath, value);
22
42
  } else {
23
- results.push(process(accumulatedPrefix, key));
43
+ console.log(
44
+ ` [CLASS] Treating key "${key}" as class under path "${accumulatedPath}"`
45
+ );
46
+ return process(accumulatedPath, key);
24
47
  }
25
- }
26
- return results.join(" ");
48
+ }).filter(Boolean).join(" ");
27
49
  }
28
50
  return "";
29
51
  };
30
52
  return (...inputs) => {
31
53
  const processed = inputs.map((input) => process("", input));
32
- return twMerge(processed.filter(Boolean).join(" "));
54
+ return twMerge(clsx(processed));
33
55
  };
34
56
  }
35
57
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AAGO,SAAS,YAAuD,OAAA,EAAmB;AACtF,EAAA,MAAM,WAAmC,MAAA,CAAO,MAAA,CAAO,EAAC,EAAG,GAAG,OAAO,CAAA;AAErE,EAAA,MAAM,OAAA,GAAU,CAAC,iBAAA,EAA2B,KAAA,KAAuB;AAC/D,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAGnB,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MACF,KAAA,CAAM,UAAU,EAChB,MAAA,CAAO,OAAO,EACd,GAAA,CAAI,CAAC,QAAS,iBAAA,GAAoB,CAAA,EAAG,iBAAiB,CAAA,CAAA,EAAI,GAAG,KAAK,GAAI,CAAA,CACtE,KAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA,CACF,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,iBAAA,EAAmB,CAAC,CAAC,CAAA,CACxC,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,IAAI,UAAoB,EAAC;AAEzB,MAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC9C,QAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,QAAA,MAAM,gBAAA,GAAmB,SAAS,GAAG,CAAA;AAErC,QAAA,IAAI,gBAAA,EAAkB;AAElB,UAAA,MAAM,aAAa,iBAAA,GACb,CAAA,EAAG,iBAAiB,CAAA,CAAA,EAAI,gBAAgB,CAAA,CAAA,GACxC,gBAAA;AACN,UAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,KAAK,CAAC,CAAA;AAAA,QAC3C,CAAA,MAAO;AAGH,UAAA,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAC,CAAA;AAAA,QAChD;AAAA,MACJ;AACA,MAAA,OAAO,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAC3B;AAEA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AAEA,EAAA,OAAO,IAAI,MAAA,KAAyB;AAEhC,IAAA,MAAM,SAAA,GAAY,OAAO,GAAA,CAAI,CAAC,UAAU,OAAA,CAAQ,EAAA,EAAI,KAAK,CAAC,CAAA;AAE1D,IAAA,OAAO,QAAQ,SAAA,CAAU,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,EACtD,CAAA;AACJ","file":"index.js","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n const registry: Record<string, string> = Object.assign({}, ...plugins);\r\n\r\n const process = (accumulatedPrefix: string, input: any): string => {\r\n if (!input) return '';\r\n\r\n // 1. Strings: Aplicar prefijo acumulado\r\n if (typeof input === 'string') {\r\n return input\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (accumulatedPrefix ? `${accumulatedPrefix}:${cls}` : cls))\r\n .join(' ');\r\n }\r\n\r\n // 2. Arrays: Procesar cada elemento\r\n if (Array.isArray(input)) {\r\n return input\r\n .map((i) => process(accumulatedPrefix, i))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // 3. Objetos: El corazón del problema\r\n if (typeof input === 'object') {\r\n let results: string[] = [];\r\n\r\n for (const [key, value] of Object.entries(input)) {\r\n if (!value) continue;\r\n\r\n const registeredPrefix = registry[key];\r\n\r\n if (registeredPrefix) {\r\n // Es un prefijo: acumulamos y bajamos un nivel\r\n const nextPrefix = accumulatedPrefix\r\n ? `${accumulatedPrefix}:${registeredPrefix}`\r\n : registeredPrefix;\r\n results.push(process(nextPrefix, value));\r\n } else {\r\n // NO es prefijo: es lógica { 'clase': true }\r\n // Procesamos la llave 'key' como el contenido, bajo el prefijo actual\r\n results.push(process(accumulatedPrefix, key));\r\n }\r\n }\r\n return results.join(' ');\r\n }\r\n\r\n return '';\r\n };\r\n\r\n return (...inputs: ClassValue[]) => {\r\n // Ejecutamos nuestro motor en cada input\r\n const processed = inputs.map((input) => process('', input));\r\n // twMerge se encarga de limpiar el string final\r\n return twMerge(processed.filter(Boolean).join(' '));\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { twMerge } from 'tailwind-merge';\r\nimport clsx, { type ClassValue } from 'clsx';\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n const registry: Record<string, string> = Object.assign({}, ...plugins);\r\n\r\n const process = (accumulatedPath: string, input: any): string => {\r\n console.log(`[START] Path: \"${accumulatedPath}\" | Input:`, input);\r\n\r\n if (!input) {\r\n console.log(`[SKIP] Input is falsy`);\r\n return '';\r\n }\r\n\r\n // 1. Caso String\r\n if (typeof input === 'string') {\r\n const resolvedPrefix = accumulatedPath\r\n .split(':')\r\n .map((part) => {\r\n if (part === 'base' || part === '?') return null;\r\n return registry[part] || part;\r\n })\r\n .filter(Boolean)\r\n .join(':');\r\n\r\n const result = input\r\n .split(/[,\\s\\n]+/)\r\n .filter(Boolean)\r\n .map((cls) => (resolvedPrefix ? `${resolvedPrefix}:${cls}` : cls))\r\n .join(' ');\r\n\r\n console.log(`[STRING] Resolved: \"${resolvedPrefix}\" | Out: \"${result}\"`);\r\n return result;\r\n }\r\n\r\n // 2. Caso Array\r\n if (Array.isArray(input)) {\r\n console.log(`[ARRAY] Processing ${input.length} elements...`);\r\n return input\r\n .map((i) => process(accumulatedPath, i))\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n // 3. Caso Objeto\r\n if (typeof input === 'object') {\r\n console.log(`[OBJECT] Keys:`, Object.keys(input));\r\n return Object.entries(input)\r\n .map(([key, value]) => {\r\n const isTransparent = key === 'base' || key === '?';\r\n const isRegistered = registry[key] !== undefined;\r\n\r\n console.log(\r\n ` -> Key: \"${key}\" | Value: ${value} | isPrefix: ${isRegistered} | isTransparent: ${isTransparent}`\r\n );\r\n\r\n if (!value) {\r\n console.log(` [SKIP KEY] \"${key}\" because value is falsy`);\r\n return '';\r\n }\r\n\r\n if (isTransparent || isRegistered) {\r\n const newPath = accumulatedPath ? `${accumulatedPath}:${key}` : key;\r\n console.log(` [DIVE] Moving to path: \"${newPath}\"`);\r\n return process(newPath, value);\r\n } else {\r\n console.log(\r\n ` [CLASS] Treating key \"${key}\" as class under path \"${accumulatedPath}\"`\r\n );\r\n return process(accumulatedPath, key);\r\n }\r\n })\r\n .filter(Boolean)\r\n .join(' ');\r\n }\r\n\r\n return '';\r\n };\r\n\r\n return (...inputs: ClassValue[]) => {\r\n const processed = inputs.map((input) => process('', input));\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.1.10",
3
+ "version": "1.1.12",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/index.ts CHANGED
@@ -4,57 +4,81 @@ import clsx, { type ClassValue } from 'clsx';
4
4
  export function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {
5
5
  const registry: Record<string, string> = Object.assign({}, ...plugins);
6
6
 
7
- const process = (accumulatedPrefix: string, input: any): string => {
8
- if (!input) return '';
7
+ const process = (accumulatedPath: string, input: any): string => {
8
+ console.log(`[START] Path: "${accumulatedPath}" | Input:`, input);
9
9
 
10
- // 1. Strings: Aplicar prefijo acumulado
10
+ if (!input) {
11
+ console.log(`[SKIP] Input is falsy`);
12
+ return '';
13
+ }
14
+
15
+ // 1. Caso String
11
16
  if (typeof input === 'string') {
12
- return input
17
+ const resolvedPrefix = accumulatedPath
18
+ .split(':')
19
+ .map((part) => {
20
+ if (part === 'base' || part === '?') return null;
21
+ return registry[part] || part;
22
+ })
23
+ .filter(Boolean)
24
+ .join(':');
25
+
26
+ const result = input
13
27
  .split(/[,\s\n]+/)
14
28
  .filter(Boolean)
15
- .map((cls) => (accumulatedPrefix ? `${accumulatedPrefix}:${cls}` : cls))
29
+ .map((cls) => (resolvedPrefix ? `${resolvedPrefix}:${cls}` : cls))
16
30
  .join(' ');
31
+
32
+ console.log(`[STRING] Resolved: "${resolvedPrefix}" | Out: "${result}"`);
33
+ return result;
17
34
  }
18
35
 
19
- // 2. Arrays: Procesar cada elemento
36
+ // 2. Caso Array
20
37
  if (Array.isArray(input)) {
38
+ console.log(`[ARRAY] Processing ${input.length} elements...`);
21
39
  return input
22
- .map((i) => process(accumulatedPrefix, i))
40
+ .map((i) => process(accumulatedPath, i))
23
41
  .filter(Boolean)
24
42
  .join(' ');
25
43
  }
26
44
 
27
- // 3. Objetos: El corazón del problema
45
+ // 3. Caso Objeto
28
46
  if (typeof input === 'object') {
29
- let results: string[] = [];
30
-
31
- for (const [key, value] of Object.entries(input)) {
32
- if (!value) continue;
33
-
34
- const registeredPrefix = registry[key];
35
-
36
- if (registeredPrefix) {
37
- // Es un prefijo: acumulamos y bajamos un nivel
38
- const nextPrefix = accumulatedPrefix
39
- ? `${accumulatedPrefix}:${registeredPrefix}`
40
- : registeredPrefix;
41
- results.push(process(nextPrefix, value));
42
- } else {
43
- // NO es prefijo: es lógica { 'clase': true }
44
- // Procesamos la llave 'key' como el contenido, bajo el prefijo actual
45
- results.push(process(accumulatedPrefix, key));
46
- }
47
- }
48
- return results.join(' ');
47
+ console.log(`[OBJECT] Keys:`, Object.keys(input));
48
+ return Object.entries(input)
49
+ .map(([key, value]) => {
50
+ const isTransparent = key === 'base' || key === '?';
51
+ const isRegistered = registry[key] !== undefined;
52
+
53
+ console.log(
54
+ ` -> Key: "${key}" | Value: ${value} | isPrefix: ${isRegistered} | isTransparent: ${isTransparent}`
55
+ );
56
+
57
+ if (!value) {
58
+ console.log(` [SKIP KEY] "${key}" because value is falsy`);
59
+ return '';
60
+ }
61
+
62
+ if (isTransparent || isRegistered) {
63
+ const newPath = accumulatedPath ? `${accumulatedPath}:${key}` : key;
64
+ console.log(` [DIVE] Moving to path: "${newPath}"`);
65
+ return process(newPath, value);
66
+ } else {
67
+ console.log(
68
+ ` [CLASS] Treating key "${key}" as class under path "${accumulatedPath}"`
69
+ );
70
+ return process(accumulatedPath, key);
71
+ }
72
+ })
73
+ .filter(Boolean)
74
+ .join(' ');
49
75
  }
50
76
 
51
77
  return '';
52
78
  };
53
79
 
54
80
  return (...inputs: ClassValue[]) => {
55
- // Ejecutamos nuestro motor en cada input
56
81
  const processed = inputs.map((input) => process('', input));
57
- // twMerge se encarga de limpiar el string final
58
- return twMerge(processed.filter(Boolean).join(' '));
82
+ return twMerge(clsx(processed));
59
83
  };
60
84
  }
@@ -70,4 +70,29 @@ describe('cl - Prefix Engine (Scope: Prefixes + clsx + twMerge)', () => {
70
70
  });
71
71
  expect(result).toBe('base-btn bg-blue-500 md:px-4 md:text-white');
72
72
  });
73
+
74
+ it('Nivel 8: Lógica Condicional Anidada dentro de Prefijos', () => {
75
+ const isActive = true;
76
+ const isError = false;
77
+ // Forzamos el tipo para que TS permita comparar con 'light' en el test
78
+ const theme = 'dark' as 'light' | 'dark';
79
+
80
+ const result = cl({
81
+ md: {
82
+ // Objeto de lógica pura dentro de un prefijo
83
+ 'bg-green-500': isActive,
84
+ 'bg-red-500': isError,
85
+ // Combinación con otro prefijo anidado
86
+ dark: {
87
+ 'text-white': theme === 'dark',
88
+ 'text-black': theme === 'light' // Ahora TS ya no se queja
89
+ }
90
+ }
91
+ });
92
+
93
+ expect(result).toContain('md:bg-green-500');
94
+ expect(result).toContain('md:dark:text-white');
95
+ expect(result).not.toContain('bg-red-500');
96
+ expect(result).not.toContain('text-black');
97
+ });
73
98
  });