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,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
- };