@hiscovega/grisso 1.0.3 → 1.0.5

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/lib/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/lib/cli.js ADDED
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { parseArgs } from "node:util";
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ /** Lee la versión desde package.json */
8
+ function getVersion() {
9
+ const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../package.json"), "utf8"));
10
+ return pkg.version;
11
+ }
12
+ /** Texto de ayuda general */
13
+ function printHelp() {
14
+ const version = getVersion();
15
+ console.log(`grisso v${version} — Griddo CSS utility class library
16
+
17
+ Uso:
18
+ grisso <comando> [opciones]
19
+
20
+ Comandos:
21
+ build Genera CSS de utilidades
22
+
23
+ Opciones globales:
24
+ --help, -h Muestra esta ayuda
25
+ --version, -v Muestra la versión`);
26
+ }
27
+ /** Texto de ayuda del comando build */
28
+ function printBuildHelp() {
29
+ console.log(`grisso build — Genera CSS de utilidades
30
+
31
+ Uso:
32
+ grisso build [opciones]
33
+
34
+ Opciones:
35
+ --config <ruta> Ruta a grisso.config.mjs
36
+ --content <glob> Globs para tree-shaking (repetible)
37
+ --output <ruta> Archivo de salida (sin --output → stdout)
38
+ --no-minify Deshabilitar minificación
39
+ --help, -h Muestra esta ayuda
40
+
41
+ Ejemplos:
42
+ grisso build # CSS completo a stdout
43
+ grisso build --output dist/grisso.css # Escribir a archivo
44
+ grisso build --content "src/**/*.tsx" --output out.css # Tree-shaking
45
+ grisso build --no-minify # Sin minificar`);
46
+ }
47
+ /** Comando build: genera CSS */
48
+ async function runBuild(argv) {
49
+ const { values } = parseArgs({
50
+ args: argv,
51
+ options: {
52
+ config: { type: "string" },
53
+ content: { type: "string", multiple: true },
54
+ output: { type: "string" },
55
+ minify: { type: "boolean", default: true },
56
+ help: { type: "boolean", short: "h", default: false },
57
+ },
58
+ strict: true,
59
+ allowNegative: true,
60
+ });
61
+ if (values.help) {
62
+ printBuildHelp();
63
+ return;
64
+ }
65
+ // Import dinámico para que --help sea instantáneo
66
+ const { buildCSS } = await import("./build.js");
67
+ const content = values.content && values.content.length > 0 ? values.content : undefined;
68
+ if (values.output) {
69
+ const label = content
70
+ ? "Generando CSS con tree-shaking..."
71
+ : "Generando CSS...";
72
+ console.error(label);
73
+ }
74
+ const css = await buildCSS({
75
+ config: values.config,
76
+ content,
77
+ minify: values.minify,
78
+ });
79
+ if (values.output) {
80
+ const outputPath = path.resolve(values.output);
81
+ const dir = path.dirname(outputPath);
82
+ if (!fs.existsSync(dir)) {
83
+ fs.mkdirSync(dir, { recursive: true });
84
+ }
85
+ fs.writeFileSync(outputPath, css);
86
+ const kb = (Buffer.byteLength(css, "utf8") / 1024).toFixed(1);
87
+ console.error(`Generado ${path.relative(process.cwd(), outputPath)} (${kb} KB)`);
88
+ }
89
+ else {
90
+ process.stdout.write(css);
91
+ }
92
+ }
93
+ /** Punto de entrada */
94
+ async function main() {
95
+ const { values, positionals } = parseArgs({
96
+ args: process.argv.slice(2),
97
+ options: {
98
+ help: { type: "boolean", short: "h", default: false },
99
+ version: { type: "boolean", short: "v", default: false },
100
+ },
101
+ strict: false,
102
+ allowPositionals: true,
103
+ });
104
+ if (values.version) {
105
+ console.log(getVersion());
106
+ return;
107
+ }
108
+ const command = positionals[0];
109
+ if (values.help && !command) {
110
+ printHelp();
111
+ return;
112
+ }
113
+ if (!command) {
114
+ printHelp();
115
+ process.exit(1);
116
+ }
117
+ switch (command) {
118
+ case "build":
119
+ // Pasar solo los args después de "build"
120
+ await runBuild(process.argv.slice(3));
121
+ break;
122
+ default:
123
+ console.error(`Comando desconocido: ${command}`);
124
+ printHelp();
125
+ process.exit(1);
126
+ }
127
+ }
128
+ main().catch((err) => {
129
+ console.error(err);
130
+ process.exit(1);
131
+ });
@@ -1,8 +1,4 @@
1
1
  import type { Breakpoints, Declarations, TokenMap } from "./types.js";
2
- /**
3
- * Generadores de clases CSS utility.
4
- * Replican los mixins grisso_simple_class, grisso_complex_class de SCSS.
5
- */
6
2
  /**
7
3
  * Genera una clase simple con variantes responsive.
8
4
  * Equivalente al mixin grisso_simple_class.
package/lib/generators.js CHANGED
@@ -2,14 +2,19 @@
2
2
  * Generadores de clases CSS utility.
3
3
  * Replican los mixins grisso_simple_class, grisso_complex_class de SCSS.
4
4
  */
5
+ /** Escapa caracteres especiales en classNames para selectores CSS válidos. */
6
+ function escapeCSS(name) {
7
+ return name.replace(/\//g, "\\/");
8
+ }
5
9
  /**
6
10
  * Genera una clase simple con variantes responsive.
7
11
  * Equivalente al mixin grisso_simple_class.
8
12
  */
9
13
  export function simpleClass(className, property, value, breakpoints) {
10
- let css = `.${className} { ${property}: ${value}; }\n`;
14
+ const escaped = escapeCSS(className);
15
+ let css = `.${escaped} { ${property}: ${value}; }\n`;
11
16
  for (const [bp, mq] of Object.entries(breakpoints)) {
12
- css += `@media ${mq} { .${bp}-${className} { ${property}: ${value}; } }\n`;
17
+ css += `@media ${mq} { .${bp}-${escaped} { ${property}: ${value}; } }\n`;
13
18
  }
14
19
  return css;
15
20
  }
@@ -21,12 +26,13 @@ export function complexClass(prefix, properties, tokens, breakpoints) {
21
26
  const props = Array.isArray(properties) ? properties : [properties];
22
27
  let css = "";
23
28
  for (const [name, value] of Object.entries(tokens)) {
29
+ const escaped = escapeCSS(`${prefix}${name}`);
24
30
  for (const prop of props) {
25
- css += `.${prefix}${name} { ${prop}: ${value}; }\n`;
31
+ css += `.${escaped} { ${prop}: ${value}; }\n`;
26
32
  }
27
33
  for (const [bp, mq] of Object.entries(breakpoints)) {
28
34
  for (const prop of props) {
29
- css += `@media ${mq} { .${bp}-${prefix}${name} { ${prop}: ${value}; } }\n`;
35
+ css += `@media ${mq} { .${bp}-${escaped} { ${prop}: ${value}; } }\n`;
30
36
  }
31
37
  }
32
38
  }
@@ -37,13 +43,14 @@ export function complexClass(prefix, properties, tokens, breakpoints) {
37
43
  * Para casos especiales: divide >*+*, truncate, smoothing, outline-none, etc.
38
44
  */
39
45
  export function customClass(className, declarations, breakpoints, selectorSuffix) {
46
+ const escaped = escapeCSS(className);
40
47
  const suffix = selectorSuffix || "";
41
48
  const decls = Object.entries(declarations)
42
49
  .map(([p, v]) => `${p}: ${v}`)
43
50
  .join("; ");
44
- let css = `.${className}${suffix} { ${decls}; }\n`;
51
+ let css = `.${escaped}${suffix} { ${decls}; }\n`;
45
52
  for (const [bp, mq] of Object.entries(breakpoints)) {
46
- css += `@media ${mq} { .${bp}-${className}${suffix} { ${decls}; } }\n`;
53
+ css += `@media ${mq} { .${bp}-${escaped}${suffix} { ${decls}; } }\n`;
47
54
  }
48
55
  return css;
49
56
  }
@@ -19,6 +19,13 @@ export default function borders(config) {
19
19
  };
20
20
  // border-width
21
21
  css += complexClass("border-", "border-width", borderWidth, breakpoints);
22
+ // border-{side}-width
23
+ css += complexClass("border-t-", "border-top-width", borderWidth, breakpoints);
24
+ css += complexClass("border-r-", "border-right-width", borderWidth, breakpoints);
25
+ css += complexClass("border-b-", "border-bottom-width", borderWidth, breakpoints);
26
+ css += complexClass("border-l-", "border-left-width", borderWidth, breakpoints);
27
+ // border-color
28
+ css += complexClass("border-", "border-color", extendedColors, breakpoints);
22
29
  // border-style
23
30
  css += complexClass("border-", "border-style", borderStyle, breakpoints);
24
31
  // divide-color
@@ -1,4 +1,4 @@
1
- import { complexClass, simpleClass } from "../generators.js";
1
+ import { complexClass, customClass, simpleClass } from "../generators.js";
2
2
  export default function layout(config) {
3
3
  const { columns, breakpoints, spacing } = config;
4
4
  let css = "";
@@ -31,8 +31,6 @@ export default function layout(config) {
31
31
  for (let i = 1; i <= columns; i++) {
32
32
  css += simpleClass(`columns-${i}`, "columns", String(i), breakpoints);
33
33
  }
34
- // columns (spacing tokens)
35
- css += complexClass("columns-", "columns", spacing, breakpoints);
36
34
  // float
37
35
  const float = {
38
36
  left: "left",
@@ -98,14 +96,14 @@ export default function layout(config) {
98
96
  const zIndex = {
99
97
  auto: "auto",
100
98
  "0": "0",
101
- "1": "10",
99
+ "10": "10",
102
100
  "20": "20",
103
101
  "30": "30",
104
102
  "40": "40",
105
103
  "50": "50",
106
104
  };
107
105
  const zIndexNeg = {
108
- "1": "-10",
106
+ "10": "-10",
109
107
  "20": "-20",
110
108
  "30": "-30",
111
109
  "40": "-40",
@@ -114,13 +112,19 @@ export default function layout(config) {
114
112
  css += complexClass("z-", "z-index", zIndex, breakpoints);
115
113
  css += complexClass("-z-", "z-index", zIndexNeg, breakpoints);
116
114
  // top/right/bottom/left
117
- css += simpleClass("top-0", "top", "0", breakpoints);
118
- css += simpleClass("right-0", "right", "0", breakpoints);
119
- css += simpleClass("bottom-0", "bottom", "0", breakpoints);
120
- css += simpleClass("left-0", "left", "0", breakpoints);
121
115
  css += complexClass("top-", "top", spacing, breakpoints);
122
116
  css += complexClass("right-", "right", spacing, breakpoints);
123
117
  css += complexClass("bottom-", "bottom", spacing, breakpoints);
124
118
  css += complexClass("left-", "left", spacing, breakpoints);
119
+ // inset (top + right + bottom + left)
120
+ css += complexClass("inset-", "inset", spacing, breakpoints);
121
+ // inset-x (left + right)
122
+ for (const [key, value] of Object.entries(spacing)) {
123
+ css += customClass(`inset-x-${key}`, { left: value, right: value }, breakpoints);
124
+ }
125
+ // inset-y (top + bottom)
126
+ for (const [key, value] of Object.entries(spacing)) {
127
+ css += customClass(`inset-y-${key}`, { top: value, bottom: value }, breakpoints);
128
+ }
125
129
  return css;
126
130
  }
@@ -1,7 +1,35 @@
1
1
  import { complexClass, simpleClass } from "../generators.js";
2
2
  import { fractionPercent } from "../utils.js";
3
+ const fractions = [
4
+ [1, 2],
5
+ [1, 3],
6
+ [2, 3],
7
+ [1, 4],
8
+ [2, 4],
9
+ [3, 4],
10
+ [1, 5],
11
+ [2, 5],
12
+ [3, 5],
13
+ [4, 5],
14
+ [1, 6],
15
+ [2, 6],
16
+ [3, 6],
17
+ [4, 6],
18
+ [5, 6],
19
+ [1, 12],
20
+ [2, 12],
21
+ [3, 12],
22
+ [4, 12],
23
+ [5, 12],
24
+ [6, 12],
25
+ [7, 12],
26
+ [8, 12],
27
+ [9, 12],
28
+ [10, 12],
29
+ [11, 12],
30
+ ];
3
31
  export default function sizing(config) {
4
- const { columns, breakpoints } = config;
32
+ const { breakpoints } = config;
5
33
  let css = "";
6
34
  // width
7
35
  const width = {
@@ -14,8 +42,8 @@ export default function sizing(config) {
14
42
  fit: "fit-content",
15
43
  };
16
44
  css += complexClass("w-", "width", width, breakpoints);
17
- for (let i = 1; i <= columns; i++) {
18
- css += simpleClass(`w-${i}`, "width", fractionPercent(i, columns), breakpoints);
45
+ for (const [n, d] of fractions) {
46
+ css += simpleClass(`w-${n}/${d}`, "width", fractionPercent(n, d), breakpoints);
19
47
  }
20
48
  css += complexClass("min-w-", "min-width", width, breakpoints);
21
49
  css += complexClass("max-w-", "max-width", width, breakpoints);
@@ -30,8 +58,8 @@ export default function sizing(config) {
30
58
  fit: "fit-content",
31
59
  };
32
60
  css += complexClass("h-", "height", height, breakpoints);
33
- for (let i = 1; i <= columns; i++) {
34
- css += simpleClass(`h-${i}`, "height", fractionPercent(i, columns), breakpoints);
61
+ for (const [n, d] of fractions) {
62
+ css += simpleClass(`h-${n}/${d}`, "height", fractionPercent(n, d), breakpoints);
35
63
  }
36
64
  css += complexClass("min-h-", "min-height", height, breakpoints);
37
65
  css += complexClass("max-h-", "max-height", height, breakpoints);
@@ -83,7 +83,7 @@ export default function typography(config) {
83
83
  const fontWeight = {
84
84
  thin: "100",
85
85
  extralight: "200",
86
- light: "200",
86
+ light: "300",
87
87
  normal: "400",
88
88
  medium: "500",
89
89
  semibold: "600",
@@ -93,7 +93,14 @@ export default function typography(config) {
93
93
  };
94
94
  css += complexClass("font-", "font-weight", fontWeight, breakpoints);
95
95
  // letter-spacing
96
- const letterSpacing = omit(spacing, "auto");
96
+ const letterSpacing = {
97
+ tighter: "-0.05em",
98
+ tight: "-0.025em",
99
+ normal: "0em",
100
+ wide: "0.025em",
101
+ wider: "0.05em",
102
+ widest: "0.1em",
103
+ };
97
104
  css += complexClass("tracking-", "letter-spacing", letterSpacing, breakpoints);
98
105
  // line-height
99
106
  const lineHeight = omit(spacing, "auto", "zero");
@@ -101,7 +108,7 @@ export default function typography(config) {
101
108
  ...lineHeight,
102
109
  none: "1",
103
110
  tight: "1.25",
104
- snug: "1.3755",
111
+ snug: "1.375",
105
112
  normal: "1.5",
106
113
  relaxed: "1.625",
107
114
  loose: "2",
package/lib/purge.js CHANGED
@@ -11,8 +11,8 @@ export async function purgeCSS(css, options) {
11
11
  css: [{ raw: css }],
12
12
  extractors: [
13
13
  {
14
- // Extractor para uso directo en HTML/JSX: class="flex gap-md"
15
- extractor: (content) => content.match(/[A-Za-z0-9_-]+/g) || [],
14
+ // Extractor para uso directo en HTML/JSX: class="flex gap-md w-1/2"
15
+ extractor: (content) => content.match(/[A-Za-z0-9_/.-]+/g) || [],
16
16
  extensions: ["html", "jsx", "tsx", "js", "ts"],
17
17
  },
18
18
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hiscovega/grisso",
3
3
  "description": "Griddo CSS utility class library",
4
- "version": "1.0.3",
4
+ "version": "1.0.5",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
7
7
  "type": "module",
@@ -9,10 +9,6 @@
9
9
  ".": {
10
10
  "style": "./dist/grisso.css"
11
11
  },
12
- "./plugin": {
13
- "import": "./plugin.js",
14
- "require": "./plugin.cjs"
15
- },
16
12
  "./build": "./lib/build.js",
17
13
  "./config": "./lib/defaults.js",
18
14
  "./tokens-example.css": "./tokens-example.css"
@@ -20,41 +16,36 @@
20
16
  "engines": {
21
17
  "node": ">=24"
22
18
  },
19
+ "bin": {
20
+ "grisso": "lib/cli.js"
21
+ },
23
22
  "files": [
24
23
  "dist/",
25
24
  "lib/",
26
- "plugin.js",
27
- "plugin.cjs",
28
25
  "tokens-example.css",
29
26
  "README.md"
30
27
  ],
31
28
  "scripts": {
32
- "build": "tsc && node scripts/build.js",
29
+ "build": "tsc && node lib/cli.js build --output dist/grisso.css",
33
30
  "typecheck": "tsc --noEmit",
34
31
  "lint": "biome check .",
35
32
  "lint:fix": "biome check --write .",
36
- "playground": "npm run build && node scripts/build.js --config playground/grisso.config.mjs --content playground/index.html --content playground/example.module.css --output playground/grisso.css && open playground/index.html",
33
+ "playground": "npm run build && node lib/cli.js build --config playground/grisso.config.mjs --content playground/index.html --content playground/example.module.css --output playground/grisso.css && open playground/index.html",
37
34
  "test": "vitest run",
38
35
  "test:watch": "vitest",
39
36
  "prepublishOnly": "npm run build",
40
37
  "release": "release-it"
41
38
  },
39
+ "dependencies": {
40
+ "browserslist": "^4.24.0",
41
+ "lightningcss": "^1.28.0",
42
+ "purgecss": "^6.0.0"
43
+ },
42
44
  "devDependencies": {
43
45
  "@biomejs/biome": "2.4.5",
44
46
  "@types/node": "^25.3.3",
45
- "browserslist": "^4.24.0",
46
- "lightningcss": "^1.28.0",
47
- "purgecss": "^6.0.0",
48
47
  "release-it": "^19.2.4",
49
48
  "typescript": "^5.9.3",
50
49
  "vitest": "^4.0.18"
51
- },
52
- "peerDependencies": {
53
- "postcss": "^8.0.0"
54
- },
55
- "peerDependenciesMeta": {
56
- "postcss": {
57
- "optional": true
58
- }
59
50
  }
60
51
  }
@@ -1,4 +1,4 @@
1
- /* @griddo/grisso — tokens-example.css
1
+ /* @hiscovega/grisso — tokens-example.css
2
2
  Copia este archivo y adapta los valores a tu design system.
3
3
  Define estas variables en :root o en el scope que prefieras.
4
4
 
package/plugin.cjs DELETED
@@ -1,5 +0,0 @@
1
- // CJS wrapper — require(esm) supported in Node 22+
2
- const mod = require("./plugin.js");
3
- module.exports = mod.default;
4
- module.exports.default = mod.default;
5
- module.exports.postcss = true;
package/plugin.js DELETED
@@ -1,43 +0,0 @@
1
- import { generateCSS } from "./lib/index.js";
2
- import { purgeCSS } from "./lib/purge.js";
3
-
4
- /**
5
- * PostCSS plugin de Grisso.
6
- * Genera CSS desde JS y aplica tree-shaking usando PurgeCSS
7
- * si se pasan rutas de contenido.
8
- *
9
- * No aplica optimización (el consumidor tiene su propio pipeline PostCSS).
10
- *
11
- * @param {Object} options
12
- * @param {string[]} [options.content] - Rutas glob de archivos a escanear para tree-shaking.
13
- * Si se omite, se incluye todo el CSS de Grisso (útil en desarrollo).
14
- * @param {string} [options.config] - Ruta a grisso.config.mjs del consumidor.
15
- *
16
- * @example
17
- * // postcss.config.js del proyecto consumidor
18
- * import grisso from "@griddo/grisso/plugin";
19
- * export default {
20
- * plugins: [
21
- * grisso({ content: ["./src/**\/*.{js,ts,jsx,tsx,css}"] })
22
- * ]
23
- * }
24
- */
25
- export default function grissoPlugin(options = {}) {
26
- const { content, config: configPath } = options;
27
-
28
- return {
29
- postcssPlugin: "postcss-grisso",
30
- async Once(root, { parse }) {
31
- let css = await generateCSS(configPath);
32
-
33
- if (content && content.length > 0) {
34
- css = await purgeCSS(css, { content });
35
- }
36
-
37
- const grissoRoot = parse(css);
38
- grissoRoot.each((node) => root.prepend(node.clone()));
39
- },
40
- };
41
- }
42
-
43
- grissoPlugin.postcss = true;