clases 1.1.1 → 1.1.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/dist/index.cjs +15 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -6
- package/dist/index.d.ts +0 -6
- package/dist/index.js +15 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +23 -48
- package/src/test/cn.test.ts +41 -0
package/dist/index.cjs
CHANGED
|
@@ -9,7 +9,7 @@ var clsx__default = /*#__PURE__*/_interopDefault(clsx);
|
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
11
|
function createCl(...plugins) {
|
|
12
|
-
const registry = Object.assign({
|
|
12
|
+
const registry = Object.assign({}, ...plugins);
|
|
13
13
|
const process = (key, value) => {
|
|
14
14
|
if (!value) return "";
|
|
15
15
|
if (Array.isArray(value)) {
|
|
@@ -18,14 +18,20 @@ function createCl(...plugins) {
|
|
|
18
18
|
if (typeof value === "object") {
|
|
19
19
|
return Object.entries(value).map(([nestedKey, nestedValue]) => {
|
|
20
20
|
const isRegistered = registry[nestedKey] !== void 0;
|
|
21
|
-
|
|
21
|
+
let nextKey;
|
|
22
|
+
if (key === "base") {
|
|
23
|
+
nextKey = nestedKey;
|
|
24
|
+
} else if (isRegistered) {
|
|
25
|
+
nextKey = `${key}:${nestedKey}`;
|
|
26
|
+
} else {
|
|
27
|
+
nextKey = key;
|
|
28
|
+
}
|
|
22
29
|
return process(nextKey, nestedValue);
|
|
23
30
|
}).join(" ");
|
|
24
31
|
}
|
|
25
32
|
const resolvedPrefix = key.split(":").map((part) => {
|
|
26
33
|
if (part === "base") return null;
|
|
27
|
-
|
|
28
|
-
return null;
|
|
34
|
+
return registry[part] || null;
|
|
29
35
|
}).filter(Boolean).join(":");
|
|
30
36
|
if (typeof value === "string") {
|
|
31
37
|
return value.split(/[,\s\n]+/).filter(Boolean).map((cls) => !resolvedPrefix ? cls : `${resolvedPrefix}:${cls}`).join(" ");
|
|
@@ -35,7 +41,11 @@ function createCl(...plugins) {
|
|
|
35
41
|
return (...inputs) => {
|
|
36
42
|
const processed = inputs.map((input) => {
|
|
37
43
|
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
38
|
-
return Object.entries(input).map(([k, v]) =>
|
|
44
|
+
return Object.entries(input).map(([k, v]) => {
|
|
45
|
+
if (v === true) return k;
|
|
46
|
+
const isRegistered = registry[k] !== void 0;
|
|
47
|
+
return process(isRegistered ? k : "base", v);
|
|
48
|
+
}).join(" ");
|
|
39
49
|
}
|
|
40
50
|
return input;
|
|
41
51
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":";;;;;;;;;;AAGO,SAAS,YAAuD,OAAA,EAAmB;AAEtF,EAAA,MAAM,WAAmC,MAAA,CAAO,MAAA,CAAO,EAAC,EAAG,GAAG,OAAO,CAAA;AAErE,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,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,IACrE;AAEA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAC/B,QAAA,MAAM,YAAA,GAAe,QAAA,CAAS,SAAS,CAAA,KAAM,MAAA;AAE7C,QAAA,IAAI,OAAA;AACJ,QAAA,IAAI,QAAQ,MAAA,EAAQ;AAChB,UAAA,OAAA,GAAU,SAAA;AAAA,QACd,WAAW,YAAA,EAAc;AACrB,UAAA,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAAA,QACjC,CAAA,MAAO;AAEH,UAAA,OAAA,GAAU,GAAA;AAAA,QACd;AAEA,QAAA,OAAO,OAAA,CAAQ,SAAS,WAAW,CAAA;AAAA,MACvC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,MAAM,iBAAiB,GAAA,CAClB,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS;AACX,MAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,IAAA;AAG5B,MAAA,OAAO,QAAA,CAAS,IAAI,CAAA,IAAK,IAAA;AAAA,IAC7B,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEb,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,KAAA,CACF,MAAM,UAAU,CAAA,CAChB,OAAO,OAAO,CAAA,CACd,IAAI,CAAC,GAAA,KAAS,CAAC,cAAA,GAAiB,GAAA,GAAM,GAAG,cAAc,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA,CACjE,KAAK,GAAG,CAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AAEA,EAAA,OAAO,IAAI,MAAA,KAAkB;AACzB,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,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM;AACb,UAAA,IAAI,CAAA,KAAM,MAAM,OAAO,CAAA;AAEvB,UAAA,MAAM,YAAA,GAAe,QAAA,CAAS,CAAC,CAAA,KAAM,MAAA;AACrC,UAAA,OAAO,OAAA,CAAQ,YAAA,GAAe,CAAA,GAAI,MAAA,EAAQ,CAAC,CAAA;AAAA,QAC/C,CAAC,CAAA,CACA,IAAA,CAAK,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 from 'clsx';\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n // Importante: No incluimos 'base' aquí para que no interfiera en el filtrado final\r\n const registry: Record<string, string> = Object.assign({}, ...plugins);\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.map((v) => process(key, v)).filter(Boolean).join(' ');\r\n }\r\n\r\n if (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n const isRegistered = registry[nestedKey] !== undefined;\r\n \r\n let nextKey: string;\r\n if (key === 'base') {\r\n nextKey = nestedKey;\r\n } else if (isRegistered) {\r\n nextKey = `${key}:${nestedKey}`;\r\n } else {\r\n // Si no está registrado, mantenemos el key actual (transparencia)\r\n nextKey = key;\r\n }\r\n\r\n return process(nextKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n // RESOLUCIÓN FINAL: Filtro estricto\r\n const resolvedPrefix = key\r\n .split(':')\r\n .map((part) => {\r\n if (part === 'base') return null;\r\n // SOLO devolvemos si existe en el registro. \r\n // Si 'variants' no está, esto devuelve null y se limpia.\r\n return registry[part] || null; \r\n })\r\n .filter(Boolean)\r\n .join(':');\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) => (!resolvedPrefix ? cls : `${resolvedPrefix}:${cls}`))\r\n .join(' ');\r\n }\r\n return '';\r\n };\r\n\r\n return (...inputs: 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]) => {\r\n if (v === true) return k;\r\n // Si la llave inicial no está registrada, empezamos con 'base'\r\n const isRegistered = registry[k] !== undefined;\r\n return process(isRegistered ? k : 'base', v);\r\n })\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,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a specialized utility for managing CSS classes with prefix support,
|
|
3
|
-
* plugin mapping, and transparent logical nesting.
|
|
4
|
-
* * @param plugins - An array of objects mapping custom aliases to real CSS prefixes.
|
|
5
|
-
* @returns A function that processes class values, objects, and nested structures.
|
|
6
|
-
*/
|
|
7
1
|
declare function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins): (...inputs: any[]) => string;
|
|
8
2
|
|
|
9
3
|
export { createCl };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates a specialized utility for managing CSS classes with prefix support,
|
|
3
|
-
* plugin mapping, and transparent logical nesting.
|
|
4
|
-
* * @param plugins - An array of objects mapping custom aliases to real CSS prefixes.
|
|
5
|
-
* @returns A function that processes class values, objects, and nested structures.
|
|
6
|
-
*/
|
|
7
1
|
declare function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins): (...inputs: any[]) => string;
|
|
8
2
|
|
|
9
3
|
export { createCl };
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import clsx from 'clsx';
|
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
function createCl(...plugins) {
|
|
6
|
-
const registry = Object.assign({
|
|
6
|
+
const registry = Object.assign({}, ...plugins);
|
|
7
7
|
const process = (key, value) => {
|
|
8
8
|
if (!value) return "";
|
|
9
9
|
if (Array.isArray(value)) {
|
|
@@ -12,14 +12,20 @@ function createCl(...plugins) {
|
|
|
12
12
|
if (typeof value === "object") {
|
|
13
13
|
return Object.entries(value).map(([nestedKey, nestedValue]) => {
|
|
14
14
|
const isRegistered = registry[nestedKey] !== void 0;
|
|
15
|
-
|
|
15
|
+
let nextKey;
|
|
16
|
+
if (key === "base") {
|
|
17
|
+
nextKey = nestedKey;
|
|
18
|
+
} else if (isRegistered) {
|
|
19
|
+
nextKey = `${key}:${nestedKey}`;
|
|
20
|
+
} else {
|
|
21
|
+
nextKey = key;
|
|
22
|
+
}
|
|
16
23
|
return process(nextKey, nestedValue);
|
|
17
24
|
}).join(" ");
|
|
18
25
|
}
|
|
19
26
|
const resolvedPrefix = key.split(":").map((part) => {
|
|
20
27
|
if (part === "base") return null;
|
|
21
|
-
|
|
22
|
-
return null;
|
|
28
|
+
return registry[part] || null;
|
|
23
29
|
}).filter(Boolean).join(":");
|
|
24
30
|
if (typeof value === "string") {
|
|
25
31
|
return value.split(/[,\s\n]+/).filter(Boolean).map((cls) => !resolvedPrefix ? cls : `${resolvedPrefix}:${cls}`).join(" ");
|
|
@@ -29,7 +35,11 @@ function createCl(...plugins) {
|
|
|
29
35
|
return (...inputs) => {
|
|
30
36
|
const processed = inputs.map((input) => {
|
|
31
37
|
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
32
|
-
return Object.entries(input).map(([k, v]) =>
|
|
38
|
+
return Object.entries(input).map(([k, v]) => {
|
|
39
|
+
if (v === true) return k;
|
|
40
|
+
const isRegistered = registry[k] !== void 0;
|
|
41
|
+
return process(isRegistered ? k : "base", v);
|
|
42
|
+
}).join(" ");
|
|
33
43
|
}
|
|
34
44
|
return input;
|
|
35
45
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AAGO,SAAS,YAAuD,OAAA,EAAmB;AAEtF,EAAA,MAAM,WAAmC,MAAA,CAAO,MAAA,CAAO,EAAC,EAAG,GAAG,OAAO,CAAA;AAErE,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,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,OAAA,CAAQ,GAAA,EAAK,CAAC,CAAC,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,IACrE;AAEA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAC/B,QAAA,MAAM,YAAA,GAAe,QAAA,CAAS,SAAS,CAAA,KAAM,MAAA;AAE7C,QAAA,IAAI,OAAA;AACJ,QAAA,IAAI,QAAQ,MAAA,EAAQ;AAChB,UAAA,OAAA,GAAU,SAAA;AAAA,QACd,WAAW,YAAA,EAAc;AACrB,UAAA,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAAA,QACjC,CAAA,MAAO;AAEH,UAAA,OAAA,GAAU,GAAA;AAAA,QACd;AAEA,QAAA,OAAO,OAAA,CAAQ,SAAS,WAAW,CAAA;AAAA,MACvC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,MAAM,iBAAiB,GAAA,CAClB,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS;AACX,MAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,IAAA;AAG5B,MAAA,OAAO,QAAA,CAAS,IAAI,CAAA,IAAK,IAAA;AAAA,IAC7B,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEb,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,KAAA,CACF,MAAM,UAAU,CAAA,CAChB,OAAO,OAAO,CAAA,CACd,IAAI,CAAC,GAAA,KAAS,CAAC,cAAA,GAAiB,GAAA,GAAM,GAAG,cAAc,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA,CACjE,KAAK,GAAG,CAAA;AAAA,IACjB;AACA,IAAA,OAAO,EAAA;AAAA,EACX,CAAA;AAEA,EAAA,OAAO,IAAI,MAAA,KAAkB;AACzB,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,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM;AACb,UAAA,IAAI,CAAA,KAAM,MAAM,OAAO,CAAA;AAEvB,UAAA,MAAM,YAAA,GAAe,QAAA,CAAS,CAAC,CAAA,KAAM,MAAA;AACrC,UAAA,OAAO,OAAA,CAAQ,YAAA,GAAe,CAAA,GAAI,MAAA,EAAQ,CAAC,CAAA;AAAA,QAC/C,CAAC,CAAA,CACA,IAAA,CAAK,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 from 'clsx';\r\n\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n // Importante: No incluimos 'base' aquí para que no interfiera en el filtrado final\r\n const registry: Record<string, string> = Object.assign({}, ...plugins);\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.map((v) => process(key, v)).filter(Boolean).join(' ');\r\n }\r\n\r\n if (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n const isRegistered = registry[nestedKey] !== undefined;\r\n \r\n let nextKey: string;\r\n if (key === 'base') {\r\n nextKey = nestedKey;\r\n } else if (isRegistered) {\r\n nextKey = `${key}:${nestedKey}`;\r\n } else {\r\n // Si no está registrado, mantenemos el key actual (transparencia)\r\n nextKey = key;\r\n }\r\n\r\n return process(nextKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n // RESOLUCIÓN FINAL: Filtro estricto\r\n const resolvedPrefix = key\r\n .split(':')\r\n .map((part) => {\r\n if (part === 'base') return null;\r\n // SOLO devolvemos si existe en el registro. \r\n // Si 'variants' no está, esto devuelve null y se limpia.\r\n return registry[part] || null; \r\n })\r\n .filter(Boolean)\r\n .join(':');\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) => (!resolvedPrefix ? cls : `${resolvedPrefix}:${cls}`))\r\n .join(' ');\r\n }\r\n return '';\r\n };\r\n\r\n return (...inputs: 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]) => {\r\n if (v === true) return k;\r\n // Si la llave inicial no está registrada, empezamos con 'base'\r\n const isRegistered = registry[k] !== undefined;\r\n return process(isRegistered ? k : 'base', v);\r\n })\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
package/src/index.ts
CHANGED
|
@@ -1,73 +1,49 @@
|
|
|
1
1
|
import { twMerge } from 'tailwind-merge';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Creates a specialized utility for managing CSS classes with prefix support,
|
|
6
|
-
* plugin mapping, and transparent logical nesting.
|
|
7
|
-
* * @param plugins - An array of objects mapping custom aliases to real CSS prefixes.
|
|
8
|
-
* @returns A function that processes class values, objects, and nested structures.
|
|
9
|
-
*/
|
|
10
4
|
export function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* Any key not found here will be treated as a "transparent" logical container
|
|
14
|
-
* and will be discarded in the final string resolution.
|
|
15
|
-
*/
|
|
16
|
-
const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);
|
|
5
|
+
// Importante: No incluimos 'base' aquí para que no interfiera en el filtrado final
|
|
6
|
+
const registry: Record<string, string> = Object.assign({}, ...plugins);
|
|
17
7
|
|
|
18
|
-
/**
|
|
19
|
-
* Recursively processes keys and values to build the prefixed class string.
|
|
20
|
-
* * @param key - The current accumulated prefix path.
|
|
21
|
-
* @param value - The class value, array, or nested object to process.
|
|
22
|
-
* @returns A space-separated string of prefixed classes.
|
|
23
|
-
*/
|
|
24
8
|
const process = (key: string, value: any): string => {
|
|
25
9
|
if (!value) return '';
|
|
26
10
|
|
|
27
|
-
// Handle Arrays: Process each element with the current key
|
|
28
11
|
if (Array.isArray(value)) {
|
|
29
|
-
return value
|
|
30
|
-
.map((v) => process(key, v))
|
|
31
|
-
.filter(Boolean)
|
|
32
|
-
.join(' ');
|
|
12
|
+
return value.map((v) => process(key, v)).filter(Boolean).join(' ');
|
|
33
13
|
}
|
|
34
14
|
|
|
35
|
-
// Handle Objects: Manage nesting and logical transparency
|
|
36
15
|
if (typeof value === 'object') {
|
|
37
16
|
return Object.entries(value)
|
|
38
17
|
.map(([nestedKey, nestedValue]) => {
|
|
39
|
-
/**
|
|
40
|
-
* Rule: If the child key is registered, we concatenate it.
|
|
41
|
-
* If it's not registered, it's a "logical" key (transparent),
|
|
42
|
-
* so we inherit the parent's prefix to keep the path clean.
|
|
43
|
-
*/
|
|
44
18
|
const isRegistered = registry[nestedKey] !== undefined;
|
|
45
|
-
|
|
46
|
-
|
|
19
|
+
|
|
20
|
+
let nextKey: string;
|
|
21
|
+
if (key === 'base') {
|
|
22
|
+
nextKey = nestedKey;
|
|
23
|
+
} else if (isRegistered) {
|
|
24
|
+
nextKey = `${key}:${nestedKey}`;
|
|
25
|
+
} else {
|
|
26
|
+
// Si no está registrado, mantenemos el key actual (transparencia)
|
|
27
|
+
nextKey = key;
|
|
28
|
+
}
|
|
47
29
|
|
|
48
30
|
return process(nextKey, nestedValue);
|
|
49
31
|
})
|
|
50
32
|
.join(' ');
|
|
51
33
|
}
|
|
52
34
|
|
|
53
|
-
|
|
54
|
-
* FINAL RESOLUTION
|
|
55
|
-
* Maps aliases (e.g., 'ui' -> 'prefix') and filters out any part
|
|
56
|
-
* of the path that is not explicitly registered in the registry.
|
|
57
|
-
*/
|
|
35
|
+
// RESOLUCIÓN FINAL: Filtro estricto
|
|
58
36
|
const resolvedPrefix = key
|
|
59
37
|
.split(':')
|
|
60
38
|
.map((part) => {
|
|
61
39
|
if (part === 'base') return null;
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return null;
|
|
40
|
+
// SOLO devolvemos si existe en el registro.
|
|
41
|
+
// Si 'variants' no está, esto devuelve null y se limpia.
|
|
42
|
+
return registry[part] || null;
|
|
66
43
|
})
|
|
67
44
|
.filter(Boolean)
|
|
68
45
|
.join(':');
|
|
69
46
|
|
|
70
|
-
// Apply the resolved prefix to each class in the string
|
|
71
47
|
if (typeof value === 'string') {
|
|
72
48
|
return value
|
|
73
49
|
.split(/[,\s\n]+/)
|
|
@@ -78,17 +54,16 @@ export function createCl<TPlugins extends Record<string, string>[]>(...plugins:
|
|
|
78
54
|
return '';
|
|
79
55
|
};
|
|
80
56
|
|
|
81
|
-
/**
|
|
82
|
-
* The final utility function.
|
|
83
|
-
* Processes inputs through the prefix engine and cleans them using tailwind-merge.
|
|
84
|
-
* * @param inputs - Variadic arguments including strings, objects, arrays, or booleans.
|
|
85
|
-
* @returns A merged and optimized string of Tailwind CSS classes.
|
|
86
|
-
*/
|
|
87
57
|
return (...inputs: any[]) => {
|
|
88
58
|
const processed = inputs.map((input) => {
|
|
89
59
|
if (input !== null && typeof input === 'object' && !Array.isArray(input)) {
|
|
90
60
|
return Object.entries(input)
|
|
91
|
-
.map(([k, v]) =>
|
|
61
|
+
.map(([k, v]) => {
|
|
62
|
+
if (v === true) return k;
|
|
63
|
+
// Si la llave inicial no está registrada, empezamos con 'base'
|
|
64
|
+
const isRegistered = registry[k] !== undefined;
|
|
65
|
+
return process(isRegistered ? k : 'base', v);
|
|
66
|
+
})
|
|
92
67
|
.join(' ');
|
|
93
68
|
}
|
|
94
69
|
return input;
|
package/src/test/cn.test.ts
CHANGED
|
@@ -122,4 +122,45 @@ it('Nivel 5: El "Inception" (Lógica anidada, condicionales y plugins)', () => {
|
|
|
122
122
|
// 'md' y 'hover' se mantienen, 'container' y 'secondary' desaparecen
|
|
123
123
|
expect(result).toBe('md:p-4 md:hover:shadow-xl');
|
|
124
124
|
});
|
|
125
|
+
|
|
126
|
+
it('Nivel 9: El Caso del Botón (Reproducción de Bug)', () => {
|
|
127
|
+
const variant = 'secondary';
|
|
128
|
+
const onHover = 'scale';
|
|
129
|
+
|
|
130
|
+
const result = cl(
|
|
131
|
+
// 1. Clases base (Strings)
|
|
132
|
+
'py-2 px-4 rounded-lg flex clickable',
|
|
133
|
+
// 2. Objeto de configuración con lógica dinámica
|
|
134
|
+
{
|
|
135
|
+
variants: {
|
|
136
|
+
primary: 'bg-action text-white',
|
|
137
|
+
secondary: 'bg-neutral-50 text-text-muted border-2',
|
|
138
|
+
danger: 'bg-red-400 text-white'
|
|
139
|
+
}[variant],
|
|
140
|
+
|
|
141
|
+
effects: {
|
|
142
|
+
scale: 'elevate-hover',
|
|
143
|
+
dim: 'hover:opacity-80 transition-opacity',
|
|
144
|
+
color: {
|
|
145
|
+
primary: 'hover:bg-action-hover',
|
|
146
|
+
secondary: 'hover:bg-neutral-200'
|
|
147
|
+
}[variant]
|
|
148
|
+
}[onHover]
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Verificación de limpieza
|
|
153
|
+
expect(result).not.toContain('variants:');
|
|
154
|
+
expect(result).not.toContain('effects:');
|
|
155
|
+
|
|
156
|
+
// Verificación de contenido
|
|
157
|
+
expect(result).toContain('bg-neutral-50');
|
|
158
|
+
expect(result).toContain('elevate-hover');
|
|
159
|
+
expect(result).toContain('clickable'); // Debe mantener las clases base
|
|
160
|
+
|
|
161
|
+
// El resultado final debe ser un string limpio de Tailwind
|
|
162
|
+
expect(result).toBe(
|
|
163
|
+
'py-2 px-4 rounded-lg flex clickable bg-neutral-50 text-text-muted border-2 elevate-hover'
|
|
164
|
+
);
|
|
165
|
+
});
|
|
125
166
|
});
|