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.
- 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 +11889 -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 +6 -3
- 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,176 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useState, useRef, useEffect, useCallback, useMemo, } from "react";
|
|
3
|
-
import { createPortal } from "react-dom";
|
|
4
|
-
import { Button } from "../form-controls/Button";
|
|
5
|
-
export const DropdownMenu = ({ options, onOptionSelected, renderNode, getOptionLabel, renderOption, replaceOnSingleOption = false, openOnHover = false, }) => {
|
|
6
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
7
|
-
const [menuPosition, setMenuPosition] = useState("bottom");
|
|
8
|
-
const [scrollUpdate, setScrollUpdate] = useState(0);
|
|
9
|
-
const triggerRef = useRef(null);
|
|
10
|
-
const menuRef = useRef(null);
|
|
11
|
-
const hoverTimeoutRef = useRef(null);
|
|
12
|
-
// Calcular posición del menú
|
|
13
|
-
const calculatePosition = useCallback(() => {
|
|
14
|
-
if (isOpen && triggerRef.current) {
|
|
15
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
16
|
-
const viewportHeight = window.innerHeight;
|
|
17
|
-
// Estimar altura del menú (aproximadamente 40px por opción + padding)
|
|
18
|
-
const estimatedMenuHeight = options.length * 40 + 16;
|
|
19
|
-
const menuMargin = 4;
|
|
20
|
-
// Calcular espacio disponible arriba y abajo
|
|
21
|
-
const spaceBelow = viewportHeight - triggerRect.bottom - menuMargin;
|
|
22
|
-
const spaceAbove = triggerRect.top - menuMargin;
|
|
23
|
-
// Si no hay suficiente espacio abajo pero sí arriba, mostrar arriba
|
|
24
|
-
// Usamos un margen de seguridad para asegurar que el menú quepa
|
|
25
|
-
if (spaceBelow < estimatedMenuHeight && spaceAbove > spaceBelow) {
|
|
26
|
-
setMenuPosition("top");
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
setMenuPosition("bottom");
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}, [isOpen, options.length]);
|
|
33
|
-
useEffect(() => {
|
|
34
|
-
calculatePosition();
|
|
35
|
-
}, [calculatePosition]);
|
|
36
|
-
// Recalcular posición al hacer scroll o redimensionar
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (isOpen) {
|
|
39
|
-
const handleScroll = () => {
|
|
40
|
-
calculatePosition();
|
|
41
|
-
// Forzar actualización del estilo del menú
|
|
42
|
-
setScrollUpdate((prev) => prev + 1);
|
|
43
|
-
};
|
|
44
|
-
window.addEventListener("scroll", handleScroll, true);
|
|
45
|
-
window.addEventListener("resize", handleScroll);
|
|
46
|
-
return () => {
|
|
47
|
-
window.removeEventListener("scroll", handleScroll, true);
|
|
48
|
-
window.removeEventListener("resize", handleScroll);
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}, [isOpen, calculatePosition]);
|
|
52
|
-
// Cerrar menú al hacer click fuera
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const handleClickOutside = (event) => {
|
|
55
|
-
if (isOpen &&
|
|
56
|
-
triggerRef.current &&
|
|
57
|
-
menuRef.current &&
|
|
58
|
-
!triggerRef.current.contains(event.target) &&
|
|
59
|
-
!menuRef.current.contains(event.target)) {
|
|
60
|
-
setIsOpen(false);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
if (isOpen) {
|
|
64
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
65
|
-
}
|
|
66
|
-
return () => {
|
|
67
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
68
|
-
};
|
|
69
|
-
}, [isOpen]);
|
|
70
|
-
// Cerrar menú al presionar Escape
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
const handleEscape = (event) => {
|
|
73
|
-
if (event.key === "Escape" && isOpen) {
|
|
74
|
-
setIsOpen(false);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
if (isOpen) {
|
|
78
|
-
document.addEventListener("keydown", handleEscape);
|
|
79
|
-
}
|
|
80
|
-
return () => {
|
|
81
|
-
document.removeEventListener("keydown", handleEscape);
|
|
82
|
-
};
|
|
83
|
-
}, [isOpen]);
|
|
84
|
-
// Limpiar timeout al desmontar
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
return () => {
|
|
87
|
-
if (hoverTimeoutRef.current) {
|
|
88
|
-
window.clearTimeout(hoverTimeoutRef.current);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
}, []);
|
|
92
|
-
const labelGetter = useCallback((item) => {
|
|
93
|
-
if (getOptionLabel)
|
|
94
|
-
return getOptionLabel(item);
|
|
95
|
-
const anyItem = item;
|
|
96
|
-
return (anyItem.label ?? "").toString();
|
|
97
|
-
}, [getOptionLabel]);
|
|
98
|
-
const handleToggle = () => {
|
|
99
|
-
setIsOpen(!isOpen);
|
|
100
|
-
};
|
|
101
|
-
const handleMouseEnter = () => {
|
|
102
|
-
if (!openOnHover)
|
|
103
|
-
return;
|
|
104
|
-
if (hoverTimeoutRef.current) {
|
|
105
|
-
window.clearTimeout(hoverTimeoutRef.current);
|
|
106
|
-
hoverTimeoutRef.current = null;
|
|
107
|
-
}
|
|
108
|
-
setIsOpen(true);
|
|
109
|
-
};
|
|
110
|
-
const handleMouseLeave = () => {
|
|
111
|
-
if (!openOnHover)
|
|
112
|
-
return;
|
|
113
|
-
hoverTimeoutRef.current = window.setTimeout(() => {
|
|
114
|
-
setIsOpen(false);
|
|
115
|
-
}, 150); // Pequeño delay para permitir mover el mouse al menú
|
|
116
|
-
};
|
|
117
|
-
const handleOptionClick = (item) => {
|
|
118
|
-
setIsOpen(false);
|
|
119
|
-
onOptionSelected(item);
|
|
120
|
-
};
|
|
121
|
-
// Si replaceOnSingleOption es true y hay una sola opción, mostrar directamente la opción
|
|
122
|
-
const shouldReplace = replaceOnSingleOption && options.length === 1;
|
|
123
|
-
const singleOption = shouldReplace ? options[0] : null;
|
|
124
|
-
const menuStyles = useMemo(() => {
|
|
125
|
-
if (!isOpen || !triggerRef.current) {
|
|
126
|
-
return {};
|
|
127
|
-
}
|
|
128
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
129
|
-
const menuMargin = 4;
|
|
130
|
-
// Asegurar que el menú no se salga de la pantalla horizontalmente
|
|
131
|
-
let leftPosition = triggerRect.left;
|
|
132
|
-
const menuMinWidth = 160;
|
|
133
|
-
const viewportWidth = window.innerWidth;
|
|
134
|
-
// Si el menú se sale por la derecha, ajustar la posición
|
|
135
|
-
if (leftPosition + menuMinWidth > viewportWidth) {
|
|
136
|
-
leftPosition = viewportWidth - menuMinWidth - 8; // 8px de margen
|
|
137
|
-
}
|
|
138
|
-
// Asegurar que no se salga por la izquierda
|
|
139
|
-
if (leftPosition < 8) {
|
|
140
|
-
leftPosition = 8;
|
|
141
|
-
}
|
|
142
|
-
if (menuPosition === "top") {
|
|
143
|
-
return {
|
|
144
|
-
position: "fixed",
|
|
145
|
-
bottom: window.innerHeight - triggerRect.top + menuMargin,
|
|
146
|
-
left: leftPosition,
|
|
147
|
-
minWidth: Math.max(triggerRect.width, menuMinWidth),
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
return {
|
|
152
|
-
position: "fixed",
|
|
153
|
-
top: triggerRect.bottom + menuMargin,
|
|
154
|
-
left: leftPosition,
|
|
155
|
-
minWidth: Math.max(triggerRect.width, menuMinWidth),
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
// scrollUpdate se usa intencionalmente para forzar el recálculo en scroll
|
|
159
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
160
|
-
}, [isOpen, menuPosition, scrollUpdate]);
|
|
161
|
-
// Si debe reemplazar con la opción única, mostrar directamente la opción
|
|
162
|
-
if (shouldReplace && singleOption) {
|
|
163
|
-
return (_jsx("div", { onClick: () => handleOptionClick(singleOption), className: "cursor-pointer", children: renderOption ? renderOption(singleOption) : labelGetter(singleOption) }));
|
|
164
|
-
}
|
|
165
|
-
return (_jsxs("div", { className: "relative inline-block", ref: triggerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsx("div", { onClick: handleToggle, className: "cursor-pointer", children: renderNode ? (renderNode) : (_jsx(Button, { variant: "ghost", icon: "fa-ellipsis-h" })) }), isOpen &&
|
|
166
|
-
(typeof document !== "undefined" && document.body
|
|
167
|
-
? createPortal(_jsx("div", { ref: menuRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: (e) => e.stopPropagation(), className: "fixed z-[2000] bg-[var(--color-bg-default)] border border-[var(--color-border-default)] rounded-md shadow-[var(--shadow-lg)] py-1 min-w-[160px] font-[var(--font-default)]", style: menuStyles, children: options.map((option, index) => {
|
|
168
|
-
const key = String(option?.id ??
|
|
169
|
-
labelGetter(option) ??
|
|
170
|
-
index);
|
|
171
|
-
return (_jsx("div", { onClick: () => handleOptionClick(option), className: "px-4 py-2 text-sm text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] cursor-pointer transition-colors flex items-center", children: renderOption
|
|
172
|
-
? renderOption(option)
|
|
173
|
-
: labelGetter(option) }, key));
|
|
174
|
-
}) }), document.body)
|
|
175
|
-
: null)] }));
|
|
176
|
-
};
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useState, useRef, useEffect, useCallback, useMemo, } from "react";
|
|
3
|
-
import { createPortal } from "react-dom";
|
|
4
|
-
import { Button } from "../form-controls/Button";
|
|
5
|
-
export const DropdownPanel = ({ renderNode, children, openOnHover = false, }) => {
|
|
6
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
7
|
-
const [menuPosition, setMenuPosition] = useState("bottom");
|
|
8
|
-
const [scrollUpdate, setScrollUpdate] = useState(0);
|
|
9
|
-
const triggerRef = useRef(null);
|
|
10
|
-
const menuRef = useRef(null);
|
|
11
|
-
const hoverTimeoutRef = useRef(null);
|
|
12
|
-
// Calcular posición del menú
|
|
13
|
-
const calculatePosition = useCallback(() => {
|
|
14
|
-
if (isOpen && triggerRef.current) {
|
|
15
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
16
|
-
const viewportHeight = window.innerHeight;
|
|
17
|
-
// Intentar obtener la altura real del menú, o usar una estimación si no está montado aún
|
|
18
|
-
let menuHeight = 200; // valor por defecto
|
|
19
|
-
if (menuRef.current) {
|
|
20
|
-
menuHeight = menuRef.current.getBoundingClientRect().height;
|
|
21
|
-
}
|
|
22
|
-
const menuMargin = 4;
|
|
23
|
-
// Calcular espacio disponible arriba y abajo
|
|
24
|
-
const spaceBelow = viewportHeight - triggerRect.bottom - menuMargin;
|
|
25
|
-
const spaceAbove = triggerRect.top - menuMargin;
|
|
26
|
-
// Si no hay suficiente espacio abajo pero sí arriba, mostrar arriba
|
|
27
|
-
if (spaceBelow < menuHeight && spaceAbove > spaceBelow) {
|
|
28
|
-
setMenuPosition("top");
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
setMenuPosition("bottom"); // Preferir abajo si cabe o si es el que más espacio tiene, o por defecto
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}, [isOpen]);
|
|
35
|
-
// Recalcular posición cuando cambia isOpen (y cuando el contenido podría haber cambiado el tamaño)
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
calculatePosition();
|
|
38
|
-
// Podríamos necesitar un ResizeObserver para ser más robustos si el contenido cambia
|
|
39
|
-
}, [calculatePosition]);
|
|
40
|
-
// Recalcular posición al hacer scroll o redimensionar
|
|
41
|
-
useEffect(() => {
|
|
42
|
-
if (isOpen) {
|
|
43
|
-
const handleScroll = () => {
|
|
44
|
-
calculatePosition();
|
|
45
|
-
// Forzar actualización del estilo del menú
|
|
46
|
-
setScrollUpdate((prev) => prev + 1);
|
|
47
|
-
};
|
|
48
|
-
window.addEventListener("scroll", handleScroll, true);
|
|
49
|
-
window.addEventListener("resize", handleScroll);
|
|
50
|
-
return () => {
|
|
51
|
-
window.removeEventListener("scroll", handleScroll, true);
|
|
52
|
-
window.removeEventListener("resize", handleScroll);
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
}, [isOpen, calculatePosition]);
|
|
56
|
-
// Cerrar menú al hacer click fuera
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
const handleClickOutside = (event) => {
|
|
59
|
-
if (isOpen &&
|
|
60
|
-
triggerRef.current &&
|
|
61
|
-
menuRef.current &&
|
|
62
|
-
!triggerRef.current.contains(event.target) &&
|
|
63
|
-
!menuRef.current.contains(event.target)) {
|
|
64
|
-
setIsOpen(false);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
if (isOpen) {
|
|
68
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
69
|
-
}
|
|
70
|
-
return () => {
|
|
71
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
72
|
-
};
|
|
73
|
-
}, [isOpen]);
|
|
74
|
-
// Cerrar menú al presionar Escape
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
const handleEscape = (event) => {
|
|
77
|
-
if (event.key === "Escape" && isOpen) {
|
|
78
|
-
setIsOpen(false);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
if (isOpen) {
|
|
82
|
-
document.addEventListener("keydown", handleEscape);
|
|
83
|
-
}
|
|
84
|
-
return () => {
|
|
85
|
-
document.removeEventListener("keydown", handleEscape);
|
|
86
|
-
};
|
|
87
|
-
}, [isOpen]);
|
|
88
|
-
// Limpiar timeout al desmontar
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
return () => {
|
|
91
|
-
if (hoverTimeoutRef.current) {
|
|
92
|
-
window.clearTimeout(hoverTimeoutRef.current);
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}, []);
|
|
96
|
-
const handleToggle = () => {
|
|
97
|
-
setIsOpen(!isOpen);
|
|
98
|
-
};
|
|
99
|
-
const handleMouseEnter = () => {
|
|
100
|
-
if (!openOnHover)
|
|
101
|
-
return;
|
|
102
|
-
if (hoverTimeoutRef.current) {
|
|
103
|
-
window.clearTimeout(hoverTimeoutRef.current);
|
|
104
|
-
hoverTimeoutRef.current = null;
|
|
105
|
-
}
|
|
106
|
-
setIsOpen(true);
|
|
107
|
-
};
|
|
108
|
-
const handleMouseLeave = () => {
|
|
109
|
-
if (!openOnHover)
|
|
110
|
-
return;
|
|
111
|
-
hoverTimeoutRef.current = window.setTimeout(() => {
|
|
112
|
-
setIsOpen(false);
|
|
113
|
-
}, 150); // Pequeño delay para permitir mover el mouse al panel
|
|
114
|
-
};
|
|
115
|
-
const menuStyles = useMemo(() => {
|
|
116
|
-
if (!isOpen || !triggerRef.current) {
|
|
117
|
-
return {};
|
|
118
|
-
}
|
|
119
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
120
|
-
const menuMargin = 4;
|
|
121
|
-
// Asegurar que el menú no se salga de la pantalla horizontalmente
|
|
122
|
-
let leftPosition = triggerRect.left;
|
|
123
|
-
const menuMinWidth = 160;
|
|
124
|
-
const viewportWidth = window.innerWidth;
|
|
125
|
-
// Si el menú se sale por la derecha, ajustar la posición
|
|
126
|
-
// Nota: Como el ancho es dinámico (basado en children), idealmente deberíamos medirlo.
|
|
127
|
-
// Usaremos menuRef si está disponible o un estimado.
|
|
128
|
-
let currentMenuWidth = menuMinWidth;
|
|
129
|
-
if (menuRef.current) {
|
|
130
|
-
currentMenuWidth = menuRef.current.getBoundingClientRect().width;
|
|
131
|
-
}
|
|
132
|
-
if (leftPosition + currentMenuWidth > viewportWidth) {
|
|
133
|
-
leftPosition = viewportWidth - currentMenuWidth - 8; // 8px de margen
|
|
134
|
-
}
|
|
135
|
-
// Asegurar que no se salga por la izquierda
|
|
136
|
-
if (leftPosition < 8) {
|
|
137
|
-
leftPosition = 8;
|
|
138
|
-
}
|
|
139
|
-
if (menuPosition === "top") {
|
|
140
|
-
return {
|
|
141
|
-
position: "fixed",
|
|
142
|
-
bottom: window.innerHeight - triggerRect.top + menuMargin,
|
|
143
|
-
left: leftPosition,
|
|
144
|
-
minWidth: Math.max(triggerRect.width, menuMinWidth), // Mantener el minWidth del trigger o 160
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
return {
|
|
149
|
-
position: "fixed",
|
|
150
|
-
top: triggerRect.bottom + menuMargin,
|
|
151
|
-
left: leftPosition,
|
|
152
|
-
minWidth: Math.max(triggerRect.width, menuMinWidth),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
// scrollUpdate se usa intencionalmente para forzar el recálculo en scroll
|
|
156
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
157
|
-
}, [isOpen, menuPosition, scrollUpdate]);
|
|
158
|
-
return (_jsxs("div", { className: "relative inline-block", ref: triggerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsx("div", { onClick: handleToggle, className: "cursor-pointer", children: renderNode ? (renderNode) : (_jsx(Button, { variant: "ghost", icon: "fa-ellipsis-h" })) }), isOpen &&
|
|
159
|
-
(typeof document !== "undefined" && document.body
|
|
160
|
-
? createPortal(_jsx("div", { ref: menuRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onClick: (e) => e.stopPropagation(), className: "fixed z-[2000] bg-[var(--color-bg-default)] border border-[var(--color-border-default)] rounded-md shadow-[var(--shadow-lg)] py-1 min-w-[160px] font-[var(--font-default)]", style: menuStyles, children: children }), document.body)
|
|
161
|
-
: null)] }));
|
|
162
|
-
};
|