flysoft-react-ui 0.1.9 → 0.1.10

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.
Files changed (45) hide show
  1. package/README.md +152 -1
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +3 -2
  4. package/dist/components/form-controls/Button.d.ts +1 -1
  5. package/dist/components/form-controls/Button.d.ts.map +1 -1
  6. package/dist/components/form-controls/Button.js +4 -4
  7. package/dist/components/layout/AppLayout.d.ts +9 -0
  8. package/dist/components/layout/AppLayout.d.ts.map +1 -0
  9. package/dist/components/layout/AppLayout.js +89 -0
  10. package/dist/components/layout/index.d.ts +2 -0
  11. package/dist/components/layout/index.d.ts.map +1 -1
  12. package/dist/components/layout/index.js +1 -0
  13. package/dist/hooks/index.d.ts +2 -0
  14. package/dist/hooks/index.d.ts.map +1 -1
  15. package/dist/hooks/index.js +1 -0
  16. package/dist/hooks/useBreakpoint.d.ts +14 -0
  17. package/dist/hooks/useBreakpoint.d.ts.map +1 -0
  18. package/dist/hooks/useBreakpoint.js +59 -0
  19. package/dist/hooks/useElementScroll.d.ts +5 -0
  20. package/dist/hooks/useElementScroll.d.ts.map +1 -0
  21. package/dist/hooks/useElementScroll.js +28 -0
  22. package/dist/index.css +1 -1
  23. package/dist/index.d.ts +12 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +7 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/templates/forms/ContactForm.d.ts +27 -0
  28. package/dist/templates/forms/ContactForm.d.ts.map +1 -0
  29. package/dist/templates/forms/ContactForm.js +58 -0
  30. package/dist/templates/forms/LoginForm.d.ts +24 -0
  31. package/dist/templates/forms/LoginForm.d.ts.map +1 -0
  32. package/dist/templates/forms/LoginForm.js +36 -0
  33. package/dist/templates/forms/RegistrationForm.d.ts +27 -0
  34. package/dist/templates/forms/RegistrationForm.d.ts.map +1 -0
  35. package/dist/templates/forms/RegistrationForm.js +54 -0
  36. package/dist/templates/layouts/DashboardLayout.d.ts +38 -0
  37. package/dist/templates/layouts/DashboardLayout.d.ts.map +1 -0
  38. package/dist/templates/layouts/DashboardLayout.js +26 -0
  39. package/dist/templates/layouts/SidebarLayout.d.ts +48 -0
  40. package/dist/templates/layouts/SidebarLayout.d.ts.map +1 -0
  41. package/dist/templates/layouts/SidebarLayout.js +27 -0
  42. package/dist/templates/patterns/FormPattern.d.ts +54 -0
  43. package/dist/templates/patterns/FormPattern.d.ts.map +1 -0
  44. package/dist/templates/patterns/FormPattern.js +67 -0
  45. package/package.json +20 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Flysoft React UI
2
2
 
3
- Una biblioteca de componentes React moderna y accesible construida con TypeScript, Tailwind CSS y FontAwesome.
3
+ Una biblioteca de componentes React moderna y accesible construida con TypeScript, Tailwind CSS y FontAwesome 5. Incluye formularios, layouts, temas y templates para desarrollo rápido.
4
4
 
5
5
  ## 🚀 Características
6
6
 
@@ -11,6 +11,8 @@ Una biblioteca de componentes React moderna y accesible construida con TypeScrip
11
11
  - **Personalizable**: Fácil de personalizar con clases de Tailwind
12
12
  - **Tree-shakable**: Solo importa los componentes que uses
13
13
  - **🎨 Sistema de Temas**: Sistema completo de temas personalizables con Context API
14
+ - **📋 Templates Listos**: Formularios y layouts pre-construidos
15
+ - **🤖 Cursor AI Ready**: Optimizado para uso con Cursor AI
14
16
 
15
17
  ## 📦 Instalación
16
18
 
@@ -18,6 +20,94 @@ Una biblioteca de componentes React moderna y accesible construida con TypeScrip
18
20
  npm install flysoft-react-ui
19
21
  ```
20
22
 
23
+ ## ⚡ Quick Start
24
+
25
+ ### 1. Configuración Básica
26
+
27
+ ```tsx
28
+ import { ThemeProvider } from "flysoft-react-ui";
29
+ import "flysoft-react-ui/styles";
30
+
31
+ function App() {
32
+ return (
33
+ <ThemeProvider initialTheme="light">
34
+ {/* Tu aplicación aquí */}
35
+ </ThemeProvider>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ### 2. Formulario de Login Rápido
41
+
42
+ ```tsx
43
+ import { LoginForm } from "flysoft-react-ui";
44
+
45
+ function LoginPage() {
46
+ const handleLogin = (data) => {
47
+ console.log("Login data:", data);
48
+ };
49
+
50
+ return <LoginForm onSubmit={handleLogin} />;
51
+ }
52
+ ```
53
+
54
+ ### 3. Dashboard Básico
55
+
56
+ ```tsx
57
+ import { DashboardLayout } from "flysoft-react-ui";
58
+
59
+ function Dashboard() {
60
+ const stats = [
61
+ {
62
+ title: "Usuarios",
63
+ value: "1,234",
64
+ change: "+12%",
65
+ changeType: "positive",
66
+ },
67
+ {
68
+ title: "Ventas",
69
+ value: "$45,678",
70
+ change: "+8%",
71
+ changeType: "positive",
72
+ },
73
+ ];
74
+
75
+ return (
76
+ <DashboardLayout title="Mi Dashboard" stats={stats}>
77
+ <div>Contenido del dashboard</div>
78
+ </DashboardLayout>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ### 4. Integración con Cursor AI
84
+
85
+ Para que Cursor AI priorice automáticamente estos componentes, crea un archivo `.cursorrules` en tu proyecto:
86
+
87
+ ```markdown
88
+ # Priorizar flysoft-react-ui
89
+
90
+ SIEMPRE usa los componentes de flysoft-react-ui antes de crear nuevos:
91
+
92
+ ## Componentes Disponibles:
93
+
94
+ - Button, Input, Card, Badge, ThemeSwitcher
95
+ - LoginForm, RegistrationForm, ContactForm
96
+ - DashboardLayout, SidebarLayout, FormPattern
97
+
98
+ ## Para formularios:
99
+
100
+ - SIEMPRE usar Input y Button de flysoft-react-ui
101
+ - SIEMPRE usar Card como contenedor
102
+ - SIEMPRE usar FontAwesome 5 para iconos (fa fa-\*)
103
+
104
+ ## Importación requerida:
105
+
106
+ import "flysoft-react-ui/styles";
107
+ ```
108
+
109
+ Ver [INTEGRATION_GUIDE.md](./INTEGRATION_GUIDE.md) para configuración completa.
110
+
21
111
  ## 🔧 Configuración
22
112
 
23
113
  ### Tailwind CSS
@@ -155,6 +245,46 @@ function App() {
155
245
  }
156
246
  ```
157
247
 
248
+ ## 📋 Templates Disponibles
249
+
250
+ ### Formularios
251
+
252
+ - **LoginForm**: Formulario de login completo con validación
253
+ - **RegistrationForm**: Formulario de registro con validación de contraseñas
254
+ - **ContactForm**: Formulario de contacto con textarea y validación
255
+
256
+ ### Layouts
257
+
258
+ - **DashboardLayout**: Layout de dashboard con estadísticas y métricas
259
+ - **SidebarLayout**: Layout con sidebar de navegación y contenido principal
260
+
261
+ ### Patrones
262
+
263
+ - **FormPattern**: Patrón reutilizable para cualquier formulario
264
+
265
+ ### Ejemplo de Uso de Templates
266
+
267
+ ```tsx
268
+ import { LoginForm, DashboardLayout, SidebarLayout } from "flysoft-react-ui";
269
+
270
+ // Formulario de login
271
+ <LoginForm onSubmit={handleLogin} loading={isLoading} />
272
+
273
+ // Dashboard con estadísticas
274
+ <DashboardLayout title="Mi App" stats={stats}>
275
+ <div>Contenido del dashboard</div>
276
+ </DashboardLayout>
277
+
278
+ // Layout con sidebar
279
+ <SidebarLayout
280
+ title="Mi App"
281
+ menuItems={menuItems}
282
+ user={user}
283
+ >
284
+ <div>Contenido principal</div>
285
+ </SidebarLayout>
286
+ ```
287
+
158
288
  ## 🧩 Componentes
159
289
 
160
290
  ### Button
@@ -305,6 +435,27 @@ MIT
305
435
 
306
436
  Las contribuciones son bienvenidas. Por favor, abre un issue o un pull request.
307
437
 
438
+ ## 📚 Recursos Adicionales
439
+
440
+ - **[INTEGRATION_GUIDE.md](./INTEGRATION_GUIDE.md)**: Guía completa de integración con Cursor AI
441
+ - **[THEME_SYSTEM.md](./THEME_SYSTEM.md)**: Documentación detallada del sistema de temas
442
+ - **[examples/common-patterns.tsx](./examples/common-patterns.tsx)**: Ejemplos completos de uso
443
+ - **[flysoft-ui.config.ts](./flysoft-ui.config.ts)**: Configuración centralizada de la librería
444
+ - **[docs/component-metadata.json](./docs/component-metadata.json)**: Metadatos de todos los componentes
445
+
446
+ ## 🔧 Scripts de Mantenimiento
447
+
448
+ ```bash
449
+ # Actualizar documentación automáticamente
450
+ npm run update-docs
451
+
452
+ # Validar que toda la documentación esté sincronizada
453
+ npm run validate-docs
454
+
455
+ # Ver ejemplos completos
456
+ npm run dev
457
+ ```
458
+
308
459
  ## 📞 Soporte
309
460
 
310
461
  Si tienes alguna pregunta o necesitas ayuda, abre un issue en el repositorio.
package/dist/App.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAUA,OAAO,aAAa,CAAC;AA6CrB,iBAAS,GAAG,4CAqNX;AAED,eAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAWA,OAAO,aAAa,CAAC;AA6CrB,iBAAS,GAAG,4CA+MX;AAED,eAAe,GAAG,CAAC"}
package/dist/App.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AppLayout } from "./components";
2
3
  import { Button, Input, Card, Badge, ThemeProvider, ThemeSwitcher, useTheme, useGlobalThemeStyles, } from "./index";
3
4
  import "./index.css";
4
5
  // Componente para probar la funcionalidad de resetToDefault
@@ -13,9 +14,9 @@ const GlobalThemeDemo = () => {
13
14
  return (_jsxs("div", { className: "p-4 rounded-lg border", style: {
14
15
  borderColor: "var(--flysoft-border-default)",
15
16
  backgroundColor: "var(--flysoft-bg-secondary)",
16
- }, children: [_jsx("h3", { className: "text-lg font-semibold mb-2", style: { color: "var(--flysoft-text-primary)" }, children: "Hook useGlobalThemeStyles" }), _jsx("p", { className: "text-sm", style: { color: "var(--flysoft-text-secondary)" }, children: "Este componente usa el hook useGlobalThemeStyles que aplica autom\u00E1ticamente los colores del tema al body y html de la p\u00E1gina." })] }));
17
+ }, children: [_jsx("h3", { className: "text-lg font-semibold mb-2", style: { color: "var(--flysoft-text-primary)" }, children: "Hook useGlobalThemeStyles" }), _jsx("p", { className: "text-sm", style: { color: "var(--flysoft-text-secondary)" }, children: "Este componente usa el hook useGlobalThemeStyles que aplica autom\u00E1ticamente los estilos del tema actual al body y html." })] }));
17
18
  };
18
19
  function App() {
19
- return (_jsx(ThemeProvider, { initialTheme: "light", forceInitialTheme: false, children: _jsx("div", { className: "min-h-screen p-8", style: { backgroundColor: "var(--flysoft-bg-secondary)" }, children: _jsxs("div", { className: "max-w-4xl mx-auto", children: [_jsxs("div", { className: "text-center mb-12", children: [_jsx("h1", { className: "text-4xl font-bold mb-4", style: { color: "var(--flysoft-text-primary)" }, children: "Flysoft React UI" }), _jsx("p", { className: "text-xl", style: { color: "var(--flysoft-text-secondary)" }, children: "Biblioteca de componentes React moderna con Tailwind CSS, FontAwesome y sistema de temas personalizable" })] }), _jsx("div", { className: "mb-8", children: _jsx(ThemeSwitcher, {}) }), _jsx("div", { className: "mb-8 text-center", children: _jsx(ResetToDefaultButton, {}) }), _jsx("div", { className: "mb-8", children: _jsx(GlobalThemeDemo, {}) }), _jsx(Card, { title: "Botones", subtitle: "Diferentes variantes y tama\u00F1os de botones", className: "mb-8", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsx(Button, { variant: "primary", icon: "fa-heart", children: "Bot\u00F3n Primario" }), _jsx(Button, { variant: "outline", icon: "fa-download", children: "Bot\u00F3n Outline" }), _jsx(Button, { variant: "ghost", icon: "fa-edit", children: "Bot\u00F3n Ghost" })] }), _jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsx(Button, { size: "sm", icon: "fa-plus", children: "Peque\u00F1o" }), _jsx(Button, { size: "md", icon: "fa-check", children: "Mediano" }), _jsx(Button, { size: "lg", icon: "fa-arrow-right", children: "Grande" })] }), _jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsx(Button, { loading: true, children: "Cargando..." }), _jsx(Button, { disabled: true, children: "Deshabilitado" }), _jsx(Button, { icon: "fa-arrow-right", iconPosition: "right", children: "Con Icono Derecha" })] })] }) }), _jsx(Card, { title: "Campos de Entrada", subtitle: "Diferentes tipos de inputs con iconos", className: "mb-8", children: _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsx(Input, { label: "Nombre completo", placeholder: "Ingresa tu nombre", icon: "fa-user" }), _jsx(Input, { label: "Email", type: "email", placeholder: "tu@email.com", icon: "fa-envelope" }), _jsx(Input, { label: "Contrase\u00F1a", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", icon: "fa-lock" }), _jsx(Input, { label: "B\u00FAsqueda", placeholder: "Buscar...", icon: "fa-search", iconPosition: "right" }), _jsx(Input, { label: "Con error", placeholder: "Campo con error", error: "Este campo es requerido", icon: "fa-exclamation-triangle" })] }) }), _jsx(Card, { title: "Badges", subtitle: "Diferentes variantes de badges", className: "mb-8", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { variant: "primary", children: "Primary" }), _jsx(Badge, { variant: "secondary", children: "Secondary" }), _jsx(Badge, { variant: "success", children: "Success" }), _jsx(Badge, { variant: "warning", children: "Warning" }), _jsx(Badge, { variant: "danger", children: "Danger" }), _jsx(Badge, { variant: "info", children: "Info" })] }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { size: "sm", children: "Small" }), _jsx(Badge, { size: "md", children: "Medium" }), _jsx(Badge, { size: "lg", children: "Large" })] }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { rounded: true, children: "Rounded" }), _jsx(Badge, { variant: "success", rounded: true, children: "Success Rounded" }), _jsx(Badge, { variant: "warning", rounded: true, children: "Warning Rounded" })] })] }) }), _jsx(Card, { title: "Tarjetas", subtitle: "Diferentes variantes de tarjetas", className: "mb-8", children: _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: [_jsx(Card, { title: "Tarjeta Simple", subtitle: "Sin acciones ni footer", variant: "default", children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Esta es una tarjeta simple con contenido b\u00E1sico." }) }), _jsx(Card, { title: "Con Acciones", subtitle: "Incluye botones en el header", variant: "elevated", headerActions: _jsx(Button, { size: "sm", variant: "outline", icon: "fa-edit", children: "Editar" }), children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Tarjeta con botones de acci\u00F3n en el header." }) }), _jsx(Card, { title: "Con Footer", subtitle: "Incluye secci\u00F3n de footer", variant: "outlined", footer: _jsxs("div", { className: "flex justify-between items-center", children: [_jsx("span", { className: "text-sm", style: { color: "var(--flysoft-text-muted)" }, children: "\u00DAltima actualizaci\u00F3n: hoy" }), _jsx(Button, { size: "sm", variant: "primary", icon: "fa-save", children: "Guardar" })] }), children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Tarjeta con footer personalizado y botones." }) })] }) })] }) }) }));
20
+ return (_jsx(ThemeProvider, { initialTheme: "light", forceInitialTheme: false, children: _jsx(AppLayout, { navBarDrawer: _jsx("div", { children: _jsx("h2", { children: "Flysoft React UI" }) }), leftDrawer: _jsx("div", { children: "Left Drawer" }), children: _jsx("div", { children: _jsxs("div", { className: "max-w-4xl mx-auto", children: [_jsx("div", { className: "text-center mb-12", children: _jsx("p", { className: "text-xl", style: { color: "var(--flysoft-text-secondary)" }, children: "Biblioteca de componentes React moderna con Tailwind CSS, FontAwesome y sistema de temas personalizable" }) }), _jsx("div", { className: "mb-8", children: _jsx(ThemeSwitcher, {}) }), _jsx("div", { className: "mb-8 text-center", children: _jsx(ResetToDefaultButton, {}) }), _jsx("div", { className: "mb-8", children: _jsx(GlobalThemeDemo, {}) }), _jsx("div", { className: "mb-8", children: _jsx(Card, { title: "Form Controls", className: "mb-6", children: _jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", style: { color: "var(--flysoft-text-primary)" }, children: "Botones" }), _jsxs("div", { className: "flex flex-wrap gap-4", children: [_jsx(Button, { variant: "primary", icon: "fa-save", children: "Primary" }), _jsx(Button, { variant: "outline", icon: "fa-edit", children: "Outline" }), _jsx(Button, { variant: "ghost", icon: "fa-trash", children: "Ghost" }), _jsx(Button, { size: "sm", variant: "primary", children: "Small" }), _jsx(Button, { size: "lg", variant: "outline", children: "Large" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", style: { color: "var(--flysoft-text-primary)" }, children: "Campos de Entrada" }), _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Nombre", placeholder: "Ingresa tu nombre", icon: "fa-user" }), _jsx(Input, { label: "Email", type: "email", placeholder: "tu@email.com", icon: "fa-envelope" }), _jsx(Input, { label: "Contrase\u00F1a", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", icon: "fa-lock" }), _jsx(Input, { label: "Mensaje", placeholder: "Escribe tu mensaje aqu\u00ED...", icon: "fa-comment" })] })] })] }) }) }), _jsx("div", { className: "mb-8", children: _jsx(Card, { title: "Utility Components", children: _jsx("div", { className: "space-y-6", children: _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", style: { color: "var(--flysoft-text-primary)" }, children: "Badges" }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { variant: "primary", children: "Primary" }), _jsx(Badge, { variant: "secondary", children: "Secondary" }), _jsx(Badge, { variant: "success", children: "Success" }), _jsx(Badge, { variant: "warning", children: "Warning" }), _jsx(Badge, { variant: "danger", children: "Danger" }), _jsx(Badge, { variant: "info", children: "Info" })] })] }) }) }) }), _jsx("div", { className: "mb-8", children: _jsx(Card, { title: "Layout Components", children: _jsx("div", { className: "space-y-6", children: _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", style: { color: "var(--flysoft-text-primary)" }, children: "Cards con Diferentes Variantes" }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsx(Card, { variant: "default", title: "Card Default", children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Esta es una tarjeta con variante por defecto." }) }), _jsx(Card, { variant: "elevated", title: "Card Elevated", children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Esta es una tarjeta con sombra elevada." }) }), _jsx(Card, { variant: "outlined", title: "Card Outlined", children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Esta es una tarjeta con borde destacado." }) }), _jsx(Card, { title: "Card con Footer", footer: _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", children: "Cancelar" }), _jsx(Button, { size: "sm", variant: "primary", icon: "fa-save", children: "Guardar" })] }), children: _jsx("p", { style: { color: "var(--flysoft-text-secondary)" }, children: "Tarjeta con footer personalizado y botones." }) })] })] }) }) }) }), _jsxs("div", { className: "mt-8 space-y-8", children: [_jsxs("div", { className: "h-96 bg-blue-100 rounded p-4", children: [_jsx("h3", { className: "text-lg font-bold mb-4", children: "Secci\u00F3n 1" }), _jsx("p", { children: "Contenido adicional para hacer scroll..." })] }), _jsxs("div", { className: "h-96 bg-green-100 rounded p-4", children: [_jsx("h3", { className: "text-lg font-bold mb-4", children: "Secci\u00F3n 2" }), _jsx("p", { children: "M\u00E1s contenido para probar el comportamiento del navbar..." })] }), _jsxs("div", { className: "h-96 bg-yellow-100 rounded p-4", children: [_jsx("h3", { className: "text-lg font-bold mb-4", children: "Secci\u00F3n 3" }), _jsx("p", { children: "Contenido final para asegurar que hay suficiente altura..." })] }), _jsxs("div", { className: "h-96 bg-red-100 rounded p-4", children: [_jsx("h3", { className: "text-lg font-bold mb-4", children: "Secci\u00F3n 4" }), _jsx("p", { children: "\u00DAltima secci\u00F3n para completar la prueba de scroll..." })] })] })] }) }) }) }));
20
21
  }
21
22
  export default App;
@@ -5,7 +5,7 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
5
5
  icon?: string;
6
6
  iconPosition?: "left" | "right";
7
7
  loading?: boolean;
8
- children: React.ReactNode;
8
+ children?: React.ReactNode;
9
9
  }
10
10
  export declare const Button: React.FC<ButtonProps>;
11
11
  //# sourceMappingURL=Button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAC1C,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAgExC,CAAC"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAC1C,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAgExC,CAAC"}
@@ -22,16 +22,16 @@ export const Button = ({ variant = "primary", size = "md", icon, iconPosition =
22
22
  `,
23
23
  };
24
24
  const sizeClasses = {
25
- sm: "px-3 py-1.5 text-sm",
26
- md: "px-4 py-2 text-base",
27
- lg: "px-6 py-3 text-lg",
25
+ sm: `${children ? "px-3 py-1.5" : "p-1.5"} text-sm`,
26
+ md: `${children ? "px-4 py-2" : "p-2"} text-base`,
27
+ lg: `${children ? "px-6 py-3" : "p-3"} text-lg`,
28
28
  };
29
29
  const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className}`;
30
30
  const renderIcon = () => {
31
31
  if (!icon)
32
32
  return null;
33
33
  const iconClasses = size === "sm" ? "w-4 h-4" : size === "md" ? "w-5 h-5" : "w-6 h-6";
34
- return (_jsx("i", { className: `fa ${icon} ${iconClasses} ${iconPosition === "right" ? "ml-2" : "mr-2"}` }));
34
+ return (_jsx("i", { className: `fa ${icon} ${iconClasses} ${children ? (iconPosition === "right" ? "ml-2" : "mr-2") : ""}` }));
35
35
  };
36
36
  return (_jsxs("button", { className: classes, disabled: disabled || loading, ...props, children: [loading && _jsx("i", { className: "fa fa-spinner fa-spin mr-2" }), icon && iconPosition === "left" && !loading && renderIcon(), children, icon && iconPosition === "right" && !loading && renderIcon()] }));
37
37
  };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ export interface AppLayoutProps {
3
+ navBarDrawer?: React.ReactNode;
4
+ leftDrawer?: React.ReactNode;
5
+ children: React.ReactNode;
6
+ className?: string;
7
+ }
8
+ export declare const AppLayout: React.FC<AppLayoutProps>;
9
+ //# sourceMappingURL=AppLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppLayout.d.ts","sourceRoot":"","sources":["../../../src/components/layout/AppLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAKhD,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAoK9C,CAAC"}
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState, useRef } from "react";
3
+ import { useBreakpoint } from "../../hooks";
4
+ import { useElementScroll } from "../../hooks/useElementScroll";
5
+ import { Button } from "../form-controls";
6
+ export const AppLayout = ({ navBarDrawer, leftDrawer, children, className = "", }) => {
7
+ const { isMobile, isTablet } = useBreakpoint();
8
+ const contentRef = useRef(null);
9
+ const { scrollY, scrollDirection } = useElementScroll(contentRef);
10
+ const [isMobileDrawerOpen, setIsMobileDrawerOpen] = useState(false);
11
+ const [isNavbarVisible, setIsNavbarVisible] = useState(true);
12
+ const shouldShowMobileDrawer = isMobile || isTablet;
13
+ const shouldShowDesktopDrawer = !shouldShowMobileDrawer && leftDrawer;
14
+ // Controlar visibilidad del navbar basado en scroll
15
+ React.useEffect(() => {
16
+ if (scrollY < 100) {
17
+ // Siempre mostrar navbar cerca del top
18
+ setIsNavbarVisible(true);
19
+ }
20
+ else if (scrollDirection === "down" && scrollY > 100) {
21
+ // Ocultar navbar al hacer scroll hacia abajo
22
+ setIsNavbarVisible(false);
23
+ }
24
+ else if (scrollDirection === "up" && scrollY > 100) {
25
+ // Mostrar navbar al hacer scroll hacia arriba
26
+ setIsNavbarVisible(true);
27
+ }
28
+ }, [scrollDirection, scrollY, isNavbarVisible]);
29
+ const handleMobileDrawerToggle = () => {
30
+ setIsMobileDrawerOpen(!isMobileDrawerOpen);
31
+ };
32
+ const handleOverlayClick = () => {
33
+ setIsMobileDrawerOpen(false);
34
+ };
35
+ // Clases base del layout
36
+ const layoutClasses = `
37
+ flex flex-col h-screen w-full
38
+ font-[var(--font-default)]
39
+ ${className}
40
+ `;
41
+ // Clases del navbar
42
+ const navbarClasses = `
43
+ bg-[var(--color-bg-default)] border-b border-[var(--color-border-default)]
44
+ z-[1000] fixed top-0 left-0 right-0
45
+ transform transition-transform duration-300 ease-in-out
46
+ ${isNavbarVisible ? "translate-y-0" : "-translate-y-full"}
47
+ `;
48
+ // Estilos inline para debug
49
+ const navbarStyle = {
50
+ transform: isNavbarVisible ? "translateY(0)" : "translateY(-100%)",
51
+ transition: "transform 300ms ease-in-out",
52
+ };
53
+ const navbarContentClasses = `
54
+ flex items-center pr-4 lg:px-4 h-16 gap-2
55
+ md:px-3
56
+ `;
57
+ const navbarDrawerClasses = `flex-1`;
58
+ // Clases del contenido principal
59
+ const mainClasses = `
60
+ flex flex-1 overflow-hidden
61
+ transition-all duration-300 ease-in-out
62
+ ${navBarDrawer && isNavbarVisible ? "pt-16" : ""}
63
+ `;
64
+ const leftDrawerClasses = `
65
+ w-64 bg-[var(--color-bg-default)]
66
+ overflow-y-auto flex-shrink-0 p-4
67
+ transition-all duration-300 ease-in-out
68
+ ${navBarDrawer && isNavbarVisible ? "pt-20" : "pt-4"}
69
+ `;
70
+ const contentClasses = `
71
+ flex-1 overflow-y-auto px-2 py-4 lg:px-6
72
+ `;
73
+ // Clases del overlay móvil
74
+ const overlayClasses = `
75
+ fixed inset-0 bg-black/50 backdrop-blur-sm z-[1998]
76
+ `;
77
+ // Clases del drawer móvil
78
+ const mobileDrawerBaseClasses = `
79
+ fixed top-0 left-0 h-screen w-64 max-w-[80vw]
80
+ bg-[var(--color-bg-default)] shadow-[var(--shadow-xl)]
81
+ transform -translate-x-full transition-transform duration-300 ease-in-out
82
+ z-[1999] flex flex-col
83
+ `;
84
+ const mobileDrawerOpenClasses = `translate-x-0`;
85
+ const mobileDrawerContentClasses = `
86
+ flex-1 overflow-y-auto p-4
87
+ `;
88
+ return (_jsxs("div", { className: layoutClasses, children: [navBarDrawer && (_jsx("nav", { className: navbarClasses, style: navbarStyle, children: _jsxs("div", { className: navbarContentClasses, children: [shouldShowMobileDrawer && leftDrawer && (_jsx(Button, { variant: "ghost", icon: "fa-bars", onClick: handleMobileDrawerToggle, "aria-label": "Abrir men\u00FA" })), _jsx("div", { className: navbarDrawerClasses, children: navBarDrawer })] }) })), _jsxs("div", { className: mainClasses, children: [shouldShowDesktopDrawer && (_jsx("aside", { className: leftDrawerClasses, children: leftDrawer })), _jsx("main", { ref: contentRef, className: contentClasses, children: children })] }), shouldShowMobileDrawer && leftDrawer && isMobileDrawerOpen && (_jsx("div", { className: overlayClasses, onClick: handleOverlayClick })), shouldShowMobileDrawer && leftDrawer && (_jsxs("aside", { className: `${mobileDrawerBaseClasses} ${isMobileDrawerOpen ? mobileDrawerOpenClasses : ""}`, children: [_jsx("div", { className: "text-right", children: _jsx(Button, { variant: "ghost", icon: "fa-times", onClick: handleMobileDrawerToggle, "aria-label": "Cerrar men\u00FA" }) }), _jsx("div", { className: mobileDrawerContentClasses, children: leftDrawer })] }))] }));
89
+ };
@@ -1,3 +1,5 @@
1
1
  export { Card } from "./Card";
2
2
  export type { CardProps } from "./Card";
3
+ export { AppLayout } from "./AppLayout";
4
+ export type { AppLayoutProps } from "./AppLayout";
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/layout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/layout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -1 +1,2 @@
1
1
  export { Card } from "./Card";
2
+ export { AppLayout } from "./AppLayout";
@@ -1,3 +1,5 @@
1
1
  export { useThemeOverride, useTemporaryOverride } from "./useThemeOverride";
2
2
  export { useGlobalThemeStyles } from "./useGlobalThemeStyles";
3
+ export { useBreakpoint } from "./useBreakpoint";
4
+ export type { Breakpoint, WindowSize, BreakpointInfo } from "./useBreakpoint";
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export { useThemeOverride, useTemporaryOverride } from "./useThemeOverride";
2
2
  export { useGlobalThemeStyles } from "./useGlobalThemeStyles";
3
+ export { useBreakpoint } from "./useBreakpoint";
@@ -0,0 +1,14 @@
1
+ export type Breakpoint = "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
2
+ export interface WindowSize {
3
+ width: number;
4
+ height: number;
5
+ }
6
+ export interface BreakpointInfo {
7
+ breakpoint: Breakpoint;
8
+ windowSize: WindowSize;
9
+ isMobile: boolean;
10
+ isTablet: boolean;
11
+ isDesktop: boolean;
12
+ }
13
+ export declare const useBreakpoint: () => BreakpointInfo;
14
+ //# sourceMappingURL=useBreakpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBreakpoint.d.ts","sourceRoot":"","sources":["../../src/hooks/useBreakpoint.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAYD,eAAO,MAAM,aAAa,QAAO,cAqDhC,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { useState, useEffect } from "react";
2
+ // Breakpoints basados en Tailwind CSS
3
+ const breakpoints = {
4
+ xs: 0,
5
+ sm: 640,
6
+ md: 768,
7
+ lg: 1024,
8
+ xl: 1280,
9
+ "2xl": 1536,
10
+ };
11
+ export const useBreakpoint = () => {
12
+ const [windowSize, setWindowSize] = useState({
13
+ width: typeof window !== "undefined" ? window.innerWidth : 1024,
14
+ height: typeof window !== "undefined" ? window.innerHeight : 768,
15
+ });
16
+ const [breakpoint, setBreakpoint] = useState("lg");
17
+ useEffect(() => {
18
+ const handleResize = () => {
19
+ const width = window.innerWidth;
20
+ const height = window.innerHeight;
21
+ setWindowSize({ width, height });
22
+ // Determinar el breakpoint actual
23
+ if (width >= breakpoints["2xl"]) {
24
+ setBreakpoint("2xl");
25
+ }
26
+ else if (width >= breakpoints.xl) {
27
+ setBreakpoint("xl");
28
+ }
29
+ else if (width >= breakpoints.lg) {
30
+ setBreakpoint("lg");
31
+ }
32
+ else if (width >= breakpoints.md) {
33
+ setBreakpoint("md");
34
+ }
35
+ else if (width >= breakpoints.sm) {
36
+ setBreakpoint("sm");
37
+ }
38
+ else {
39
+ setBreakpoint("xs");
40
+ }
41
+ };
42
+ // Ejecutar una vez al montar
43
+ handleResize();
44
+ // Agregar listener para cambios de tamaño
45
+ window.addEventListener("resize", handleResize);
46
+ // Cleanup
47
+ return () => window.removeEventListener("resize", handleResize);
48
+ }, []);
49
+ const isMobile = breakpoint === "xs" || breakpoint === "sm";
50
+ const isTablet = breakpoint === "md";
51
+ const isDesktop = breakpoint === "lg" || breakpoint === "xl" || breakpoint === "2xl";
52
+ return {
53
+ breakpoint,
54
+ windowSize,
55
+ isMobile,
56
+ isTablet,
57
+ isDesktop,
58
+ };
59
+ };
@@ -0,0 +1,5 @@
1
+ export declare const useElementScroll: (elementRef: React.RefObject<HTMLElement | null>) => {
2
+ scrollY: number;
3
+ scrollDirection: "up" | "down" | null;
4
+ };
5
+ //# sourceMappingURL=useElementScroll.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useElementScroll.d.ts","sourceRoot":"","sources":["../../src/hooks/useElementScroll.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,GAC3B,YAAY,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC;;;CAoChD,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { useState, useEffect } from "react";
2
+ export const useElementScroll = (elementRef) => {
3
+ const [scrollY, setScrollY] = useState(0);
4
+ const [scrollDirection, setScrollDirection] = useState(null);
5
+ useEffect(() => {
6
+ if (!elementRef.current)
7
+ return;
8
+ const element = elementRef.current;
9
+ let lastScrollY = element.scrollTop;
10
+ const handleScroll = () => {
11
+ const currentScrollY = element.scrollTop;
12
+ setScrollY(currentScrollY);
13
+ if (currentScrollY > lastScrollY && currentScrollY > 10) {
14
+ setScrollDirection("down");
15
+ }
16
+ else if (currentScrollY < lastScrollY) {
17
+ setScrollDirection("up");
18
+ }
19
+ lastScrollY = currentScrollY;
20
+ };
21
+ // Agregar el listener al elemento
22
+ element.addEventListener("scroll", handleScroll, { passive: true });
23
+ return () => {
24
+ element.removeEventListener("scroll", handleScroll);
25
+ };
26
+ }, [elementRef]);
27
+ return { scrollY, scrollDirection };
28
+ };