flysoft-react-ui 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_CONTEXT.md +1400 -217
- package/AI_INTEGRATION_GUIDE.md +343 -0
- package/INTEGRATION_GUIDE.md +60 -0
- package/README.md +5 -3
- package/dist/components/form-controls/Input.d.ts.map +1 -1
- package/dist/components/layout/Accordion.d.ts +1 -0
- package/dist/components/layout/Accordion.d.ts.map +1 -1
- package/dist/components/layout/DataTable.d.ts.map +1 -1
- package/dist/components/layout/DropdownMenu.d.ts +2 -1
- package/dist/components/layout/DropdownMenu.d.ts.map +1 -1
- package/dist/components/layout/DropdownPanel.d.ts +2 -1
- package/dist/components/layout/DropdownPanel.d.ts.map +1 -1
- package/dist/components/layout/Filter.d.ts +1 -0
- package/dist/components/layout/Filter.d.ts.map +1 -1
- package/dist/components/layout/Menu.d.ts +2 -1
- package/dist/components/layout/Menu.d.ts.map +1 -1
- package/dist/components/layout/TabsGroup.d.ts +1 -0
- package/dist/components/layout/TabsGroup.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11190 -24
- package/dist/index.js.map +1 -1
- package/dist/templates/forms/ContactForm.d.ts +1 -0
- package/dist/templates/forms/ContactForm.d.ts.map +1 -1
- package/dist/templates/forms/LoginForm.d.ts +1 -0
- package/dist/templates/forms/LoginForm.d.ts.map +1 -1
- package/dist/templates/forms/RegistrationForm.d.ts +1 -0
- package/dist/templates/forms/RegistrationForm.d.ts.map +1 -1
- package/dist/templates/layouts/DashboardLayout.d.ts +1 -0
- package/dist/templates/layouts/DashboardLayout.d.ts.map +1 -1
- package/dist/templates/layouts/SidebarLayout.d.ts +1 -0
- package/dist/templates/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/templates/patterns/FormPattern.d.ts +1 -0
- package/dist/templates/patterns/FormPattern.d.ts.map +1 -1
- package/dist/templates/patterns/ListPattern.d.ts +77 -0
- package/dist/templates/patterns/ListPattern.d.ts.map +1 -0
- package/package.json +8 -4
- package/dist/App.d.ts +0 -4
- package/dist/App.d.ts.map +0 -1
- package/dist/App.js +0 -30
- package/dist/components/ThemeSwitcher.js +0 -12
- package/dist/components/form-controls/AutocompleteInput.js +0 -680
- package/dist/components/form-controls/Button.js +0 -211
- package/dist/components/form-controls/Checkbox.js +0 -79
- package/dist/components/form-controls/CurrencyInput.js +0 -106
- package/dist/components/form-controls/DateInput.js +0 -578
- package/dist/components/form-controls/DatePicker.js +0 -144
- package/dist/components/form-controls/Input.js +0 -35
- package/dist/components/form-controls/LinkButton.js +0 -248
- package/dist/components/form-controls/Pagination.js +0 -23
- package/dist/components/form-controls/RadioButtonGroup.js +0 -220
- package/dist/components/form-controls/SearchSelectInput.js +0 -336
- package/dist/components/form-controls/index.js +0 -11
- package/dist/components/index.js +0 -7
- package/dist/components/layout/Accordion.js +0 -67
- package/dist/components/layout/AppLayout.js +0 -230
- package/dist/components/layout/Card.js +0 -54
- package/dist/components/layout/Collection.js +0 -18
- package/dist/components/layout/DataField.js +0 -38
- package/dist/components/layout/DataTable.js +0 -164
- package/dist/components/layout/DropdownMenu.js +0 -176
- package/dist/components/layout/DropdownPanel.js +0 -162
- package/dist/components/layout/Filter.js +0 -629
- package/dist/components/layout/Menu.js +0 -21
- package/dist/components/layout/TabPanel.js +0 -11
- package/dist/components/layout/TabsGroup.js +0 -52
- package/dist/components/layout/index.js +0 -12
- package/dist/components/utils/Avatar.js +0 -77
- package/dist/components/utils/Badge.js +0 -151
- package/dist/components/utils/Dialog.js +0 -44
- package/dist/components/utils/FiltersDialog.js +0 -104
- package/dist/components/utils/Loader.js +0 -44
- package/dist/components/utils/RoadMap.js +0 -139
- package/dist/components/utils/Skeleton.js +0 -10
- package/dist/components/utils/Snackbar.js +0 -136
- package/dist/components/utils/SnackbarContainer.js +0 -26
- package/dist/components/utils/iconUtils.js +0 -40
- package/dist/components/utils/index.js +0 -9
- package/dist/contexts/AppLayoutContext.js +0 -104
- package/dist/contexts/AuthContext.js +0 -224
- package/dist/contexts/CrudContext.js +0 -333
- package/dist/contexts/SnackbarContext.js +0 -41
- package/dist/contexts/ThemeContext.js +0 -197
- package/dist/contexts/index.js +0 -13
- package/dist/contexts/presets.js +0 -311
- package/dist/contexts/types.js +0 -1
- package/dist/docs/AccordionDocs.d.ts +0 -4
- package/dist/docs/AccordionDocs.d.ts.map +0 -1
- package/dist/docs/AccordionDocs.js +0 -21
- package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts +0 -13
- package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts.map +0 -1
- package/dist/docs/AuthDocs.tsx/AuthDocs.js +0 -18
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts +0 -2
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts.map +0 -1
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +0 -22
- package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts +0 -24
- package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts.map +0 -1
- package/dist/docs/AuthDocs.tsx/mockAuthService.js +0 -78
- package/dist/docs/AutocompleteInputDocs.d.ts +0 -4
- package/dist/docs/AutocompleteInputDocs.d.ts.map +0 -1
- package/dist/docs/AutocompleteInputDocs.js +0 -84
- package/dist/docs/AvatarDocs.d.ts +0 -4
- package/dist/docs/AvatarDocs.d.ts.map +0 -1
- package/dist/docs/AvatarDocs.js +0 -7
- package/dist/docs/BadgeDocs.d.ts +0 -4
- package/dist/docs/BadgeDocs.d.ts.map +0 -1
- package/dist/docs/BadgeDocs.js +0 -9
- package/dist/docs/ButtonDocs.d.ts +0 -4
- package/dist/docs/ButtonDocs.d.ts.map +0 -1
- package/dist/docs/ButtonDocs.js +0 -7
- package/dist/docs/CardDocs.d.ts +0 -4
- package/dist/docs/CardDocs.d.ts.map +0 -1
- package/dist/docs/CardDocs.js +0 -22
- package/dist/docs/CheckboxDocs.d.ts +0 -4
- package/dist/docs/CheckboxDocs.d.ts.map +0 -1
- package/dist/docs/CheckboxDocs.js +0 -7
- package/dist/docs/CurrencyInputDocs.d.ts +0 -4
- package/dist/docs/CurrencyInputDocs.d.ts.map +0 -1
- package/dist/docs/CurrencyInputDocs.js +0 -22
- package/dist/docs/DataFieldDocs.d.ts +0 -4
- package/dist/docs/DataFieldDocs.d.ts.map +0 -1
- package/dist/docs/DataFieldDocs.js +0 -7
- package/dist/docs/DataTableDocs.d.ts +0 -4
- package/dist/docs/DataTableDocs.d.ts.map +0 -1
- package/dist/docs/DataTableDocs.js +0 -244
- package/dist/docs/DateInputDocs.d.ts +0 -5
- package/dist/docs/DateInputDocs.d.ts.map +0 -1
- package/dist/docs/DateInputDocs.js +0 -19
- package/dist/docs/DatePickerDocs.d.ts +0 -5
- package/dist/docs/DatePickerDocs.d.ts.map +0 -1
- package/dist/docs/DatePickerDocs.js +0 -16
- package/dist/docs/DialogDocs.d.ts +0 -4
- package/dist/docs/DialogDocs.d.ts.map +0 -1
- package/dist/docs/DialogDocs.js +0 -13
- package/dist/docs/DocAdmin.d.ts +0 -4
- package/dist/docs/DocAdmin.d.ts.map +0 -1
- package/dist/docs/DocAdmin.js +0 -68
- package/dist/docs/DocsMenu.d.ts +0 -2
- package/dist/docs/DocsMenu.d.ts.map +0 -1
- package/dist/docs/DocsMenu.js +0 -5
- package/dist/docs/DocsRouter.d.ts +0 -4
- package/dist/docs/DocsRouter.d.ts.map +0 -1
- package/dist/docs/DocsRouter.js +0 -39
- package/dist/docs/DropdownMenuDocs.d.ts +0 -4
- package/dist/docs/DropdownMenuDocs.d.ts.map +0 -1
- package/dist/docs/DropdownMenuDocs.js +0 -66
- package/dist/docs/DropdownPanelDocs.d.ts +0 -4
- package/dist/docs/DropdownPanelDocs.d.ts.map +0 -1
- package/dist/docs/DropdownPanelDocs.js +0 -7
- package/dist/docs/ExampleFormDocs.d.ts +0 -4
- package/dist/docs/ExampleFormDocs.d.ts.map +0 -1
- package/dist/docs/ExampleFormDocs.js +0 -153
- package/dist/docs/FilterDocs.d.ts +0 -4
- package/dist/docs/FilterDocs.d.ts.map +0 -1
- package/dist/docs/FilterDocs.js +0 -130
- package/dist/docs/InputDocs.d.ts +0 -4
- package/dist/docs/InputDocs.d.ts.map +0 -1
- package/dist/docs/InputDocs.js +0 -17
- package/dist/docs/LinkButtonDocs.d.ts +0 -4
- package/dist/docs/LinkButtonDocs.d.ts.map +0 -1
- package/dist/docs/LinkButtonDocs.js +0 -7
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +0 -47
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.js +0 -34
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.js +0 -66
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.js +0 -7
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts +0 -10
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.js +0 -39
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +0 -57
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts +0 -9
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.js +0 -30
- package/dist/docs/LoaderDocs.d.ts +0 -4
- package/dist/docs/LoaderDocs.d.ts.map +0 -1
- package/dist/docs/LoaderDocs.js +0 -33
- package/dist/docs/MenuDocs.d.ts +0 -4
- package/dist/docs/MenuDocs.d.ts.map +0 -1
- package/dist/docs/MenuDocs.js +0 -26
- package/dist/docs/PaginationDocs.d.ts +0 -4
- package/dist/docs/PaginationDocs.d.ts.map +0 -1
- package/dist/docs/PaginationDocs.js +0 -38
- package/dist/docs/RadioButtonGroupDocs.d.ts +0 -4
- package/dist/docs/RadioButtonGroupDocs.d.ts.map +0 -1
- package/dist/docs/RadioButtonGroupDocs.js +0 -46
- package/dist/docs/RoadMapDocs.d.ts +0 -4
- package/dist/docs/RoadMapDocs.d.ts.map +0 -1
- package/dist/docs/RoadMapDocs.js +0 -171
- package/dist/docs/SearchSelectInputDocs.d.ts +0 -4
- package/dist/docs/SearchSelectInputDocs.d.ts.map +0 -1
- package/dist/docs/SearchSelectInputDocs.js +0 -168
- package/dist/docs/SkeletonDocs.d.ts +0 -4
- package/dist/docs/SkeletonDocs.d.ts.map +0 -1
- package/dist/docs/SkeletonDocs.js +0 -7
- package/dist/docs/SnackbarDocs.d.ts +0 -4
- package/dist/docs/SnackbarDocs.d.ts.map +0 -1
- package/dist/docs/SnackbarDocs.js +0 -69
- package/dist/docs/TabsGroupDocs.d.ts +0 -4
- package/dist/docs/TabsGroupDocs.d.ts.map +0 -1
- package/dist/docs/TabsGroupDocs.js +0 -38
- package/dist/docs/ThemeSwitcherDocs.d.ts +0 -4
- package/dist/docs/ThemeSwitcherDocs.d.ts.map +0 -1
- package/dist/docs/ThemeSwitcherDocs.js +0 -11
- package/dist/docs/docMockServices/empresaService.d.ts +0 -38
- package/dist/docs/docMockServices/empresaService.d.ts.map +0 -1
- package/dist/docs/docMockServices/empresaService.js +0 -125
- package/dist/docs/docMockServices/index.d.ts +0 -9
- package/dist/docs/docMockServices/index.d.ts.map +0 -1
- package/dist/docs/docMockServices/index.js +0 -8
- package/dist/docs/docMockServices/initialData.d.ts +0 -6
- package/dist/docs/docMockServices/initialData.d.ts.map +0 -1
- package/dist/docs/docMockServices/initialData.js +0 -132
- package/dist/docs/docMockServices/interfaces.d.ts +0 -38
- package/dist/docs/docMockServices/interfaces.d.ts.map +0 -1
- package/dist/docs/docMockServices/interfaces.js +0 -1
- package/dist/docs/docMockServices/personaEmpresaService.d.ts +0 -43
- package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +0 -1
- package/dist/docs/docMockServices/personaEmpresaService.js +0 -151
- package/dist/docs/docMockServices/personaService.d.ts +0 -39
- package/dist/docs/docMockServices/personaService.d.ts.map +0 -1
- package/dist/docs/docMockServices/personaService.js +0 -190
- package/dist/helpers/currencyFormat.js +0 -3
- package/dist/helpers/getErrorMessage.js +0 -13
- package/dist/helpers/getInitialLetters.js +0 -5
- package/dist/helpers/getQueryString.js +0 -13
- package/dist/helpers/index.js +0 -9
- package/dist/helpers/mappers.js +0 -27
- package/dist/helpers/nameValueArrayToObject.js +0 -3
- package/dist/helpers/objectToQueryString.js +0 -3
- package/dist/helpers/queryStringToObject.js +0 -13
- package/dist/helpers/regularExpressions.js +0 -5
- package/dist/hooks/index.js +0 -6
- package/dist/hooks/useAsyncRequest.js +0 -53
- package/dist/hooks/useBreakpoint.js +0 -59
- package/dist/hooks/useElementScroll.js +0 -58
- package/dist/hooks/useEnum.js +0 -21
- package/dist/hooks/useGlobalThemeStyles.js +0 -40
- package/dist/hooks/useThemeOverride.js +0 -99
- package/dist/interfaces/index.js +0 -1
- package/dist/interfaces/name-value.interface.js +0 -1
- package/dist/interfaces/pagination.interface.js +0 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js +0 -6
- package/dist/services/apiClient.js +0 -216
- package/dist/services/index.js +0 -1
- package/dist/styles.d.ts +0 -2
- package/dist/styles.d.ts.map +0 -1
- package/dist/styles.js +0 -3
- package/dist/templates/forms/ContactForm.js +0 -58
- package/dist/templates/forms/LoginForm.js +0 -36
- package/dist/templates/forms/RegistrationForm.js +0 -54
- package/dist/templates/layouts/DashboardLayout.js +0 -26
- package/dist/templates/layouts/SidebarLayout.js +0 -28
- package/dist/templates/patterns/FormPattern.js +0 -68
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import React, { useState, useRef } from "react";
|
|
3
|
-
import { useBreakpoint } from "../../hooks";
|
|
4
|
-
import { useElementScroll } from "../../hooks/useElementScroll";
|
|
5
|
-
import { Button } from "../form-controls";
|
|
6
|
-
export const AppLayout = ({ navbar, leftDrawer, contentFooter, 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;
|
|
18
|
-
const { isMobile, isTablet } = useBreakpoint();
|
|
19
|
-
const contentRef = useRef(null);
|
|
20
|
-
const { scrollY, scrollDirection } = useElementScroll(contentRef);
|
|
21
|
-
const [isMobileDrawerOpen, setIsMobileDrawerOpen] = useState(false);
|
|
22
|
-
const [isNavbarVisible, setIsNavbarVisible] = useState(true);
|
|
23
|
-
const isNavbarVisibleRef = useRef(isNavbarVisible);
|
|
24
|
-
const isTransitioningRef = useRef(false);
|
|
25
|
-
const lastScrollYRef = useRef(0);
|
|
26
|
-
// Determinar si hay algún contenido en el drawer izquierdo
|
|
27
|
-
const hasLeftDrawerContent = leftDrawerHeader || leftDrawerContent || leftDrawerFooter;
|
|
28
|
-
const shouldShowMobileDrawer = isMobile || isTablet;
|
|
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);
|
|
35
|
-
// Mantener el ref sincronizado con el estado
|
|
36
|
-
React.useEffect(() => {
|
|
37
|
-
isNavbarVisibleRef.current = isNavbarVisible;
|
|
38
|
-
// Marcar que estamos en transición por 350ms (duración de la transición + margen)
|
|
39
|
-
isTransitioningRef.current = true;
|
|
40
|
-
const timer = setTimeout(() => {
|
|
41
|
-
isTransitioningRef.current = false;
|
|
42
|
-
}, 350);
|
|
43
|
-
return () => clearTimeout(timer);
|
|
44
|
-
}, [isNavbarVisible]);
|
|
45
|
-
// Controlar visibilidad del navbar basado en scroll con histeresis mejorada
|
|
46
|
-
React.useEffect(() => {
|
|
47
|
-
// Ignorar cambios durante transiciones o cambios muy pequeños de scroll
|
|
48
|
-
if (isTransitioningRef.current) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const SCROLL_DELTA_THRESHOLD = 5; // Mínimo cambio de scroll para considerar
|
|
52
|
-
const scrollDelta = Math.abs(scrollY - lastScrollYRef.current);
|
|
53
|
-
// Ignorar cambios muy pequeños que pueden ser causados por el cambio de padding
|
|
54
|
-
if (scrollDelta < SCROLL_DELTA_THRESHOLD && lastScrollYRef.current > 0) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const SHOW_THRESHOLD = 80;
|
|
58
|
-
const HIDE_THRESHOLD = 120;
|
|
59
|
-
// Verificar si estamos cerca del final del scroll (margen de error de 10px)
|
|
60
|
-
const element = contentRef.current;
|
|
61
|
-
const isNearBottom = element
|
|
62
|
-
? Math.abs(element.scrollHeight - element.clientHeight - element.scrollTop) < 10
|
|
63
|
-
: false;
|
|
64
|
-
let shouldBeVisible;
|
|
65
|
-
if (scrollY < SHOW_THRESHOLD) {
|
|
66
|
-
// Siempre mostrar navbar cerca del top
|
|
67
|
-
shouldBeVisible = true;
|
|
68
|
-
}
|
|
69
|
-
else if (scrollDirection === "down" &&
|
|
70
|
-
scrollY > HIDE_THRESHOLD &&
|
|
71
|
-
!isNearBottom) {
|
|
72
|
-
// Ocultar navbar al hacer scroll hacia abajo, excepto si estamos cerca del final
|
|
73
|
-
shouldBeVisible = false;
|
|
74
|
-
}
|
|
75
|
-
else if (scrollDirection === "up" && scrollY > SHOW_THRESHOLD) {
|
|
76
|
-
// Mostrar navbar al hacer scroll hacia arriba
|
|
77
|
-
shouldBeVisible = true;
|
|
78
|
-
}
|
|
79
|
-
else if (isNearBottom && scrollDirection === "down") {
|
|
80
|
-
// Si estamos en el final y scrolleamos hacia abajo, mantener el estado actual
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
// No cambiar el estado si scrollDirection es null o no se cumple ninguna condición
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
// Solo actualizar el estado si hay un cambio real
|
|
88
|
-
if (shouldBeVisible !== isNavbarVisibleRef.current) {
|
|
89
|
-
lastScrollYRef.current = scrollY;
|
|
90
|
-
setIsNavbarVisible(shouldBeVisible);
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
// Actualizar la referencia del scroll incluso si no cambiamos la visibilidad
|
|
94
|
-
lastScrollYRef.current = scrollY;
|
|
95
|
-
}
|
|
96
|
-
}, [scrollDirection, scrollY]);
|
|
97
|
-
const handleMobileDrawerToggle = () => {
|
|
98
|
-
setIsMobileDrawerOpen(!isMobileDrawerOpen);
|
|
99
|
-
};
|
|
100
|
-
const handleOverlayClick = () => {
|
|
101
|
-
setIsMobileDrawerOpen(false);
|
|
102
|
-
};
|
|
103
|
-
// Clases base del layout
|
|
104
|
-
const layoutClasses = `
|
|
105
|
-
flex flex-col w-full ${navbar?.navBarLeftNode || navbar?.navBarRightNode || leftDrawer?.contentNode || leftDrawer?.headerNode || leftDrawer?.footerNode ? "h-screen overflow-hidden" : "h-auto"}
|
|
106
|
-
font-[var(--font-default)]
|
|
107
|
-
${className}
|
|
108
|
-
`;
|
|
109
|
-
// Clases del navbar
|
|
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 100ms ease-in",
|
|
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 100ms ease-in, min-height 100ms ease-in, max-height 100ms ease-in",
|
|
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 100ms ease-in, max-height 100ms ease-in",
|
|
139
|
-
opacity: isNavbarVisible || fullWidthNavbar ? 1 : 0,
|
|
140
|
-
};
|
|
141
|
-
const navbarLeftClasses = `flex items-center gap-2`;
|
|
142
|
-
const navbarRightClasses = `flex items-center gap-2`;
|
|
143
|
-
// Clases del contenido principal
|
|
144
|
-
const mainClasses = `flex flex-1 overflow-hidden transition-all duration-100 ease-in`;
|
|
145
|
-
// Style for main content with dynamic navbar height padding
|
|
146
|
-
// No padding here anymore, it's handled by individual elements
|
|
147
|
-
const mainStyle = {};
|
|
148
|
-
// Style for the main content area (actual scrollable area)
|
|
149
|
-
// When fullWidthNavbar is true, we need top padding to avoid being covered by fixed navbar
|
|
150
|
-
const contentStyle = fullWidthNavbar && shouldShowNavbar && isNavbarVisible
|
|
151
|
-
? { paddingTop: navbarHeight }
|
|
152
|
-
: {};
|
|
153
|
-
// Clases del drawer izquierdo (contenedor principal)
|
|
154
|
-
// width se aplica como estilo inline para tener prioridad sobre className
|
|
155
|
-
const leftDrawerClasses = `
|
|
156
|
-
${leftDrawerWidth ? "" : "w-64"} bg-[var(--color-bg-default)]
|
|
157
|
-
flex-shrink-0 flex flex-col
|
|
158
|
-
transition-all duration-100 ease-in
|
|
159
|
-
${leftDrawerClassName}
|
|
160
|
-
`
|
|
161
|
-
.trim()
|
|
162
|
-
.replace(/\s+/g, " ");
|
|
163
|
-
// Style for left drawer with dynamic height and positioning
|
|
164
|
-
const leftDrawerStyle = {
|
|
165
|
-
...(leftDrawerWidth ? { width: leftDrawerWidth } : {}),
|
|
166
|
-
height: "100%", // Siempre 100% para evitar huecos en la parte superior
|
|
167
|
-
};
|
|
168
|
-
if (fullWidthNavbar) {
|
|
169
|
-
// Si el navbar es fullwidth, el drawer mide 100% y usamos padding para que el contenido
|
|
170
|
-
// no quede debajo del navbar fixed.
|
|
171
|
-
leftDrawerStyle.paddingTop =
|
|
172
|
-
shouldShowNavbar && isNavbarVisible ? navbarHeight : "0px";
|
|
173
|
-
leftDrawerStyle.transition = "padding-top 100ms ease-in";
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
// Si no es fullwidth, el drawer está al lado del navbar.
|
|
177
|
-
// No necesitamos marginTop ni height dinámico porque ya está en un flex-row
|
|
178
|
-
// y queremos que ocupe siempre todo el alto desde el borde superior.
|
|
179
|
-
leftDrawerStyle.marginTop = "0px";
|
|
180
|
-
leftDrawerStyle.transition = "padding-top 100ms ease-in";
|
|
181
|
-
}
|
|
182
|
-
// Clases del contenedor que incluye drawer y contenido (cuando fullWidthNavbar es false)
|
|
183
|
-
const contentWrapperClasses = fullWidthNavbar
|
|
184
|
-
? ""
|
|
185
|
-
: `flex flex-row flex-1 overflow-hidden`;
|
|
186
|
-
// Clases del contenedor que incluye navbar y main (cuando fullWidthNavbar es false)
|
|
187
|
-
const drawerAndContentClasses = fullWidthNavbar
|
|
188
|
-
? ""
|
|
189
|
-
: `flex flex-col flex-1 overflow-hidden`;
|
|
190
|
-
// Style for drawer and content wrapper with dynamic navbar height padding
|
|
191
|
-
const drawerAndContentStyle = !fullWidthNavbar && shouldShowNavbar && isNavbarVisible
|
|
192
|
-
? { paddingTop: 0 }
|
|
193
|
-
: {};
|
|
194
|
-
// Clases del header del drawer (fijo arriba)
|
|
195
|
-
const leftDrawerHeaderClasses = `
|
|
196
|
-
flex-shrink-0
|
|
197
|
-
`;
|
|
198
|
-
// Clases del contenido del drawer (scrolleable sin scrollbar visible)
|
|
199
|
-
const leftDrawerContentClasses = `
|
|
200
|
-
flex-1 overflow-y-auto scrollbar-hide
|
|
201
|
-
`;
|
|
202
|
-
// Clases del footer del drawer (fijo abajo)
|
|
203
|
-
const leftDrawerFooterClasses = `
|
|
204
|
-
flex-shrink-0
|
|
205
|
-
`;
|
|
206
|
-
const contentClasses = `
|
|
207
|
-
flex-1 overflow-y-auto flex flex-col
|
|
208
|
-
`;
|
|
209
|
-
// Clases del overlay móvil
|
|
210
|
-
const overlayClasses = `
|
|
211
|
-
fixed inset-0 bg-black/50 backdrop-blur-sm z-[1998]
|
|
212
|
-
`;
|
|
213
|
-
// Clases del drawer móvil
|
|
214
|
-
const mobileDrawerBaseClasses = `
|
|
215
|
-
fixed top-0 left-0 h-screen w-64 max-w-[80vw]
|
|
216
|
-
bg-[var(--color-bg-default)] shadow-[var(--shadow-xl)]
|
|
217
|
-
transform -translate-x-full transition-transform duration-100 ease-in
|
|
218
|
-
z-[1999] flex flex-col
|
|
219
|
-
${leftDrawerClassName}
|
|
220
|
-
`
|
|
221
|
-
.trim()
|
|
222
|
-
.replace(/\s+/g, " ");
|
|
223
|
-
// Style for mobile drawer with dynamic width
|
|
224
|
-
const mobileDrawerStyle = leftDrawerWidth ? { width: leftDrawerWidth } : {};
|
|
225
|
-
const mobileDrawerOpenClasses = `translate-x-0`;
|
|
226
|
-
const mobileDrawerContentClasses = `
|
|
227
|
-
flex-1 overflow-y-auto scrollbar-hide
|
|
228
|
-
`;
|
|
229
|
-
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 }))] })), _jsxs("main", { ref: contentRef, className: contentClasses, style: contentStyle, children: [_jsx("div", { className: "flex-1", children: children }), contentFooter && _jsx("div", { role: "contentinfo", children: contentFooter })] })] })] })) : (_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 px-2", 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("main", { ref: contentRef, className: contentClasses, style: contentStyle, children: [_jsx("div", { className: "flex-1", children: children }), contentFooter && _jsx("div", { role: "contentinfo", children: contentFooter })] })] })] }) })), 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: "absolute top-3 right-2", 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 }))] }))] }));
|
|
230
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { twMerge } from "tailwind-merge";
|
|
4
|
-
export const Card = ({ title, subtitle, children, className = "", headerActions, footer, variant = "default", alwaysDisplayHeaderActions = false, headerClassName = "", contentClassName = "", footerClassName = "", compact = false, }) => {
|
|
5
|
-
const variantClasses = {
|
|
6
|
-
default: "border-[var(--color-border-default)]",
|
|
7
|
-
elevated: "border-[var(--color-border-default)] shadow-[var(--shadow-lg)]",
|
|
8
|
-
outlined: "border-[var(--color-gray-300)]",
|
|
9
|
-
};
|
|
10
|
-
// Unimos las clases usando twMerge para consistencia
|
|
11
|
-
const mergedClasses = twMerge("bg-[var(--color-bg-default)] rounded-lg border font-[var(--font-default)]", variantClasses[variant], className);
|
|
12
|
-
// Verificamos si existe alguna clase de ancho (w-*) que no sea w-auto.
|
|
13
|
-
// Es importante distinguir entre w-* (ancho) y max-w-*/min-w-* (límites),
|
|
14
|
-
// ya que un max-w-* sin un w-full puede hacer que la card colapse a su contenido.
|
|
15
|
-
const hasExplicitWidth = mergedClasses.split(/\s+/).some((cls) => {
|
|
16
|
-
const mainClass = cls.split(":").pop() || "";
|
|
17
|
-
return (mainClass.startsWith("w-") &&
|
|
18
|
-
mainClass !== "w-auto" &&
|
|
19
|
-
!mainClass.startsWith("max-w-") &&
|
|
20
|
-
!mainClass.startsWith("min-w-"));
|
|
21
|
-
});
|
|
22
|
-
// Si no hay un ancho explícito, forzamos w-full para que ocupe todo el espacio disponible
|
|
23
|
-
// (incluyendo el espacio limitado por un posible max-w- en la misma card o en su padre).
|
|
24
|
-
const classes = hasExplicitWidth ? mergedClasses : `${mergedClasses} w-full`;
|
|
25
|
-
const [isHovered, setIsHovered] = React.useState(false);
|
|
26
|
-
const [isLargeScreen, setIsLargeScreen] = React.useState(false);
|
|
27
|
-
React.useEffect(() => {
|
|
28
|
-
const checkScreenSize = () => {
|
|
29
|
-
// md breakpoint en Tailwind es 768px, así que lg es 1024px
|
|
30
|
-
setIsLargeScreen(window.innerWidth >= 1024);
|
|
31
|
-
};
|
|
32
|
-
checkScreenSize();
|
|
33
|
-
window.addEventListener("resize", checkScreenSize);
|
|
34
|
-
return () => {
|
|
35
|
-
window.removeEventListener("resize", checkScreenSize);
|
|
36
|
-
};
|
|
37
|
-
}, []);
|
|
38
|
-
// Determinar la opacidad de las headerActions
|
|
39
|
-
const getHeaderActionsOpacity = () => {
|
|
40
|
-
if (!headerActions)
|
|
41
|
-
return 0;
|
|
42
|
-
// En pantallas pequeñas (md e inferiores) siempre se muestran
|
|
43
|
-
if (!isLargeScreen)
|
|
44
|
-
return 1;
|
|
45
|
-
// Si alwaysDisplayHeaderActions es true, siempre se muestran
|
|
46
|
-
if (alwaysDisplayHeaderActions)
|
|
47
|
-
return 1;
|
|
48
|
-
// Si es false y pantalla grande, solo al hacer hover
|
|
49
|
-
return isHovered ? 1 : 0;
|
|
50
|
-
};
|
|
51
|
-
return (_jsxs("div", { className: `${classes} relative`, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [(title || subtitle || headerActions) && (_jsx("div", { className: twMerge(compact ? "px-4 pt-2" : "px-6 pt-4", headerClassName), 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("div", { className: "text-sm text-[var(--color-text-secondary)] mt-1", children: subtitle }))] }), headerActions && (_jsx("div", { className: "flex items-center transition-opacity", style: {
|
|
52
|
-
opacity: getHeaderActionsOpacity(),
|
|
53
|
-
}, children: headerActions }))] }) })), children && (_jsx("div", { className: twMerge(compact ? "px-4 py-4" : "px-6 py-4", contentClassName), children: children })), footer && (_jsx("div", { className: twMerge(compact ? "px-4 pb-2" : "px-6 pb-4", "flex items-center justify-end", footerClassName), children: footer }))] }));
|
|
54
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
export const Collection = ({ children, gap = "1rem", direction = "column", wrap = false, className = "", }) => {
|
|
4
|
-
const baseClasses = `
|
|
5
|
-
flex
|
|
6
|
-
font-[var(--font-default)]
|
|
7
|
-
`;
|
|
8
|
-
const directionClasses = {
|
|
9
|
-
column: "flex-col",
|
|
10
|
-
row: "flex-row",
|
|
11
|
-
};
|
|
12
|
-
const wrapClass = wrap ? "flex-wrap" : "flex-nowrap";
|
|
13
|
-
const classes = `${baseClasses} ${directionClasses[direction]} ${wrapClass} ${className}`.trim();
|
|
14
|
-
const style = {
|
|
15
|
-
gap: gap,
|
|
16
|
-
};
|
|
17
|
-
return (_jsx("div", { className: classes, style: style, children: children }));
|
|
18
|
-
};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { Button } from "../form-controls";
|
|
4
|
-
export const DataField = ({ label, value, inline = false, align = "left", title, link, className = "", labelClassName = "", }) => {
|
|
5
|
-
const handleLinkClick = () => {
|
|
6
|
-
if (link) {
|
|
7
|
-
window.open(link, "_blank", "noopener,noreferrer");
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
const alignClasses = {
|
|
11
|
-
left: "text-left",
|
|
12
|
-
right: "text-right",
|
|
13
|
-
center: "text-center",
|
|
14
|
-
};
|
|
15
|
-
const justifyClasses = {
|
|
16
|
-
left: "justify-start",
|
|
17
|
-
right: "justify-end",
|
|
18
|
-
center: "justify-center",
|
|
19
|
-
};
|
|
20
|
-
const baseContainerClasses = `
|
|
21
|
-
font-[var(--font-default)]
|
|
22
|
-
${alignClasses[align]}
|
|
23
|
-
${className}
|
|
24
|
-
`.trim();
|
|
25
|
-
const baseLabelClasses = `
|
|
26
|
-
text-sm text-[var(--color-text-primary)]
|
|
27
|
-
${labelClassName}
|
|
28
|
-
`.trim();
|
|
29
|
-
const baseValueClasses = `
|
|
30
|
-
text-base text-[var(--color-text-primary)]
|
|
31
|
-
`;
|
|
32
|
-
if (inline) {
|
|
33
|
-
// Modo inline: label y value en la misma línea
|
|
34
|
-
return (_jsx("div", { className: baseContainerClasses, title: title, children: _jsxs("div", { className: `flex items-center gap-2 ${justifyClasses[align]}`, children: [label && _jsxs("span", { className: baseLabelClasses, children: [label, ":"] }), _jsx("span", { className: baseValueClasses, children: value }), link && (_jsx(Button, { size: "sm", variant: "ghost", icon: "fa-arrow-right", onClick: handleLinkClick, "aria-label": "Abrir enlace" }))] }) }));
|
|
35
|
-
}
|
|
36
|
-
// Modo vertical: label arriba, value abajo
|
|
37
|
-
return (_jsxs("div", { className: baseContainerClasses, title: title, children: [label && _jsx("div", { className: baseLabelClasses, children: label }), _jsxs("div", { className: `flex items-center gap-2 ${justifyClasses[align]}`, children: [_jsx("div", { className: baseValueClasses, children: value }), link && (_jsx(Button, { size: "sm", variant: "ghost", icon: "fa-arrow-right", onClick: handleLinkClick, "aria-label": "Abrir enlace" }))] })] }));
|
|
38
|
-
};
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { twMerge } from "tailwind-merge";
|
|
4
|
-
import { DropdownMenu } from "./DropdownMenu";
|
|
5
|
-
export const DataTable = ({ columns, rows, className = "", maxRows, locale = "es-AR", isLoading = false, loadingRows = 5, rowClassName, headerClassName = "", footerClassName = "", headerCellClassName = "", footerCellClassName = "", cellClassName = "", compact = false, }) => {
|
|
6
|
-
// Calcular si necesitamos scroll
|
|
7
|
-
const displayRows = isLoading ? loadingRows : rows.length;
|
|
8
|
-
const needsScroll = maxRows !== undefined && displayRows > maxRows;
|
|
9
|
-
// Altura aproximada de una fila (px-4 py-3 = ~48px por fila, compact es menos)
|
|
10
|
-
const rowHeight = compact ? 32 : 48;
|
|
11
|
-
const maxHeight = maxRows ? `${maxRows * rowHeight}px` : undefined;
|
|
12
|
-
const cellPadding = compact ? "px-2 py-1" : "px-4 py-3";
|
|
13
|
-
// Verificar si alguna columna tiene footer
|
|
14
|
-
const hasFooter = columns.some((column) => column.footer !== undefined);
|
|
15
|
-
const getCellValue = (column, row) => {
|
|
16
|
-
if (!column.value)
|
|
17
|
-
return null;
|
|
18
|
-
if (typeof column.value === "function") {
|
|
19
|
-
return column.value(row);
|
|
20
|
-
}
|
|
21
|
-
// Si es string o number, puede ser un nombre de propiedad o un valor directo
|
|
22
|
-
if (typeof column.value === "string" || typeof column.value === "number") {
|
|
23
|
-
// Intentar obtener la propiedad del objeto si existe
|
|
24
|
-
if (typeof column.value === "string" &&
|
|
25
|
-
typeof row === "object" &&
|
|
26
|
-
row !== null) {
|
|
27
|
-
const value = row[column.value];
|
|
28
|
-
if (value !== undefined) {
|
|
29
|
-
return value;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// Si no es una propiedad, retornar el valor directo
|
|
33
|
-
return column.value;
|
|
34
|
-
}
|
|
35
|
-
return column.value;
|
|
36
|
-
};
|
|
37
|
-
const formatValue = (value, type) => {
|
|
38
|
-
if (React.isValidElement(value)) {
|
|
39
|
-
return value;
|
|
40
|
-
}
|
|
41
|
-
// Convertir string a número si es necesario para currency o numeric
|
|
42
|
-
let numericValue = null;
|
|
43
|
-
if (typeof value === "number") {
|
|
44
|
-
numericValue = value;
|
|
45
|
-
}
|
|
46
|
-
else if (typeof value === "string" &&
|
|
47
|
-
(type === "currency" || type === "numeric")) {
|
|
48
|
-
const parsed = parseFloat(value);
|
|
49
|
-
if (!isNaN(parsed)) {
|
|
50
|
-
numericValue = parsed;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (numericValue !== null) {
|
|
54
|
-
if (type === "currency") {
|
|
55
|
-
// Formatear usando el locale proporcionado sin símbolo de moneda
|
|
56
|
-
const parts = new Intl.NumberFormat(locale, {
|
|
57
|
-
style: "currency",
|
|
58
|
-
currency: "EUR",
|
|
59
|
-
minimumFractionDigits: 2,
|
|
60
|
-
maximumFractionDigits: 2,
|
|
61
|
-
}).formatToParts(numericValue);
|
|
62
|
-
// Construir el string sin el símbolo de moneda
|
|
63
|
-
return parts
|
|
64
|
-
.filter((part) => part.type !== "currency")
|
|
65
|
-
.map((part) => part.value)
|
|
66
|
-
.join("");
|
|
67
|
-
}
|
|
68
|
-
if (type === "numeric") {
|
|
69
|
-
// Formatear usando el locale proporcionado
|
|
70
|
-
const hasDecimals = numericValue % 1 !== 0;
|
|
71
|
-
return new Intl.NumberFormat(locale, {
|
|
72
|
-
minimumFractionDigits: hasDecimals ? 2 : 0,
|
|
73
|
-
maximumFractionDigits: hasDecimals ? 2 : 0,
|
|
74
|
-
}).format(numericValue);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (typeof value === "string" && type === "date") {
|
|
78
|
-
try {
|
|
79
|
-
const date = new Date(value);
|
|
80
|
-
return date.toLocaleDateString(locale);
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return value;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return value;
|
|
87
|
-
};
|
|
88
|
-
const getAlignmentClass = (align, type) => {
|
|
89
|
-
// Las columnas de tipo 'date' siempre se alinean a la izquierda
|
|
90
|
-
// Las columnas de tipo 'currency' y 'numeric' siempre se alinean a la derecha
|
|
91
|
-
let effectiveAlign = align;
|
|
92
|
-
if (type === "date") {
|
|
93
|
-
effectiveAlign = "left";
|
|
94
|
-
}
|
|
95
|
-
else if (type === "currency" || type === "numeric") {
|
|
96
|
-
effectiveAlign = "right";
|
|
97
|
-
}
|
|
98
|
-
switch (effectiveAlign) {
|
|
99
|
-
case "right":
|
|
100
|
-
return "text-right";
|
|
101
|
-
case "center":
|
|
102
|
-
return "text-center";
|
|
103
|
-
case "left":
|
|
104
|
-
default:
|
|
105
|
-
return "text-left";
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
// Convertir array de ReactNode a array de ActionItem para DropdownMenu
|
|
109
|
-
const convertActionsToOptions = (actions) => {
|
|
110
|
-
return actions.map((action, index) => ({
|
|
111
|
-
id: index,
|
|
112
|
-
content: (_jsx("div", { onClick: (e) => {
|
|
113
|
-
// Detener la propagación para que el onClick del DropdownMenu no interfiera
|
|
114
|
-
e.stopPropagation();
|
|
115
|
-
}, children: action })),
|
|
116
|
-
}));
|
|
117
|
-
};
|
|
118
|
-
// Componente Skeleton para celdas de carga
|
|
119
|
-
const SkeletonCell = () => (_jsx("div", { className: "h-4 bg-[var(--color-border-default)]/40 rounded animate-pulse w-full" }));
|
|
120
|
-
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: twMerge("border-b border-[var(--color-border-default)] text-[var(--color-text-primary)]", headerClassName), children: columns.map((column, index) => {
|
|
121
|
-
const headerActions = column.headerActions?.();
|
|
122
|
-
const hasHeaderActions = headerActions && headerActions.length > 0;
|
|
123
|
-
const headerBgClasses = headerClassName
|
|
124
|
-
.split(/\s+/)
|
|
125
|
-
.filter((cls) => cls.split(":").pop()?.startsWith("bg-"))
|
|
126
|
-
.join(" ");
|
|
127
|
-
return (_jsx("th", { className: twMerge(cellPadding, "text-sm font-semibold", headerBgClasses || "bg-[var(--color-bg-secondary)]", getAlignmentClass(column.align, column.type), hasHeaderActions ? "relative" : "", headerCellClassName), style: {
|
|
128
|
-
...(column.width ? { width: column.width } : {}),
|
|
129
|
-
}, 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: () => {
|
|
130
|
-
// Las acciones ya manejan sus propios eventos
|
|
131
|
-
}, renderOption: (item) => item.content, replaceOnSingleOption: true })] })) : (column.header || "") }, index));
|
|
132
|
-
}) }) }), _jsx("tbody", { children: isLoading
|
|
133
|
-
? Array.from({ length: loadingRows }).map((_, rowIndex) => (_jsx("tr", { className: "border-b border-[var(--color-border-default)] text-[var(--color-text-primary)]", children: columns.map((column, colIndex) => (_jsx("td", { className: twMerge(cellPadding, "text-sm", getAlignmentClass(column.align, column.type)), style: {
|
|
134
|
-
...(column.width ? { width: column.width } : {}),
|
|
135
|
-
}, children: _jsx(SkeletonCell, {}) }, colIndex))) }, `skeleton-${rowIndex}`)))
|
|
136
|
-
: rows.map((row, rowIndex) => (_jsx("tr", { className: twMerge("group/row border-b border-[var(--color-border-default)] transition-colors hover:bg-[var(--color-bg-secondary)] text-[var(--color-text-primary)]", rowClassName?.(row)), children: columns.map((column, colIndex) => {
|
|
137
|
-
const cellValue = getCellValue(column, row);
|
|
138
|
-
const formattedValue = formatValue(cellValue, column.type);
|
|
139
|
-
const tooltip = column.tooltip
|
|
140
|
-
? column.tooltip(row)
|
|
141
|
-
: undefined;
|
|
142
|
-
const rowActions = column.actions?.(row);
|
|
143
|
-
const hasRowActions = rowActions && rowActions.length > 0;
|
|
144
|
-
return (_jsx("td", { className: twMerge(cellPadding, "text-sm", getAlignmentClass(column.align, column.type), typeof cellClassName === "function"
|
|
145
|
-
? cellClassName(row, column)
|
|
146
|
-
: cellClassName), style: {
|
|
147
|
-
...(column.width ? { width: column.width } : {}),
|
|
148
|
-
}, title: tooltip
|
|
149
|
-
? typeof tooltip === "string"
|
|
150
|
-
? tooltip
|
|
151
|
-
: undefined
|
|
152
|
-
: 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: () => {
|
|
153
|
-
// Las acciones ya manejan sus propios eventos
|
|
154
|
-
}, renderOption: (item) => item.content, replaceOnSingleOption: true }) })] })) : (formattedValue) }, colIndex));
|
|
155
|
-
}) }, rowIndex))) }), hasFooter && (_jsx("tfoot", { className: needsScroll ? "sticky bottom-0 z-10" : "", children: _jsx("tr", { className: twMerge("border-t border-[var(--color-border-default)] text-[var(--color-text-primary)]", footerClassName), children: columns.map((column, index) => {
|
|
156
|
-
const footerBgClasses = footerClassName
|
|
157
|
-
.split(/\s+/)
|
|
158
|
-
.filter((cls) => cls.split(":").pop()?.startsWith("bg-"))
|
|
159
|
-
.join(" ");
|
|
160
|
-
return (_jsx("td", { className: twMerge(cellPadding, "text-sm font-semibold", footerBgClasses || "bg-[var(--color-bg-secondary)]", getAlignmentClass(column.align, column.type), footerCellClassName), style: {
|
|
161
|
-
...(column.width ? { width: column.width } : {}),
|
|
162
|
-
}, children: isLoading ? _jsx(SkeletonCell, {}) : column.footer || "" }, index));
|
|
163
|
-
}) }) }))] }) }) }));
|
|
164
|
-
};
|