flysoft-react-ui 0.4.0 → 0.5.2

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 (178) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/App.js +20 -4
  3. package/dist/components/form-controls/AutocompleteInput.d.ts +11 -3
  4. package/dist/components/form-controls/AutocompleteInput.d.ts.map +1 -1
  5. package/dist/components/form-controls/AutocompleteInput.js +410 -31
  6. package/dist/components/form-controls/Button.js +1 -1
  7. package/dist/components/form-controls/Checkbox.d.ts +14 -0
  8. package/dist/components/form-controls/Checkbox.d.ts.map +1 -0
  9. package/dist/components/form-controls/Checkbox.js +77 -0
  10. package/dist/components/form-controls/DateInput.d.ts +20 -4
  11. package/dist/components/form-controls/DateInput.d.ts.map +1 -1
  12. package/dist/components/form-controls/DateInput.js +425 -70
  13. package/dist/components/form-controls/DatePicker.d.ts +4 -3
  14. package/dist/components/form-controls/DatePicker.d.ts.map +1 -1
  15. package/dist/components/form-controls/DatePicker.js +26 -30
  16. package/dist/components/form-controls/Input.d.ts +10 -1
  17. package/dist/components/form-controls/Input.d.ts.map +1 -1
  18. package/dist/components/form-controls/Input.js +16 -10
  19. package/dist/components/form-controls/Pagination.d.ts +1 -0
  20. package/dist/components/form-controls/Pagination.d.ts.map +1 -1
  21. package/dist/components/form-controls/Pagination.js +3 -40
  22. package/dist/components/form-controls/RadioButtonGroup.d.ts +62 -0
  23. package/dist/components/form-controls/RadioButtonGroup.d.ts.map +1 -0
  24. package/dist/components/form-controls/RadioButtonGroup.js +220 -0
  25. package/dist/components/form-controls/SearchSelectInput-OLD.d.ts +68 -0
  26. package/dist/components/form-controls/SearchSelectInput-OLD.d.ts.map +1 -0
  27. package/dist/components/form-controls/SearchSelectInput-OLD.js +962 -0
  28. package/dist/components/form-controls/SearchSelectInput.d.ts +70 -0
  29. package/dist/components/form-controls/SearchSelectInput.d.ts.map +1 -0
  30. package/dist/components/form-controls/SearchSelectInput.js +335 -0
  31. package/dist/components/form-controls/index.d.ts +7 -1
  32. package/dist/components/form-controls/index.d.ts.map +1 -1
  33. package/dist/components/form-controls/index.js +3 -0
  34. package/dist/components/layout/AppLayout.d.ts +3 -2
  35. package/dist/components/layout/AppLayout.d.ts.map +1 -1
  36. package/dist/components/layout/AppLayout.js +104 -31
  37. package/dist/components/layout/Card.d.ts +4 -1
  38. package/dist/components/layout/Card.d.ts.map +1 -1
  39. package/dist/components/layout/Card.js +30 -1
  40. package/dist/components/layout/Collection.js +1 -1
  41. package/dist/components/layout/DataTable.d.ts +29 -0
  42. package/dist/components/layout/DataTable.d.ts.map +1 -0
  43. package/dist/components/layout/DataTable.js +165 -0
  44. package/dist/components/layout/index.d.ts +2 -0
  45. package/dist/components/layout/index.d.ts.map +1 -1
  46. package/dist/components/layout/index.js +1 -0
  47. package/dist/components/utils/Avatar.d.ts +49 -0
  48. package/dist/components/utils/Avatar.d.ts.map +1 -0
  49. package/dist/components/utils/Avatar.js +93 -0
  50. package/dist/components/utils/Badge.d.ts +3 -0
  51. package/dist/components/utils/Badge.d.ts.map +1 -1
  52. package/dist/components/utils/Badge.js +130 -26
  53. package/dist/components/utils/Dialog.d.ts.map +1 -1
  54. package/dist/components/utils/Dialog.js +5 -1
  55. package/dist/components/utils/DropdownMenu.d.ts +25 -0
  56. package/dist/components/utils/DropdownMenu.d.ts.map +1 -0
  57. package/dist/components/utils/DropdownMenu.js +145 -0
  58. package/dist/components/utils/Filter.d.ts +57 -0
  59. package/dist/components/utils/Filter.d.ts.map +1 -0
  60. package/dist/components/utils/Filter.js +580 -0
  61. package/dist/components/utils/FiltersDialog.d.ts +21 -0
  62. package/dist/components/utils/FiltersDialog.d.ts.map +1 -0
  63. package/dist/components/utils/FiltersDialog.js +104 -0
  64. package/dist/components/utils/Loader.js +1 -1
  65. package/dist/components/utils/RoadMap.d.ts +59 -0
  66. package/dist/components/utils/RoadMap.d.ts.map +1 -0
  67. package/dist/components/utils/RoadMap.js +138 -0
  68. package/dist/components/utils/Snackbar.d.ts +13 -0
  69. package/dist/components/utils/Snackbar.d.ts.map +1 -0
  70. package/dist/components/utils/Snackbar.js +121 -0
  71. package/dist/components/utils/SnackbarContainer.d.ts +7 -0
  72. package/dist/components/utils/SnackbarContainer.d.ts.map +1 -0
  73. package/dist/components/utils/SnackbarContainer.js +25 -0
  74. package/dist/components/utils/index.d.ts +12 -0
  75. package/dist/components/utils/index.d.ts.map +1 -1
  76. package/dist/components/utils/index.js +6 -0
  77. package/dist/contexts/AppLayoutContext.d.ts +40 -0
  78. package/dist/contexts/AppLayoutContext.d.ts.map +1 -0
  79. package/dist/contexts/AppLayoutContext.js +98 -0
  80. package/dist/contexts/ListCrudContext.d.ts +29 -0
  81. package/dist/contexts/ListCrudContext.d.ts.map +1 -0
  82. package/dist/contexts/ListCrudContext.js +209 -0
  83. package/dist/contexts/SnackbarContext.d.ts +26 -0
  84. package/dist/contexts/SnackbarContext.d.ts.map +1 -0
  85. package/dist/contexts/SnackbarContext.js +34 -0
  86. package/dist/contexts/index.d.ts +6 -0
  87. package/dist/contexts/index.d.ts.map +1 -1
  88. package/dist/contexts/index.js +6 -0
  89. package/dist/contexts/presets.js +6 -6
  90. package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +3 -1
  91. package/dist/docs/AvatarDocs.d.ts +4 -0
  92. package/dist/docs/AvatarDocs.d.ts.map +1 -0
  93. package/dist/docs/AvatarDocs.js +7 -0
  94. package/dist/docs/BadgeDocs.d.ts.map +1 -1
  95. package/dist/docs/BadgeDocs.js +4 -2
  96. package/dist/docs/CardDocs.d.ts.map +1 -1
  97. package/dist/docs/CardDocs.js +7 -1
  98. package/dist/docs/CheckboxDocs.d.ts +4 -0
  99. package/dist/docs/CheckboxDocs.d.ts.map +1 -0
  100. package/dist/docs/CheckboxDocs.js +7 -0
  101. package/dist/docs/DataTableDocs.d.ts +4 -0
  102. package/dist/docs/DataTableDocs.d.ts.map +1 -0
  103. package/dist/docs/DataTableDocs.js +244 -0
  104. package/dist/docs/DateInputDocs.d.ts +1 -0
  105. package/dist/docs/DateInputDocs.d.ts.map +1 -1
  106. package/dist/docs/DateInputDocs.js +7 -9
  107. package/dist/docs/DatePickerDocs.d.ts +1 -0
  108. package/dist/docs/DatePickerDocs.d.ts.map +1 -1
  109. package/dist/docs/DatePickerDocs.js +6 -8
  110. package/dist/docs/DocAdmin.d.ts +4 -0
  111. package/dist/docs/DocAdmin.d.ts.map +1 -0
  112. package/dist/docs/DocAdmin.js +68 -0
  113. package/dist/docs/DocsMenu.d.ts.map +1 -1
  114. package/dist/docs/DocsMenu.js +1 -1
  115. package/dist/docs/DocsRouter.d.ts.map +1 -1
  116. package/dist/docs/DocsRouter.js +13 -1
  117. package/dist/docs/DropdownMenuDocs.d.ts +4 -0
  118. package/dist/docs/DropdownMenuDocs.d.ts.map +1 -0
  119. package/dist/docs/DropdownMenuDocs.js +66 -0
  120. package/dist/docs/ExampleFormDocs.d.ts +4 -0
  121. package/dist/docs/ExampleFormDocs.d.ts.map +1 -0
  122. package/dist/docs/ExampleFormDocs.js +148 -0
  123. package/dist/docs/FilterDocs.d.ts +4 -0
  124. package/dist/docs/FilterDocs.d.ts.map +1 -0
  125. package/dist/docs/FilterDocs.js +112 -0
  126. package/dist/docs/InputDocs.d.ts.map +1 -1
  127. package/dist/docs/InputDocs.js +11 -1
  128. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +11 -0
  129. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +1 -0
  130. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +25 -0
  131. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +2 -0
  132. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +1 -0
  133. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +51 -0
  134. package/dist/docs/PaginationDocs.js +6 -6
  135. package/dist/docs/RadioButtonGroupDocs.d.ts +4 -0
  136. package/dist/docs/RadioButtonGroupDocs.d.ts.map +1 -0
  137. package/dist/docs/RadioButtonGroupDocs.js +46 -0
  138. package/dist/docs/RoadMapDocs.d.ts +4 -0
  139. package/dist/docs/RoadMapDocs.d.ts.map +1 -0
  140. package/dist/docs/RoadMapDocs.js +171 -0
  141. package/dist/docs/SearchSelectInputDocs.d.ts +4 -0
  142. package/dist/docs/SearchSelectInputDocs.d.ts.map +1 -0
  143. package/dist/docs/SearchSelectInputDocs.js +168 -0
  144. package/dist/docs/SnackbarDocs.d.ts +4 -0
  145. package/dist/docs/SnackbarDocs.d.ts.map +1 -0
  146. package/dist/docs/SnackbarDocs.js +50 -0
  147. package/dist/docs/TabsGroupDocs.d.ts.map +1 -1
  148. package/dist/docs/TabsGroupDocs.js +12 -1
  149. package/dist/docs/docMockServices/empresaService.d.ts +38 -0
  150. package/dist/docs/docMockServices/empresaService.d.ts.map +1 -0
  151. package/dist/docs/docMockServices/empresaService.js +116 -0
  152. package/dist/docs/docMockServices/index.d.ts +9 -0
  153. package/dist/docs/docMockServices/index.d.ts.map +1 -0
  154. package/dist/docs/docMockServices/index.js +8 -0
  155. package/dist/docs/docMockServices/initialData.d.ts +6 -0
  156. package/dist/docs/docMockServices/initialData.d.ts.map +1 -0
  157. package/dist/docs/docMockServices/initialData.js +132 -0
  158. package/dist/docs/docMockServices/interfaces.d.ts +26 -0
  159. package/dist/docs/docMockServices/interfaces.d.ts.map +1 -0
  160. package/dist/docs/docMockServices/interfaces.js +1 -0
  161. package/dist/docs/docMockServices/personaEmpresaService.d.ts +43 -0
  162. package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +1 -0
  163. package/dist/docs/docMockServices/personaEmpresaService.js +113 -0
  164. package/dist/docs/docMockServices/personaService.d.ts +39 -0
  165. package/dist/docs/docMockServices/personaService.d.ts.map +1 -0
  166. package/dist/docs/docMockServices/personaService.js +180 -0
  167. package/dist/hooks/index.d.ts +2 -0
  168. package/dist/hooks/index.d.ts.map +1 -1
  169. package/dist/hooks/index.js +1 -0
  170. package/dist/hooks/useAsyncRequest.d.ts +17 -0
  171. package/dist/hooks/useAsyncRequest.d.ts.map +1 -0
  172. package/dist/hooks/useAsyncRequest.js +70 -0
  173. package/dist/index.css +1 -1
  174. package/dist/index.d.ts +22 -0
  175. package/dist/index.d.ts.map +1 -1
  176. package/dist/index.js +11 -0
  177. package/dist/index.js.map +1 -1
  178. package/package.json +5 -2
@@ -1,9 +1,20 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useState, useRef } from "react";
3
3
  import { useBreakpoint } from "../../hooks";
4
4
  import { useElementScroll } from "../../hooks/useElementScroll";
5
5
  import { Button } from "../form-controls";
6
- export const AppLayout = ({ navBarDrawer, leftDrawer, children, className = "", }) => {
6
+ export const AppLayout = ({ navbar, leftDrawer, children, className = "", }) => {
7
+ // Extract values from interfaces
8
+ const navBarLeftNode = navbar?.navBarLeftNode;
9
+ const navBarRightNode = navbar?.navBarRightNode;
10
+ const fullWidthNavbar = navbar?.fullWidthNavbar ?? true;
11
+ const navbarHeight = navbar?.height ?? "64px";
12
+ const navbarClassName = navbar?.className || "";
13
+ const leftDrawerHeader = leftDrawer?.headerNode;
14
+ const leftDrawerContent = leftDrawer?.contentNode;
15
+ const leftDrawerFooter = leftDrawer?.footerNode;
16
+ const leftDrawerClassName = leftDrawer?.className || "";
17
+ const leftDrawerWidth = leftDrawer?.width;
7
18
  const { isMobile, isTablet } = useBreakpoint();
8
19
  const contentRef = useRef(null);
9
20
  const { scrollY, scrollDirection } = useElementScroll(contentRef);
@@ -12,8 +23,15 @@ export const AppLayout = ({ navBarDrawer, leftDrawer, children, className = "",
12
23
  const isNavbarVisibleRef = useRef(isNavbarVisible);
13
24
  const isTransitioningRef = useRef(false);
14
25
  const lastScrollYRef = useRef(0);
26
+ // Determinar si hay algún contenido en el drawer izquierdo
27
+ const hasLeftDrawerContent = leftDrawerHeader || leftDrawerContent || leftDrawerFooter;
15
28
  const shouldShowMobileDrawer = isMobile || isTablet;
16
- const shouldShowDesktopDrawer = !shouldShowMobileDrawer && leftDrawer;
29
+ const shouldShowDesktopDrawer = !shouldShowMobileDrawer && hasLeftDrawerContent;
30
+ // Determinar si debemos mostrar el navbar
31
+ // Se muestra si hay navBarLeftNode o navBarRightNode o si estamos en móvil/tablet con contenido en el drawer
32
+ const shouldShowNavbar = navBarLeftNode ||
33
+ navBarRightNode ||
34
+ (shouldShowMobileDrawer && hasLeftDrawerContent);
17
35
  // Mantener el ref sincronizado con el estado
18
36
  React.useEffect(() => {
19
37
  isNavbarVisibleRef.current = isNavbarVisible;
@@ -48,7 +66,9 @@ export const AppLayout = ({ navBarDrawer, leftDrawer, children, className = "",
48
66
  // Siempre mostrar navbar cerca del top
49
67
  shouldBeVisible = true;
50
68
  }
51
- else if (scrollDirection === "down" && scrollY > HIDE_THRESHOLD && !isNearBottom) {
69
+ else if (scrollDirection === "down" &&
70
+ scrollY > HIDE_THRESHOLD &&
71
+ !isNearBottom) {
52
72
  // Ocultar navbar al hacer scroll hacia abajo, excepto si estamos cerca del final
53
73
  shouldBeVisible = false;
54
74
  }
@@ -87,36 +107,84 @@ export const AppLayout = ({ navBarDrawer, leftDrawer, children, className = "",
87
107
  ${className}
88
108
  `;
89
109
  // Clases del navbar
90
- const navbarClasses = `
91
- bg-[var(--color-bg-default)] border-b border-[var(--color-border-default)]
92
- z-[1000] fixed top-0 left-0 right-0
93
- transform transition-transform duration-300 ease-in-out
94
- ${isNavbarVisible ? "translate-y-0" : "-translate-y-full"}
95
- `;
96
- // Estilos inline para debug
97
- const navbarStyle = {
98
- transform: isNavbarVisible ? "translateY(0)" : "translateY(-100%)",
99
- transition: "transform 300ms ease-in-out",
110
+ const navbarClasses = `${fullWidthNavbar
111
+ ? `z-[1000] fixed top-0 left-0 right-0 overflow-hidden`
112
+ : `relative z-[1000] overflow-hidden`} ${navbarClassName}`.trim();
113
+ // Estilos inline para la transformación
114
+ // Cuando fullWidthNavbar es false, solo usamos height para ocultar (sin transform)
115
+ // Cuando fullWidthNavbar es true, usamos transform para ocultar (manteniendo height)
116
+ const navbarStyle = fullWidthNavbar
117
+ ? {
118
+ transform: isNavbarVisible ? "translateY(0)" : "translateY(-100%)",
119
+ transition: "transform 300ms ease-in-out",
120
+ willChange: "transform",
121
+ height: navbarHeight, // Override any height classes in className
122
+ }
123
+ : {
124
+ height: isNavbarVisible ? navbarHeight : "0",
125
+ minHeight: isNavbarVisible ? navbarHeight : "0",
126
+ maxHeight: isNavbarVisible ? navbarHeight : "0",
127
+ transition: "height 300ms ease-in-out, min-height 300ms ease-in-out, max-height 300ms ease-in-out",
128
+ overflow: "hidden",
129
+ };
130
+ const navbarContentClasses = `flex items-center justify-between gap-2`;
131
+ // Style for navbar content with dynamic height
132
+ // When fullWidthNavbar is false and hidden, set height to 0 to not occupy space
133
+ // When fullWidthNavbar is true, always maintain height to prevent layout shifts
134
+ const navbarContentStyle = {
135
+ height: fullWidthNavbar || isNavbarVisible ? navbarHeight : "0",
136
+ maxHeight: fullWidthNavbar || isNavbarVisible ? navbarHeight : "0",
137
+ overflow: "hidden",
138
+ transition: "height 300ms ease-in-out, max-height 300ms ease-in-out",
139
+ opacity: isNavbarVisible || fullWidthNavbar ? 1 : 0,
100
140
  };
101
- const navbarContentClasses = `
102
- flex items-center pr-4 lg:px-4 h-16 gap-2
103
- md:px-3
104
- `;
105
- const navbarDrawerClasses = `flex-1`;
141
+ const navbarLeftClasses = `flex items-center gap-2`;
142
+ const navbarRightClasses = `flex items-center gap-2`;
106
143
  // Clases del contenido principal
107
- const mainClasses = `
108
- flex flex-1 overflow-hidden
109
- transition-all duration-300 ease-in-out
110
- ${navBarDrawer && isNavbarVisible ? "pt-16" : ""}
111
- `;
144
+ const mainClasses = `flex flex-1 overflow-hidden transition-all duration-300 ease-in-out`;
145
+ // Style for main content with dynamic navbar height padding
146
+ const mainStyle = fullWidthNavbar && shouldShowNavbar && isNavbarVisible
147
+ ? { paddingTop: navbarHeight }
148
+ : {};
149
+ // Clases del drawer izquierdo (contenedor principal)
150
+ // width se aplica como estilo inline para tener prioridad sobre className
112
151
  const leftDrawerClasses = `
113
- w-64 bg-[var(--color-bg-default)]
114
- overflow-y-auto flex-shrink-0 p-4
152
+ ${leftDrawerWidth ? "" : "w-64"} bg-[var(--color-bg-default)]
153
+ flex-shrink-0 flex flex-col
115
154
  transition-all duration-300 ease-in-out
116
- ${navBarDrawer && isNavbarVisible ? "pt-20" : "pt-4"}
155
+ ${fullWidthNavbar && shouldShowNavbar && isNavbarVisible ? "pt-4" : "h-full"}
156
+ ${leftDrawerClassName}
157
+ `
158
+ .trim()
159
+ .replace(/\s+/g, " ");
160
+ // Style for left drawer with dynamic width
161
+ const leftDrawerStyle = leftDrawerWidth ? { width: leftDrawerWidth } : {};
162
+ // Clases del contenedor que incluye drawer y contenido (cuando fullWidthNavbar es false)
163
+ const contentWrapperClasses = fullWidthNavbar
164
+ ? ""
165
+ : `flex flex-row flex-1 overflow-hidden`;
166
+ // Clases del contenedor que incluye navbar y main (cuando fullWidthNavbar es false)
167
+ const drawerAndContentClasses = fullWidthNavbar
168
+ ? ""
169
+ : `flex flex-col flex-1 overflow-hidden`;
170
+ // Style for drawer and content wrapper with dynamic navbar height padding
171
+ const drawerAndContentStyle = !fullWidthNavbar && shouldShowNavbar && isNavbarVisible
172
+ ? { paddingTop: 0 }
173
+ : {};
174
+ // Clases del header del drawer (fijo arriba)
175
+ const leftDrawerHeaderClasses = `
176
+ flex-shrink-0
177
+ `;
178
+ // Clases del contenido del drawer (scrolleable sin scrollbar visible)
179
+ const leftDrawerContentClasses = `
180
+ flex-1 overflow-y-auto scrollbar-hide
181
+ `;
182
+ // Clases del footer del drawer (fijo abajo)
183
+ const leftDrawerFooterClasses = `
184
+ flex-shrink-0
117
185
  `;
118
186
  const contentClasses = `
119
- flex-1 overflow-y-auto px-2 py-4 lg:px-6
187
+ flex-1 overflow-y-auto px-2 pb-4 lg:px-6 pt-4
120
188
  `;
121
189
  // Clases del overlay móvil
122
190
  const overlayClasses = `
@@ -128,10 +196,15 @@ export const AppLayout = ({ navBarDrawer, leftDrawer, children, className = "",
128
196
  bg-[var(--color-bg-default)] shadow-[var(--shadow-xl)]
129
197
  transform -translate-x-full transition-transform duration-300 ease-in-out
130
198
  z-[1999] flex flex-col
131
- `;
199
+ ${leftDrawerClassName}
200
+ `
201
+ .trim()
202
+ .replace(/\s+/g, " ");
203
+ // Style for mobile drawer with dynamic width
204
+ const mobileDrawerStyle = leftDrawerWidth ? { width: leftDrawerWidth } : {};
132
205
  const mobileDrawerOpenClasses = `translate-x-0`;
133
206
  const mobileDrawerContentClasses = `
134
- flex-1 overflow-y-auto p-4
207
+ flex-1 overflow-y-auto scrollbar-hide
135
208
  `;
136
- 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 })] }))] }));
209
+ return (_jsxs("div", { className: layoutClasses, children: [fullWidthNavbar ? (_jsxs(_Fragment, { children: [shouldShowNavbar && (_jsx("nav", { className: navbarClasses, style: navbarStyle, children: _jsxs("div", { className: navbarContentClasses, style: navbarContentStyle, children: [_jsxs("div", { className: navbarLeftClasses, children: [shouldShowMobileDrawer && hasLeftDrawerContent && (_jsx("div", { className: "pr-4 lg:px-4 md:px-3", children: _jsx(Button, { variant: "ghost", icon: "fa-bars", onClick: handleMobileDrawerToggle, "aria-label": "Abrir men\u00FA" }) })), navBarLeftNode && (_jsx("div", { children: typeof navBarLeftNode === "string" ? (_jsx("span", { children: navBarLeftNode })) : (navBarLeftNode) }))] }), navBarRightNode && (_jsx("div", { className: navbarRightClasses, children: typeof navBarRightNode === "string" ? (_jsx("span", { children: navBarRightNode })) : (navBarRightNode) }))] }) })), _jsxs("div", { className: mainClasses, style: mainStyle, children: [shouldShowDesktopDrawer && (_jsxs("aside", { className: leftDrawerClasses, style: leftDrawerStyle, children: [leftDrawerHeader && (_jsx("div", { className: leftDrawerHeaderClasses, children: leftDrawerHeader })), leftDrawerContent && (_jsx("div", { className: leftDrawerContentClasses, children: leftDrawerContent })), leftDrawerFooter && (_jsx("div", { className: leftDrawerFooterClasses, children: leftDrawerFooter }))] })), _jsx("main", { ref: contentRef, className: contentClasses, children: children })] })] })) : (_jsx(_Fragment, { children: _jsxs("div", { className: contentWrapperClasses, children: [shouldShowDesktopDrawer && (_jsxs("aside", { className: leftDrawerClasses, style: leftDrawerStyle, children: [leftDrawerHeader && (_jsx("div", { className: leftDrawerHeaderClasses, children: leftDrawerHeader })), leftDrawerContent && (_jsx("div", { className: leftDrawerContentClasses, children: leftDrawerContent })), leftDrawerFooter && (_jsx("div", { className: leftDrawerFooterClasses, children: leftDrawerFooter }))] })), _jsxs("div", { className: drawerAndContentClasses, style: drawerAndContentStyle, children: [shouldShowNavbar && (_jsx("nav", { className: navbarClasses, style: navbarStyle, children: _jsxs("div", { className: navbarContentClasses, style: navbarContentStyle, children: [_jsxs("div", { className: navbarLeftClasses, children: [shouldShowMobileDrawer && hasLeftDrawerContent && (_jsx("div", { className: "pr-4 lg:px-4 md:px-3", children: _jsx(Button, { variant: "ghost", icon: "fa-bars", onClick: handleMobileDrawerToggle, "aria-label": "Abrir men\u00FA" }) })), navBarLeftNode && (_jsx("div", { children: typeof navBarLeftNode === "string" ? (_jsx("span", { children: navBarLeftNode })) : (navBarLeftNode) }))] }), navBarRightNode && (_jsx("div", { className: navbarRightClasses, children: typeof navBarRightNode === "string" ? (_jsx("span", { children: navBarRightNode })) : (navBarRightNode) }))] }) })), _jsx("main", { ref: contentRef, className: contentClasses, children: children })] })] }) })), shouldShowMobileDrawer && hasLeftDrawerContent && isMobileDrawerOpen && (_jsx("div", { className: overlayClasses, onClick: handleOverlayClick })), shouldShowMobileDrawer && hasLeftDrawerContent && (_jsxs("aside", { className: `${mobileDrawerBaseClasses} ${isMobileDrawerOpen ? mobileDrawerOpenClasses : ""}`, style: mobileDrawerStyle, children: [_jsxs("div", { className: "flex-shrink-0 flex items-center justify-between", children: [leftDrawerHeader ? (_jsx("div", { className: "flex-1", children: leftDrawerHeader })) : (_jsx("div", { className: "flex-1" })), _jsx("div", { className: "p-4", children: _jsx(Button, { variant: "ghost", icon: "fa-times", onClick: handleMobileDrawerToggle, "aria-label": "Cerrar men\u00FA" }) })] }), leftDrawerContent && (_jsx("div", { className: mobileDrawerContentClasses, children: leftDrawerContent })), leftDrawerFooter && (_jsx("div", { className: "flex-shrink-0", children: leftDrawerFooter }))] }))] }));
137
210
  };
@@ -4,7 +4,10 @@ export interface CardProps {
4
4
  subtitle?: string | React.ReactNode;
5
5
  children: React.ReactNode;
6
6
  className?: string;
7
- headerActions?: React.ReactNode;
7
+ /**
8
+ * Acciones para el header de la tarjeta. Retorna un array de ReactNode que se mostrarán en un DropdownMenu.
9
+ */
10
+ headerActions?: () => Array<React.ReactNode>;
8
11
  footer?: React.ReactNode;
9
12
  variant?: "default" | "elevated" | "outlined";
10
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;CAC/C;AAED,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CAsEpC,CAAC"}
1
+ {"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;CAC/C;AAED,eAAO,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,SAAS,CA6HpC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React from "react";
3
+ import { DropdownMenu } from "../utils/DropdownMenu";
3
4
  export const Card = ({ title, subtitle, children, className = "", headerActions, footer, variant = "default", }) => {
4
5
  // Separar clases de background del className
5
6
  const classArray = className.trim().split(/\s+/).filter(Boolean);
@@ -25,5 +26,33 @@ export const Card = ({ title, subtitle, children, className = "", headerActions,
25
26
  outlined: `border-[var(--color-gray-300)]`,
26
27
  };
27
28
  const classes = `${baseClasses} ${variantClasses[variant]} ${otherClasses.join(" ")}`;
28
- return (_jsxs("div", { className: classes, children: [(title || subtitle || headerActions) && (_jsx("div", { className: "px-6 pt-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [title && (_jsx("h3", { className: "text-lg font-semibold text-[var(--color-text-primary)]", children: title })), subtitle && (_jsx("p", { className: "text-sm text-[var(--color-text-secondary)] mt-1", children: subtitle }))] }), headerActions && (_jsx("div", { className: "flex items-center space-x-2", children: headerActions }))] }) })), _jsx("div", { className: "px-6 py-4", children: children }), footer && _jsx("div", { className: "px-6 pb-4", children: footer })] }));
29
+ // Convertir array de ReactNode a array de ActionItem para DropdownMenu
30
+ const convertActionsToOptions = (actions) => {
31
+ return actions.map((action, index) => ({
32
+ id: index,
33
+ content: (_jsx("div", { onClick: (e) => {
34
+ // Detener la propagación para que el onClick del DropdownMenu no interfiera
35
+ e.stopPropagation();
36
+ }, children: action })),
37
+ }));
38
+ };
39
+ const headerActionsArray = headerActions?.();
40
+ const hasHeaderActions = headerActionsArray && headerActionsArray.length > 0;
41
+ const [isHovered, setIsHovered] = React.useState(false);
42
+ const [isLargeScreen, setIsLargeScreen] = React.useState(false);
43
+ React.useEffect(() => {
44
+ const checkScreenSize = () => {
45
+ setIsLargeScreen(window.innerWidth >= 1024);
46
+ };
47
+ checkScreenSize();
48
+ window.addEventListener("resize", checkScreenSize);
49
+ return () => {
50
+ window.removeEventListener("resize", checkScreenSize);
51
+ };
52
+ }, []);
53
+ return (_jsxs("div", { className: `${classes} relative`, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [(title || subtitle || hasHeaderActions) && (_jsx("div", { className: "px-6 pt-4", children: _jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { children: [title && (_jsx("h3", { className: "text-lg font-semibold text-[var(--color-text-primary)]", children: title })), subtitle && (_jsx("p", { className: "text-sm text-[var(--color-text-secondary)] mt-1", children: subtitle }))] }) }) })), hasHeaderActions && (_jsx("div", { className: "absolute top-2 right-2 transition-opacity", style: {
54
+ opacity: isLargeScreen ? (isHovered ? 1 : 0) : 1,
55
+ }, children: _jsx(DropdownMenu, { options: convertActionsToOptions(headerActionsArray), onOptionSelected: () => {
56
+ // Las acciones ya manejan sus propios eventos
57
+ }, renderOption: (item) => item.content, replaceOnSingleOption: true }) })), _jsx("div", { className: "px-6 py-4", children: children }), footer && _jsx("div", { className: "px-6 pb-4", children: footer })] }));
29
58
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React from "react";
3
- export const Collection = ({ children, gap = "0", direction = "column", wrap = false, className = "", }) => {
3
+ export const Collection = ({ children, gap = "1rem", direction = "column", wrap = false, className = "", }) => {
4
4
  const baseClasses = `
5
5
  flex
6
6
  font-[var(--font-default)]
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ export interface DataTableColumn<T> {
3
+ align?: "left" | "right" | "center";
4
+ width?: string;
5
+ header?: string | React.ReactNode;
6
+ footer?: string | React.ReactNode;
7
+ value?: string | number | ((row: T) => string | React.ReactNode);
8
+ tooltip?: (row: T) => string | React.ReactNode;
9
+ type?: "text" | "numeric" | "currency" | "date";
10
+ /**
11
+ * Acciones para cada fila. Retorna un array de ReactNode que se mostrarán en un DropdownMenu.
12
+ */
13
+ actions?: (row: T) => Array<React.ReactNode>;
14
+ /**
15
+ * Acciones para el header de la columna. Retorna un array de ReactNode que se mostrarán en un DropdownMenu.
16
+ */
17
+ headerActions?: () => Array<React.ReactNode>;
18
+ }
19
+ export interface DataTableProps<T> {
20
+ columns: DataTableColumn<T>[];
21
+ rows: T[];
22
+ className?: string;
23
+ maxRows?: number;
24
+ locale?: string;
25
+ isLoading?: boolean;
26
+ loadingRows?: number;
27
+ }
28
+ export declare const DataTable: <T>({ columns, rows, className, maxRows, locale, isLoading, loadingRows, }: DataTableProps<T>) => import("react/jsx-runtime").JSX.Element;
29
+ //# sourceMappingURL=DataTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataTable.d.ts","sourceRoot":"","sources":["../../../src/components/layout/DataTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACjE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IAC/C,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IAChD;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7C;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9B,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,EAAG,wEAQ3B,cAAc,CAAC,CAAC,CAAC,4CAgTnB,CAAC"}
@@ -0,0 +1,165 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { DropdownMenu } from "../utils/DropdownMenu";
4
+ export const DataTable = ({ columns, rows, className = "", maxRows, locale = "es-AR", isLoading = false, loadingRows = 5, }) => {
5
+ // Calcular si necesitamos scroll
6
+ const displayRows = isLoading ? loadingRows : rows.length;
7
+ const needsScroll = maxRows !== undefined && displayRows > maxRows;
8
+ // Altura aproximada de una fila (px-4 py-3 = ~48px por fila)
9
+ const rowHeight = 48;
10
+ const maxHeight = maxRows ? `${maxRows * rowHeight}px` : undefined;
11
+ // Verificar si alguna columna tiene footer
12
+ const hasFooter = columns.some((column) => column.footer !== undefined);
13
+ const getCellValue = (column, row) => {
14
+ if (!column.value)
15
+ return null;
16
+ if (typeof column.value === "function") {
17
+ return column.value(row);
18
+ }
19
+ // Si es string o number, puede ser un nombre de propiedad o un valor directo
20
+ if (typeof column.value === "string" || typeof column.value === "number") {
21
+ // Intentar obtener la propiedad del objeto si existe
22
+ if (typeof column.value === "string" &&
23
+ typeof row === "object" &&
24
+ row !== null) {
25
+ const value = row[column.value];
26
+ if (value !== undefined) {
27
+ return value;
28
+ }
29
+ }
30
+ // Si no es una propiedad, retornar el valor directo
31
+ return column.value;
32
+ }
33
+ return column.value;
34
+ };
35
+ const formatValue = (value, type) => {
36
+ if (React.isValidElement(value)) {
37
+ return value;
38
+ }
39
+ // Convertir string a número si es necesario para currency o numeric
40
+ let numericValue = null;
41
+ if (typeof value === "number") {
42
+ numericValue = value;
43
+ }
44
+ else if (typeof value === "string" &&
45
+ (type === "currency" || type === "numeric")) {
46
+ const parsed = parseFloat(value);
47
+ if (!isNaN(parsed)) {
48
+ numericValue = parsed;
49
+ }
50
+ }
51
+ if (numericValue !== null) {
52
+ if (type === "currency") {
53
+ // Formatear usando el locale proporcionado sin símbolo de moneda
54
+ const parts = new Intl.NumberFormat(locale, {
55
+ style: "currency",
56
+ currency: "EUR",
57
+ minimumFractionDigits: 2,
58
+ maximumFractionDigits: 2,
59
+ }).formatToParts(numericValue);
60
+ // Construir el string sin el símbolo de moneda
61
+ return parts
62
+ .filter((part) => part.type !== "currency")
63
+ .map((part) => part.value)
64
+ .join("");
65
+ }
66
+ if (type === "numeric") {
67
+ // Formatear usando el locale proporcionado
68
+ const hasDecimals = numericValue % 1 !== 0;
69
+ return new Intl.NumberFormat(locale, {
70
+ minimumFractionDigits: hasDecimals ? 2 : 0,
71
+ maximumFractionDigits: hasDecimals ? 2 : 0,
72
+ }).format(numericValue);
73
+ }
74
+ }
75
+ if (typeof value === "string" && type === "date") {
76
+ try {
77
+ const date = new Date(value);
78
+ return date.toLocaleDateString(locale);
79
+ }
80
+ catch {
81
+ return value;
82
+ }
83
+ }
84
+ return value;
85
+ };
86
+ const getAlignmentClass = (align, type) => {
87
+ // Las columnas de tipo 'date' siempre se alinean a la izquierda
88
+ // Las columnas de tipo 'currency' y 'numeric' siempre se alinean a la derecha
89
+ let effectiveAlign = align;
90
+ if (type === "date") {
91
+ effectiveAlign = "left";
92
+ }
93
+ else if (type === "currency" || type === "numeric") {
94
+ effectiveAlign = "right";
95
+ }
96
+ switch (effectiveAlign) {
97
+ case "right":
98
+ return "text-right";
99
+ case "center":
100
+ return "text-center";
101
+ case "left":
102
+ default:
103
+ return "text-left";
104
+ }
105
+ };
106
+ // Convertir array de ReactNode a array de ActionItem para DropdownMenu
107
+ const convertActionsToOptions = (actions) => {
108
+ return actions.map((action, index) => ({
109
+ id: index,
110
+ content: (_jsx("div", { onClick: (e) => {
111
+ // Detener la propagación para que el onClick del DropdownMenu no interfiera
112
+ e.stopPropagation();
113
+ }, children: action })),
114
+ }));
115
+ };
116
+ // Componente Skeleton para celdas de carga
117
+ const SkeletonCell = () => (_jsx("div", { className: "h-4 bg-[var(--color-border-default)]/40 rounded animate-pulse w-full" }));
118
+ return (_jsx("div", { className: `overflow-x-auto ${className}`, children: _jsx("div", { className: needsScroll ? "relative overflow-y-auto" : "", style: needsScroll && maxHeight ? { maxHeight: maxHeight } : undefined, children: _jsxs("table", { className: "w-full border-collapse font-[var(--font-default)]", children: [_jsx("thead", { className: needsScroll ? "sticky top-0 z-10" : "", children: _jsx("tr", { className: "border-b border-[var(--color-border-default)]", children: columns.map((column, index) => {
119
+ const headerActions = column.headerActions?.();
120
+ const hasHeaderActions = headerActions && headerActions.length > 0;
121
+ return (_jsx("th", { className: `
122
+ px-4 py-3 text-sm font-semibold text-[var(--color-text-primary)]
123
+ bg-[var(--color-bg-secondary)]
124
+ ${getAlignmentClass(column.align, column.type)}
125
+ ${hasHeaderActions ? "relative" : ""}
126
+ `, style: {
127
+ ...(column.width ? { width: column.width } : {}),
128
+ }, children: isLoading ? (_jsx(SkeletonCell, {})) : hasHeaderActions ? (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { children: column.header || "" }), _jsx(DropdownMenu, { options: convertActionsToOptions(headerActions), onOptionSelected: () => {
129
+ // Las acciones ya manejan sus propios eventos
130
+ }, renderOption: (item) => item.content, replaceOnSingleOption: true })] })) : (column.header || "") }, index));
131
+ }) }) }), _jsx("tbody", { children: isLoading
132
+ ? Array.from({ length: loadingRows }).map((_, rowIndex) => (_jsx("tr", { className: "border-b border-[var(--color-border-default)]", children: columns.map((column, colIndex) => (_jsx("td", { className: `
133
+ px-4 py-3 text-sm text-[var(--color-text-primary)]
134
+ ${getAlignmentClass(column.align, column.type)}
135
+ `, style: {
136
+ ...(column.width ? { width: column.width } : {}),
137
+ }, children: _jsx(SkeletonCell, {}) }, colIndex))) }, `skeleton-${rowIndex}`)))
138
+ : rows.map((row, rowIndex) => (_jsx("tr", { className: "group/row border-b border-[var(--color-border-default)] transition-colors hover:bg-[var(--color-bg-secondary)]", children: columns.map((column, colIndex) => {
139
+ const cellValue = getCellValue(column, row);
140
+ const formattedValue = formatValue(cellValue, column.type);
141
+ const tooltip = column.tooltip
142
+ ? column.tooltip(row)
143
+ : undefined;
144
+ const rowActions = column.actions?.(row);
145
+ const hasRowActions = rowActions && rowActions.length > 0;
146
+ return (_jsx("td", { className: `
147
+ px-4 py-3 text-sm text-[var(--color-text-primary)]
148
+ ${getAlignmentClass(column.align, column.type)}
149
+ `, style: {
150
+ ...(column.width ? { width: column.width } : {}),
151
+ }, title: tooltip
152
+ ? typeof tooltip === "string"
153
+ ? tooltip
154
+ : undefined
155
+ : undefined, children: hasRowActions ? (_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { children: formattedValue }), _jsx("div", { className: "lg:opacity-0 lg:group-hover/row:opacity-100 transition-opacity", children: _jsx(DropdownMenu, { options: convertActionsToOptions(rowActions), onOptionSelected: () => {
156
+ // Las acciones ya manejan sus propios eventos
157
+ }, renderOption: (item) => item.content, replaceOnSingleOption: true }) })] })) : (formattedValue) }, colIndex));
158
+ }) }, rowIndex))) }), hasFooter && (_jsx("tfoot", { className: needsScroll ? "sticky bottom-0 z-10" : "", children: _jsx("tr", { className: "border-t border-[var(--color-border-default)]", children: columns.map((column, index) => (_jsx("td", { className: `
159
+ px-4 py-3 text-sm font-semibold text-[var(--color-text-primary)]
160
+ bg-[var(--color-bg-secondary)]
161
+ ${getAlignmentClass(column.align, column.type)}
162
+ `, style: {
163
+ ...(column.width ? { width: column.width } : {}),
164
+ }, children: isLoading ? _jsx(SkeletonCell, {}) : column.footer || "" }, index))) }) }))] }) }) }));
165
+ };
@@ -10,4 +10,6 @@ export { TabsGroup } from "./TabsGroup";
10
10
  export type { TabsGroupProps, Tab } from "./TabsGroup";
11
11
  export { TabPanel } from "./TabPanel";
12
12
  export type { TabPanelProps } from "./TabPanel";
13
+ export { DataTable } from "./DataTable";
14
+ export type { DataTableProps, DataTableColumn } from "./DataTable";
13
15
  //# 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;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,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;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
@@ -4,3 +4,4 @@ export { Collection } from "./Collection";
4
4
  export { DataField } from "./DataField";
5
5
  export { TabsGroup } from "./TabsGroup";
6
6
  export { TabPanel } from "./TabPanel";
7
+ export { DataTable } from "./DataTable";
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ export interface AvatarProps {
3
+ /**
4
+ * Text to extract initials from
5
+ * The component will show the first letter of the first word
6
+ * and the first letter of the last word if there are multiple words
7
+ */
8
+ text: string;
9
+ /**
10
+ * Optional image URL to display instead of initials
11
+ */
12
+ image?: string;
13
+ /**
14
+ * Optional background color (hexadecimal, rgb, or color name)
15
+ * Default: gray-600 (#4b5563)
16
+ */
17
+ bgColor?: string;
18
+ /**
19
+ * Optional text color (hexadecimal, rgb, or color name)
20
+ * Default: white (#ffffff)
21
+ */
22
+ textColor?: string;
23
+ /**
24
+ * Optional size variant
25
+ * Default: md
26
+ */
27
+ size?: "sm" | "md" | "lg";
28
+ /**
29
+ * Optional additional CSS classes
30
+ */
31
+ className?: string;
32
+ }
33
+ /**
34
+ * Avatar component displays a circular avatar with initials or an image
35
+ *
36
+ * @example
37
+ * // Basic usage with text
38
+ * <Avatar text="John Doe" />
39
+ *
40
+ * @example
41
+ * // With image
42
+ * <Avatar text="John Doe" image="https://example.com/avatar.jpg" />
43
+ *
44
+ * @example
45
+ * // Custom colors
46
+ * <Avatar text="Jane Smith" bgColor="#3b82f6" textColor="#ffffff" />
47
+ */
48
+ export declare const Avatar: React.FC<AvatarProps>;
49
+ //# sourceMappingURL=Avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../../src/components/utils/Avatar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAuDxC,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA2DxC,CAAC"}
@@ -0,0 +1,93 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useState } from "react";
3
+ /**
4
+ * Helper function to convert color names to CSS values
5
+ */
6
+ const getColorValue = (color) => {
7
+ if (!color)
8
+ return undefined;
9
+ // If already a valid CSS value (hex, rgb, rgba, hsl, etc.), return it
10
+ if (color.startsWith("#") ||
11
+ color.startsWith("rgb") ||
12
+ color.startsWith("hsl")) {
13
+ return color;
14
+ }
15
+ // Map common color names
16
+ const colorMap = {
17
+ white: "#ffffff",
18
+ black: "#000000",
19
+ "gray-800": "#1f2937",
20
+ "gray-700": "#374151",
21
+ "gray-600": "#4b5563",
22
+ "gray-500": "#6b7280",
23
+ "gray-400": "#9ca3af",
24
+ "gray-300": "#d1d5db",
25
+ "gray-200": "#e5e7eb",
26
+ "gray-100": "#f3f4f6",
27
+ "gray-50": "#f9fafb",
28
+ };
29
+ return colorMap[color.toLowerCase()] || color;
30
+ };
31
+ /**
32
+ * Helper function to extract initials from text
33
+ * Returns first letter of first word and first letter of last word (if multiple words)
34
+ */
35
+ const getInitials = (text) => {
36
+ if (!text || text.trim().length === 0)
37
+ return "";
38
+ const words = text.trim().split(/\s+/);
39
+ if (words.length === 0)
40
+ return "";
41
+ const firstLetter = words[0].charAt(0).toUpperCase();
42
+ if (words.length === 1) {
43
+ return firstLetter;
44
+ }
45
+ const lastLetter = words[words.length - 1].charAt(0).toUpperCase();
46
+ return `${firstLetter}${lastLetter}`;
47
+ };
48
+ /**
49
+ * Avatar component displays a circular avatar with initials or an image
50
+ *
51
+ * @example
52
+ * // Basic usage with text
53
+ * <Avatar text="John Doe" />
54
+ *
55
+ * @example
56
+ * // With image
57
+ * <Avatar text="John Doe" image="https://example.com/avatar.jpg" />
58
+ *
59
+ * @example
60
+ * // Custom colors
61
+ * <Avatar text="Jane Smith" bgColor="#3b82f6" textColor="#ffffff" />
62
+ */
63
+ export const Avatar = ({ text, image, bgColor = "gray-600", textColor = "white", size = "md", className = "", }) => {
64
+ const [imageError, setImageError] = useState(false);
65
+ const initials = getInitials(text);
66
+ const showImage = image && !imageError;
67
+ const sizeClasses = {
68
+ sm: "w-8 h-8 text-xs",
69
+ md: "w-10 h-10 text-sm",
70
+ lg: "w-12 h-12 text-base",
71
+ };
72
+ const baseClasses = `
73
+ rounded-full
74
+ flex
75
+ items-center
76
+ justify-center
77
+ font-semibold
78
+ font-[var(--font-default)]
79
+ overflow-hidden
80
+ flex-shrink-0
81
+ ${sizeClasses[size]}
82
+ ${className}
83
+ `;
84
+ // Inline styles for colors (only if no image or image failed to load)
85
+ const inlineStyles = showImage
86
+ ? {}
87
+ : {
88
+ backgroundColor: getColorValue(bgColor) || bgColor || "#4b5563",
89
+ color: getColorValue(textColor) || textColor || "#ffffff",
90
+ };
91
+ return (_jsx("div", { className: baseClasses, style: inlineStyles, title: text, role: "img", "aria-label": text, children: showImage ? (_jsx("img", { src: image, alt: text, className: "w-full h-full object-cover", onError: () => setImageError(true) })) : (_jsx("span", { children: initials })) }));
92
+ };
93
+ Avatar.displayName = "Avatar";
@@ -8,6 +8,9 @@ export interface BadgeProps {
8
8
  icon?: string;
9
9
  iconPosition?: "left" | "right";
10
10
  iconLabel?: string;
11
+ bg?: string;
12
+ textColor?: string;
13
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
11
14
  }
12
15
  export declare const Badge: React.FC<BadgeProps>;
13
16
  //# sourceMappingURL=Badge.d.ts.map