@hiscovega/grisso 1.1.0 → 2.0.0-rc.0
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 +270 -11
- package/lib/postcss.d.ts +26 -0
- package/lib/postcss.js +243 -0
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
- [API programática](#api-programática)
|
|
15
15
|
- [Ejemplos](#ejemplos)
|
|
16
16
|
- [`extractTokens()`](#extracttokens--scaffold-de-tokens)
|
|
17
|
+
- [PostCSS plugin (`@grisso`)](#postcss-plugin-grisso)
|
|
17
18
|
- [Configuración personalizada](#configuración-personalizada)
|
|
18
19
|
- [Design Tokens (CSS custom properties)](#design-tokens-css-custom-properties)
|
|
19
20
|
- [Clases disponibles](#clases-disponibles)
|
|
@@ -240,6 +241,87 @@ app.get("/grisso.css", async (req, res) => {
|
|
|
240
241
|
});
|
|
241
242
|
```
|
|
242
243
|
|
|
244
|
+
### PostCSS plugin (`@grisso`)
|
|
245
|
+
|
|
246
|
+
Alternativa al uso de clases directamente en HTML. Permite usar clases Grisso dentro de archivos CSS (incluyendo `.module.css`) con el separador `:` para estados y breakpoints — sin depender de `composes: ... from global`.
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
npm install -D postcss
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Configuración PostCSS:**
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
// postcss.config.mjs
|
|
256
|
+
import grissoApply from "@hiscovega/grisso/postcss";
|
|
257
|
+
|
|
258
|
+
export default {
|
|
259
|
+
plugins: [grissoApply({ config: "./grisso.config.mjs" })],
|
|
260
|
+
};
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Uso en CSS Modules:**
|
|
264
|
+
|
|
265
|
+
```css
|
|
266
|
+
/* component.module.css */
|
|
267
|
+
.card {
|
|
268
|
+
border-radius: 8px;
|
|
269
|
+
transition: box-shadow 0.2s;
|
|
270
|
+
@grisso flex flex-col p-md bg-ui shadow-lg hover:shadow-xl tablet:p-lg;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.title {
|
|
274
|
+
@grisso text-1 font-bold hover:text-2;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.input {
|
|
278
|
+
@grisso p-sm border-sm border-1 focus:border-3 focus-visible:border-3;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.disabledBtn {
|
|
282
|
+
@grisso p-sm bg-3 text-1 disabled:bg-disabled disabled:opacity-3;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**CSS generado:**
|
|
287
|
+
|
|
288
|
+
```css
|
|
289
|
+
.card {
|
|
290
|
+
border-radius: 8px;
|
|
291
|
+
transition: box-shadow 0.2s;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
294
|
+
padding: var(--spc-md);
|
|
295
|
+
background-color: var(--bg-ui);
|
|
296
|
+
box-shadow: var(--box-shadow-lg);
|
|
297
|
+
}
|
|
298
|
+
.card:hover { box-shadow: var(--box-shadow-xl); }
|
|
299
|
+
@media (min-width: 700px) { .card { padding: var(--spc-lg); } }
|
|
300
|
+
|
|
301
|
+
.title { color: var(--text-1); font-weight: 700; }
|
|
302
|
+
.title:hover { color: var(--text-2); }
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Sintaxis de prefijos:**
|
|
306
|
+
|
|
307
|
+
| Patrón | Ejemplo | Resultado |
|
|
308
|
+
| --- | --- | --- |
|
|
309
|
+
| `clase` | `text-1` | Declaraciones base |
|
|
310
|
+
| `estado:clase` | `hover:text-2` | `.selector:hover { ... }` |
|
|
311
|
+
| `breakpoint:clase` | `tablet:flex` | `@media (min-width: 700px) { ... }` |
|
|
312
|
+
| `bp:estado:clase` | `tablet:hover:text-1` | Media query + pseudo-clase |
|
|
313
|
+
| `estado:bp:clase` | `hover:tablet:text-1` | Mismo resultado (orden flexible) |
|
|
314
|
+
|
|
315
|
+
Soporta todos los estados (`hover`, `focus`, `focus-visible`, `active`, `disabled`) y breakpoints (`tablet`, `desktop`, `ultrawide`). Se pueden combinar múltiples clases y prefijos en una sola directiva. Las reglas vacías se eliminan automáticamente.
|
|
316
|
+
|
|
317
|
+
**Opciones del plugin:**
|
|
318
|
+
|
|
319
|
+
| Opción | Tipo | Default | Descripción |
|
|
320
|
+
| --- | --- | --- | --- |
|
|
321
|
+
| `config` | `string` | — | Ruta a `grisso.config.mjs` personalizado |
|
|
322
|
+
|
|
323
|
+
Requiere `postcss` como peer dependency (`^8.1.0`).
|
|
324
|
+
|
|
243
325
|
## Configuración personalizada
|
|
244
326
|
|
|
245
327
|
Crea un `grisso.config.mjs` en la raíz de tu proyecto para extender o reemplazar los tokens por defecto.
|
|
@@ -351,19 +433,196 @@ Se combinan con breakpoints: `tablet-hover-bg-1`, `desktop-focus-p-sm`.
|
|
|
351
433
|
|
|
352
434
|
Orden del cascade: base → state → responsive → responsive+state.
|
|
353
435
|
|
|
436
|
+
### Escalas de tokens (referencia)
|
|
437
|
+
|
|
438
|
+
| Token | Valores |
|
|
439
|
+
| ------------------ | ---------------------------------------------------------------------------------------------------- |
|
|
440
|
+
| **Spacing** | `auto` `zero` `0` `4xs` `3xs` `2xs` `xs` `sm` `md` `lg` `xl` `2xl` `3xl` `4xl` `5xl` |
|
|
441
|
+
| **Border width** | `none` `xs` `sm` `md` `lg` |
|
|
442
|
+
| **Border color** | `1` `2` `3` `4` `disabled` `inherit` `current` `transparent` |
|
|
443
|
+
| **Background** | `ui` `1` `2` `3` `4` `5` `disabled` |
|
|
444
|
+
| **Text color** | `1` `2` `3` `4` |
|
|
445
|
+
| **Icon color** | `1` `2` `3` `4` `disabled` |
|
|
446
|
+
| **Opacity** | `0` `1` `2` `3` `4` `5` `6` |
|
|
447
|
+
| **Shadows** | `sm` `md` `lg` `xl` `inner` `none` |
|
|
448
|
+
| **Overlay** | `1` `2` `3` `4` |
|
|
449
|
+
|
|
354
450
|
### Categorías
|
|
355
451
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
452
|
+
#### Layout
|
|
453
|
+
|
|
454
|
+
**Display:**
|
|
455
|
+
`block` `inline` `inline-block` `flex` `inline-flex` `grid` `inline-grid` `inline-table` `table` `table-row` `table-caption` `table-cell` `table-column` `table-column-group` `table-footer-group` `table-header-group` `table-row-group` `contents` `flow-root` `list-item` `hidden`
|
|
456
|
+
|
|
457
|
+
**Columns:**
|
|
458
|
+
`columns-1` … `columns-12`
|
|
459
|
+
|
|
460
|
+
**Float:**
|
|
461
|
+
`float-left` `float-right` `float-none`
|
|
462
|
+
|
|
463
|
+
**Clear:**
|
|
464
|
+
`clear-left` `clear-right` `clear-both` `clear-none`
|
|
465
|
+
|
|
466
|
+
**Object fit:**
|
|
467
|
+
`object-contain` `object-cover` `object-fill` `object-none` `object-scale-down`
|
|
468
|
+
|
|
469
|
+
**Object position:**
|
|
470
|
+
`object-bottom` `object-center` `object-left` `object-left-bottom` `object-left-top` `object-right` `object-right-bottom` `object-right-top` `object-top`
|
|
471
|
+
|
|
472
|
+
**Overflow:**
|
|
473
|
+
`overflow-auto` `overflow-hidden` `overflow-clip` `overflow-visible` `overflow-scroll`
|
|
474
|
+
`overflow-x-{…}` `overflow-y-{…}` (mismos valores)
|
|
475
|
+
|
|
476
|
+
**Position:**
|
|
477
|
+
`static` `fixed` `absolute` `relative` `sticky`
|
|
478
|
+
|
|
479
|
+
**Visibility:**
|
|
480
|
+
`visible` `invisible` `collapse`
|
|
481
|
+
|
|
482
|
+
**Z-index:**
|
|
483
|
+
`z-auto` `z-0` `z-10` `z-20` `z-30` `z-40` `z-50`
|
|
484
|
+
`-z-10` `-z-20` `-z-30` `-z-40` `-z-50`
|
|
485
|
+
|
|
486
|
+
**Inset / posicionamiento:**
|
|
487
|
+
`top-{spacing}` `right-{spacing}` `bottom-{spacing}` `left-{spacing}`
|
|
488
|
+
`inset-{spacing}` `inset-x-{spacing}` `inset-y-{spacing}`
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
#### Flex & Grid
|
|
493
|
+
|
|
494
|
+
**Flex:**
|
|
495
|
+
`flex-row` `flex-row-reverse` `flex-col` `flex-col-reverse`
|
|
496
|
+
`flex-wrap` `flex-wrap-reverse` `flex-nowrap`
|
|
497
|
+
`flex-1` `flex-auto` `flex-initial` `flex-none`
|
|
498
|
+
`grow` `grow-0` `shrink` `shrink-0`
|
|
499
|
+
|
|
500
|
+
**Order:**
|
|
501
|
+
`order-1` … `order-12` `order-first` `order-last` `order-none`
|
|
502
|
+
|
|
503
|
+
**Justify:**
|
|
504
|
+
`justify-normal` `justify-start` `justify-end` `justify-center` `justify-between` `justify-around` `justify-evenly` `justify-stretch`
|
|
505
|
+
`justify-items-start` `justify-items-end` `justify-items-center` `justify-items-stretch`
|
|
506
|
+
`justify-self-auto` `justify-self-start` `justify-self-end` `justify-self-center` `justify-self-stretch`
|
|
507
|
+
|
|
508
|
+
**Align:**
|
|
509
|
+
`items-start` `items-end` `items-center` `items-baseline` `items-stretch`
|
|
510
|
+
`content-normal` `content-center` `content-start` `content-end` `content-between` `content-around` `content-evenly` `content-baseline` `content-stretch`
|
|
511
|
+
`self-auto` `self-start` `self-end` `self-center` `self-baseline` `self-stretch`
|
|
512
|
+
|
|
513
|
+
**Place:**
|
|
514
|
+
`place-content-center` `place-content-start` `place-content-end` `place-content-between` `place-content-around` `place-content-evenly` `place-content-baseline` `place-content-stretch`
|
|
515
|
+
`place-items-start` `place-items-end` `place-items-center` `place-items-baseline` `place-items-stretch`
|
|
516
|
+
`place-self-auto` `place-self-start` `place-self-end` `place-self-center` `place-self-stretch`
|
|
517
|
+
|
|
518
|
+
**Grid template columns:**
|
|
519
|
+
`grid-cols-1` … `grid-cols-12` `grid-cols-none`
|
|
520
|
+
|
|
521
|
+
**Grid column:**
|
|
522
|
+
`col-auto` `col-span-1` … `col-span-12` `col-span-full`
|
|
523
|
+
`col-start-1` … `col-start-12` `col-start-auto`
|
|
524
|
+
`col-end-1` … `col-end-13` `col-end-auto`
|
|
525
|
+
|
|
526
|
+
**Grid template rows:**
|
|
527
|
+
`grid-rows-1` … `grid-rows-12` `grid-rows-none`
|
|
528
|
+
|
|
529
|
+
**Grid row:**
|
|
530
|
+
`row-auto` `row-span-1` … `row-span-12` `row-span-full`
|
|
531
|
+
`row-start-1` … `row-start-12` `row-start-auto`
|
|
532
|
+
`row-end-1` … `row-end-12` `row-end-auto`
|
|
533
|
+
|
|
534
|
+
**Grid auto:**
|
|
535
|
+
`grid-flow-row` `grid-flow-col` `grid-flow-dense` `grid-flow-row-dense` `grid-flow-col-dense`
|
|
536
|
+
`auto-cols-auto` `auto-cols-min` `auto-cols-max` `auto-cols-fr`
|
|
537
|
+
`auto-rows-auto` `auto-rows-min` `auto-rows-max` `auto-rows-fr`
|
|
538
|
+
|
|
539
|
+
**Gap** (escala de spacing sin `auto`):
|
|
540
|
+
`gap-{spacing}` `gap-x-{spacing}` `gap-y-{spacing}`
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
#### Spacing
|
|
545
|
+
|
|
546
|
+
**Margin** (escala completa de spacing):
|
|
547
|
+
`m-{spacing}` `mt-{spacing}` `mr-{spacing}` `mb-{spacing}` `ml-{spacing}` `mx-{spacing}` `my-{spacing}`
|
|
548
|
+
|
|
549
|
+
**Padding** (escala sin `auto`):
|
|
550
|
+
`p-{spacing}` `pt-{spacing}` `pr-{spacing}` `pb-{spacing}` `pl-{spacing}` `px-{spacing}` `py-{spacing}`
|
|
551
|
+
|
|
552
|
+
---
|
|
553
|
+
|
|
554
|
+
#### Sizing
|
|
555
|
+
|
|
556
|
+
**Width:**
|
|
557
|
+
`w-auto` `w-0` `w-full` `w-screen` `w-min` `w-max` `w-fit`
|
|
558
|
+
`w-1/2` `w-1/3` `w-2/3` `w-1/4` `w-2/4` `w-3/4` `w-1/5` `w-2/5` `w-3/5` `w-4/5` `w-1/6` … `w-5/6` `w-1/12` … `w-11/12`
|
|
559
|
+
`min-w-{…}` `max-w-{…}` (mismos valores)
|
|
560
|
+
|
|
561
|
+
**Height:**
|
|
562
|
+
`h-auto` `h-0` `h-full` `h-screen` `h-min` `h-max` `h-fit`
|
|
563
|
+
`h-1/2` `h-1/3` … `h-11/12` (mismas fracciones que width)
|
|
564
|
+
`min-h-{…}` `max-h-{…}` (mismos valores)
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
#### Fondos
|
|
569
|
+
|
|
570
|
+
**Background color:** `bg-ui` `bg-1` `bg-2` `bg-3` `bg-4` `bg-5` `bg-disabled`
|
|
571
|
+
**Background attachment:** `bg-fixed` `bg-local` `bg-scroll`
|
|
572
|
+
**Background clip:** `bg-clip-border` `bg-clip-padding` `bg-clip-content` `bg-clip-text`
|
|
573
|
+
**Background origin:** `bg-origin-border` `bg-origin-padding` `bg-origin-content`
|
|
574
|
+
**Background position:** `bg-bottom` `bg-center` `bg-left` `bg-left-bottom` `bg-left-top` `bg-right` `bg-right-bottom` `bg-right-top` `bg-top`
|
|
575
|
+
**Background repeat:** `bg-repeat` `bg-no-repeat` `bg-repeat-x` `bg-repeat-y` `bg-repeat-round` `bg-repeat-space`
|
|
576
|
+
**Background size:** `bg-auto` `bg-cover` `bg-contain` `bg-inherit` `bg-initial` `bg-revert` `bg-unset`
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
#### Bordes
|
|
581
|
+
|
|
582
|
+
**Border width:** `border-none` `border-xs` `border-sm` `border-md` `border-lg`
|
|
583
|
+
**Border width (lados):** `border-t-{…}` `border-r-{…}` `border-b-{…}` `border-l-{…}` (misma escala)
|
|
584
|
+
**Border color:** `border-1` `border-2` `border-3` `border-4` `border-disabled` `border-inherit` `border-current` `border-transparent`
|
|
585
|
+
**Border style:** `border-solid` `border-dashed` `border-dotted` `border-double` `border-hidden` `border-none`
|
|
586
|
+
|
|
587
|
+
**Divide color:** `divide-1` `divide-2` `divide-3` `divide-4` `divide-disabled` `divide-inherit` `divide-current` `divide-transparent`
|
|
588
|
+
**Divide width:** `divide-x` `divide-y` `divide-x-{borderWidth}` `divide-y-{borderWidth}`
|
|
589
|
+
**Divide style:** `divide-solid` `divide-dashed` `divide-dotted` `divide-double` `divide-hidden` `divide-none`
|
|
590
|
+
|
|
591
|
+
**Outline color:** `outline-1` `outline-2` `outline-3` `outline-4` `outline-disabled` `outline-inherit` `outline-current` `outline-transparent`
|
|
592
|
+
**Outline width:** `outline-none` `outline-xs` `outline-sm` `outline-md` `outline-lg`
|
|
593
|
+
**Outline style:** `outline` `outline-dashed` `outline-dotted` `outline-double` `outline-none`
|
|
594
|
+
**Outline offset:** `outline-offset-none` `outline-offset-xs` `outline-offset-sm` `outline-offset-md` `outline-offset-lg`
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
#### Tipografía
|
|
599
|
+
|
|
600
|
+
**Text color:** `text-1` `text-2` `text-3` `text-4`
|
|
601
|
+
**Text align:** `text-left` `text-center` `text-right` `text-justify` `text-start` `text-end`
|
|
602
|
+
**Text transform:** `uppercase` `lowercase` `capitalize` `normal-case`
|
|
603
|
+
**Text overflow:** `text-ellipsis` `text-clip` `truncate`
|
|
604
|
+
**Vertical align:** `align-baseline` `align-top` `align-middle` `align-bottom` `align-text-top` `align-text-bottom` `align-sub` `align-super`
|
|
605
|
+
**White space:** `whitespace-normal` `whitespace-nowrap` `whitespace-pre` `whitespace-pre-line` `whitespace-pre-wrap` `whitespace-break-spaces`
|
|
606
|
+
**Word break:** `break-all` `break-keep` `break-words` `break-normal`
|
|
607
|
+
**Font smoothing:** `antialiased` `subpixel-antialiased`
|
|
608
|
+
**Font style:** `italic` `not-italic`
|
|
609
|
+
**Font weight:** `font-thin` `font-extralight` `font-light` `font-normal` `font-medium` `font-semibold` `font-bold` `font-extrabold` `font-black`
|
|
610
|
+
**Letter spacing:** `tracking-tighter` `tracking-tight` `tracking-normal` `tracking-wide` `tracking-wider` `tracking-widest`
|
|
611
|
+
**Line height:** `leading-{spacing}` (sin `auto` ni `zero`), además `leading-none` `leading-tight` `leading-snug` `leading-normal` `leading-relaxed` `leading-loose`
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
#### Efectos
|
|
616
|
+
|
|
617
|
+
**Opacity:** `opacity-0` `opacity-1` `opacity-2` `opacity-3` `opacity-4` `opacity-5` `opacity-6`
|
|
618
|
+
**Box shadow:** `shadow-sm` `shadow-md` `shadow-lg` `shadow-xl` `shadow-inner` `shadow-none`
|
|
619
|
+
**Overlay:** `overlay-1` `overlay-2` `overlay-3` `overlay-4`
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
#### Iconos
|
|
624
|
+
|
|
625
|
+
`icon-1` `icon-2` `icon-3` `icon-4` `icon-disabled`
|
|
367
626
|
|
|
368
627
|
## Build
|
|
369
628
|
|
package/lib/postcss.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PluginCreator } from "postcss";
|
|
2
|
+
export interface GrissoApplyOptions {
|
|
3
|
+
/** Ruta a grisso.config.mjs del consumidor */
|
|
4
|
+
config?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Plugin PostCSS que permite usar clases Grisso con `@grisso` dentro de reglas CSS.
|
|
8
|
+
* Soporta prefijos de estado y responsive con separador `:`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```css
|
|
12
|
+
* .title {
|
|
13
|
+
* font-size: 24px;
|
|
14
|
+
* @grisso text-1 hover:text-2 tablet:text-3;
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* Genera:
|
|
19
|
+
* ```css
|
|
20
|
+
* .title { font-size: 24px; color: var(--text-1); }
|
|
21
|
+
* .title:hover { color: var(--text-2); }
|
|
22
|
+
* @media (min-width: 700px) { .title { color: var(--text-3); } }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare const plugin: PluginCreator<GrissoApplyOptions>;
|
|
26
|
+
export default plugin;
|
package/lib/postcss.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { generateCSS, resolveConfig } from "./index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Plugin PostCSS que permite usar clases Grisso con `@grisso` dentro de reglas CSS.
|
|
4
|
+
* Soporta prefijos de estado y responsive con separador `:`.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```css
|
|
8
|
+
* .title {
|
|
9
|
+
* font-size: 24px;
|
|
10
|
+
* @grisso text-1 hover:text-2 tablet:text-3;
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Genera:
|
|
15
|
+
* ```css
|
|
16
|
+
* .title { font-size: 24px; color: var(--text-1); }
|
|
17
|
+
* .title:hover { color: var(--text-2); }
|
|
18
|
+
* @media (min-width: 700px) { .title { color: var(--text-3); } }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
const plugin = (opts = {}) => {
|
|
22
|
+
// Cache del mapa de clases (se reutiliza entre archivos)
|
|
23
|
+
let classMap = null;
|
|
24
|
+
let breakpoints;
|
|
25
|
+
let states;
|
|
26
|
+
return {
|
|
27
|
+
postcssPlugin: "grisso-apply",
|
|
28
|
+
async Once(root, { result, postcss }) {
|
|
29
|
+
// Early exit si no hay @grisso
|
|
30
|
+
let hasGrisso = false;
|
|
31
|
+
root.walkAtRules("grisso", () => {
|
|
32
|
+
hasGrisso = true;
|
|
33
|
+
});
|
|
34
|
+
if (!hasGrisso)
|
|
35
|
+
return;
|
|
36
|
+
// Construir mapa de clases (lazy, una sola vez)
|
|
37
|
+
if (!classMap) {
|
|
38
|
+
const config = await resolveConfig(opts?.config);
|
|
39
|
+
breakpoints = config.breakpoints;
|
|
40
|
+
states = config.states;
|
|
41
|
+
const rawCSS = await generateCSS(opts?.config);
|
|
42
|
+
const grissoRoot = postcss.parse(rawCSS);
|
|
43
|
+
const map = new Map();
|
|
44
|
+
grissoRoot.walkRules((rule) => {
|
|
45
|
+
// Solo reglas top-level (no dentro de @media)
|
|
46
|
+
if (rule.parent?.type !== "root")
|
|
47
|
+
return;
|
|
48
|
+
// Saltar variantes de estado (contienen pseudo-clase)
|
|
49
|
+
if (rule.selector.includes(":"))
|
|
50
|
+
return;
|
|
51
|
+
// Extraer nombre de clase del selector
|
|
52
|
+
const match = rule.selector.match(/^\.([^\s>~+{]+)/);
|
|
53
|
+
if (!match)
|
|
54
|
+
return;
|
|
55
|
+
// Unescape (e.g. w-1\/2 → w-1/2)
|
|
56
|
+
const className = match[1].replace(/\\/g, "");
|
|
57
|
+
// Merge declaraciones (complexClass con array de properties genera múltiples reglas)
|
|
58
|
+
let existing = map.get(className);
|
|
59
|
+
if (!existing) {
|
|
60
|
+
existing = new Map();
|
|
61
|
+
map.set(className, existing);
|
|
62
|
+
}
|
|
63
|
+
rule.walkDecls((decl) => {
|
|
64
|
+
existing.set(decl.prop, decl.value);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
classMap = map;
|
|
68
|
+
}
|
|
69
|
+
// Recopilar @grisso rules (para no mutar durante walk)
|
|
70
|
+
const grissoRules = [];
|
|
71
|
+
root.walkAtRules("grisso", (atRule) => {
|
|
72
|
+
grissoRules.push(atRule);
|
|
73
|
+
});
|
|
74
|
+
for (const atRule of grissoRules) {
|
|
75
|
+
const parentRule = atRule.parent;
|
|
76
|
+
if (!parentRule || parentRule.type !== "rule") {
|
|
77
|
+
result.warn("@grisso debe estar dentro de una regla CSS", {
|
|
78
|
+
node: atRule,
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const params = atRule.params.trim();
|
|
83
|
+
if (!params) {
|
|
84
|
+
result.warn("@grisso requiere al menos una clase", {
|
|
85
|
+
node: atRule,
|
|
86
|
+
});
|
|
87
|
+
atRule.remove();
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const tokens = params.split(/\s+/);
|
|
91
|
+
const selector = parentRule.selector;
|
|
92
|
+
// Agrupar declaraciones por contexto
|
|
93
|
+
const baseDecls = [];
|
|
94
|
+
const stateGroups = new Map();
|
|
95
|
+
const bpGroups = new Map();
|
|
96
|
+
const bpStateGroups = new Map();
|
|
97
|
+
for (const token of tokens) {
|
|
98
|
+
const parts = token.split(":");
|
|
99
|
+
let bp = null;
|
|
100
|
+
let state = null;
|
|
101
|
+
let className;
|
|
102
|
+
if (parts.length === 1) {
|
|
103
|
+
className = parts[0];
|
|
104
|
+
}
|
|
105
|
+
else if (parts.length === 2) {
|
|
106
|
+
const prefix = parts[0];
|
|
107
|
+
className = parts[1];
|
|
108
|
+
if (prefix in breakpoints) {
|
|
109
|
+
bp = prefix;
|
|
110
|
+
}
|
|
111
|
+
else if (prefix in states) {
|
|
112
|
+
state = prefix;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
result.warn(`Prefijo desconocido "${prefix}" en "${token}"`, {
|
|
116
|
+
node: atRule,
|
|
117
|
+
});
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (parts.length === 3) {
|
|
122
|
+
const [a, b, c] = parts;
|
|
123
|
+
className = c;
|
|
124
|
+
if (a in breakpoints && b in states) {
|
|
125
|
+
bp = a;
|
|
126
|
+
state = b;
|
|
127
|
+
}
|
|
128
|
+
else if (a in states && b in breakpoints) {
|
|
129
|
+
state = a;
|
|
130
|
+
bp = b;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
result.warn(`Prefijos inválidos en "${token}"`, { node: atRule });
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
result.warn(`Demasiados prefijos en "${token}"`, {
|
|
139
|
+
node: atRule,
|
|
140
|
+
});
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const decls = classMap.get(className);
|
|
144
|
+
if (!decls) {
|
|
145
|
+
result.warn(`Clase Grisso desconocida "${className}"`, {
|
|
146
|
+
node: atRule,
|
|
147
|
+
word: className,
|
|
148
|
+
});
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const entries = [...decls.entries()];
|
|
152
|
+
if (!bp && !state) {
|
|
153
|
+
baseDecls.push(...entries);
|
|
154
|
+
}
|
|
155
|
+
else if (state && !bp) {
|
|
156
|
+
const arr = stateGroups.get(state) || [];
|
|
157
|
+
arr.push(...entries);
|
|
158
|
+
stateGroups.set(state, arr);
|
|
159
|
+
}
|
|
160
|
+
else if (bp && !state) {
|
|
161
|
+
const arr = bpGroups.get(bp) || [];
|
|
162
|
+
arr.push(...entries);
|
|
163
|
+
bpGroups.set(bp, arr);
|
|
164
|
+
}
|
|
165
|
+
else if (bp && state) {
|
|
166
|
+
let stateMap = bpStateGroups.get(bp);
|
|
167
|
+
if (!stateMap) {
|
|
168
|
+
stateMap = new Map();
|
|
169
|
+
bpStateGroups.set(bp, stateMap);
|
|
170
|
+
}
|
|
171
|
+
const arr = stateMap.get(state) || [];
|
|
172
|
+
arr.push(...entries);
|
|
173
|
+
stateMap.set(state, arr);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 1. Declaraciones base — insertar en la regla actual
|
|
177
|
+
for (const [prop, value] of baseDecls) {
|
|
178
|
+
atRule.before(postcss.decl({ prop, value }));
|
|
179
|
+
}
|
|
180
|
+
// Nodos a insertar después de la regla padre
|
|
181
|
+
const newNodes = [];
|
|
182
|
+
// 2. Variantes de estado
|
|
183
|
+
for (const [stateName, entries] of stateGroups) {
|
|
184
|
+
const pseudo = states[stateName];
|
|
185
|
+
const rule = postcss.rule({
|
|
186
|
+
selector: `${selector}${pseudo}`,
|
|
187
|
+
});
|
|
188
|
+
for (const [prop, value] of entries) {
|
|
189
|
+
rule.append(postcss.decl({ prop, value }));
|
|
190
|
+
}
|
|
191
|
+
newNodes.push(rule);
|
|
192
|
+
}
|
|
193
|
+
// 3. Variantes responsive
|
|
194
|
+
for (const [bpName, entries] of bpGroups) {
|
|
195
|
+
const mq = breakpoints[bpName];
|
|
196
|
+
const media = postcss.atRule({
|
|
197
|
+
name: "media",
|
|
198
|
+
params: mq,
|
|
199
|
+
});
|
|
200
|
+
const rule = postcss.rule({ selector });
|
|
201
|
+
for (const [prop, value] of entries) {
|
|
202
|
+
rule.append(postcss.decl({ prop, value }));
|
|
203
|
+
}
|
|
204
|
+
media.append(rule);
|
|
205
|
+
newNodes.push(media);
|
|
206
|
+
}
|
|
207
|
+
// 4. Variantes responsive + estado
|
|
208
|
+
for (const [bpName, stateMap] of bpStateGroups) {
|
|
209
|
+
const mq = breakpoints[bpName];
|
|
210
|
+
for (const [stateName, entries] of stateMap) {
|
|
211
|
+
const pseudo = states[stateName];
|
|
212
|
+
const media = postcss.atRule({
|
|
213
|
+
name: "media",
|
|
214
|
+
params: mq,
|
|
215
|
+
});
|
|
216
|
+
const rule = postcss.rule({
|
|
217
|
+
selector: `${selector}${pseudo}`,
|
|
218
|
+
});
|
|
219
|
+
for (const [prop, value] of entries) {
|
|
220
|
+
rule.append(postcss.decl({ prop, value }));
|
|
221
|
+
}
|
|
222
|
+
media.append(rule);
|
|
223
|
+
newNodes.push(media);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Insertar nodos después de la regla padre (en orden)
|
|
227
|
+
let insertAfter = parentRule;
|
|
228
|
+
for (const node of newNodes) {
|
|
229
|
+
insertAfter.after(node);
|
|
230
|
+
insertAfter = node;
|
|
231
|
+
}
|
|
232
|
+
// Eliminar @grisso
|
|
233
|
+
atRule.remove();
|
|
234
|
+
// Limpiar regla padre si queda vacía (e.g. solo tenía @grisso con prefijos)
|
|
235
|
+
if (parentRule.nodes && parentRule.nodes.length === 0) {
|
|
236
|
+
parentRule.remove();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
};
|
|
242
|
+
plugin.postcss = true;
|
|
243
|
+
export default plugin;
|
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": "
|
|
4
|
+
"version": "2.0.0-rc.0",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
7
7
|
"type": "module",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"./build": "./lib/build.js",
|
|
13
13
|
"./tokens": "./lib/tokens.js",
|
|
14
14
|
"./config": "./lib/defaults.js",
|
|
15
|
+
"./postcss": "./lib/postcss.js",
|
|
15
16
|
"./tokens-example.css": "./tokens-example.css"
|
|
16
17
|
},
|
|
17
18
|
"engines": {
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"typecheck": "tsc --noEmit",
|
|
32
33
|
"lint": "biome check .",
|
|
33
34
|
"lint:fix": "biome check --write .",
|
|
34
|
-
"playground": "npm run build && node lib/cli.js build --config playground/grisso.config.mjs --content playground/index.html --
|
|
35
|
+
"playground": "npm run build && node lib/cli.js build --config playground/grisso.config.mjs --content playground/index.html --output playground/grisso.css && node playground/build.mjs && open playground/index.html",
|
|
35
36
|
"test": "vitest run",
|
|
36
37
|
"test:watch": "vitest",
|
|
37
38
|
"prepublishOnly": "npm run build",
|
|
@@ -42,9 +43,18 @@
|
|
|
42
43
|
"lightningcss": "^1.28.0",
|
|
43
44
|
"purgecss": "^6.0.0"
|
|
44
45
|
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"postcss": "^8.1.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"postcss": {
|
|
51
|
+
"optional": true
|
|
52
|
+
}
|
|
53
|
+
},
|
|
45
54
|
"devDependencies": {
|
|
46
55
|
"@biomejs/biome": "2.4.5",
|
|
47
56
|
"@types/node": "^25.3.3",
|
|
57
|
+
"postcss": "^8.5.8",
|
|
48
58
|
"release-it": "^19.2.4",
|
|
49
59
|
"typescript": "^5.9.3",
|
|
50
60
|
"vitest": "^4.0.18"
|