clases 1.1.0 → 1.1.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/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +7 -6
- package/src/test/cn.test.ts +45 -0
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":";;;;;;;;;;AASO,SAAS,YAAuD,OAAA,EAAmB;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"mappings":";;;;;;;;;;AASO,SAAS,YAAuD,OAAA,EAAmB;AAMtF,EAAA,MAAM,QAAA,GAAmC,OAAO,MAAA,CAAO,EAAE,MAAM,MAAA,EAAO,EAAG,GAAG,OAAO,CAAA;AAQnF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAA,EAAa,KAAA,KAAuB;AACjD,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAGnB,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;AAGA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAM/B,QAAA,MAAM,YAAA,GAAe,QAAA,CAAS,SAAS,CAAA,KAAM,MAAA;AAC7C,QAAA,MAAM,OAAA,GACF,QAAQ,MAAA,GAAS,SAAA,GAAY,eAAe,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,GAAK,GAAA;AAExE,QAAA,OAAO,OAAA,CAAQ,SAAS,WAAW,CAAA;AAAA,MACvC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAOA,IAAA,MAAM,iBAAiB,GAAA,CAClB,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS;AACX,MAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,IAAA;AAE5B,MAAA,IAAI,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,SAAS,IAAI,CAAA;AAExC,MAAA,OAAO,IAAA;AAAA,IACX,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAGb,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;AAQA,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,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 from 'clsx';\r\n\r\n/**\r\n * Creates a specialized utility for managing CSS classes with prefix support,\r\n * plugin mapping, and transparent logical nesting.\r\n * * @param plugins - An array of objects mapping custom aliases to real CSS prefixes.\r\n * @returns A function that processes class values, objects, and nested structures.\r\n */\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n /**\r\n * Internal registry that stores all official prefixes.\r\n * Any key not found here will be treated as a \"transparent\" logical container\r\n * and will be discarded in the final string resolution.\r\n */\r\n const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);\r\n\r\n /**\r\n * Recursively processes keys and values to build the prefixed class string.\r\n * * @param key - The current accumulated prefix path.\r\n * @param value - The class value, array, or nested object to process.\r\n * @returns A space-separated string of prefixed classes.\r\n */\r\n const process = (key: string, value: any): string => {\r\n if (!value) return '';\r\n\r\n // Handle Arrays: Process each element with the current key\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 // Handle Objects: Manage nesting and logical transparency\r\n if (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n /**\r\n * Rule: If the child key is registered, we concatenate it.\r\n * If it's not registered, it's a \"logical\" key (transparent),\r\n * so we inherit the parent's prefix to keep the path clean.\r\n */\r\n const isRegistered = registry[nestedKey] !== undefined;\r\n const nextKey =\r\n key === 'base' ? nestedKey : isRegistered ? `${key}:${nestedKey}` : key;\r\n\r\n return process(nextKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n /**\r\n * FINAL RESOLUTION\r\n * Maps aliases (e.g., 'ui' -> 'prefix') and filters out any part\r\n * of the path that is not explicitly registered in the registry.\r\n */\r\n const resolvedPrefix = key\r\n .split(':')\r\n .map((part) => {\r\n if (part === 'base') return null;\r\n // Only return the part if it's found in our registry\r\n if (registry[part]) return registry[part];\r\n // Otherwise, it's a logical container and should be ignored\r\n return null;\r\n })\r\n .filter(Boolean)\r\n .join(':');\r\n\r\n // Apply the resolved prefix to each class in the string\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 /**\r\n * The final utility function.\r\n * Processes inputs through the prefix engine and cleans them using tailwind-merge.\r\n * * @param inputs - Variadic arguments including strings, objects, arrays, or booleans.\r\n * @returns A merged and optimized string of Tailwind CSS classes.\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]) => (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.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AASO,SAAS,YAAuD,OAAA,EAAmB;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AASO,SAAS,YAAuD,OAAA,EAAmB;AAMtF,EAAA,MAAM,QAAA,GAAmC,OAAO,MAAA,CAAO,EAAE,MAAM,MAAA,EAAO,EAAG,GAAG,OAAO,CAAA;AAQnF,EAAA,MAAM,OAAA,GAAU,CAAC,GAAA,EAAa,KAAA,KAAuB;AACjD,IAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AAGnB,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;AAGA,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC3B,MAAA,OAAO,MAAA,CAAO,QAAQ,KAAK,CAAA,CACtB,IAAI,CAAC,CAAC,SAAA,EAAW,WAAW,CAAA,KAAM;AAM/B,QAAA,MAAM,YAAA,GAAe,QAAA,CAAS,SAAS,CAAA,KAAM,MAAA;AAC7C,QAAA,MAAM,OAAA,GACF,QAAQ,MAAA,GAAS,SAAA,GAAY,eAAe,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,GAAK,GAAA;AAExE,QAAA,OAAO,OAAA,CAAQ,SAAS,WAAW,CAAA;AAAA,MACvC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAOA,IAAA,MAAM,iBAAiB,GAAA,CAClB,KAAA,CAAM,GAAG,CAAA,CACT,GAAA,CAAI,CAAC,IAAA,KAAS;AACX,MAAA,IAAI,IAAA,KAAS,QAAQ,OAAO,IAAA;AAE5B,MAAA,IAAI,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,SAAS,IAAI,CAAA;AAExC,MAAA,OAAO,IAAA;AAAA,IACX,CAAC,CAAA,CACA,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAGb,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;AAQA,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,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 from 'clsx';\r\n\r\n/**\r\n * Creates a specialized utility for managing CSS classes with prefix support,\r\n * plugin mapping, and transparent logical nesting.\r\n * * @param plugins - An array of objects mapping custom aliases to real CSS prefixes.\r\n * @returns A function that processes class values, objects, and nested structures.\r\n */\r\nexport function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {\r\n /**\r\n * Internal registry that stores all official prefixes.\r\n * Any key not found here will be treated as a \"transparent\" logical container\r\n * and will be discarded in the final string resolution.\r\n */\r\n const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);\r\n\r\n /**\r\n * Recursively processes keys and values to build the prefixed class string.\r\n * * @param key - The current accumulated prefix path.\r\n * @param value - The class value, array, or nested object to process.\r\n * @returns A space-separated string of prefixed classes.\r\n */\r\n const process = (key: string, value: any): string => {\r\n if (!value) return '';\r\n\r\n // Handle Arrays: Process each element with the current key\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 // Handle Objects: Manage nesting and logical transparency\r\n if (typeof value === 'object') {\r\n return Object.entries(value)\r\n .map(([nestedKey, nestedValue]) => {\r\n /**\r\n * Rule: If the child key is registered, we concatenate it.\r\n * If it's not registered, it's a \"logical\" key (transparent),\r\n * so we inherit the parent's prefix to keep the path clean.\r\n */\r\n const isRegistered = registry[nestedKey] !== undefined;\r\n const nextKey =\r\n key === 'base' ? nestedKey : isRegistered ? `${key}:${nestedKey}` : key;\r\n\r\n return process(nextKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n /**\r\n * FINAL RESOLUTION\r\n * Maps aliases (e.g., 'ui' -> 'prefix') and filters out any part\r\n * of the path that is not explicitly registered in the registry.\r\n */\r\n const resolvedPrefix = key\r\n .split(':')\r\n .map((part) => {\r\n if (part === 'base') return null;\r\n // Only return the part if it's found in our registry\r\n if (registry[part]) return registry[part];\r\n // Otherwise, it's a logical container and should be ignored\r\n return null;\r\n })\r\n .filter(Boolean)\r\n .join(':');\r\n\r\n // Apply the resolved prefix to each class in the string\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 /**\r\n * The final utility function.\r\n * Processes inputs through the prefix engine and cleans them using tailwind-merge.\r\n * * @param inputs - Variadic arguments including strings, objects, arrays, or booleans.\r\n * @returns A merged and optimized string of Tailwind CSS classes.\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]) => (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
package/src/index.ts
CHANGED
|
@@ -10,7 +10,8 @@ import clsx from 'clsx';
|
|
|
10
10
|
export function createCl<TPlugins extends Record<string, string>[]>(...plugins: TPlugins) {
|
|
11
11
|
/**
|
|
12
12
|
* Internal registry that stores all official prefixes.
|
|
13
|
-
* Any key not found here will be treated as "transparent"
|
|
13
|
+
* Any key not found here will be treated as a "transparent" logical container
|
|
14
|
+
* and will be discarded in the final string resolution.
|
|
14
15
|
*/
|
|
15
16
|
const registry: Record<string, string> = Object.assign({ base: 'base' }, ...plugins);
|
|
16
17
|
|
|
@@ -38,7 +39,7 @@ export function createCl<TPlugins extends Record<string, string>[]>(...plugins:
|
|
|
38
39
|
/**
|
|
39
40
|
* Rule: If the child key is registered, we concatenate it.
|
|
40
41
|
* If it's not registered, it's a "logical" key (transparent),
|
|
41
|
-
* so we inherit the parent's prefix.
|
|
42
|
+
* so we inherit the parent's prefix to keep the path clean.
|
|
42
43
|
*/
|
|
43
44
|
const isRegistered = registry[nestedKey] !== undefined;
|
|
44
45
|
const nextKey =
|
|
@@ -51,16 +52,16 @@ export function createCl<TPlugins extends Record<string, string>[]>(...plugins:
|
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
54
|
* FINAL RESOLUTION
|
|
54
|
-
* Maps aliases (e.g., 'ui')
|
|
55
|
-
*
|
|
55
|
+
* Maps aliases (e.g., 'ui' -> 'prefix') and filters out any part
|
|
56
|
+
* of the path that is not explicitly registered in the registry.
|
|
56
57
|
*/
|
|
57
58
|
const resolvedPrefix = key
|
|
58
59
|
.split(':')
|
|
59
60
|
.map((part) => {
|
|
60
61
|
if (part === 'base') return null;
|
|
61
|
-
//
|
|
62
|
+
// Only return the part if it's found in our registry
|
|
62
63
|
if (registry[part]) return registry[part];
|
|
63
|
-
// Otherwise,
|
|
64
|
+
// Otherwise, it's a logical container and should be ignored
|
|
64
65
|
return null;
|
|
65
66
|
})
|
|
66
67
|
.filter(Boolean)
|
package/src/test/cn.test.ts
CHANGED
|
@@ -77,4 +77,49 @@ it('Nivel 5: El "Inception" (Lógica anidada, condicionales y plugins)', () => {
|
|
|
77
77
|
// md:p-8 debe ganar a md:p-4
|
|
78
78
|
expect(result).toBe('md:p-8');
|
|
79
79
|
});
|
|
80
|
+
|
|
81
|
+
it('Nivel 7: Selectores Dinámicos (Sintaxis de Componente)', () => {
|
|
82
|
+
const variant = 'primary';
|
|
83
|
+
const onHover = 'scale';
|
|
84
|
+
|
|
85
|
+
const result = cl({
|
|
86
|
+
// 'variants' no está registrado -> Desaparece
|
|
87
|
+
variants: {
|
|
88
|
+
primary: 'bg-action text-white',
|
|
89
|
+
secondary: 'bg-neutral-50 text-black'
|
|
90
|
+
}[variant],
|
|
91
|
+
|
|
92
|
+
// 'effects' no está registrado -> Desaparece
|
|
93
|
+
effects: {
|
|
94
|
+
scale: 'elevate-hover',
|
|
95
|
+
dim: 'hover:opacity-80'
|
|
96
|
+
}[onHover]
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// El resultado no debe contener ni 'variants:' ni 'effects:'
|
|
100
|
+
expect(result).toBe('bg-action text-white elevate-hover');
|
|
101
|
+
expect(result).not.toContain('variants:');
|
|
102
|
+
expect(result).not.toContain('effects:');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('Nivel 8: Combinación de Selectores con Prefijos Registrados', () => {
|
|
106
|
+
const variant = 'secondary';
|
|
107
|
+
const isDark = true;
|
|
108
|
+
|
|
109
|
+
const result = cl({
|
|
110
|
+
md: {
|
|
111
|
+
// Selector dinámico dentro de un prefijo registrado
|
|
112
|
+
container: {
|
|
113
|
+
[variant]: {
|
|
114
|
+
base: 'p-4',
|
|
115
|
+
// Prefijo registrado dentro de un selector dinámico
|
|
116
|
+
hover: 'shadow-xl'
|
|
117
|
+
}
|
|
118
|
+
}[variant]
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// 'md' y 'hover' se mantienen, 'container' y 'secondary' desaparecen
|
|
123
|
+
expect(result).toBe('md:p-4 md:hover:shadow-xl');
|
|
124
|
+
});
|
|
80
125
|
});
|