holygrail5 1.0.5 → 1.0.6

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 CHANGED
@@ -578,4 +578,471 @@ Para desplegar en GitHub Pages, puedes:
578
578
 
579
579
  ---
580
580
 
581
+ ## 🚀 ¿Por qué HolyGrail5? Evolución desde HolyGrail CSS (SASS)
582
+
583
+ ### El Problema con SASS
584
+
585
+ HolyGrail CSS original se basaba en **SASS/SCSS**, lo que presentaba varios desafíos:
586
+
587
+ #### Limitaciones de SASS
588
+
589
+ 1. **Dependencia de compilación**: Requiere herramientas de build (Gulp, Webpack, etc.) y procesos de compilación
590
+ 2. **Curva de aprendizaje**: Necesitas conocer SASS/SCSS para personalizar
591
+ 3. **Configuración compleja**: Variables SASS dispersas en múltiples archivos
592
+ 4. **Sin documentación automática**: No genera guías visuales de las clases disponibles
593
+ 5. **Mantenimiento manual**: Cambios en variables requieren editar código SASS directamente
594
+ 6. **Sin historial**: No hay gestión automática de variables no usadas
595
+ 7. **Menos portable**: Depende del ecosistema SASS y sus herramientas
596
+
597
+ ### La Solución: HolyGrail5
598
+
599
+ HolyGrail5 nace de la necesidad de **simplificar, modernizar y potenciar** el framework original.
600
+
601
+ #### Ventajas Clave de HolyGrail5
602
+
603
+ ##### 1. **Configuración Declarativa con JSON**
604
+
605
+ **Antes (SASS):**
606
+ ```scss
607
+ // Variables dispersas en múltiples archivos
608
+ $font-size-mobile: 18px;
609
+ $font-size-desktop: 24px;
610
+ $spacing-16: 16px;
611
+ // ... más variables en diferentes archivos
612
+ ```
613
+
614
+ **Ahora (JSON):**
615
+ ```json
616
+ {
617
+ "classes": {
618
+ "h2": {
619
+ "mobile": { "fontSize": "18px" },
620
+ "desktop": { "fontSize": "24px" }
621
+ }
622
+ },
623
+ "spacingMap": { "16": "16px" }
624
+ }
625
+ ```
626
+
627
+ ✅ **Ventaja**: Todo en un solo archivo, fácil de entender y modificar
628
+
629
+ ##### 2. **Sin Dependencias de Build Complejas**
630
+
631
+ **Antes (SASS):**
632
+ - Requiere Gulp/Webpack/Grunt
633
+ - Configuración de compilación
634
+ - Dependencias de Node.js específicas
635
+ - Procesos de build complejos
636
+
637
+ **Ahora (HolyGrail5):**
638
+ ```bash
639
+ npm run generate
640
+ # ¡Listo! CSS generado
641
+ ```
642
+
643
+ ✅ **Ventaja**: Un solo comando, sin configuración de build
644
+
645
+ ##### 3. **Guía Interactiva Automática**
646
+
647
+ **Antes (SASS):**
648
+ - Documentación manual
649
+ - Sin preview visual
650
+ - Difícil saber qué clases están disponibles
651
+
652
+ **Ahora (HolyGrail5):**
653
+ - Guía HTML generada automáticamente
654
+ - Preview visual de todas las clases
655
+ - Búsqueda en tiempo real
656
+ - Detección de cambios
657
+
658
+ ✅ **Ventaja**: Documentación siempre actualizada y visual
659
+
660
+ ##### 4. **Gestión Inteligente de Variables**
661
+
662
+ **Antes (SASS):**
663
+ - Variables se eliminan si no se usan
664
+ - Puede romper CSS personalizado
665
+ - Sin historial
666
+
667
+ **Ahora (HolyGrail5):**
668
+ - Historial persistente de variables
669
+ - Nunca se eliminan automáticamente
670
+ - Comandos para gestionar variables no usadas
671
+ - Protege tu CSS personalizado
672
+
673
+ ✅ **Ventaja**: Seguridad y control total sobre las variables
674
+
675
+ ##### 5. **Variables CSS Nativas (No SASS)**
676
+
677
+ **Antes (SASS):**
678
+ ```scss
679
+ // Variables SASS (solo en compilación)
680
+ $primary-color: #000000;
681
+ .my-class {
682
+ color: $primary-color; // Compilado a CSS estático
683
+ }
684
+ ```
685
+
686
+ **Ahora (HolyGrail5):**
687
+ ```css
688
+ /* Variables CSS nativas (runtime) */
689
+ :root {
690
+ --hg-color-primary: #000000;
691
+ }
692
+ .my-class {
693
+ color: var(--hg-color-primary); // Cambiable en runtime
694
+ }
695
+ ```
696
+
697
+ ✅ **Ventaja**: Variables CSS nativas, modificables en runtime, mejor rendimiento
698
+
699
+ ##### 6. **Optimización Automática**
700
+
701
+ **Antes (SASS):**
702
+ - Duplicación de valores en múltiples lugares
703
+ - CSS más pesado
704
+ - Sin deduplicación automática
705
+
706
+ **Ahora (HolyGrail5):**
707
+ - Variables compartidas automáticamente
708
+ - Un valor único → una variable CSS
709
+ - CSS más pequeño y eficiente
710
+
711
+ ✅ **Ventaja**: CSS optimizado automáticamente, menos código
712
+
713
+ ##### 7. **Modo Watch Integrado**
714
+
715
+ **Antes (SASS):**
716
+ - Requiere configurar watch en Gulp/Webpack
717
+ - Configuración adicional necesaria
718
+
719
+ **Ahora (HolyGrail5):**
720
+ ```bash
721
+ npm run watch
722
+ # Regenera automáticamente al cambiar config.json
723
+ ```
724
+
725
+ ✅ **Ventaja**: Watch listo para usar, sin configuración
726
+
727
+ ##### 8. **Portabilidad y Simplicidad**
728
+
729
+ **Antes (SASS):**
730
+ - Múltiples archivos SASS
731
+ - Estructura compleja
732
+ - Dependencias de herramientas de build
733
+
734
+ **Ahora (HolyGrail5):**
735
+ - Un solo archivo JSON de configuración
736
+ - Estructura simple y clara
737
+ - Solo Node.js (sin SASS, Gulp, etc.)
738
+
739
+ ✅ **Ventaja**: Más fácil de entender, mantener y compartir
740
+
741
+ ##### 9. **Mejor para Equipos**
742
+
743
+ **Antes (SASS):**
744
+ - Solo desarrolladores que conocen SASS pueden modificar
745
+ - Cambios requieren conocimiento técnico
746
+
747
+ **Ahora (HolyGrail5):**
748
+ - Cualquiera puede editar JSON
749
+ - Cambios visibles inmediatamente
750
+ - Menos barrera de entrada
751
+
752
+ ✅ **Ventaja**: Colaboración más fácil, menos dependencia de desarrolladores
753
+
754
+ ##### 10. **Ecosistema Moderno**
755
+
756
+ **Antes (SASS):**
757
+ - Tecnología más antigua
758
+ - Menos integración con herramientas modernas
759
+ - Ecosistema SASS en declive
760
+
761
+ **Ahora (HolyGrail5):**
762
+ - Tecnología moderna (Node.js, JSON, CSS Variables)
763
+ - Mejor integración con herramientas actuales
764
+ - Alineado con estándares web modernos
765
+
766
+ ✅ **Ventaja**: Framework preparado para el futuro
767
+
768
+ ##### 11. **Separación de Componentes y Flexibilidad**
769
+
770
+ **Antes (HolyGrail CSS con Angular):**
771
+ - Framework acoplado a Angular
772
+ - Componentes incluidos (botones, cards, etc.) que aumentaban el peso
773
+ - CSS pesado con estilos de componentes que no siempre se usaban
774
+ - Difícil integrar otras librerías de componentes
775
+ - Dependencia de Angular y sus componentes
776
+
777
+ **Ahora (HolyGrail5):**
778
+ - **Solo CSS puro**: Sin dependencias de frameworks
779
+ - **Sin componentes incluidos**: Solo clases de utilidad y layout
780
+ - **CSS ligero**: Solo lo esencial (tipografía, spacing, layout, grid)
781
+ - **Integración flexible**: Puedes usar cualquier librería de componentes
782
+ - **Compatible con MDS de Inditex**: Diseñado para trabajar junto con sistemas de componentes externos
783
+
784
+ ✅ **Ventaja**: Framework ligero, flexible y compatible con cualquier librería de componentes
785
+
786
+ ##### 12. **Maquetación con IA**
787
+
788
+ **Antes (SASS + Angular):**
789
+ - Estructura compleja difícil de entender para IA
790
+ - Código SASS disperso
791
+ - Componentes acoplados
792
+ - Difícil generar código automáticamente
793
+
794
+ **Ahora (HolyGrail5):**
795
+ - **Configuración JSON clara**: Fácil de entender y generar por IA
796
+ - **Clases semánticas**: Nomenclatura clara y predecible
797
+ - **Superprompt disponible**: Guía completa para que IA genere código correcto
798
+ - **Estructura simple**: Patrones claros y repetibles
799
+
800
+ ✅ **Ventaja**: Perfecto para maquetación asistida por IA, generación automática de código
801
+
802
+ ### Separación de Responsabilidades
803
+
804
+ HolyGrail5 adopta una **filosofía de separación de responsabilidades**:
805
+
806
+ #### Lo que INCLUYE HolyGrail5:
807
+ - ✅ Sistema de tipografía
808
+ - ✅ Helpers de spacing (padding, margin)
809
+ - ✅ Helpers de layout (flexbox, grid)
810
+ - ✅ Sistema de grid responsive
811
+ - ✅ Variables CSS para colores
812
+ - ✅ Reset CSS mínimo
813
+
814
+ #### Lo que NO incluye (y por qué es mejor):
815
+ - ❌ Componentes UI (botones, cards, modales, etc.)
816
+ - ❌ Estilos de formularios
817
+ - ❌ Estilos de navegación
818
+ - ❌ Estilos específicos de Angular/React/Vue
819
+
820
+ **Razón**: Esto permite:
821
+ 1. **Usar MDS de Inditex** u otras librerías de componentes sin conflictos
822
+ 2. **CSS más ligero**: Solo lo esencial
823
+ 3. **Flexibilidad total**: Eliges tus propios componentes
824
+ 4. **Mejor mantenimiento**: Cada cosa en su lugar
825
+
826
+ ### Integración con MDS de Inditex
827
+
828
+ HolyGrail5 está diseñado para trabajar **perfectamente** junto con MDS (Massimo Dutti System) de Inditex:
829
+
830
+ ```html
831
+ <!-- Usa HolyGrail5 para layout y spacing -->
832
+ <div class="row">
833
+ <div class="col-xs-12 col-md-6">
834
+ <!-- Usa componentes MDS para UI -->
835
+ <mds-button variant="primary">Botón MDS</mds-button>
836
+ </div>
837
+ </div>
838
+ ```
839
+
840
+ **Ventajas de esta combinación:**
841
+ - ✅ HolyGrail5 maneja el layout y estructura
842
+ - ✅ MDS proporciona los componentes UI
843
+ - ✅ Sin conflictos de estilos
844
+ - ✅ Mejor de ambos mundos
845
+
846
+ ### Maquetación con IA
847
+
848
+ HolyGrail5 es **ideal para maquetación asistida por IA** gracias a:
849
+
850
+ 1. **Superprompt disponible**: Guía completa (`SUPERPROMPT.md`) que permite a la IA entender el sistema
851
+ 2. **Nomenclatura clara**: Clases predecibles y semánticas
852
+ 3. **Patrones simples**: Estructura fácil de seguir
853
+ 4. **Configuración JSON**: Fácil de generar y modificar automáticamente
854
+
855
+ **Ejemplo de uso con IA:**
856
+ ```
857
+ Prompt: "Crea una página de restaurante con header, hero, menú de platos y footer usando HolyGrail5"
858
+
859
+ La IA puede:
860
+ - Consultar SUPERPROMPT.md para entender las clases
861
+ - Generar HTML con las clases correctas
862
+ - Usar el grid system apropiado
863
+ - Aplicar spacing y layout helpers correctamente
864
+ ```
865
+
866
+ ✅ **Ventaja**: Acelera el desarrollo con generación automática de código
867
+
868
+ ### Comparación Directa
869
+
870
+ | Característica | HolyGrail CSS (SASS) | HolyGrail5 | ¿Por qué HolyGrail5 es mejor? |
871
+ |----------------|----------------------|------------|------------------------------|
872
+ | **Configuración** | Múltiples archivos SASS dispersos | Un solo archivo JSON (`config.json`) | ✅ **Simplicidad**: Todo en un lugar, fácil de entender y modificar |
873
+ | **Compilación** | Requiere Gulp/Webpack y configuración compleja | `npm run generate` (comando simple) | ✅ **Sin complejidad**: No necesitas configurar build tools |
874
+ | **Variables** | Variables SASS (compiladas, estáticas) | Variables CSS nativas (runtime, dinámicas) | ✅ **Flexibilidad**: Puedes cambiar valores en runtime con JavaScript |
875
+ | **Documentación** | Manual, requiere mantenimiento | Automática (HTML interactivo generado) | ✅ **Siempre actualizada**: Se genera automáticamente desde la configuración |
876
+ | **Gestión de variables** | Manual, propenso a errores | Automática con historial y herramientas CLI | ✅ **Seguridad**: Herramientas para detectar y eliminar variables no usadas |
877
+ | **Curva de aprendizaje** | Media-Alta (requiere conocer SASS) | Baja (solo JSON, fácil de entender) | ✅ **Accesibilidad**: Cualquiera puede editar sin conocimientos técnicos avanzados |
878
+ | **Portabilidad** | Media (depende de SASS y build tools) | Alta (solo Node.js, sin dependencias complejas) | ✅ **Fácil de mover**: Menos dependencias, más portable |
879
+ | **Optimización** | Manual (debes optimizar tú mismo) | Automática (elimina código no usado) | ✅ **Rendimiento**: CSS más pequeño automáticamente |
880
+ | **Watch mode** | Requiere configuración en Gulp/Webpack | Integrado (`npm run watch`) | ✅ **Desarrollo rápido**: Watch mode listo para usar |
881
+ | **Accesibilidad** | Solo desarrolladores con conocimientos SASS | Cualquiera puede editar (diseñadores, PMs, etc.) | ✅ **Colaboración**: Más personas pueden contribuir |
882
+ | **Componentes** | Incluidos (botones, cards, modales, etc.) | Separados (solo utilidades) | ✅ **Ligereza**: No incluye código que no uses |
883
+ | **Peso CSS** | Pesado (cientos de clases de componentes) | Ligero (solo utilidades esenciales) | ✅ **Rendimiento**: CSS más pequeño = páginas más rápidas |
884
+ | **Integración** | Acoplado a Angular | Compatible con cualquier librería | ✅ **Flexibilidad**: Puedes usar MDS, Material, Bootstrap, etc. |
885
+ | **Maquetación IA** | Difícil (estructura compleja) | Optimizado (JSON claro, superprompt) | ✅ **Futuro**: Perfecto para generación automática de código |
886
+
887
+ ### Casos de Uso Ideales para HolyGrail5
888
+
889
+ ✅ **Perfecto para:**
890
+ - Proyectos que buscan simplicidad
891
+ - Equipos con diferentes niveles técnicos
892
+ - Proyectos que necesitan documentación automática
893
+ - Aplicaciones que requieren variables CSS en runtime
894
+ - Proyectos que quieren evitar dependencias de build complejas
895
+ - Design systems que necesitan mantenimiento fácil
896
+ - **Proyectos que usan MDS de Inditex u otras librerías de componentes**
897
+ - **Maquetación asistida por IA**
898
+ - **Proyectos que necesitan CSS ligero sin componentes incluidos**
899
+
900
+ ### Migración desde HolyGrail CSS (SASS)
901
+
902
+ Si vienes de HolyGrail CSS (SASS), la migración es sencilla:
903
+
904
+ 1. **Extrae tus variables SASS** → Conviértelas a `config.json`
905
+ 2. **Mantén tus clases HTML** → Son compatibles
906
+ 3. **Regenera el CSS** → `npm run generate`
907
+ 4. **Disfruta de las nuevas características** → Guía interactiva, watch mode, etc.
908
+
909
+ ### Arquitectura Ligera y Flexible
910
+
911
+ #### El Problema del Framework Anterior
912
+
913
+ El framework original (HolyGrail CSS) incluía:
914
+ - **Componentes de Angular**: Botones, cards, modales, etc.
915
+ - **CSS pesado**: Estilos de componentes que no siempre se necesitaban
916
+ - **Acoplamiento**: Dependencia de Angular y sus componentes
917
+ - **Poco flexible**: Difícil usar otras librerías de componentes
918
+
919
+ **Ejemplos de clases incluidas en el framework antiguo (que aumentaban el peso):**
920
+ ```css
921
+ /* Formularios acoplados a Angular */
922
+ .form-input-label-2
923
+ .form-input-label-2.has-ico-pre
924
+ .form-input-label-2.has-ico-post
925
+ .validation-error-messages
926
+
927
+ /* Botones y links específicos */
928
+ .btn
929
+ .link-line
930
+ .link-svg-pre
931
+ .link-svg-post
932
+
933
+ /* Componentes de navegación */
934
+ .header-account-back
935
+ .mn-mainmenu
936
+ .mn-mainbar
937
+ .tabs-mini
938
+
939
+ /* Componentes UI */
940
+ .tooltip-sm
941
+ .toast
942
+ .md-accordion
943
+ .md-toggle
944
+ .bottom-sheet
945
+ .tag-product
946
+ .list-state
947
+
948
+ /* Soporte RTL específico */
949
+ .is-rtl .form-input-label-2
950
+ .is-rtl .btn
951
+ .is-rtl .tooltip-sm
952
+ /* ... y cientos más */
953
+ ```
954
+
955
+ **Problema**: Estas clases ocupaban espacio en el CSS final aunque no se usaran, y creaban conflictos al intentar usar otras librerías de componentes como MDS.
956
+
957
+ #### La Solución: Separación de Responsabilidades
958
+
959
+ HolyGrail5 adopta el principio de **"hacer una cosa y hacerla bien"**:
960
+
961
+ **HolyGrail5 se enfoca en:**
962
+ - Layout y estructura (grid, flexbox)
963
+ - Spacing y tipografía
964
+ - Variables CSS compartidas
965
+ - Helpers de utilidad
966
+
967
+ **NO incluye:**
968
+ - Componentes UI (botones, cards, etc.)
969
+ - Estilos de formularios
970
+ - Estilos específicos de frameworks
971
+
972
+ **Resultado:**
973
+ - ✅ CSS más ligero (solo lo esencial)
974
+ - ✅ Compatible con MDS de Inditex
975
+ - ✅ Compatible con cualquier librería de componentes
976
+ - ✅ Flexibilidad total para elegir tus componentes
977
+
978
+ ### Integración con MDS de Inditex
979
+
980
+ HolyGrail5 está diseñado específicamente para trabajar junto con **MDS (Massimo Dutti System)** de Inditex:
981
+
982
+ ```html
983
+ <!-- Layout con HolyGrail5 -->
984
+ <div class="row">
985
+ <div class="col-xs-12 col-md-6 p-16">
986
+ <!-- Componentes de MDS -->
987
+ <mds-button variant="primary">Reservar Mesa</mds-button>
988
+ <mds-card>
989
+ <mds-card-header>Título</mds-card-header>
990
+ <mds-card-content>Contenido</mds-card-content>
991
+ </mds-card>
992
+ </div>
993
+ </div>
994
+ ```
995
+
996
+ **Ventajas:**
997
+ - ✅ Sin conflictos de estilos
998
+ - ✅ HolyGrail5 maneja layout, MDS maneja componentes
999
+ - ✅ Mejor de ambos mundos
1000
+ - ✅ CSS optimizado y ligero
1001
+
1002
+ ### Maquetación con IA
1003
+
1004
+ HolyGrail5 es **perfecto para maquetación asistida por IA**:
1005
+
1006
+ #### ¿Por qué funciona tan bien con IA?
1007
+
1008
+ 1. **Superprompt disponible**: `SUPERPROMPT.md` contiene toda la información necesaria
1009
+ 2. **Nomenclatura clara**: Clases predecibles y semánticas
1010
+ 3. **Patrones simples**: Estructura fácil de seguir
1011
+ 4. **Configuración JSON**: Fácil de generar automáticamente
1012
+ 5. **Sin complejidad**: No hay componentes acoplados que confundan a la IA
1013
+
1014
+ #### Ejemplo de Uso con IA
1015
+
1016
+ ```
1017
+ Prompt para IA:
1018
+ "Crea una página de restaurante con header sticky, hero section,
1019
+ grid de 6 platos destacados, sección sobre nosotros y footer,
1020
+ usando HolyGrail5 según SUPERPROMPT.md"
1021
+
1022
+ La IA puede:
1023
+ ✅ Generar HTML con las clases correctas
1024
+ ✅ Usar el grid system apropiado
1025
+ ✅ Aplicar spacing helpers correctamente
1026
+ ✅ Crear layouts responsive
1027
+ ✅ Integrar con componentes MDS si es necesario
1028
+ ```
1029
+
1030
+ **Resultado**: Desarrollo más rápido y código consistente generado automáticamente.
1031
+
1032
+ ### Conclusión
1033
+
1034
+ HolyGrail5 representa la **evolución natural** del framework original, eliminando las complejidades de SASS, separando los componentes pesados de Angular, y aprovechando las capacidades modernas de CSS y JavaScript.
1035
+
1036
+ **Es más simple, más ligero, más potente y más accesible**, manteniendo la filosofía de diseño que hizo grande a HolyGrail CSS, pero adaptado a las necesidades actuales:
1037
+
1038
+ - ✅ **Sin dependencias pesadas**: No incluye componentes Angular
1039
+ - ✅ **CSS ligero**: Solo utilidades esenciales
1040
+ - ✅ **Flexible**: Compatible con MDS de Inditex y cualquier librería
1041
+ - ✅ **IA-friendly**: Optimizado para maquetación asistida por IA
1042
+ - ✅ **Moderno**: Variables CSS nativas, JSON, Node.js
1043
+
1044
+ **En resumen**: HolyGrail5 es HolyGrail CSS **mejorado, simplificado, modernizado y optimizado** para el desarrollo web actual, con especial atención a la flexibilidad, ligereza y compatibilidad con sistemas de componentes externos.
1045
+
1046
+ ---
1047
+
581
1048
  **Hecho con ❤️ por HolyGrail CSS**
package/config.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "secondary": "\"ms-serif\", serif"
7
7
  },
8
8
  "breakpoints": {
9
- "mobile": "0px",
9
+ "mobile": "1px",
10
10
  "desktop": "992px"
11
11
  },
12
12
  "spacingMap": {
@@ -235,7 +235,174 @@
235
235
  "responsive": true,
236
236
  "description": "Espacio entre filas y columnas",
237
237
  "useSpacing": true
238
+ },
239
+ "text-align": {
240
+ "property": "text-align",
241
+ "class": "text",
242
+ "responsive": true,
243
+ "description": "Alineación del texto",
244
+ "values": {
245
+ "left": "left",
246
+ "center": "center",
247
+ "right": "right",
248
+ "justify": "justify"
249
+ }
250
+ },
251
+ "position": {
252
+ "property": "position",
253
+ "class": "position",
254
+ "responsive": true,
255
+ "description": "Tipo de posicionamiento",
256
+ "values": {
257
+ "static": "static",
258
+ "relative": "relative",
259
+ "absolute": "absolute",
260
+ "fixed": "fixed",
261
+ "sticky": "sticky"
262
+ }
263
+ },
264
+ "overflow": {
265
+ "property": "overflow",
266
+ "class": "overflow",
267
+ "responsive": true,
268
+ "description": "Control de desbordamiento",
269
+ "values": {
270
+ "auto": "auto",
271
+ "hidden": "hidden",
272
+ "visible": "visible",
273
+ "scroll": "scroll"
274
+ }
275
+ },
276
+ "overflow-x": {
277
+ "property": "overflow-x",
278
+ "class": "overflow-x",
279
+ "responsive": true,
280
+ "description": "Control de desbordamiento horizontal",
281
+ "values": {
282
+ "auto": "auto",
283
+ "hidden": "hidden",
284
+ "visible": "visible",
285
+ "scroll": "scroll"
286
+ }
287
+ },
288
+ "overflow-y": {
289
+ "property": "overflow-y",
290
+ "class": "overflow-y",
291
+ "responsive": true,
292
+ "description": "Control de desbordamiento vertical",
293
+ "values": {
294
+ "auto": "auto",
295
+ "hidden": "hidden",
296
+ "visible": "visible",
297
+ "scroll": "scroll"
298
+ }
299
+ },
300
+ "visibility": {
301
+ "property": "visibility",
302
+ "class": "visibility",
303
+ "responsive": true,
304
+ "description": "Visibilidad del elemento",
305
+ "values": {
306
+ "visible": "visible",
307
+ "hidden": "hidden",
308
+ "collapse": "collapse"
309
+ }
310
+ },
311
+ "opacity": {
312
+ "property": "opacity",
313
+ "class": "opacity",
314
+ "responsive": true,
315
+ "description": "Transparencia del elemento",
316
+ "values": {
317
+ "0": "0",
318
+ "25": "0.25",
319
+ "50": "0.5",
320
+ "75": "0.75",
321
+ "100": "1"
322
+ }
323
+ },
324
+ "z-index": {
325
+ "property": "z-index",
326
+ "class": "z",
327
+ "responsive": true,
328
+ "description": "Nivel de apilamiento",
329
+ "values": {
330
+ "0": "0",
331
+ "10": "10",
332
+ "20": "20",
333
+ "30": "30",
334
+ "40": "40",
335
+ "50": "50",
336
+ "auto": "auto"
337
+ }
338
+ },
339
+ "cursor": {
340
+ "property": "cursor",
341
+ "class": "cursor",
342
+ "responsive": false,
343
+ "description": "Tipo de cursor",
344
+ "values": {
345
+ "auto": "auto",
346
+ "default": "default",
347
+ "pointer": "pointer",
348
+ "not-allowed": "not-allowed",
349
+ "wait": "wait",
350
+ "text": "text",
351
+ "move": "move",
352
+ "grab": "grab",
353
+ "grabbing": "grabbing"
354
+ }
355
+ },
356
+ "object-fit": {
357
+ "property": "object-fit",
358
+ "class": "object",
359
+ "responsive": true,
360
+ "description": "Ajuste de objeto (imágenes)",
361
+ "values": {
362
+ "contain": "contain",
363
+ "cover": "cover",
364
+ "fill": "fill",
365
+ "none": "none",
366
+ "scale-down": "scale-down"
367
+ }
368
+ },
369
+ "height": {
370
+ "property": "height",
371
+ "class": "h",
372
+ "responsive": true,
373
+ "description": "Altura del elemento",
374
+ "values": {
375
+ "auto": "auto",
376
+ "100-percent": "100%",
377
+ "100vh": "100vh",
378
+ "100svh": "100svh",
379
+ "100lvh": "100lvh",
380
+ "100dvh": "100dvh",
381
+ "50-percent": "50%",
382
+ "75-percent": "75%",
383
+ "fit-content": "fit-content",
384
+ "min-content": "min-content",
385
+ "max-content": "max-content"
386
+ }
387
+ },
388
+
389
+
390
+ "min-height": {
391
+ "property": "min-height",
392
+ "class": "min-h",
393
+ "responsive": true,
394
+ "description": "Altura mínima del elemento",
395
+ "values": {
396
+ "0": "0",
397
+ "100-percent": "100%",
398
+ "100vh": "100vh",
399
+ "100svh": "100svh",
400
+ "100lvh": "100lvh",
401
+ "100dvh": "100dvh",
402
+ "fit-content": "fit-content"
403
+ }
238
404
  }
405
+
239
406
  },
240
407
  "classes": {
241
408
  "h2": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "holygrail5",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Framework CSS generator con Node.js - Genera CSS optimizado con variables CSS desde un archivo JSON de configuración",
5
5
  "main": "generator.js",
6
6
  "bin": {
@@ -8,10 +8,11 @@
8
8
  },
9
9
  "scripts": {
10
10
  "generate": "node generator.js",
11
- "start": "node generator.js && NODE_NO_WARNINGS=1 npx http-server dist -p 3000 -o index.html",
11
+ "build": "node generator.js",
12
+ "start": "node generator.js && NODE_NO_WARNINGS=1 npx http-server dist -p ${PORT:-5001} -o index.html",
12
13
  "dev": "node src/dev.js",
13
14
  "watch": "node src/watch.js",
14
- "serve": "NODE_NO_WARNINGS=1 npx http-server dist -p 3000 -o index.html",
15
+ "serve": "NODE_NO_WARNINGS=1 npx http-server dist -p ${PORT:-5000} -o index.html",
15
16
  "test": "node tests/run-all.js",
16
17
  "prepublishOnly": "npm run generate",
17
18
  "vars:list": "node src/cli-variables.js list",
@@ -19,6 +20,7 @@
19
20
  "vars:remove": "node src/cli-variables.js remove",
20
21
  "vars:remove-all-unused": "node src/cli-variables.js remove-all-unused",
21
22
  "vars:show-all": "node src/cli-variables.js show-all"
23
+
22
24
  },
23
25
  "keywords": [
24
26
  "css",
package/src/dev.js CHANGED
@@ -13,14 +13,15 @@ const watchProcess = spawn('node', [path.join(__dirname, 'watch.js')], {
13
13
 
14
14
  // Esperar un momento para que watch genere los archivos inicialmente
15
15
  setTimeout(() => {
16
- console.log('\n🌐 Iniciando servidor HTTP en http://localhost:3000\n');
16
+ const port = process.env.PORT || '5000';
17
+ console.log(`\n🌐 Iniciando servidor HTTP en http://localhost:${port}\n`);
17
18
  console.log('💡 Los archivos se regenerarán automáticamente cuando cambies config.json\n');
18
19
  console.log('💡 Recarga el navegador (Cmd+Shift+R o Ctrl+Shift+R) para ver los cambios\n');
19
20
 
20
21
  // Iniciar servidor HTTP
21
22
  // Suprimir warnings de deprecación de http-server
22
23
  // Servir desde dist/ como raíz, así la URL será /index.html sin mostrar "dist"
23
- const serverProcess = spawn('npx', ['http-server', 'dist', '-p', '3000', '-o', 'index.html'], {
24
+ const serverProcess = spawn('npx', ['http-server', 'dist', '-p', port, '-o', 'index.html'], {
24
25
  stdio: 'inherit',
25
26
  shell: true,
26
27
  env: { ...process.env, NODE_NO_WARNINGS: '1' }
package/src/guide.js CHANGED
@@ -36,48 +36,9 @@ function saveCurrentValues(currentValues, previousValuesPath) {
36
36
  function getChangedValues(currentValues, previousValues) {
37
37
  const changes = new Set();
38
38
 
39
- // Si no hay valores previos, marca todo como nuevo (primera ejecución)
39
+ // Si no hay valores previos, no marca nada como cambiado (primera ejecución o build limpio)
40
+ // Solo se marcarán cambios cuando haya valores previos para comparar
40
41
  if (!previousValues) {
41
- // Marca todas las variables como nuevas
42
- if (currentValues.variables) {
43
- Object.keys(currentValues.variables).forEach(varName => {
44
- changes.add(`variable.${varName}`);
45
- });
46
- }
47
- // Marca todos los breakpoints como nuevos
48
- if (currentValues.breakpoints) {
49
- changes.add('breakpoints.mobile');
50
- changes.add('breakpoints.desktop');
51
- }
52
- // Marca todas las fuentes como nuevas
53
- if (currentValues.fontFamilyMap) {
54
- Object.keys(currentValues.fontFamilyMap).forEach(fontName => {
55
- changes.add(`fontFamilyMap.${fontName}`);
56
- });
57
- }
58
- // Marca todos los colores como nuevos
59
- if (currentValues.colors) {
60
- Object.keys(currentValues.colors).forEach(colorName => {
61
- changes.add(`colors.${colorName}`);
62
- });
63
- }
64
- // Marca todas las clases como nuevas
65
- if (currentValues.classes) {
66
- Object.keys(currentValues.classes).forEach(className => {
67
- const cls = currentValues.classes[className];
68
- ['fontFamily', 'fontWeight', 'letterSpacing', 'textTransform'].forEach(prop => {
69
- if (cls[prop] !== undefined) {
70
- changes.add(`${className}.${prop}`);
71
- }
72
- });
73
- ['mobile', 'desktop'].forEach(bp => {
74
- if (cls[bp]) {
75
- if (cls[bp].fontSize) changes.add(`${className}.${bp}.fontSize`);
76
- if (cls[bp].lineHeight) changes.add(`${className}.${bp}.lineHeight`);
77
- }
78
- });
79
- });
80
- }
81
42
  return changes;
82
43
  }
83
44
 
@@ -1661,6 +1622,12 @@ function generateHTML(configData, previousValuesPath = null) {
1661
1622
  <li class="text-m guide-info-box-list-item">
1662
1623
  <strong>.col-xl-*</strong> - Columnas para pantallas desde ${configData.grid.breakpoints.xl} (24 columnas)
1663
1624
  </li>
1625
+ <li class="text-m guide-info-box-list-item">
1626
+ <strong>.bleed</strong> - Permite que las columnas vayan a sangre (full bleed), eliminando los márgenes laterales del gutter
1627
+ </li>
1628
+ <li class="text-m guide-info-box-list-item">
1629
+ <strong>.bleed-0</strong> - Elimina completamente el padding y márgenes, útil para contenido que debe ocupar todo el ancho sin espacios
1630
+ </li>
1664
1631
  </ul>
1665
1632
  <p class="text-m guide-info-box-text">
1666
1633
  <strong>Gutter:</strong> ${configData.grid.gutter} (padding horizontal en cada columna)
@@ -1719,7 +1686,7 @@ function generateHTML(configData, previousValuesPath = null) {
1719
1686
  </div>
1720
1687
 
1721
1688
  <div class="guide-info-box guide-info-box-info guide-info-box-margin-top">
1722
- <h3 class="guide-info-box-title guide-info-box-title-info">Ejemplo de uso</h3>
1689
+ <h3 class="guide-info-box-title guide-info-box-title-info">Ejemplo de uso básico</h3>
1723
1690
  <p class="text-m guide-info-box-text">
1724
1691
  <strong>HTML:</strong>
1725
1692
  </p>
@@ -1749,6 +1716,33 @@ function generateHTML(configData, previousValuesPath = null) {
1749
1716
  </li>
1750
1717
  </ul>
1751
1718
  </div>
1719
+
1720
+
1721
+
1722
+ <div class="guide-info-box guide-info-box-info guide-info-box-margin-top">
1723
+ <h3 class="guide-info-box-title guide-info-box-title-info">Columnas a sangre (Bleed)</h3>
1724
+ <p class="text-m guide-info-box-text">
1725
+ Cuando necesitas que las columnas vayan a sangre (full bleed), eliminando los márgenes laterales del gutter, usa la clase <code class="guide-info-box-code-info">.bleed</code>:
1726
+ </p>
1727
+ <pre class="guide-code-example"><code>&lt;div class="row"&gt;
1728
+ &lt;div class="col-xs-12 bleed"&gt;
1729
+ Contenido que va a sangre (sin márgenes laterales)
1730
+ &lt;/div&gt;
1731
+ &lt;/div&gt;</code></pre>
1732
+ <p class="text-m guide-info-box-text">
1733
+ Para eliminar completamente el padding y márgenes, usa <code class="guide-info-box-code-info">.bleed-0</code>:
1734
+ </p>
1735
+ <pre class="guide-code-example"><code>&lt;div class="bleed-0"&gt;
1736
+ &lt;div class="row"&gt;
1737
+ &lt;div class="col-xs-12"&gt;
1738
+ Contenido sin padding ni márgenes
1739
+ &lt;/div&gt;
1740
+ &lt;/div&gt;
1741
+ &lt;/div&gt;</code></pre>
1742
+ <p class="text-m guide-info-box-text-small">
1743
+ <strong>Nota:</strong> <code class="guide-info-box-code-info">.bleed</code> aplica márgenes negativos iguales al gutter (${configData.grid.gutter}) para que el contenido llegue hasta los bordes. <code class="guide-info-box-code-info">.bleed-0</code> elimina todo el padding y márgenes, útil para imágenes o contenido que debe ocupar todo el ancho disponible.
1744
+ </p>
1745
+ </div>
1752
1746
  </div>
1753
1747
  </div>
1754
1748
  ` : ''}
package/src/parser.js CHANGED
@@ -329,7 +329,10 @@ function generateClassCSS(className, cls, breakpointName, valueMap, prefix, cate
329
329
  // Genera una media query con todas las clases para un breakpoint
330
330
  // Convierte el breakpoint a rem y genera el CSS de todas las clases
331
331
  function generateMediaQuery(breakpointName, minWidth, classes, valueMap, prefix, category, baseFontSize, fontFamilyMap) {
332
- const minWidthRem = pxToRem(minWidth, baseFontSize);
332
+ // Convertir breakpoint a rem de forma consistente
333
+ const minWidthRem = typeof minWidth === 'string' && minWidth.includes('px')
334
+ ? pxToRem(minWidth, baseFontSize)
335
+ : minWidth;
333
336
 
334
337
  const cssClasses = Object.entries(classes)
335
338
  .map(([className, cls]) => generateClassCSS(className, cls, breakpointName, valueMap, prefix, category, baseFontSize, fontFamilyMap))
@@ -341,7 +344,10 @@ function generateMediaQuery(breakpointName, minWidth, classes, valueMap, prefix,
341
344
  // Genera un bloque de tipografías para un breakpoint específico con comentario descriptivo
342
345
  // Incluye un comentario que indica qué breakpoint es y el min-width
343
346
  function generateTypographyBlock(breakpointName, minWidth, classes, valueMap, prefix, category, baseFontSize, fontFamilyMap) {
344
- const minWidthRem = pxToRem(minWidth, baseFontSize);
347
+ // Convertir breakpoint a rem de forma consistente
348
+ const minWidthRem = typeof minWidth === 'string' && minWidth.includes('px')
349
+ ? pxToRem(minWidth, baseFontSize)
350
+ : minWidth;
345
351
  const breakpointLabel = breakpointName === 'mobile' ? 'Mobile' : 'Desktop';
346
352
 
347
353
  const cssClasses = Object.entries(classes)
@@ -430,77 +436,80 @@ function generateSpacingHelpers(spacingMap, prefix, desktopBreakpoint, baseFontS
430
436
 
431
437
  const helpers = [];
432
438
  const desktopHelpers = [];
433
- const desktopBreakpointRem = pxToRem(desktopBreakpoint, baseFontSize);
439
+ // Convertir breakpoint a rem de forma consistente
440
+ const desktopBreakpointRem = typeof desktopBreakpoint === 'string' && desktopBreakpoint.includes('px')
441
+ ? pxToRem(desktopBreakpoint, baseFontSize)
442
+ : desktopBreakpoint;
434
443
 
435
- // Generar helpers para cada valor en spacingMap
436
- Object.entries(spacingMap).forEach(([key, value]) => {
444
+ // Generar helpers para cada valor en spacingMap
445
+ Object.entries(spacingMap).forEach(([key, value]) => {
446
+ const varName = `--${prefix}-spacing-${key}`;
447
+
448
+ // Padding helpers base (mobile) usando variables CSS con propiedades lógicas para RTL
449
+ helpers.push(` .p-${key} { padding: var(${varName}); }`);
450
+ helpers.push(` .pr-${key} { padding-inline-end: var(${varName}); }`);
451
+ helpers.push(` .pl-${key} { padding-inline-start: var(${varName}); }`);
452
+ helpers.push(` .pb-${key} { padding-bottom: var(${varName}); }`);
453
+ helpers.push(` .pt-${key} { padding-top: var(${varName}); }`);
454
+
455
+ // Margin helpers base (mobile) usando variables CSS con propiedades lógicas para RTL
456
+ helpers.push(` .m-${key} { margin: var(${varName}); }`);
457
+ helpers.push(` .mr-${key} { margin-inline-end: var(${varName}); }`);
458
+ helpers.push(` .ml-${key} { margin-inline-start: var(${varName}); }`);
459
+ helpers.push(` .mb-${key} { margin-bottom: var(${varName}); }`);
460
+ helpers.push(` .mt-${key} { margin-top: var(${varName}); }`);
461
+
462
+ // Padding helpers con prefijo md: (desktop) usando variables CSS con propiedades lógicas para RTL
463
+ desktopHelpers.push(` .md\\:p-${key} { padding: var(${varName}); }`);
464
+ desktopHelpers.push(` .md\\:pr-${key} { padding-inline-end: var(${varName}); }`);
465
+ desktopHelpers.push(` .md\\:pl-${key} { padding-inline-start: var(${varName}); }`);
466
+ desktopHelpers.push(` .md\\:pb-${key} { padding-bottom: var(${varName}); }`);
467
+ desktopHelpers.push(` .md\\:pt-${key} { padding-top: var(${varName}); }`);
468
+
469
+ // Margin helpers con prefijo md: (desktop) usando variables CSS con propiedades lógicas para RTL
470
+ desktopHelpers.push(` .md\\:m-${key} { margin: var(${varName}); }`);
471
+ desktopHelpers.push(` .md\\:mr-${key} { margin-inline-end: var(${varName}); }`);
472
+ desktopHelpers.push(` .md\\:ml-${key} { margin-inline-start: var(${varName}); }`);
473
+ desktopHelpers.push(` .md\\:mb-${key} { margin-bottom: var(${varName}); }`);
474
+ desktopHelpers.push(` .md\\:mt-${key} { margin-top: var(${varName}); }`);
475
+ });
476
+
477
+ // Generar helpers con !important para los valores especificados en spacingImportant
478
+ if (spacingImportant && Array.isArray(spacingImportant)) {
479
+ spacingImportant.forEach(key => {
480
+ if (spacingMap[key]) {
437
481
  const varName = `--${prefix}-spacing-${key}`;
438
482
 
439
- // Padding helpers base (mobile) usando variables CSS con propiedades lógicas para RTL
440
- helpers.push(` .p-${key} { padding: var(${varName}); }`);
441
- helpers.push(` .pr-${key} { padding-inline-end: var(${varName}); }`);
442
- helpers.push(` .pl-${key} { padding-inline-start: var(${varName}); }`);
443
- helpers.push(` .pb-${key} { padding-bottom: var(${varName}); }`);
444
- helpers.push(` .pt-${key} { padding-top: var(${varName}); }`);
483
+ // Padding helpers con !important (mobile)
484
+ helpers.push(` .p-${key}\\! { padding: var(${varName}) !important; }`);
485
+ helpers.push(` .pr-${key}\\! { padding-inline-end: var(${varName}) !important; }`);
486
+ helpers.push(` .pl-${key}\\! { padding-inline-start: var(${varName}) !important; }`);
487
+ helpers.push(` .pb-${key}\\! { padding-bottom: var(${varName}) !important; }`);
488
+ helpers.push(` .pt-${key}\\! { padding-top: var(${varName}) !important; }`);
445
489
 
446
- // Margin helpers base (mobile) usando variables CSS con propiedades lógicas para RTL
447
- helpers.push(` .m-${key} { margin: var(${varName}); }`);
448
- helpers.push(` .mr-${key} { margin-inline-end: var(${varName}); }`);
449
- helpers.push(` .ml-${key} { margin-inline-start: var(${varName}); }`);
450
- helpers.push(` .mb-${key} { margin-bottom: var(${varName}); }`);
451
- helpers.push(` .mt-${key} { margin-top: var(${varName}); }`);
490
+ // Margin helpers con !important (mobile)
491
+ helpers.push(` .m-${key}\\! { margin: var(${varName}) !important; }`);
492
+ helpers.push(` .mr-${key}\\! { margin-inline-end: var(${varName}) !important; }`);
493
+ helpers.push(` .ml-${key}\\! { margin-inline-start: var(${varName}) !important; }`);
494
+ helpers.push(` .mb-${key}\\! { margin-bottom: var(${varName}) !important; }`);
495
+ helpers.push(` .mt-${key}\\! { margin-top: var(${varName}) !important; }`);
452
496
 
453
- // Padding helpers con prefijo md: (desktop) usando variables CSS con propiedades lógicas para RTL
454
- desktopHelpers.push(` .md\\:p-${key} { padding: var(${varName}); }`);
455
- desktopHelpers.push(` .md\\:pr-${key} { padding-inline-end: var(${varName}); }`);
456
- desktopHelpers.push(` .md\\:pl-${key} { padding-inline-start: var(${varName}); }`);
457
- desktopHelpers.push(` .md\\:pb-${key} { padding-bottom: var(${varName}); }`);
458
- desktopHelpers.push(` .md\\:pt-${key} { padding-top: var(${varName}); }`);
497
+ // Padding helpers con !important y prefijo md: (desktop)
498
+ desktopHelpers.push(` .md\\:p-${key}\\! { padding: var(${varName}) !important; }`);
499
+ desktopHelpers.push(` .md\\:pr-${key}\\! { padding-inline-end: var(${varName}) !important; }`);
500
+ desktopHelpers.push(` .md\\:pl-${key}\\! { padding-inline-start: var(${varName}) !important; }`);
501
+ desktopHelpers.push(` .md\\:pb-${key}\\! { padding-bottom: var(${varName}) !important; }`);
502
+ desktopHelpers.push(` .md\\:pt-${key}\\! { padding-top: var(${varName}) !important; }`);
459
503
 
460
- // Margin helpers con prefijo md: (desktop) usando variables CSS con propiedades lógicas para RTL
461
- desktopHelpers.push(` .md\\:m-${key} { margin: var(${varName}); }`);
462
- desktopHelpers.push(` .md\\:mr-${key} { margin-inline-end: var(${varName}); }`);
463
- desktopHelpers.push(` .md\\:ml-${key} { margin-inline-start: var(${varName}); }`);
464
- desktopHelpers.push(` .md\\:mb-${key} { margin-bottom: var(${varName}); }`);
465
- desktopHelpers.push(` .md\\:mt-${key} { margin-top: var(${varName}); }`);
466
- });
467
-
468
- // Generar helpers con !important para los valores especificados en spacingImportant
469
- if (spacingImportant && Array.isArray(spacingImportant)) {
470
- spacingImportant.forEach(key => {
471
- if (spacingMap[key]) {
472
- const varName = `--${prefix}-spacing-${key}`;
473
-
474
- // Padding helpers con !important (mobile)
475
- helpers.push(` .p-${key}\\! { padding: var(${varName}) !important; }`);
476
- helpers.push(` .pr-${key}\\! { padding-inline-end: var(${varName}) !important; }`);
477
- helpers.push(` .pl-${key}\\! { padding-inline-start: var(${varName}) !important; }`);
478
- helpers.push(` .pb-${key}\\! { padding-bottom: var(${varName}) !important; }`);
479
- helpers.push(` .pt-${key}\\! { padding-top: var(${varName}) !important; }`);
480
-
481
- // Margin helpers con !important (mobile)
482
- helpers.push(` .m-${key}\\! { margin: var(${varName}) !important; }`);
483
- helpers.push(` .mr-${key}\\! { margin-inline-end: var(${varName}) !important; }`);
484
- helpers.push(` .ml-${key}\\! { margin-inline-start: var(${varName}) !important; }`);
485
- helpers.push(` .mb-${key}\\! { margin-bottom: var(${varName}) !important; }`);
486
- helpers.push(` .mt-${key}\\! { margin-top: var(${varName}) !important; }`);
487
-
488
- // Padding helpers con !important y prefijo md: (desktop)
489
- desktopHelpers.push(` .md\\:p-${key}\\! { padding: var(${varName}) !important; }`);
490
- desktopHelpers.push(` .md\\:pr-${key}\\! { padding-inline-end: var(${varName}) !important; }`);
491
- desktopHelpers.push(` .md\\:pl-${key}\\! { padding-inline-start: var(${varName}) !important; }`);
492
- desktopHelpers.push(` .md\\:pb-${key}\\! { padding-bottom: var(${varName}) !important; }`);
493
- desktopHelpers.push(` .md\\:pt-${key}\\! { padding-top: var(${varName}) !important; }`);
494
-
495
- // Margin helpers con !important y prefijo md: (desktop)
496
- desktopHelpers.push(` .md\\:m-${key}\\! { margin: var(${varName}) !important; }`);
497
- desktopHelpers.push(` .md\\:mr-${key}\\! { margin-inline-end: var(${varName}) !important; }`);
498
- desktopHelpers.push(` .md\\:ml-${key}\\! { margin-inline-start: var(${varName}) !important; }`);
499
- desktopHelpers.push(` .md\\:mb-${key}\\! { margin-bottom: var(${varName}) !important; }`);
500
- desktopHelpers.push(` .md\\:mt-${key}\\! { margin-top: var(${varName}) !important; }`);
501
- }
502
- });
504
+ // Margin helpers con !important y prefijo md: (desktop)
505
+ desktopHelpers.push(` .md\\:m-${key}\\! { margin: var(${varName}) !important; }`);
506
+ desktopHelpers.push(` .md\\:mr-${key}\\! { margin-inline-end: var(${varName}) !important; }`);
507
+ desktopHelpers.push(` .md\\:ml-${key}\\! { margin-inline-start: var(${varName}) !important; }`);
508
+ desktopHelpers.push(` .md\\:mb-${key}\\! { margin-bottom: var(${varName}) !important; }`);
509
+ desktopHelpers.push(` .md\\:mt-${key}\\! { margin-top: var(${varName}) !important; }`);
503
510
  }
511
+ });
512
+ }
504
513
 
505
514
  if (helpers.length === 0) {
506
515
  return '';
@@ -520,13 +529,23 @@ ${desktopHelpers.join('\n')}
520
529
  return baseHelpers;
521
530
  }
522
531
 
532
+ // Genera helpers de layout (display, flexbox, alignment, etc.)
533
+ // Crea clases como hg-d-flex, hg-justify-center, etc.
534
+ // Agrupa todos los helpers responsive en un solo media query
523
535
  function generateLayoutHelpers(helpers, spacingMap, prefix, desktopBreakpoint, baseFontSize = 16) {
524
536
  if (!helpers || typeof helpers !== 'object') {
525
537
  return '';
526
538
  }
527
539
 
540
+ // Convertir breakpoint a rem de forma consistente
541
+ const breakpointInRem = typeof desktopBreakpoint === 'string' && desktopBreakpoint.includes('px')
542
+ ? pxToRem(desktopBreakpoint, baseFontSize)
543
+ : desktopBreakpoint;
544
+
528
545
  let css = '\n/* Layout Helpers */\n';
546
+ let responsiveCSS = '';
529
547
 
548
+ // Primero generar todas las clases base
530
549
  Object.entries(helpers).forEach(([helperName, config]) => {
531
550
  const { property, class: className, responsive, values, useSpacing } = config;
532
551
 
@@ -537,12 +556,10 @@ function generateLayoutHelpers(helpers, spacingMap, prefix, desktopBreakpoint, b
537
556
  });
538
557
 
539
558
  if (responsive) {
540
- css += `\n@media (min-width: ${desktopBreakpoint}) {\n`;
541
559
  Object.entries(spacingMap).forEach(([key, value]) => {
542
560
  const finalValue = value.endsWith('%') ? value : pxToRem(value, baseFontSize);
543
- css += ` .md\\:${prefix}-${className}-${key} { ${property}: ${finalValue}; }\n`;
561
+ responsiveCSS += ` .md\\:${prefix}-${className}-${key} { ${property}: ${finalValue}; }\n`;
544
562
  });
545
- css += '}\n';
546
563
  }
547
564
  } else if (values) {
548
565
  if (Array.isArray(values)) {
@@ -551,11 +568,9 @@ function generateLayoutHelpers(helpers, spacingMap, prefix, desktopBreakpoint, b
551
568
  });
552
569
 
553
570
  if (responsive) {
554
- css += `\n@media (min-width: ${desktopBreakpoint}) {\n`;
555
571
  values.forEach(value => {
556
- css += ` .md\\:${prefix}-${className}-${value} { ${property}: ${value}; }\n`;
572
+ responsiveCSS += ` .md\\:${prefix}-${className}-${value} { ${property}: ${value}; }\n`;
557
573
  });
558
- css += '}\n';
559
574
  }
560
575
  } else if (typeof values === 'object') {
561
576
  Object.entries(values).forEach(([key, value]) => {
@@ -563,18 +578,19 @@ function generateLayoutHelpers(helpers, spacingMap, prefix, desktopBreakpoint, b
563
578
  });
564
579
 
565
580
  if (responsive) {
566
- css += `\n@media (min-width: ${desktopBreakpoint}) {\n`;
567
581
  Object.entries(values).forEach(([key, value]) => {
568
- css += ` .md\\:${prefix}-${className}-${key} { ${property}: ${value}; }\n`;
582
+ responsiveCSS += ` .md\\:${prefix}-${className}-${key} { ${property}: ${value}; }\n`;
569
583
  });
570
- css += '}\n';
571
584
  }
572
585
  }
573
586
  }
574
-
575
- css += '\n';
576
587
  });
577
588
 
589
+ // Agrupar todos los helpers responsive en un solo media query
590
+ if (responsiveCSS) {
591
+ css += `\n@media (min-width: ${breakpointInRem}) {\n${responsiveCSS}}\n`;
592
+ }
593
+
578
594
  return css;
579
595
  }
580
596
 
@@ -596,6 +612,14 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
596
612
  const columnsXs = gridConfig.columnsXs || 12;
597
613
  const columnsXl = gridConfig.columnsXl || 24;
598
614
 
615
+ // Función helper para convertir breakpoints a rem de forma consistente
616
+ const breakpointToRem = (value) => {
617
+ if (typeof value === 'string' && value.includes('px')) {
618
+ return pxToRem(value, baseFontSize);
619
+ }
620
+ return value;
621
+ };
622
+
599
623
  let css = '\n/* Grid System */\n';
600
624
 
601
625
  // Genera .row
@@ -609,7 +633,8 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
609
633
  // Genera .row para cada breakpoint
610
634
  Object.entries(breakpoints).forEach(([name, value]) => {
611
635
  if (name !== 'xs') {
612
- css += `@media (min-width: ${value}) {
636
+ const remValue = breakpointToRem(value);
637
+ css += `@media (min-width: ${remValue}) {
613
638
  .row {
614
639
  margin-left: -${gutterValue};
615
640
  margin-right: -${gutterValue};
@@ -625,8 +650,9 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
625
650
  return percentage.replace(/\.?0+$/, '') || '0';
626
651
  };
627
652
 
628
- // Genera columnas para xs (12 columnas) - usar 1px directamente
629
- css += `@media (min-width: ${breakpoints.xs}) {\n`;
653
+ // Genera columnas para xs (12 columnas) - convertir a rem
654
+ const xsBreakpoint = breakpointToRem(breakpoints.xs);
655
+ css += `@media (min-width: ${xsBreakpoint}) {\n`;
630
656
  for (let i = 1; i <= columnsXs; i++) {
631
657
  const percentage = formatPercentage(i / columnsXs);
632
658
  css += ` .col-xs-${i} {
@@ -638,7 +664,8 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
638
664
 
639
665
  // Genera columnas para sm (12 columnas)
640
666
  if (breakpoints.sm) {
641
- css += `@media (min-width: ${breakpoints.sm}) {\n`;
667
+ const smBreakpoint = breakpointToRem(breakpoints.sm);
668
+ css += `@media (min-width: ${smBreakpoint}) {\n`;
642
669
  for (let i = 1; i <= columnsXs; i++) {
643
670
  const percentage = formatPercentage(i / columnsXs);
644
671
  css += ` .col-sm-${i} {
@@ -651,7 +678,8 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
651
678
 
652
679
  // Genera columnas para md (12 columnas)
653
680
  if (breakpoints.md) {
654
- css += `@media (min-width: ${breakpoints.md}) {\n`;
681
+ const mdBreakpoint = breakpointToRem(breakpoints.md);
682
+ css += `@media (min-width: ${mdBreakpoint}) {\n`;
655
683
  for (let i = 1; i <= columnsXs; i++) {
656
684
  const percentage = formatPercentage(i / columnsXs);
657
685
  css += ` .col-md-${i} {
@@ -664,7 +692,8 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
664
692
 
665
693
  // Genera columnas para lg (12 columnas)
666
694
  if (breakpoints.lg) {
667
- css += `@media (min-width: ${breakpoints.lg}) {\n`;
695
+ const lgBreakpoint = breakpointToRem(breakpoints.lg);
696
+ css += `@media (min-width: ${lgBreakpoint}) {\n`;
668
697
  for (let i = 1; i <= columnsXs; i++) {
669
698
  const percentage = formatPercentage(i / columnsXs);
670
699
  css += ` .col-lg-${i} {
@@ -677,7 +706,8 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
677
706
 
678
707
  // Genera columnas para xl (24 columnas)
679
708
  if (breakpoints.xl) {
680
- css += `@media (min-width: ${breakpoints.xl}) {\n`;
709
+ const xlBreakpoint = breakpointToRem(breakpoints.xl);
710
+ css += `@media (min-width: ${xlBreakpoint}) {\n`;
681
711
  for (let i = 1; i <= columnsXl; i++) {
682
712
  const percentage = formatPercentage(i / columnsXl);
683
713
  css += ` .col-xl-${i} {
@@ -695,7 +725,48 @@ function generateGridSystem(gridConfig, baseFontSize = 16) {
695
725
  padding-left: ${gutterValue};
696
726
  padding-right: ${gutterValue};
697
727
  position: relative;
698
- }\n`;
728
+ }\n\n`;
729
+
730
+ // Estilos para bleed
731
+ css += `.bleed {
732
+ margin-left: -${gutterValue};
733
+ margin-right: -${gutterValue};
734
+ width: auto;
735
+ }\n\n`;
736
+
737
+ css += `.bleed.row {
738
+ margin-left: -${gutterValue};
739
+ margin-right: -${gutterValue};
740
+ }\n\n`;
741
+
742
+ css += `.bleed-0 {
743
+ padding: 0 0px 0 0px;
744
+ overflow: hidden;
745
+ }\n\n`;
746
+
747
+ css += `.bleed-0 .container-fluid {
748
+ margin-left: -0px;
749
+ margin-right: -0px;
750
+ padding: 0 0px 0 0px;
751
+ }\n\n`;
752
+
753
+ css += `.bleed-0 > .row {
754
+ margin-left: 0;
755
+ margin-right: 0;
756
+ box-sizing: border-box;
757
+ display: flex;
758
+ flex: 0 1 auto;
759
+ -webkit-box-orient: horizontal;
760
+ -webkit-box-direction: normal;
761
+ flex-flow: row wrap;
762
+ flex-wrap: wrap;
763
+ }\n\n`;
764
+
765
+ css += `.bleed-0 > [class*=col-],
766
+ .bleed-0 > .col {
767
+ padding: 0px;
768
+ box-sizing: border-box;
769
+ }\n\n`;
699
770
 
700
771
  return css;
701
772
  }