flysoft-react-ui 1.2.4 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/AI_CONTEXT.md +1400 -217
  2. package/AI_INTEGRATION_GUIDE.md +343 -0
  3. package/INTEGRATION_GUIDE.md +60 -0
  4. package/README.md +5 -3
  5. package/dist/components/form-controls/Input.d.ts.map +1 -1
  6. package/dist/components/layout/Accordion.d.ts +1 -0
  7. package/dist/components/layout/Accordion.d.ts.map +1 -1
  8. package/dist/components/layout/DataTable.d.ts.map +1 -1
  9. package/dist/components/layout/DropdownMenu.d.ts +2 -1
  10. package/dist/components/layout/DropdownMenu.d.ts.map +1 -1
  11. package/dist/components/layout/DropdownPanel.d.ts +2 -1
  12. package/dist/components/layout/DropdownPanel.d.ts.map +1 -1
  13. package/dist/components/layout/Filter.d.ts +1 -0
  14. package/dist/components/layout/Filter.d.ts.map +1 -1
  15. package/dist/components/layout/Menu.d.ts +2 -1
  16. package/dist/components/layout/Menu.d.ts.map +1 -1
  17. package/dist/components/layout/TabsGroup.d.ts +1 -0
  18. package/dist/components/layout/TabsGroup.d.ts.map +1 -1
  19. package/dist/index.css +1 -1
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +11889 -24
  23. package/dist/index.js.map +1 -1
  24. package/dist/templates/forms/ContactForm.d.ts +1 -0
  25. package/dist/templates/forms/ContactForm.d.ts.map +1 -1
  26. package/dist/templates/forms/LoginForm.d.ts +1 -0
  27. package/dist/templates/forms/LoginForm.d.ts.map +1 -1
  28. package/dist/templates/forms/RegistrationForm.d.ts +1 -0
  29. package/dist/templates/forms/RegistrationForm.d.ts.map +1 -1
  30. package/dist/templates/layouts/DashboardLayout.d.ts +1 -0
  31. package/dist/templates/layouts/DashboardLayout.d.ts.map +1 -1
  32. package/dist/templates/layouts/SidebarLayout.d.ts +1 -0
  33. package/dist/templates/layouts/SidebarLayout.d.ts.map +1 -1
  34. package/dist/templates/patterns/FormPattern.d.ts +1 -0
  35. package/dist/templates/patterns/FormPattern.d.ts.map +1 -1
  36. package/dist/templates/patterns/ListPattern.d.ts +77 -0
  37. package/dist/templates/patterns/ListPattern.d.ts.map +1 -0
  38. package/package.json +6 -3
  39. package/dist/App.d.ts +0 -4
  40. package/dist/App.d.ts.map +0 -1
  41. package/dist/App.js +0 -30
  42. package/dist/components/ThemeSwitcher.js +0 -12
  43. package/dist/components/form-controls/AutocompleteInput.js +0 -680
  44. package/dist/components/form-controls/Button.js +0 -211
  45. package/dist/components/form-controls/Checkbox.js +0 -79
  46. package/dist/components/form-controls/CurrencyInput.js +0 -106
  47. package/dist/components/form-controls/DateInput.js +0 -578
  48. package/dist/components/form-controls/DatePicker.js +0 -144
  49. package/dist/components/form-controls/Input.js +0 -35
  50. package/dist/components/form-controls/LinkButton.js +0 -248
  51. package/dist/components/form-controls/Pagination.js +0 -23
  52. package/dist/components/form-controls/RadioButtonGroup.js +0 -220
  53. package/dist/components/form-controls/SearchSelectInput.js +0 -336
  54. package/dist/components/form-controls/index.js +0 -11
  55. package/dist/components/index.js +0 -7
  56. package/dist/components/layout/Accordion.js +0 -67
  57. package/dist/components/layout/AppLayout.js +0 -230
  58. package/dist/components/layout/Card.js +0 -54
  59. package/dist/components/layout/Collection.js +0 -18
  60. package/dist/components/layout/DataField.js +0 -38
  61. package/dist/components/layout/DataTable.js +0 -164
  62. package/dist/components/layout/DropdownMenu.js +0 -176
  63. package/dist/components/layout/DropdownPanel.js +0 -162
  64. package/dist/components/layout/Filter.js +0 -629
  65. package/dist/components/layout/Menu.js +0 -21
  66. package/dist/components/layout/TabPanel.js +0 -11
  67. package/dist/components/layout/TabsGroup.js +0 -52
  68. package/dist/components/layout/index.js +0 -12
  69. package/dist/components/utils/Avatar.js +0 -77
  70. package/dist/components/utils/Badge.js +0 -151
  71. package/dist/components/utils/Dialog.js +0 -44
  72. package/dist/components/utils/FiltersDialog.js +0 -104
  73. package/dist/components/utils/Loader.js +0 -44
  74. package/dist/components/utils/RoadMap.js +0 -139
  75. package/dist/components/utils/Skeleton.js +0 -10
  76. package/dist/components/utils/Snackbar.js +0 -136
  77. package/dist/components/utils/SnackbarContainer.js +0 -26
  78. package/dist/components/utils/iconUtils.js +0 -40
  79. package/dist/components/utils/index.js +0 -9
  80. package/dist/contexts/AppLayoutContext.js +0 -104
  81. package/dist/contexts/AuthContext.js +0 -224
  82. package/dist/contexts/CrudContext.js +0 -333
  83. package/dist/contexts/SnackbarContext.js +0 -41
  84. package/dist/contexts/ThemeContext.js +0 -197
  85. package/dist/contexts/index.js +0 -13
  86. package/dist/contexts/presets.js +0 -311
  87. package/dist/contexts/types.js +0 -1
  88. package/dist/docs/AccordionDocs.d.ts +0 -4
  89. package/dist/docs/AccordionDocs.d.ts.map +0 -1
  90. package/dist/docs/AccordionDocs.js +0 -21
  91. package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts +0 -13
  92. package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts.map +0 -1
  93. package/dist/docs/AuthDocs.tsx/AuthDocs.js +0 -18
  94. package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts +0 -2
  95. package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts.map +0 -1
  96. package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +0 -22
  97. package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts +0 -24
  98. package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts.map +0 -1
  99. package/dist/docs/AuthDocs.tsx/mockAuthService.js +0 -78
  100. package/dist/docs/AutocompleteInputDocs.d.ts +0 -4
  101. package/dist/docs/AutocompleteInputDocs.d.ts.map +0 -1
  102. package/dist/docs/AutocompleteInputDocs.js +0 -84
  103. package/dist/docs/AvatarDocs.d.ts +0 -4
  104. package/dist/docs/AvatarDocs.d.ts.map +0 -1
  105. package/dist/docs/AvatarDocs.js +0 -7
  106. package/dist/docs/BadgeDocs.d.ts +0 -4
  107. package/dist/docs/BadgeDocs.d.ts.map +0 -1
  108. package/dist/docs/BadgeDocs.js +0 -9
  109. package/dist/docs/ButtonDocs.d.ts +0 -4
  110. package/dist/docs/ButtonDocs.d.ts.map +0 -1
  111. package/dist/docs/ButtonDocs.js +0 -7
  112. package/dist/docs/CardDocs.d.ts +0 -4
  113. package/dist/docs/CardDocs.d.ts.map +0 -1
  114. package/dist/docs/CardDocs.js +0 -22
  115. package/dist/docs/CheckboxDocs.d.ts +0 -4
  116. package/dist/docs/CheckboxDocs.d.ts.map +0 -1
  117. package/dist/docs/CheckboxDocs.js +0 -7
  118. package/dist/docs/CurrencyInputDocs.d.ts +0 -4
  119. package/dist/docs/CurrencyInputDocs.d.ts.map +0 -1
  120. package/dist/docs/CurrencyInputDocs.js +0 -22
  121. package/dist/docs/DataFieldDocs.d.ts +0 -4
  122. package/dist/docs/DataFieldDocs.d.ts.map +0 -1
  123. package/dist/docs/DataFieldDocs.js +0 -7
  124. package/dist/docs/DataTableDocs.d.ts +0 -4
  125. package/dist/docs/DataTableDocs.d.ts.map +0 -1
  126. package/dist/docs/DataTableDocs.js +0 -244
  127. package/dist/docs/DateInputDocs.d.ts +0 -5
  128. package/dist/docs/DateInputDocs.d.ts.map +0 -1
  129. package/dist/docs/DateInputDocs.js +0 -19
  130. package/dist/docs/DatePickerDocs.d.ts +0 -5
  131. package/dist/docs/DatePickerDocs.d.ts.map +0 -1
  132. package/dist/docs/DatePickerDocs.js +0 -16
  133. package/dist/docs/DialogDocs.d.ts +0 -4
  134. package/dist/docs/DialogDocs.d.ts.map +0 -1
  135. package/dist/docs/DialogDocs.js +0 -13
  136. package/dist/docs/DocAdmin.d.ts +0 -4
  137. package/dist/docs/DocAdmin.d.ts.map +0 -1
  138. package/dist/docs/DocAdmin.js +0 -68
  139. package/dist/docs/DocsMenu.d.ts +0 -2
  140. package/dist/docs/DocsMenu.d.ts.map +0 -1
  141. package/dist/docs/DocsMenu.js +0 -5
  142. package/dist/docs/DocsRouter.d.ts +0 -4
  143. package/dist/docs/DocsRouter.d.ts.map +0 -1
  144. package/dist/docs/DocsRouter.js +0 -39
  145. package/dist/docs/DropdownMenuDocs.d.ts +0 -4
  146. package/dist/docs/DropdownMenuDocs.d.ts.map +0 -1
  147. package/dist/docs/DropdownMenuDocs.js +0 -66
  148. package/dist/docs/DropdownPanelDocs.d.ts +0 -4
  149. package/dist/docs/DropdownPanelDocs.d.ts.map +0 -1
  150. package/dist/docs/DropdownPanelDocs.js +0 -7
  151. package/dist/docs/ExampleFormDocs.d.ts +0 -4
  152. package/dist/docs/ExampleFormDocs.d.ts.map +0 -1
  153. package/dist/docs/ExampleFormDocs.js +0 -153
  154. package/dist/docs/FilterDocs.d.ts +0 -4
  155. package/dist/docs/FilterDocs.d.ts.map +0 -1
  156. package/dist/docs/FilterDocs.js +0 -130
  157. package/dist/docs/InputDocs.d.ts +0 -4
  158. package/dist/docs/InputDocs.d.ts.map +0 -1
  159. package/dist/docs/InputDocs.js +0 -17
  160. package/dist/docs/LinkButtonDocs.d.ts +0 -4
  161. package/dist/docs/LinkButtonDocs.d.ts.map +0 -1
  162. package/dist/docs/LinkButtonDocs.js +0 -7
  163. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +0 -2
  164. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +0 -1
  165. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +0 -47
  166. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts +0 -2
  167. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts.map +0 -1
  168. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.js +0 -34
  169. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts +0 -2
  170. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts.map +0 -1
  171. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.js +0 -66
  172. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts +0 -2
  173. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts.map +0 -1
  174. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.js +0 -7
  175. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts +0 -10
  176. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts.map +0 -1
  177. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.js +0 -39
  178. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +0 -2
  179. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +0 -1
  180. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +0 -57
  181. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts +0 -9
  182. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts.map +0 -1
  183. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.js +0 -30
  184. package/dist/docs/LoaderDocs.d.ts +0 -4
  185. package/dist/docs/LoaderDocs.d.ts.map +0 -1
  186. package/dist/docs/LoaderDocs.js +0 -33
  187. package/dist/docs/MenuDocs.d.ts +0 -4
  188. package/dist/docs/MenuDocs.d.ts.map +0 -1
  189. package/dist/docs/MenuDocs.js +0 -26
  190. package/dist/docs/PaginationDocs.d.ts +0 -4
  191. package/dist/docs/PaginationDocs.d.ts.map +0 -1
  192. package/dist/docs/PaginationDocs.js +0 -38
  193. package/dist/docs/RadioButtonGroupDocs.d.ts +0 -4
  194. package/dist/docs/RadioButtonGroupDocs.d.ts.map +0 -1
  195. package/dist/docs/RadioButtonGroupDocs.js +0 -46
  196. package/dist/docs/RoadMapDocs.d.ts +0 -4
  197. package/dist/docs/RoadMapDocs.d.ts.map +0 -1
  198. package/dist/docs/RoadMapDocs.js +0 -171
  199. package/dist/docs/SearchSelectInputDocs.d.ts +0 -4
  200. package/dist/docs/SearchSelectInputDocs.d.ts.map +0 -1
  201. package/dist/docs/SearchSelectInputDocs.js +0 -168
  202. package/dist/docs/SkeletonDocs.d.ts +0 -4
  203. package/dist/docs/SkeletonDocs.d.ts.map +0 -1
  204. package/dist/docs/SkeletonDocs.js +0 -7
  205. package/dist/docs/SnackbarDocs.d.ts +0 -4
  206. package/dist/docs/SnackbarDocs.d.ts.map +0 -1
  207. package/dist/docs/SnackbarDocs.js +0 -69
  208. package/dist/docs/TabsGroupDocs.d.ts +0 -4
  209. package/dist/docs/TabsGroupDocs.d.ts.map +0 -1
  210. package/dist/docs/TabsGroupDocs.js +0 -38
  211. package/dist/docs/ThemeSwitcherDocs.d.ts +0 -4
  212. package/dist/docs/ThemeSwitcherDocs.d.ts.map +0 -1
  213. package/dist/docs/ThemeSwitcherDocs.js +0 -11
  214. package/dist/docs/docMockServices/empresaService.d.ts +0 -38
  215. package/dist/docs/docMockServices/empresaService.d.ts.map +0 -1
  216. package/dist/docs/docMockServices/empresaService.js +0 -125
  217. package/dist/docs/docMockServices/index.d.ts +0 -9
  218. package/dist/docs/docMockServices/index.d.ts.map +0 -1
  219. package/dist/docs/docMockServices/index.js +0 -8
  220. package/dist/docs/docMockServices/initialData.d.ts +0 -6
  221. package/dist/docs/docMockServices/initialData.d.ts.map +0 -1
  222. package/dist/docs/docMockServices/initialData.js +0 -132
  223. package/dist/docs/docMockServices/interfaces.d.ts +0 -38
  224. package/dist/docs/docMockServices/interfaces.d.ts.map +0 -1
  225. package/dist/docs/docMockServices/interfaces.js +0 -1
  226. package/dist/docs/docMockServices/personaEmpresaService.d.ts +0 -43
  227. package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +0 -1
  228. package/dist/docs/docMockServices/personaEmpresaService.js +0 -151
  229. package/dist/docs/docMockServices/personaService.d.ts +0 -39
  230. package/dist/docs/docMockServices/personaService.d.ts.map +0 -1
  231. package/dist/docs/docMockServices/personaService.js +0 -190
  232. package/dist/helpers/currencyFormat.js +0 -3
  233. package/dist/helpers/getErrorMessage.js +0 -13
  234. package/dist/helpers/getInitialLetters.js +0 -5
  235. package/dist/helpers/getQueryString.js +0 -13
  236. package/dist/helpers/index.js +0 -9
  237. package/dist/helpers/mappers.js +0 -27
  238. package/dist/helpers/nameValueArrayToObject.js +0 -3
  239. package/dist/helpers/objectToQueryString.js +0 -3
  240. package/dist/helpers/queryStringToObject.js +0 -13
  241. package/dist/helpers/regularExpressions.js +0 -5
  242. package/dist/hooks/index.js +0 -6
  243. package/dist/hooks/useAsyncRequest.js +0 -53
  244. package/dist/hooks/useBreakpoint.js +0 -59
  245. package/dist/hooks/useElementScroll.js +0 -58
  246. package/dist/hooks/useEnum.js +0 -21
  247. package/dist/hooks/useGlobalThemeStyles.js +0 -40
  248. package/dist/hooks/useThemeOverride.js +0 -99
  249. package/dist/interfaces/index.js +0 -1
  250. package/dist/interfaces/name-value.interface.js +0 -1
  251. package/dist/interfaces/pagination.interface.js +0 -1
  252. package/dist/main.d.ts +0 -2
  253. package/dist/main.d.ts.map +0 -1
  254. package/dist/main.js +0 -6
  255. package/dist/services/apiClient.js +0 -216
  256. package/dist/services/index.js +0 -1
  257. package/dist/styles.d.ts +0 -2
  258. package/dist/styles.d.ts.map +0 -1
  259. package/dist/styles.js +0 -3
  260. package/dist/templates/forms/ContactForm.js +0 -58
  261. package/dist/templates/forms/LoginForm.js +0 -36
  262. package/dist/templates/forms/RegistrationForm.js +0 -54
  263. package/dist/templates/layouts/DashboardLayout.js +0 -26
  264. package/dist/templates/layouts/SidebarLayout.js +0 -28
  265. package/dist/templates/patterns/FormPattern.js +0 -68
@@ -1,58 +0,0 @@
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
- let lastDirection = null;
11
- let rafId = null;
12
- let pendingScrollY = element.scrollTop;
13
- const handleScroll = () => {
14
- pendingScrollY = element.scrollTop;
15
- // Usar requestAnimationFrame para agrupar actualizaciones y evitar temblores
16
- if (rafId === null) {
17
- rafId = requestAnimationFrame(() => {
18
- rafId = null;
19
- const currentScrollY = pendingScrollY;
20
- const delta = currentScrollY - lastScrollY;
21
- // Verificar si estamos cerca del final (margen de 5px)
22
- const isNearBottom = Math.abs(element.scrollHeight - element.clientHeight - currentScrollY) < 5;
23
- let newDirection = lastDirection;
24
- // Si estamos cerca del final y el delta es muy pequeño, mantener la dirección actual
25
- if (isNearBottom && Math.abs(delta) < 2) {
26
- // Mantener la dirección actual, no cambiar
27
- }
28
- else if (delta > 4 && currentScrollY > 10) {
29
- newDirection = "down";
30
- }
31
- else if (delta < -4 && currentScrollY > 0) {
32
- newDirection = "up";
33
- }
34
- else if (Math.abs(delta) < 2) {
35
- // Cambios muy pequeños, mantener la dirección actual
36
- newDirection = lastDirection;
37
- }
38
- setScrollY(currentScrollY);
39
- // Solo actualizar la dirección si cambió realmente
40
- if (newDirection !== lastDirection) {
41
- setScrollDirection(newDirection);
42
- lastDirection = newDirection;
43
- }
44
- lastScrollY = currentScrollY;
45
- });
46
- }
47
- };
48
- // Agregar el listener al elemento
49
- element.addEventListener("scroll", handleScroll, { passive: true });
50
- return () => {
51
- if (rafId !== null) {
52
- cancelAnimationFrame(rafId);
53
- }
54
- element.removeEventListener("scroll", handleScroll);
55
- };
56
- }, [elementRef]);
57
- return { scrollY, scrollDirection };
58
- };
@@ -1,21 +0,0 @@
1
- export const useEnum = (baseEnum) => {
2
- const buildArray = () => {
3
- return Object.keys(baseEnum)
4
- .filter((t) => isNaN(+t))
5
- .map((t) => ({
6
- name: t.split("_").join(" "),
7
- value: baseEnum[t],
8
- }));
9
- };
10
- const array = buildArray();
11
- const getArray = () => {
12
- return array;
13
- };
14
- const getInstance = (id) => {
15
- return array.find((i) => i.value === id);
16
- };
17
- return {
18
- getArray,
19
- getInstance,
20
- };
21
- };
@@ -1,40 +0,0 @@
1
- import { useEffect } from "react";
2
- import { useTheme } from "../contexts/ThemeContext";
3
- /**
4
- * Hook que aplica estilos globales del tema al body y html
5
- * Útil para aplicaciones host que quieren que el tema afecte toda la página
6
- */
7
- export const useGlobalThemeStyles = () => {
8
- const { theme } = useTheme();
9
- useEffect(() => {
10
- const body = document.body;
11
- const html = document.documentElement;
12
- if (body) {
13
- // Aplicar estilos al body
14
- body.style.backgroundColor = theme.colors.bgDefault;
15
- body.style.color = theme.colors.textPrimary;
16
- body.style.fontFamily = theme.fonts.default;
17
- body.style.margin = "0";
18
- body.style.padding = "0";
19
- }
20
- if (html) {
21
- // Aplicar estilos al html
22
- html.style.backgroundColor = theme.colors.bgDefault;
23
- html.style.color = theme.colors.textPrimary;
24
- }
25
- // Cleanup function para restaurar estilos originales
26
- return () => {
27
- if (body) {
28
- body.style.backgroundColor = "";
29
- body.style.color = "";
30
- body.style.fontFamily = "";
31
- body.style.margin = "";
32
- body.style.padding = "";
33
- }
34
- if (html) {
35
- html.style.backgroundColor = "";
36
- html.style.color = "";
37
- }
38
- };
39
- }, [theme]);
40
- };
@@ -1,99 +0,0 @@
1
- import { useCallback, useEffect, useRef } from "react";
2
- /**
3
- * Hook para aplicar overrides directos a variables CSS del tema
4
- * Permite personalización granular sin cambiar el tema completo
5
- */
6
- export const useThemeOverride = (options = {}) => {
7
- const { scope = "global", element = null, prefix = "flysoft" } = options;
8
- const appliedOverrides = useRef(new Set());
9
- // Función para aplicar override
10
- const applyOverride = useCallback((overrides) => {
11
- const targetElement = scope === "global" ? document.documentElement : element;
12
- if (!targetElement) {
13
- console.warn("useThemeOverride: No target element available");
14
- return;
15
- }
16
- Object.entries(overrides).forEach(([key, value]) => {
17
- const cssVarName = `--${prefix}-${key
18
- .replace(/([A-Z])/g, "-$1")
19
- .toLowerCase()}`;
20
- // Aplicar el override
21
- targetElement.style.setProperty(cssVarName, String(value));
22
- // Registrar para poder revertir después
23
- appliedOverrides.current.add(cssVarName);
24
- });
25
- }, [scope, element, prefix]);
26
- // Función para revertir overrides específicos
27
- const revertOverride = useCallback((keys) => {
28
- const targetElement = scope === "global" ? document.documentElement : element;
29
- if (!targetElement)
30
- return;
31
- keys.forEach((key) => {
32
- const cssVarName = `--${prefix}-${key
33
- .replace(/([A-Z])/g, "-$1")
34
- .toLowerCase()}`;
35
- if (appliedOverrides.current.has(cssVarName)) {
36
- targetElement.style.removeProperty(cssVarName);
37
- appliedOverrides.current.delete(cssVarName);
38
- }
39
- });
40
- }, [scope, element, prefix]);
41
- // Función para revertir todos los overrides aplicados
42
- const revertAllOverrides = useCallback(() => {
43
- const targetElement = scope === "global" ? document.documentElement : element;
44
- if (!targetElement)
45
- return;
46
- appliedOverrides.current.forEach((cssVarName) => {
47
- targetElement.style.removeProperty(cssVarName);
48
- });
49
- appliedOverrides.current.clear();
50
- }, [scope, element]);
51
- // Función para obtener el valor actual de una variable CSS
52
- const getCSSVariable = useCallback((key) => {
53
- const targetElement = scope === "global" ? document.documentElement : element;
54
- if (!targetElement)
55
- return null;
56
- const cssVarName = `--${prefix}-${key
57
- .replace(/([A-Z])/g, "-$1")
58
- .toLowerCase()}`;
59
- return (getComputedStyle(targetElement).getPropertyValue(cssVarName) || null);
60
- }, [scope, element, prefix]);
61
- // Función para verificar si un override está aplicado
62
- const isOverrideApplied = useCallback((key) => {
63
- const cssVarName = `--${prefix}-${key
64
- .replace(/([A-Z])/g, "-$1")
65
- .toLowerCase()}`;
66
- return appliedOverrides.current.has(cssVarName);
67
- }, [prefix]);
68
- // Cleanup al desmontar
69
- useEffect(() => {
70
- return () => {
71
- revertAllOverrides();
72
- };
73
- }, [revertAllOverrides]);
74
- return {
75
- applyOverride,
76
- revertOverride,
77
- revertAllOverrides,
78
- getCSSVariable,
79
- isOverrideApplied,
80
- appliedOverridesCount: appliedOverrides.current.size,
81
- };
82
- };
83
- /**
84
- * Hook para aplicar overrides temporales que se revierten automáticamente
85
- */
86
- export const useTemporaryOverride = (overrides, duration = 3000, options = {}) => {
87
- const { applyOverride, revertOverride } = useThemeOverride(options);
88
- const applyTemporaryOverride = useCallback(() => {
89
- applyOverride(overrides);
90
- const timeoutId = setTimeout(() => {
91
- revertOverride(Object.keys(overrides));
92
- }, duration);
93
- return () => {
94
- clearTimeout(timeoutId);
95
- revertOverride(Object.keys(overrides));
96
- };
97
- }, [applyOverride, revertOverride, overrides, duration]);
98
- return { applyTemporaryOverride };
99
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
package/dist/main.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=main.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":""}
package/dist/main.js DELETED
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { StrictMode } from "react";
3
- import { createRoot } from "react-dom/client";
4
- import { BrowserRouter } from "react-router-dom";
5
- import App from "./App";
6
- createRoot(document.getElementById("root")).render(_jsx(StrictMode, { children: _jsx(BrowserRouter, { future: { v7_startTransition: true, v7_relativeSplatPath: true }, children: _jsx(App, {}) }) }));
@@ -1,216 +0,0 @@
1
- import axios, {} from "axios";
2
- class ApiClientService {
3
- instance;
4
- tokenProvider;
5
- constructor(config) {
6
- this.instance = axios.create({
7
- baseURL: config?.baseURL ?? "",
8
- timeout: config?.timeout ?? 15000,
9
- headers: {
10
- "Content-Type": "application/json",
11
- ...config?.headers,
12
- },
13
- });
14
- this.setupInterceptors();
15
- }
16
- setupInterceptors() {
17
- // Request interceptor para inyectar el token automáticamente
18
- this.instance.interceptors.request.use((config) => {
19
- const token = this.tokenProvider?.();
20
- if (token && config.headers) {
21
- // Manejo compatible con diferentes versiones de axios
22
- if ("set" in config.headers &&
23
- typeof config.headers.set === "function") {
24
- config.headers.set("Authorization", `Bearer ${token}`);
25
- }
26
- else {
27
- const headers = config.headers;
28
- headers.Authorization = `Bearer ${token}`;
29
- }
30
- }
31
- return config;
32
- }, (error) => {
33
- return Promise.reject(error);
34
- });
35
- // Response interceptor para manejo de errores (opcional, puede extenderse)
36
- this.instance.interceptors.response.use((response) => response, (error) => {
37
- return Promise.reject(error);
38
- });
39
- }
40
- /**
41
- * Establece el proveedor de token que se usará en todas las peticiones
42
- * @param provider Función que retorna el token de autorización
43
- */
44
- setTokenProvider(provider) {
45
- this.tokenProvider = provider;
46
- }
47
- /**
48
- * Limpia el proveedor de token
49
- */
50
- clearTokenProvider() {
51
- this.tokenProvider = undefined;
52
- }
53
- /**
54
- * Actualiza la configuración por defecto del cliente
55
- */
56
- updateDefaults(config) {
57
- if (config.baseURL) {
58
- this.instance.defaults.baseURL = config.baseURL;
59
- }
60
- if (config.timeout) {
61
- this.instance.defaults.timeout = config.timeout;
62
- }
63
- if (config.headers) {
64
- // Actualizar headers comunes de forma segura
65
- Object.assign(this.instance.defaults.headers.common || {}, config.headers);
66
- }
67
- }
68
- async axiosRequest({ method, url, headers, body, params, }) {
69
- return await this.instance({
70
- method,
71
- headers,
72
- url,
73
- data: body,
74
- params,
75
- });
76
- }
77
- /**
78
- * Realiza una petición GET
79
- */
80
- async get(options) {
81
- const { url, params, headers } = options;
82
- const response = await this.axiosRequest({
83
- method: "GET",
84
- url,
85
- params,
86
- headers,
87
- });
88
- return response.data;
89
- }
90
- /**
91
- * Realiza una petición POST
92
- */
93
- async post(options) {
94
- const { url, body, headers } = options;
95
- const response = await this.axiosRequest({
96
- method: "POST",
97
- url,
98
- headers,
99
- body,
100
- });
101
- return response.data;
102
- }
103
- /**
104
- * Realiza una petición PUT
105
- */
106
- async put(options) {
107
- const { url, body, headers } = options;
108
- const response = await this.axiosRequest({
109
- method: "PUT",
110
- url,
111
- headers,
112
- body,
113
- });
114
- return response.data;
115
- }
116
- /**
117
- * Realiza una petición DELETE
118
- */
119
- async del(options) {
120
- const { url, headers } = options;
121
- const response = await this.axiosRequest({
122
- method: "DELETE",
123
- url,
124
- headers,
125
- });
126
- return response.data;
127
- }
128
- /**
129
- * Obtiene un archivo como Blob
130
- */
131
- async getFile(options) {
132
- const { url, headers = {} } = options;
133
- const response = await this.instance.get(url, {
134
- responseType: "blob",
135
- headers,
136
- });
137
- return {
138
- data: response.data,
139
- headers: response.headers,
140
- };
141
- }
142
- /**
143
- * Obtiene un archivo y retorna su URL como objeto
144
- */
145
- async getFileAsUrl(options) {
146
- const { data } = await this.getFile(options);
147
- const blob = new Blob([data], { type: data.type });
148
- return URL.createObjectURL(blob);
149
- }
150
- /**
151
- * Abre un archivo en una nueva ventana
152
- */
153
- async openFile(options) {
154
- const { data } = await this.getFile(options);
155
- const urlData = URL.createObjectURL(data);
156
- window.open(urlData);
157
- }
158
- /**
159
- * Descarga un archivo
160
- */
161
- async downloadFile(options) {
162
- const { data, headers: dataHeaders } = await this.getFile(options);
163
- const contentDisposition = dataHeaders["content-disposition"] || dataHeaders["Content-Disposition"];
164
- const fileName = contentDisposition
165
- ?.split("filename=")[1]
166
- ?.split(";")[0]
167
- .replaceAll('"', "");
168
- const blob = new Blob([data], { type: data.type });
169
- const link = document.createElement("a");
170
- link.href = window.URL.createObjectURL(blob);
171
- link.setAttribute("download", fileName || "");
172
- document.body.appendChild(link);
173
- link.click();
174
- link.parentNode?.removeChild(link);
175
- }
176
- /**
177
- * Sube uno o más archivos usando FormData
178
- */
179
- async uploadFile(options) {
180
- const { url, files, headers } = options;
181
- const formData = new FormData();
182
- const { paramName = "file", ...newHeaders } = headers || {};
183
- const fileArray = Array.from(files);
184
- for (const file of fileArray) {
185
- formData.append(paramName, file, file.name);
186
- }
187
- const response = await this.instance.post(url, formData, {
188
- headers: newHeaders,
189
- });
190
- return response.data;
191
- }
192
- }
193
- // Instancia compartida del cliente
194
- const sharedClient = new ApiClientService();
195
- /**
196
- * Cliente de API compartido con todas las funciones de HTTP
197
- */
198
- export const apiClient = sharedClient;
199
- /**
200
- * Crea una nueva instancia del cliente de API
201
- */
202
- export const createApiClient = (config) => {
203
- return new ApiClientService(config);
204
- };
205
- /**
206
- * Establece el proveedor de token global para el cliente compartido
207
- */
208
- export const setApiClientTokenProvider = (provider) => {
209
- sharedClient.setTokenProvider(provider);
210
- };
211
- /**
212
- * Limpia el proveedor de token global
213
- */
214
- export const clearApiClientTokenProvider = () => {
215
- sharedClient.clearTokenProvider();
216
- };
@@ -1 +0,0 @@
1
- export { apiClient, createApiClient, setApiClientTokenProvider, clearApiClientTokenProvider, } from "./apiClient";
package/dist/styles.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=styles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":""}
package/dist/styles.js DELETED
@@ -1,3 +0,0 @@
1
- export {};
2
- // This file is used to import styles in the library
3
- // The actual CSS file is available via the package exports
@@ -1,58 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useState } from "react";
3
- import { Button, Input, Card } from "../../index";
4
- export const ContactForm = ({ onSubmit, loading = false, success = false, error, className = "", }) => {
5
- const [formData, setFormData] = useState({
6
- name: "",
7
- email: "",
8
- subject: "",
9
- message: "",
10
- });
11
- const [errors, setErrors] = useState({});
12
- const handleSubmit = (e) => {
13
- e.preventDefault();
14
- // Validación
15
- const newErrors = {};
16
- if (!formData.name.trim()) {
17
- newErrors.name = "El nombre es requerido";
18
- }
19
- if (!formData.email) {
20
- newErrors.email = "El email es requerido";
21
- }
22
- else if (!/\S+@\S+\.\S+/.test(formData.email)) {
23
- newErrors.email = "El email no es válido";
24
- }
25
- if (!formData.subject.trim()) {
26
- newErrors.subject = "El asunto es requerido";
27
- }
28
- if (!formData.message.trim()) {
29
- newErrors.message = "El mensaje es requerido";
30
- }
31
- else if (formData.message.trim().length < 10) {
32
- newErrors.message = "El mensaje debe tener al menos 10 caracteres";
33
- }
34
- setErrors(newErrors);
35
- if (Object.keys(newErrors).length === 0) {
36
- onSubmit?.(formData);
37
- }
38
- };
39
- const handleChange = (field) => (e) => {
40
- setFormData((prev) => ({ ...prev, [field]: e.target.value }));
41
- // Limpiar error cuando el usuario empiece a escribir
42
- if (errors[field]) {
43
- setErrors((prev) => ({ ...prev, [field]: undefined }));
44
- }
45
- };
46
- if (success) {
47
- return (_jsx(Card, { title: "Mensaje Enviado", subtitle: "Gracias por contactarnos", className: className, children: _jsxs("div", { className: "text-center py-8", children: [_jsx("div", { className: "w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4", children: _jsx("i", { className: "fal fa-check text-green-600 text-2xl" }) }), _jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-2", children: "\u00A1Mensaje enviado con \u00E9xito!" }), _jsx("p", { className: "text-gray-600 mb-4", children: "Hemos recibido tu mensaje y te responderemos pronto." }), _jsx(Button, { variant: "outline", onClick: () => window.location.reload(), icon: "fa-refresh", children: "Enviar otro mensaje" })] }) }));
48
- }
49
- return (_jsx(Card, { title: "Cont\u00E1ctanos", subtitle: "Env\u00EDanos un mensaje y te responderemos pronto", className: className, children: _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && (_jsx("div", { className: "p-3 bg-red-50 border border-red-200 rounded-lg", children: _jsxs("p", { className: "text-sm text-red-600", children: [_jsx("i", { className: "fal fa-exclamation-triangle mr-2" }), error] }) })), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Nombre Completo", placeholder: "Tu nombre completo", icon: "fa-user", value: formData.name, onChange: handleChange("name"), error: errors.name, disabled: loading }), _jsx(Input, { label: "Email", type: "email", placeholder: "tu@email.com", icon: "fa-envelope", value: formData.email, onChange: handleChange("email"), error: errors.email, disabled: loading })] }), _jsx(Input, { label: "Asunto", placeholder: "\u00BFEn qu\u00E9 podemos ayudarte?", icon: "fa-tag", value: formData.subject, onChange: handleChange("subject"), error: errors.subject, disabled: loading }), _jsxs("div", { className: "w-full", children: [_jsx("label", { className: "block text-sm font-medium text-[var(--color-text-primary)] mb-1 font-[var(--font-default)]", children: "Mensaje" }), _jsxs("div", { className: "relative", children: [_jsx("i", { className: "fal fa-comment text-[var(--color-text-muted)] absolute top-3 left-3 w-5 h-5" }), _jsx("textarea", { placeholder: "Escribe tu mensaje aqu\u00ED...", className: `
50
- w-full border rounded-lg transition-colors focus:outline-none focus:ring-2
51
- disabled:opacity-50 disabled:cursor-not-allowed
52
- font-[var(--font-default)] text-[var(--color-text-primary)]
53
- bg-[var(--color-bg-default)] pl-10 pr-4 py-3 text-base
54
- ${errors.message
55
- ? "border-[var(--color-border-error)] focus:border-[var(--color-border-error)] focus:ring-[var(--color-border-error)]"
56
- : "border-[var(--color-border-default)] focus:border-[var(--color-border-focus)] focus:ring-[var(--color-border-focus)]"}
57
- `, rows: 5, value: formData.message, onChange: handleChange("message"), disabled: loading })] }), errors.message && (_jsx("p", { className: "mt-1 text-sm text-[var(--color-danger)] font-[var(--font-default)]", children: errors.message }))] }), _jsx(Button, { type: "submit", variant: "primary", size: "lg", icon: "fa-paper-plane", loading: loading, className: "w-full", children: "Enviar Mensaje" })] }) }));
58
- };
@@ -1,36 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useState } from "react";
3
- import { Button, Input, Card } from "../../index";
4
- export const LoginForm = ({ onSubmit, loading = false, error, className = "", }) => {
5
- const [formData, setFormData] = useState({
6
- email: "",
7
- password: "",
8
- });
9
- const [errors, setErrors] = useState({});
10
- const handleSubmit = (e) => {
11
- e.preventDefault();
12
- // Validación básica
13
- const newErrors = {};
14
- if (!formData.email) {
15
- newErrors.email = "El email es requerido";
16
- }
17
- else if (!/\S+@\S+\.\S+/.test(formData.email)) {
18
- newErrors.email = "El email no es válido";
19
- }
20
- if (!formData.password) {
21
- newErrors.password = "La contraseña es requerida";
22
- }
23
- setErrors(newErrors);
24
- if (Object.keys(newErrors).length === 0) {
25
- onSubmit?.(formData);
26
- }
27
- };
28
- const handleChange = (field) => (e) => {
29
- setFormData((prev) => ({ ...prev, [field]: e.target.value }));
30
- // Limpiar error cuando el usuario empiece a escribir
31
- if (errors[field]) {
32
- setErrors((prev) => ({ ...prev, [field]: undefined }));
33
- }
34
- };
35
- return (_jsxs(Card, { title: "Iniciar Sesi\u00F3n", subtitle: "Ingresa tus credenciales para acceder", className: className, children: [_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && (_jsx("div", { className: "p-3 bg-red-50 border border-red-200 rounded-lg", children: _jsxs("p", { className: "text-sm text-red-600", children: [_jsx("i", { className: "fal fa-exclamation-triangle mr-2" }), error] }) })), _jsx(Input, { label: "Email", type: "email", placeholder: "tu@email.com", icon: "fa-envelope", value: formData.email, onChange: handleChange("email"), error: errors.email, disabled: loading }), _jsx(Input, { label: "Contrase\u00F1a", type: "password", placeholder: "Tu contrase\u00F1a", icon: "fa-lock", value: formData.password, onChange: handleChange("password"), error: errors.password, disabled: loading }), _jsx(Button, { type: "submit", variant: "primary", size: "lg", icon: "fa-sign-in-alt", loading: loading, className: "w-full", children: "Iniciar Sesi\u00F3n" })] }), _jsx("div", { className: "mt-4 text-center", children: _jsxs("p", { className: "text-sm text-gray-600", children: ["\u00BFNo tienes cuenta?", " ", _jsx("a", { href: "#", className: "text-blue-600 hover:text-blue-800 font-medium", children: "Reg\u00EDstrate aqu\u00ED" })] }) })] }));
36
- };
@@ -1,54 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useState } from "react";
3
- import { Button, Input, Card } from "../../index";
4
- export const RegistrationForm = ({ onSubmit, loading = false, error, className = "", }) => {
5
- const [formData, setFormData] = useState({
6
- firstName: "",
7
- lastName: "",
8
- email: "",
9
- password: "",
10
- confirmPassword: "",
11
- });
12
- const [errors, setErrors] = useState({});
13
- const handleSubmit = (e) => {
14
- e.preventDefault();
15
- // Validación
16
- const newErrors = {};
17
- if (!formData.firstName.trim()) {
18
- newErrors.firstName = "El nombre es requerido";
19
- }
20
- if (!formData.lastName.trim()) {
21
- newErrors.lastName = "El apellido es requerido";
22
- }
23
- if (!formData.email) {
24
- newErrors.email = "El email es requerido";
25
- }
26
- else if (!/\S+@\S+\.\S+/.test(formData.email)) {
27
- newErrors.email = "El email no es válido";
28
- }
29
- if (!formData.password) {
30
- newErrors.password = "La contraseña es requerida";
31
- }
32
- else if (formData.password.length < 6) {
33
- newErrors.password = "La contraseña debe tener al menos 6 caracteres";
34
- }
35
- if (!formData.confirmPassword) {
36
- newErrors.confirmPassword = "Confirma tu contraseña";
37
- }
38
- else if (formData.password !== formData.confirmPassword) {
39
- newErrors.confirmPassword = "Las contraseñas no coinciden";
40
- }
41
- setErrors(newErrors);
42
- if (Object.keys(newErrors).length === 0) {
43
- onSubmit?.(formData);
44
- }
45
- };
46
- const handleChange = (field) => (e) => {
47
- setFormData((prev) => ({ ...prev, [field]: e.target.value }));
48
- // Limpiar error cuando el usuario empiece a escribir
49
- if (errors[field]) {
50
- setErrors((prev) => ({ ...prev, [field]: undefined }));
51
- }
52
- };
53
- return (_jsxs(Card, { title: "Crear Cuenta", subtitle: "Completa los datos para registrarte", className: className, children: [_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && (_jsx("div", { className: "p-3 bg-red-50 border border-red-200 rounded-lg", children: _jsxs("p", { className: "text-sm text-red-600", children: [_jsx("i", { className: "fal fa-exclamation-triangle mr-2" }), error] }) })), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsx(Input, { label: "Nombre", placeholder: "Tu nombre", icon: "fa-user", value: formData.firstName, onChange: handleChange("firstName"), error: errors.firstName, disabled: loading }), _jsx(Input, { label: "Apellido", placeholder: "Tu apellido", icon: "fa-user", value: formData.lastName, onChange: handleChange("lastName"), error: errors.lastName, disabled: loading })] }), _jsx(Input, { label: "Email", type: "email", placeholder: "tu@email.com", icon: "fa-envelope", value: formData.email, onChange: handleChange("email"), error: errors.email, disabled: loading }), _jsx(Input, { label: "Contrase\u00F1a", type: "password", placeholder: "M\u00EDnimo 6 caracteres", icon: "fa-lock", value: formData.password, onChange: handleChange("password"), error: errors.password, disabled: loading }), _jsx(Input, { label: "Confirmar Contrase\u00F1a", type: "password", placeholder: "Repite tu contrase\u00F1a", icon: "fa-lock", value: formData.confirmPassword, onChange: handleChange("confirmPassword"), error: errors.confirmPassword, disabled: loading }), _jsx(Button, { type: "submit", variant: "primary", size: "lg", icon: "fa-user-plus", loading: loading, className: "w-full", children: "Crear Cuenta" })] }), _jsx("div", { className: "mt-4 text-center", children: _jsxs("p", { className: "text-sm text-gray-600", children: ["\u00BFYa tienes cuenta?", " ", _jsx("a", { href: "#", className: "text-blue-600 hover:text-blue-800 font-medium", children: "Inicia sesi\u00F3n aqu\u00ED" })] }) })] }));
54
- };
@@ -1,26 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React from "react";
3
- import { Card } from "../../index";
4
- export const DashboardLayout = ({ title, subtitle, stats = [], actions, children, className = "", }) => {
5
- const getChangeColor = (changeType) => {
6
- switch (changeType) {
7
- case "positive":
8
- return "text-green-600";
9
- case "negative":
10
- return "text-red-600";
11
- default:
12
- return "text-gray-600";
13
- }
14
- };
15
- const getChangeIcon = (changeType) => {
16
- switch (changeType) {
17
- case "positive":
18
- return "fa-arrow-up";
19
- case "negative":
20
- return "fa-arrow-down";
21
- default:
22
- return "fa-minus";
23
- }
24
- };
25
- return (_jsxs("div", { className: `min-h-screen bg-gray-50 ${className}`, children: [_jsx("div", { className: "bg-white shadow-sm border-b", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: _jsxs("div", { className: "flex justify-between items-center py-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-gray-900", children: title }), subtitle && (_jsx("p", { className: "mt-1 text-sm text-gray-600", children: subtitle }))] }), actions && (_jsx("div", { className: "flex items-center space-x-3", children: actions }))] }) }) }), stats.length > 0 && (_jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6", children: _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6", children: stats.map((stat, index) => (_jsx(Card, { variant: "elevated", className: "p-6", children: _jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "flex-shrink-0", children: stat.icon && (_jsx("div", { className: "w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center", children: _jsx("i", { className: `fa ${stat.icon} text-blue-600` }) })) }), _jsxs("div", { className: "ml-4 flex-1", children: [_jsx("p", { className: "text-sm font-medium text-gray-600", children: stat.title }), _jsx("p", { className: "text-2xl font-semibold text-gray-900", children: stat.value }), stat.change && (_jsxs("div", { className: "flex items-center mt-1", children: [_jsx("i", { className: `fa ${getChangeIcon(stat.changeType)} text-xs mr-1 ${getChangeColor(stat.changeType)}` }), _jsx("span", { className: `text-sm ${getChangeColor(stat.changeType)}`, children: stat.change })] }))] })] }) }, index))) }) })), _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6", children: children })] }));
26
- };