clases 1.1.1 → 1.1.3

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 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({ base: "base" }, ...plugins);
12
+ const registry = Object.assign({}, ...plugins);
13
13
  const process = (key, value) => {
14
14
  if (!value) return "";
15
15
  if (Array.isArray(value)) {
@@ -22,11 +22,7 @@ function createCl(...plugins) {
22
22
  return process(nextKey, nestedValue);
23
23
  }).join(" ");
24
24
  }
25
- const resolvedPrefix = key.split(":").map((part) => {
26
- if (part === "base") return null;
27
- if (registry[part]) return registry[part];
28
- return null;
29
- }).filter(Boolean).join(":");
25
+ const resolvedPrefix = key.split(":").map((part) => part === "base" ? null : registry[part] || null).filter(Boolean).join(":");
30
26
  if (typeof value === "string") {
31
27
  return value.split(/[,\s\n]+/).filter(Boolean).map((cls) => !resolvedPrefix ? cls : `${resolvedPrefix}:${cls}`).join(" ");
32
28
  }
@@ -35,7 +31,11 @@ function createCl(...plugins) {
35
31
  return (...inputs) => {
36
32
  const processed = inputs.map((input) => {
37
33
  if (input !== null && typeof input === "object" && !Array.isArray(input)) {
38
- return Object.entries(input).map(([k, v]) => v === true ? k : process(k, v)).join(" ");
34
+ return Object.entries(input).map(([k, v]) => {
35
+ if (v === true) return k;
36
+ const isRegistered = registry[k] !== void 0;
37
+ return process(isRegistered ? k : "base", v);
38
+ }).join(" ");
39
39
  }
40
40
  return input;
41
41
  });
@@ -1 +1 @@
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"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["twMerge","clsx"],"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,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;AAK7C,QAAA,MAAM,OAAA,GAAU,QAAQ,MAAA,GAClB,SAAA,GACC,eAAe,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,GAAK,GAAA;AAE9C,QAAA,OAAO,OAAA,CAAQ,SAAS,WAAW,CAAA;AAAA,MACvC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,MAAM,cAAA,GAAiB,IAClB,KAAA,CAAM,GAAG,EACT,GAAA,CAAI,CAAC,SAAU,IAAA,KAAS,MAAA,GAAS,OAAQ,QAAA,CAAS,IAAI,KAAK,IAAM,CAAA,CACjE,OAAO,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;AAGvB,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 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 // Si el padre es 'base', el hijo toma su lugar.\r\n // Si el hijo está registrado, se concatena.\r\n // Si no, heredamos el padre para mantener la transparencia.\r\n const nextKey = key === 'base' \r\n ? nestedKey \r\n : (isRegistered ? `${key}:${nestedKey}` : key);\r\n\r\n return process(nextKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n // RESOLUCIÓN: Solo permitimos partes que existan en el registry\r\n const resolvedPrefix = key\r\n .split(':')\r\n .map((part) => (part === 'base' ? null : (registry[part] || null)))\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 NO ESTÁ REGISTRADA (ej: 'variants'), \r\n // entramos como 'base' para que sea invisible.\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({ base: "base" }, ...plugins);
6
+ const registry = Object.assign({}, ...plugins);
7
7
  const process = (key, value) => {
8
8
  if (!value) return "";
9
9
  if (Array.isArray(value)) {
@@ -16,11 +16,7 @@ function createCl(...plugins) {
16
16
  return process(nextKey, nestedValue);
17
17
  }).join(" ");
18
18
  }
19
- const resolvedPrefix = key.split(":").map((part) => {
20
- if (part === "base") return null;
21
- if (registry[part]) return registry[part];
22
- return null;
23
- }).filter(Boolean).join(":");
19
+ const resolvedPrefix = key.split(":").map((part) => part === "base" ? null : registry[part] || null).filter(Boolean).join(":");
24
20
  if (typeof value === "string") {
25
21
  return value.split(/[,\s\n]+/).filter(Boolean).map((cls) => !resolvedPrefix ? cls : `${resolvedPrefix}:${cls}`).join(" ");
26
22
  }
@@ -29,7 +25,11 @@ function createCl(...plugins) {
29
25
  return (...inputs) => {
30
26
  const processed = inputs.map((input) => {
31
27
  if (input !== null && typeof input === "object" && !Array.isArray(input)) {
32
- return Object.entries(input).map(([k, v]) => v === true ? k : process(k, v)).join(" ");
28
+ return Object.entries(input).map(([k, v]) => {
29
+ if (v === true) return k;
30
+ const isRegistered = registry[k] !== void 0;
31
+ return process(isRegistered ? k : "base", v);
32
+ }).join(" ");
33
33
  }
34
34
  return input;
35
35
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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"]}
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,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;AAK7C,QAAA,MAAM,OAAA,GAAU,QAAQ,MAAA,GAClB,SAAA,GACC,eAAe,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,GAAK,GAAA;AAE9C,QAAA,OAAO,OAAA,CAAQ,SAAS,WAAW,CAAA;AAAA,MACvC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AAAA,IACjB;AAGA,IAAA,MAAM,cAAA,GAAiB,IAClB,KAAA,CAAM,GAAG,EACT,GAAA,CAAI,CAAC,SAAU,IAAA,KAAS,MAAA,GAAS,OAAQ,QAAA,CAAS,IAAI,KAAK,IAAM,CAAA,CACjE,OAAO,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;AAGvB,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 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 // Si el padre es 'base', el hijo toma su lugar.\r\n // Si el hijo está registrado, se concatena.\r\n // Si no, heredamos el padre para mantener la transparencia.\r\n const nextKey = key === 'base' \r\n ? nestedKey \r\n : (isRegistered ? `${key}:${nestedKey}` : key);\r\n\r\n return process(nextKey, nestedValue);\r\n })\r\n .join(' ');\r\n }\r\n\r\n // RESOLUCIÓN: Solo permitimos partes que existan en el registry\r\n const resolvedPrefix = key\r\n .split(':')\r\n .map((part) => (part === 'base' ? null : (registry[part] || null)))\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 NO ESTÁ REGISTRADA (ej: 'variants'), \r\n // entramos como 'base' para que sea invisible.\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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clases",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/index.ts CHANGED
@@ -1,73 +1,40 @@
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
- * Internal registry that stores all official prefixes.
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
+ const registry: Record<string, string> = Object.assign({}, ...plugins);
17
6
 
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
7
  const process = (key: string, value: any): string => {
25
8
  if (!value) return '';
26
9
 
27
- // Handle Arrays: Process each element with the current key
28
10
  if (Array.isArray(value)) {
29
- return value
30
- .map((v) => process(key, v))
31
- .filter(Boolean)
32
- .join(' ');
11
+ return value.map((v) => process(key, v)).filter(Boolean).join(' ');
33
12
  }
34
13
 
35
- // Handle Objects: Manage nesting and logical transparency
36
14
  if (typeof value === 'object') {
37
15
  return Object.entries(value)
38
16
  .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
17
  const isRegistered = registry[nestedKey] !== undefined;
45
- const nextKey =
46
- key === 'base' ? nestedKey : isRegistered ? `${key}:${nestedKey}` : key;
18
+
19
+ // Si el padre es 'base', el hijo toma su lugar.
20
+ // Si el hijo está registrado, se concatena.
21
+ // Si no, heredamos el padre para mantener la transparencia.
22
+ const nextKey = key === 'base'
23
+ ? nestedKey
24
+ : (isRegistered ? `${key}:${nestedKey}` : key);
47
25
 
48
26
  return process(nextKey, nestedValue);
49
27
  })
50
28
  .join(' ');
51
29
  }
52
30
 
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
- */
31
+ // RESOLUCIÓN: Solo permitimos partes que existan en el registry
58
32
  const resolvedPrefix = key
59
33
  .split(':')
60
- .map((part) => {
61
- if (part === 'base') return null;
62
- // Only return the part if it's found in our registry
63
- if (registry[part]) return registry[part];
64
- // Otherwise, it's a logical container and should be ignored
65
- return null;
66
- })
34
+ .map((part) => (part === 'base' ? null : (registry[part] || null)))
67
35
  .filter(Boolean)
68
36
  .join(':');
69
37
 
70
- // Apply the resolved prefix to each class in the string
71
38
  if (typeof value === 'string') {
72
39
  return value
73
40
  .split(/[,\s\n]+/)
@@ -78,17 +45,17 @@ export function createCl<TPlugins extends Record<string, string>[]>(...plugins:
78
45
  return '';
79
46
  };
80
47
 
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
48
  return (...inputs: any[]) => {
88
49
  const processed = inputs.map((input) => {
89
50
  if (input !== null && typeof input === 'object' && !Array.isArray(input)) {
90
51
  return Object.entries(input)
91
- .map(([k, v]) => (v === true ? k : process(k, v)))
52
+ .map(([k, v]) => {
53
+ if (v === true) return k;
54
+ // SI LA LLAVE NO ESTÁ REGISTRADA (ej: 'variants'),
55
+ // entramos como 'base' para que sea invisible.
56
+ const isRegistered = registry[k] !== undefined;
57
+ return process(isRegistered ? k : 'base', v);
58
+ })
92
59
  .join(' ');
93
60
  }
94
61
  return input;
@@ -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
  });