flysoft-react-ui 1.2.3 → 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 (270) 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/form-controls/index.d.ts +2 -2
  7. package/dist/components/form-controls/index.d.ts.map +1 -1
  8. package/dist/components/layout/Accordion.d.ts +1 -0
  9. package/dist/components/layout/Accordion.d.ts.map +1 -1
  10. package/dist/components/layout/DataTable.d.ts.map +1 -1
  11. package/dist/components/layout/DropdownMenu.d.ts +2 -1
  12. package/dist/components/layout/DropdownMenu.d.ts.map +1 -1
  13. package/dist/components/layout/DropdownPanel.d.ts +2 -1
  14. package/dist/components/layout/DropdownPanel.d.ts.map +1 -1
  15. package/dist/components/layout/Filter.d.ts +1 -0
  16. package/dist/components/layout/Filter.d.ts.map +1 -1
  17. package/dist/components/layout/Menu.d.ts +2 -1
  18. package/dist/components/layout/Menu.d.ts.map +1 -1
  19. package/dist/components/layout/TabsGroup.d.ts +1 -0
  20. package/dist/components/layout/TabsGroup.d.ts.map +1 -1
  21. package/dist/index.css +1 -1
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +11889 -24
  25. package/dist/index.js.map +1 -1
  26. package/dist/templates/forms/ContactForm.d.ts +1 -0
  27. package/dist/templates/forms/ContactForm.d.ts.map +1 -1
  28. package/dist/templates/forms/LoginForm.d.ts +1 -0
  29. package/dist/templates/forms/LoginForm.d.ts.map +1 -1
  30. package/dist/templates/forms/RegistrationForm.d.ts +1 -0
  31. package/dist/templates/forms/RegistrationForm.d.ts.map +1 -1
  32. package/dist/templates/layouts/DashboardLayout.d.ts +1 -0
  33. package/dist/templates/layouts/DashboardLayout.d.ts.map +1 -1
  34. package/dist/templates/layouts/SidebarLayout.d.ts +1 -0
  35. package/dist/templates/layouts/SidebarLayout.d.ts.map +1 -1
  36. package/dist/templates/patterns/FormPattern.d.ts +1 -0
  37. package/dist/templates/patterns/FormPattern.d.ts.map +1 -1
  38. package/dist/templates/patterns/ListPattern.d.ts +77 -0
  39. package/dist/templates/patterns/ListPattern.d.ts.map +1 -0
  40. package/package.json +6 -3
  41. package/dist/App.d.ts +0 -4
  42. package/dist/App.d.ts.map +0 -1
  43. package/dist/App.js +0 -30
  44. package/dist/components/ThemeSwitcher.js +0 -12
  45. package/dist/components/form-controls/AutocompleteInput.js +0 -680
  46. package/dist/components/form-controls/Button.js +0 -211
  47. package/dist/components/form-controls/Checkbox.js +0 -79
  48. package/dist/components/form-controls/CurrencyInput.js +0 -106
  49. package/dist/components/form-controls/DateInput.js +0 -578
  50. package/dist/components/form-controls/DatePicker.js +0 -144
  51. package/dist/components/form-controls/Input.js +0 -35
  52. package/dist/components/form-controls/LinkButton.js +0 -248
  53. package/dist/components/form-controls/Pagination.js +0 -23
  54. package/dist/components/form-controls/RadioButtonGroup.js +0 -220
  55. package/dist/components/form-controls/SearchSelectInput-OLD.d.ts +0 -68
  56. package/dist/components/form-controls/SearchSelectInput-OLD.d.ts.map +0 -1
  57. package/dist/components/form-controls/SearchSelectInput-OLD.js +0 -962
  58. package/dist/components/form-controls/SearchSelectInput.js +0 -336
  59. package/dist/components/form-controls/index.js +0 -11
  60. package/dist/components/index.js +0 -7
  61. package/dist/components/layout/Accordion.js +0 -67
  62. package/dist/components/layout/AppLayout.js +0 -230
  63. package/dist/components/layout/Card.js +0 -54
  64. package/dist/components/layout/Collection.js +0 -18
  65. package/dist/components/layout/DataField.js +0 -38
  66. package/dist/components/layout/DataTable.js +0 -164
  67. package/dist/components/layout/DropdownMenu.js +0 -176
  68. package/dist/components/layout/DropdownPanel.js +0 -162
  69. package/dist/components/layout/Filter.js +0 -629
  70. package/dist/components/layout/Menu.js +0 -21
  71. package/dist/components/layout/TabPanel.js +0 -11
  72. package/dist/components/layout/TabsGroup.js +0 -52
  73. package/dist/components/layout/index.js +0 -12
  74. package/dist/components/utils/Avatar.js +0 -77
  75. package/dist/components/utils/Badge.js +0 -151
  76. package/dist/components/utils/Dialog.js +0 -44
  77. package/dist/components/utils/FiltersDialog.js +0 -104
  78. package/dist/components/utils/Loader.js +0 -44
  79. package/dist/components/utils/RoadMap.js +0 -139
  80. package/dist/components/utils/Skeleton.js +0 -10
  81. package/dist/components/utils/Snackbar.js +0 -136
  82. package/dist/components/utils/SnackbarContainer.js +0 -26
  83. package/dist/components/utils/iconUtils.js +0 -40
  84. package/dist/components/utils/index.js +0 -9
  85. package/dist/contexts/AppLayoutContext.js +0 -104
  86. package/dist/contexts/AuthContext.js +0 -224
  87. package/dist/contexts/CrudContext.js +0 -333
  88. package/dist/contexts/SnackbarContext.js +0 -41
  89. package/dist/contexts/ThemeContext.js +0 -197
  90. package/dist/contexts/index.js +0 -13
  91. package/dist/contexts/presets.js +0 -311
  92. package/dist/contexts/types.js +0 -1
  93. package/dist/docs/AccordionDocs.d.ts +0 -4
  94. package/dist/docs/AccordionDocs.d.ts.map +0 -1
  95. package/dist/docs/AccordionDocs.js +0 -21
  96. package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts +0 -13
  97. package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts.map +0 -1
  98. package/dist/docs/AuthDocs.tsx/AuthDocs.js +0 -18
  99. package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts +0 -2
  100. package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts.map +0 -1
  101. package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +0 -22
  102. package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts +0 -24
  103. package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts.map +0 -1
  104. package/dist/docs/AuthDocs.tsx/mockAuthService.js +0 -78
  105. package/dist/docs/AutocompleteInputDocs.d.ts +0 -4
  106. package/dist/docs/AutocompleteInputDocs.d.ts.map +0 -1
  107. package/dist/docs/AutocompleteInputDocs.js +0 -84
  108. package/dist/docs/AvatarDocs.d.ts +0 -4
  109. package/dist/docs/AvatarDocs.d.ts.map +0 -1
  110. package/dist/docs/AvatarDocs.js +0 -7
  111. package/dist/docs/BadgeDocs.d.ts +0 -4
  112. package/dist/docs/BadgeDocs.d.ts.map +0 -1
  113. package/dist/docs/BadgeDocs.js +0 -9
  114. package/dist/docs/ButtonDocs.d.ts +0 -4
  115. package/dist/docs/ButtonDocs.d.ts.map +0 -1
  116. package/dist/docs/ButtonDocs.js +0 -7
  117. package/dist/docs/CardDocs.d.ts +0 -4
  118. package/dist/docs/CardDocs.d.ts.map +0 -1
  119. package/dist/docs/CardDocs.js +0 -22
  120. package/dist/docs/CheckboxDocs.d.ts +0 -4
  121. package/dist/docs/CheckboxDocs.d.ts.map +0 -1
  122. package/dist/docs/CheckboxDocs.js +0 -7
  123. package/dist/docs/CurrencyInputDocs.d.ts +0 -4
  124. package/dist/docs/CurrencyInputDocs.d.ts.map +0 -1
  125. package/dist/docs/CurrencyInputDocs.js +0 -22
  126. package/dist/docs/DataFieldDocs.d.ts +0 -4
  127. package/dist/docs/DataFieldDocs.d.ts.map +0 -1
  128. package/dist/docs/DataFieldDocs.js +0 -7
  129. package/dist/docs/DataTableDocs.d.ts +0 -4
  130. package/dist/docs/DataTableDocs.d.ts.map +0 -1
  131. package/dist/docs/DataTableDocs.js +0 -244
  132. package/dist/docs/DateInputDocs.d.ts +0 -5
  133. package/dist/docs/DateInputDocs.d.ts.map +0 -1
  134. package/dist/docs/DateInputDocs.js +0 -19
  135. package/dist/docs/DatePickerDocs.d.ts +0 -5
  136. package/dist/docs/DatePickerDocs.d.ts.map +0 -1
  137. package/dist/docs/DatePickerDocs.js +0 -16
  138. package/dist/docs/DialogDocs.d.ts +0 -4
  139. package/dist/docs/DialogDocs.d.ts.map +0 -1
  140. package/dist/docs/DialogDocs.js +0 -13
  141. package/dist/docs/DocAdmin.d.ts +0 -4
  142. package/dist/docs/DocAdmin.d.ts.map +0 -1
  143. package/dist/docs/DocAdmin.js +0 -68
  144. package/dist/docs/DocsMenu.d.ts +0 -2
  145. package/dist/docs/DocsMenu.d.ts.map +0 -1
  146. package/dist/docs/DocsMenu.js +0 -5
  147. package/dist/docs/DocsRouter.d.ts +0 -4
  148. package/dist/docs/DocsRouter.d.ts.map +0 -1
  149. package/dist/docs/DocsRouter.js +0 -39
  150. package/dist/docs/DropdownMenuDocs.d.ts +0 -4
  151. package/dist/docs/DropdownMenuDocs.d.ts.map +0 -1
  152. package/dist/docs/DropdownMenuDocs.js +0 -66
  153. package/dist/docs/DropdownPanelDocs.d.ts +0 -4
  154. package/dist/docs/DropdownPanelDocs.d.ts.map +0 -1
  155. package/dist/docs/DropdownPanelDocs.js +0 -7
  156. package/dist/docs/ExampleFormDocs.d.ts +0 -4
  157. package/dist/docs/ExampleFormDocs.d.ts.map +0 -1
  158. package/dist/docs/ExampleFormDocs.js +0 -153
  159. package/dist/docs/FilterDocs.d.ts +0 -4
  160. package/dist/docs/FilterDocs.d.ts.map +0 -1
  161. package/dist/docs/FilterDocs.js +0 -130
  162. package/dist/docs/InputDocs.d.ts +0 -4
  163. package/dist/docs/InputDocs.d.ts.map +0 -1
  164. package/dist/docs/InputDocs.js +0 -17
  165. package/dist/docs/LinkButtonDocs.d.ts +0 -4
  166. package/dist/docs/LinkButtonDocs.d.ts.map +0 -1
  167. package/dist/docs/LinkButtonDocs.js +0 -7
  168. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +0 -2
  169. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +0 -1
  170. package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +0 -47
  171. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts +0 -2
  172. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts.map +0 -1
  173. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.js +0 -34
  174. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts +0 -2
  175. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts.map +0 -1
  176. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.js +0 -66
  177. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts +0 -2
  178. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts.map +0 -1
  179. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.js +0 -7
  180. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts +0 -10
  181. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts.map +0 -1
  182. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.js +0 -39
  183. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +0 -2
  184. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +0 -1
  185. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +0 -57
  186. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts +0 -9
  187. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts.map +0 -1
  188. package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.js +0 -30
  189. package/dist/docs/LoaderDocs.d.ts +0 -4
  190. package/dist/docs/LoaderDocs.d.ts.map +0 -1
  191. package/dist/docs/LoaderDocs.js +0 -33
  192. package/dist/docs/MenuDocs.d.ts +0 -4
  193. package/dist/docs/MenuDocs.d.ts.map +0 -1
  194. package/dist/docs/MenuDocs.js +0 -26
  195. package/dist/docs/PaginationDocs.d.ts +0 -4
  196. package/dist/docs/PaginationDocs.d.ts.map +0 -1
  197. package/dist/docs/PaginationDocs.js +0 -38
  198. package/dist/docs/RadioButtonGroupDocs.d.ts +0 -4
  199. package/dist/docs/RadioButtonGroupDocs.d.ts.map +0 -1
  200. package/dist/docs/RadioButtonGroupDocs.js +0 -46
  201. package/dist/docs/RoadMapDocs.d.ts +0 -4
  202. package/dist/docs/RoadMapDocs.d.ts.map +0 -1
  203. package/dist/docs/RoadMapDocs.js +0 -171
  204. package/dist/docs/SearchSelectInputDocs.d.ts +0 -4
  205. package/dist/docs/SearchSelectInputDocs.d.ts.map +0 -1
  206. package/dist/docs/SearchSelectInputDocs.js +0 -168
  207. package/dist/docs/SkeletonDocs.d.ts +0 -4
  208. package/dist/docs/SkeletonDocs.d.ts.map +0 -1
  209. package/dist/docs/SkeletonDocs.js +0 -7
  210. package/dist/docs/SnackbarDocs.d.ts +0 -4
  211. package/dist/docs/SnackbarDocs.d.ts.map +0 -1
  212. package/dist/docs/SnackbarDocs.js +0 -69
  213. package/dist/docs/TabsGroupDocs.d.ts +0 -4
  214. package/dist/docs/TabsGroupDocs.d.ts.map +0 -1
  215. package/dist/docs/TabsGroupDocs.js +0 -38
  216. package/dist/docs/ThemeSwitcherDocs.d.ts +0 -4
  217. package/dist/docs/ThemeSwitcherDocs.d.ts.map +0 -1
  218. package/dist/docs/ThemeSwitcherDocs.js +0 -11
  219. package/dist/docs/docMockServices/empresaService.d.ts +0 -38
  220. package/dist/docs/docMockServices/empresaService.d.ts.map +0 -1
  221. package/dist/docs/docMockServices/empresaService.js +0 -125
  222. package/dist/docs/docMockServices/index.d.ts +0 -9
  223. package/dist/docs/docMockServices/index.d.ts.map +0 -1
  224. package/dist/docs/docMockServices/index.js +0 -8
  225. package/dist/docs/docMockServices/initialData.d.ts +0 -6
  226. package/dist/docs/docMockServices/initialData.d.ts.map +0 -1
  227. package/dist/docs/docMockServices/initialData.js +0 -132
  228. package/dist/docs/docMockServices/interfaces.d.ts +0 -38
  229. package/dist/docs/docMockServices/interfaces.d.ts.map +0 -1
  230. package/dist/docs/docMockServices/interfaces.js +0 -1
  231. package/dist/docs/docMockServices/personaEmpresaService.d.ts +0 -43
  232. package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +0 -1
  233. package/dist/docs/docMockServices/personaEmpresaService.js +0 -151
  234. package/dist/docs/docMockServices/personaService.d.ts +0 -39
  235. package/dist/docs/docMockServices/personaService.d.ts.map +0 -1
  236. package/dist/docs/docMockServices/personaService.js +0 -190
  237. package/dist/helpers/currencyFormat.js +0 -3
  238. package/dist/helpers/getErrorMessage.js +0 -13
  239. package/dist/helpers/getInitialLetters.js +0 -5
  240. package/dist/helpers/getQueryString.js +0 -13
  241. package/dist/helpers/index.js +0 -9
  242. package/dist/helpers/mappers.js +0 -27
  243. package/dist/helpers/nameValueArrayToObject.js +0 -3
  244. package/dist/helpers/objectToQueryString.js +0 -3
  245. package/dist/helpers/queryStringToObject.js +0 -13
  246. package/dist/helpers/regularExpressions.js +0 -5
  247. package/dist/hooks/index.js +0 -6
  248. package/dist/hooks/useAsyncRequest.js +0 -53
  249. package/dist/hooks/useBreakpoint.js +0 -59
  250. package/dist/hooks/useElementScroll.js +0 -58
  251. package/dist/hooks/useEnum.js +0 -21
  252. package/dist/hooks/useGlobalThemeStyles.js +0 -40
  253. package/dist/hooks/useThemeOverride.js +0 -99
  254. package/dist/interfaces/index.js +0 -1
  255. package/dist/interfaces/name-value.interface.js +0 -1
  256. package/dist/interfaces/pagination.interface.js +0 -1
  257. package/dist/main.d.ts +0 -2
  258. package/dist/main.d.ts.map +0 -1
  259. package/dist/main.js +0 -6
  260. package/dist/services/apiClient.js +0 -216
  261. package/dist/services/index.js +0 -1
  262. package/dist/styles.d.ts +0 -2
  263. package/dist/styles.d.ts.map +0 -1
  264. package/dist/styles.js +0 -3
  265. package/dist/templates/forms/ContactForm.js +0 -58
  266. package/dist/templates/forms/LoginForm.js +0 -36
  267. package/dist/templates/forms/RegistrationForm.js +0 -54
  268. package/dist/templates/layouts/DashboardLayout.js +0 -26
  269. package/dist/templates/layouts/SidebarLayout.js +0 -28
  270. package/dist/templates/patterns/FormPattern.js +0 -68
@@ -1,680 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import React from "react";
3
- import { createPortal } from "react-dom";
4
- import { useFormContext } from "react-hook-form";
5
- import { Input } from "./Input";
6
- import { normalizeIconClass } from "../utils/iconUtils";
7
- import { Checkbox } from "./Checkbox";
8
- const AutocompleteInputInner = React.forwardRef(({ options, value, onChange, onSelectOption, noResultsText = "Sin resultados", className = "", getOptionLabel, getOptionValue, getOptionDescription, renderOption, readOnly = false, multiple = false, ...inputProps }, ref) => {
9
- const [internalValue, setInternalValue] = React.useState(value || (multiple ? [] : ""));
10
- const [displayValue, setDisplayValue] = React.useState("");
11
- const [isOpen, setIsOpen] = React.useState(false);
12
- const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
13
- const [dropdownPosition, setDropdownPosition] = React.useState(null);
14
- const containerRef = React.useRef(null);
15
- const dropdownRef = React.useRef(null);
16
- const inputRef = React.useRef(null);
17
- const hiddenInputRef = React.useRef(null);
18
- const justClearedRef = React.useRef(false);
19
- // Detectar si estamos en modo register: si viene 'name' de register, estamos en modo register
20
- // register siempre pasa 'name', 'onChange', 'onBlur', y 'ref'
21
- const isRegisterMode = React.useMemo(() => {
22
- // Si viene 'name' en inputProps, es porque viene de register
23
- return "name" in inputProps && inputProps.name !== undefined;
24
- }, [inputProps]);
25
- const fieldName = isRegisterMode && "name" in inputProps
26
- ? inputProps.name
27
- : undefined;
28
- // Obtener setValue del contexto del formulario
29
- // Para usar con register, el formulario debe estar dentro de FormProvider
30
- // useFormContext debe llamarse incondicionalmente (requisito de React Hooks)
31
- // Si no hay FormProvider y se usa en modo register, useFormContext lanzará un error
32
- // Para usar sin FormProvider, usar Controller en lugar de register
33
- const formContext = useFormContext();
34
- const setValue = formContext?.setValue;
35
- const inputValue = isRegisterMode
36
- ? displayValue
37
- : (multiple ? displayValue : (typeof value === "string" ? value : (typeof internalValue === "string" ? internalValue : "")));
38
- const selectedValuesArray = React.useMemo(() => {
39
- const currentVal = isRegisterMode && hiddenInputRef.current
40
- ? hiddenInputRef.current.value
41
- : (value !== undefined ? value : internalValue);
42
- if (Array.isArray(currentVal))
43
- return currentVal;
44
- // En modo register, los valores múltiples podrían estar como un string JSON o separados por comas.
45
- // Si el hiddenInput recibe un array en react-hook-form, su valor puede volverse "[object Object]" o concatenado.
46
- // Asumiremos que react-hook-form maneja correctamente el array si el value prop es un array.
47
- // Si recibimos un string:
48
- if (typeof currentVal === "string") {
49
- if (!currentVal)
50
- return [];
51
- try {
52
- // Intentar parsear si es JSON
53
- const parsed = JSON.parse(currentVal);
54
- if (Array.isArray(parsed))
55
- return parsed.map(String);
56
- return [currentVal];
57
- }
58
- catch {
59
- // Si no es JSON, asumir es un solo string o separado por comas (no recomendado por conflicto con comas en valores)
60
- return [currentVal];
61
- }
62
- }
63
- return [];
64
- }, [isRegisterMode, value, internalValue, multiple]);
65
- const labelGetter = React.useCallback((item) => {
66
- if (getOptionLabel)
67
- return getOptionLabel(item);
68
- const anyItem = item;
69
- return (anyItem.label ?? "").toString();
70
- }, [getOptionLabel]);
71
- const valueGetter = React.useCallback((item) => {
72
- if (getOptionValue)
73
- return getOptionValue(item);
74
- const anyItem = item;
75
- return anyItem.value ?? undefined;
76
- }, [getOptionValue]);
77
- // Calcular el label unificado para multiple
78
- const getMultipleDisplayValue = React.useCallback((values) => {
79
- if (!values || values.length === 0)
80
- return "";
81
- const labels = values.map((val) => {
82
- const matchingOption = options.find((option) => String(valueGetter(option)) === String(val));
83
- return matchingOption ? labelGetter(matchingOption) : String(val);
84
- });
85
- return labels.join(", ");
86
- }, [options, valueGetter, labelGetter]);
87
- const descriptionGetter = React.useCallback((item) => {
88
- if (getOptionDescription)
89
- return getOptionDescription(item);
90
- const anyItem = item;
91
- return anyItem.description;
92
- }, [getOptionDescription]);
93
- const filteredOptions = React.useMemo(() => {
94
- let search = displayValue.trim().toLowerCase();
95
- // Si es múltiple y no estamos enfocando el input para buscar, no filtramos por displayValue
96
- // (ya que displayValue contiene los labels de los items seleccionados separados por coma)
97
- if (multiple) {
98
- if (document.activeElement !== inputRef.current || displayValue === getMultipleDisplayValue(selectedValuesArray)) {
99
- search = "";
100
- }
101
- }
102
- else {
103
- search = inputValue.trim().toLowerCase();
104
- }
105
- if (!search)
106
- return options;
107
- return options.filter((option) => {
108
- const label = labelGetter(option).toLowerCase();
109
- const optionValue = String(valueGetter(option) ?? "").toLowerCase();
110
- return label.includes(search) || optionValue.includes(search);
111
- });
112
- }, [inputValue, options, labelGetter, valueGetter]);
113
- // Función helper para sincronizar displayValue con el valor del formulario
114
- const syncDisplayValue = React.useCallback(() => {
115
- if (isRegisterMode) {
116
- // En modo register, usamos el hiddenInputRef si existe, sino el inputRef (legacy/fallback)
117
- const targetInput = hiddenInputRef.current || inputRef.current;
118
- if (targetInput) {
119
- const formValue = targetInput.value;
120
- if (multiple) {
121
- let parsedValues = [];
122
- try {
123
- parsedValues = JSON.parse(formValue);
124
- }
125
- catch {
126
- parsedValues = formValue ? [formValue] : [];
127
- }
128
- if (Array.isArray(parsedValues)) {
129
- setDisplayValue(getMultipleDisplayValue(parsedValues));
130
- return true;
131
- }
132
- }
133
- else {
134
- // Si el valor del formulario coincide con algún getOptionValue, mostrar su label
135
- const matchingOption = options.find((option) => String(valueGetter(option)) === String(formValue));
136
- if (matchingOption) {
137
- const label = labelGetter(matchingOption);
138
- setDisplayValue(label);
139
- return true; // Indica que se encontró y sincronizó un valor
140
- }
141
- else if (formValue) {
142
- // Si hay un valor pero no coincide, mostrarlo tal cual (o buscar por label si fuera el caso)
143
- setDisplayValue(formValue);
144
- return true;
145
- }
146
- else {
147
- setDisplayValue("");
148
- return false; // No hay valor aún
149
- }
150
- }
151
- }
152
- }
153
- return false;
154
- }, [isRegisterMode, options, valueGetter, labelGetter, multiple, getMultipleDisplayValue]);
155
- // Sincronizar displayValue con el valor del formulario en modo register
156
- // Usar un intervalo que se ejecute hasta que encuentre el valor o hasta un máximo de intentos
157
- React.useEffect(() => {
158
- if (isRegisterMode) {
159
- let attempts = 0;
160
- const maxAttempts = 50; // Intentar durante ~5 segundos (50 * 100ms)
161
- // Función que intenta sincronizar y retorna true si encontró un valor
162
- const trySync = () => {
163
- const targetInput = hiddenInputRef.current || inputRef.current;
164
- if (targetInput) {
165
- const formValue = targetInput.value;
166
- if (formValue) {
167
- if (multiple) {
168
- let parsedValues = [];
169
- try {
170
- parsedValues = JSON.parse(formValue);
171
- }
172
- catch {
173
- parsedValues = [formValue];
174
- }
175
- setDisplayValue(getMultipleDisplayValue(parsedValues));
176
- return true;
177
- }
178
- else {
179
- // Hay un valor, intentar sincronizar
180
- const matchingOption = options.find((option) => String(valueGetter(option)) === String(formValue));
181
- if (matchingOption) {
182
- const label = labelGetter(matchingOption);
183
- setDisplayValue(label);
184
- return true; // Valor encontrado y sincronizado
185
- }
186
- else {
187
- setDisplayValue(formValue);
188
- return true; // Valor encontrado pero no coincide con opciones
189
- }
190
- }
191
- }
192
- }
193
- return false; // No hay valor aún
194
- };
195
- // Intentar inmediatamente
196
- if (trySync()) {
197
- return; // Ya encontramos el valor
198
- }
199
- // Si no encontramos el valor, usar un intervalo para seguir intentando
200
- const intervalId = window.setInterval(() => {
201
- attempts++;
202
- if (trySync() || attempts >= maxAttempts) {
203
- clearInterval(intervalId);
204
- }
205
- }, 100); // Intentar cada 100ms
206
- // También usar timeouts como fallback
207
- const timeouts = [];
208
- [0, 50, 100, 200, 500, 1000].forEach((delay) => {
209
- const timeoutId = window.setTimeout(() => {
210
- trySync();
211
- }, delay);
212
- timeouts.push(timeoutId);
213
- });
214
- return () => {
215
- clearInterval(intervalId);
216
- timeouts.forEach(clearTimeout);
217
- };
218
- }
219
- }, [isRegisterMode, options, valueGetter, labelGetter]);
220
- // También escuchar cambios en el input (hidden o visible) para sincronizar cuando cambie
221
- React.useEffect(() => {
222
- if (isRegisterMode) {
223
- // Observamos el hiddenInput si estamos en register mode y existe, o el input normal
224
- const targetElement = hiddenInputRef.current || inputRef.current;
225
- if (targetElement) {
226
- // Función para sincronizar cuando el input cambia
227
- const handleInputSync = () => {
228
- // Solo sincronizar si es el hidden input o si no tenemos hidden input
229
- if (targetElement === hiddenInputRef.current) {
230
- syncDisplayValue();
231
- }
232
- };
233
- // Escuchar eventos de input y change (aunque en hidden input no suelen dispararse eventos de usuario)
234
- targetElement.addEventListener("input", handleInputSync);
235
- targetElement.addEventListener("change", handleInputSync);
236
- // También usar MutationObserver para detectar cambios en el atributo value (más fiable para hidden inputs cambiados por JS)
237
- const observer = new MutationObserver(() => {
238
- syncDisplayValue();
239
- });
240
- observer.observe(targetElement, {
241
- attributes: true,
242
- attributeFilter: ["value"],
243
- });
244
- return () => {
245
- targetElement.removeEventListener("input", handleInputSync);
246
- targetElement.removeEventListener("change", handleInputSync);
247
- observer.disconnect();
248
- };
249
- }
250
- }
251
- }, [isRegisterMode, syncDisplayValue]);
252
- const handleChange = (event) => {
253
- if (readOnly)
254
- return;
255
- const newValue = event.target.value;
256
- if (isRegisterMode) {
257
- setDisplayValue(newValue);
258
- }
259
- else {
260
- if (multiple) {
261
- setDisplayValue(newValue);
262
- }
263
- else {
264
- // Modo API personalizada para input simple
265
- if (value === undefined) {
266
- setInternalValue(newValue);
267
- }
268
- if (onChange) {
269
- onChange(newValue);
270
- }
271
- }
272
- }
273
- setIsOpen(true);
274
- setHighlightedIndex(-1);
275
- };
276
- const handleSelect = (option) => {
277
- if (readOnly)
278
- return;
279
- const label = labelGetter(option);
280
- const selectedValue = valueGetter(option);
281
- const valueString = String(selectedValue ?? "");
282
- let newValuesArray = [];
283
- let newValueToSet = valueString;
284
- let newLabelToSet = label;
285
- if (multiple) {
286
- // Toggle selection
287
- if (selectedValuesArray.includes(valueString)) {
288
- newValuesArray = selectedValuesArray.filter(v => v !== valueString);
289
- }
290
- else {
291
- newValuesArray = [...selectedValuesArray, valueString];
292
- }
293
- if (!isRegisterMode && value === undefined) {
294
- setInternalValue(newValuesArray);
295
- }
296
- newLabelToSet = getMultipleDisplayValue(newValuesArray);
297
- setDisplayValue(newLabelToSet);
298
- // Pass the array to the onChange/register hooks
299
- newValueToSet = newValuesArray;
300
- }
301
- if (isRegisterMode) {
302
- // En modo register, setear el valor usando setValue o actualizando el input nativo (hidden)
303
- if (setValue && fieldName) {
304
- setValue(fieldName, newValueToSet, {
305
- shouldValidate: true,
306
- shouldDirty: true,
307
- });
308
- // Actualizar el input hidden
309
- if (hiddenInputRef.current) {
310
- hiddenInputRef.current.value = multiple ? JSON.stringify(newValuesArray) : valueString;
311
- }
312
- // Actualizar displayValue con el label
313
- setDisplayValue(newLabelToSet);
314
- }
315
- else {
316
- // Fallback
317
- const targetInput = hiddenInputRef.current || inputRef.current;
318
- if (targetInput) {
319
- const nativeInput = targetInput;
320
- const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
321
- const stringObjToSet = multiple ? JSON.stringify(newValuesArray) : valueString;
322
- if (nativeInputValueSetter) {
323
- nativeInputValueSetter.call(nativeInput, stringObjToSet);
324
- }
325
- else {
326
- nativeInput.value = stringObjToSet;
327
- }
328
- // Disparar eventos
329
- if (onChange) {
330
- const changeEvent = {
331
- target: nativeInput,
332
- currentTarget: nativeInput,
333
- };
334
- onChange(changeEvent);
335
- }
336
- const inputEvent = new Event("input", {
337
- bubbles: true,
338
- cancelable: true,
339
- });
340
- nativeInput.dispatchEvent(inputEvent);
341
- const changeEventNative = new Event("change", {
342
- bubbles: true,
343
- cancelable: true,
344
- });
345
- nativeInput.dispatchEvent(changeEventNative);
346
- }
347
- setDisplayValue(newLabelToSet);
348
- }
349
- }
350
- else {
351
- // Modo API personalizada - comportamiento original
352
- if (onChange) {
353
- if (multiple) {
354
- onChange(newValuesArray);
355
- }
356
- else {
357
- onChange(valueString);
358
- }
359
- }
360
- }
361
- onSelectOption?.(option, selectedValue);
362
- if (!multiple) {
363
- setIsOpen(false);
364
- }
365
- };
366
- const handleKeyDown = (event) => {
367
- if (readOnly)
368
- return;
369
- if (!isOpen && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
370
- setIsOpen(true);
371
- return;
372
- }
373
- if (!filteredOptions.length)
374
- return;
375
- if (event.key === "ArrowDown") {
376
- event.preventDefault();
377
- setHighlightedIndex((prev) => prev < filteredOptions.length - 1 ? prev + 1 : 0);
378
- }
379
- else if (event.key === "ArrowUp") {
380
- event.preventDefault();
381
- setHighlightedIndex((prev) => prev > 0 ? prev - 1 : filteredOptions.length - 1);
382
- }
383
- else if (event.key === "Enter") {
384
- // Si hay una opción resaltada, seleccionarla
385
- if (highlightedIndex >= 0 &&
386
- highlightedIndex < filteredOptions.length) {
387
- event.preventDefault();
388
- handleSelect(filteredOptions[highlightedIndex]);
389
- }
390
- else if (isOpen && filteredOptions.length > 0) {
391
- // Si no hay opción resaltada pero hay opciones disponibles, seleccionar la primera
392
- event.preventDefault();
393
- handleSelect(filteredOptions[0]);
394
- }
395
- }
396
- else if (event.key === "Escape") {
397
- setIsOpen(false);
398
- }
399
- };
400
- React.useEffect(() => {
401
- if (!isOpen)
402
- return;
403
- const handleClickOutside = (event) => {
404
- const target = event.target;
405
- const isClickInsideContainer = containerRef.current?.contains(target);
406
- const isClickInsideDropdown = dropdownRef.current?.contains(target);
407
- if (!isClickInsideContainer && !isClickInsideDropdown) {
408
- setIsOpen(false);
409
- }
410
- };
411
- // Pequeño delay para asegurar que el portal esté montado
412
- const timer = setTimeout(() => {
413
- document.addEventListener("mousedown", handleClickOutside);
414
- }, 0);
415
- return () => {
416
- clearTimeout(timer);
417
- document.removeEventListener("mousedown", handleClickOutside);
418
- };
419
- }, [isOpen]);
420
- React.useEffect(() => {
421
- if (!isRegisterMode) {
422
- // Solo para modo API personalizada
423
- if (value !== undefined) {
424
- // Si el value es el resultado de getOptionValue, buscar la opción correspondiente
425
- // y mostrar su label. Si no se encuentra, mostrar el value tal cual.
426
- if (multiple) {
427
- const arrayVals = Array.isArray(value) ? value : [value];
428
- setDisplayValue(getMultipleDisplayValue(arrayVals));
429
- }
430
- else {
431
- const matchingOption = options.find((option) => String(valueGetter(option)) === String(value));
432
- if (matchingOption) {
433
- setInternalValue(labelGetter(matchingOption));
434
- }
435
- else {
436
- setInternalValue(value);
437
- }
438
- }
439
- }
440
- else {
441
- // Resetear el estado interno cuando value es undefined (por ejemplo, después de un reset)
442
- if (multiple) {
443
- setDisplayValue("");
444
- setInternalValue([]);
445
- }
446
- else {
447
- setInternalValue("");
448
- }
449
- }
450
- }
451
- }, [value, options, valueGetter, labelGetter, isRegisterMode, multiple, getMultipleDisplayValue]);
452
- const showDropdown = !readOnly && isOpen && (filteredOptions.length > 0 || noResultsText);
453
- // Verificar que estamos en el navegador
454
- // Inicializar isMounted de forma síncrona si es posible
455
- const [isMounted, setIsMounted] = React.useState(() => {
456
- return typeof document !== "undefined" && !!document.body;
457
- });
458
- React.useEffect(() => {
459
- if (!isMounted && typeof document !== "undefined" && document.body) {
460
- setIsMounted(true);
461
- }
462
- }, [isMounted]);
463
- // Actualizar posición del dropdown cuando se abre
464
- React.useEffect(() => {
465
- if (showDropdown && containerRef.current && isMounted) {
466
- const updatePosition = () => {
467
- const rect = containerRef.current?.getBoundingClientRect();
468
- if (rect) {
469
- setDropdownPosition({
470
- top: rect.bottom + window.scrollY + 4,
471
- left: rect.left + window.scrollX,
472
- width: rect.width,
473
- });
474
- }
475
- };
476
- updatePosition();
477
- window.addEventListener("scroll", updatePosition, true);
478
- window.addEventListener("resize", updatePosition);
479
- return () => {
480
- window.removeEventListener("scroll", updatePosition, true);
481
- window.removeEventListener("resize", updatePosition);
482
- };
483
- }
484
- else {
485
- setDropdownPosition(null);
486
- }
487
- }, [showDropdown, isMounted]);
488
- // Detectar si hay un valor seleccionado
489
- // Un valor está seleccionado si el value coincide con el getOptionValue de alguna opción
490
- const hasSelectedValue = React.useMemo(() => {
491
- if (multiple) {
492
- return selectedValuesArray.length > 0;
493
- }
494
- if (isRegisterMode) {
495
- const targetInput = hiddenInputRef.current || inputRef.current;
496
- if (targetInput) {
497
- const formValue = targetInput.value;
498
- if (!formValue)
499
- return false;
500
- return options.some((option) => String(valueGetter(option)) === String(formValue));
501
- }
502
- return false;
503
- }
504
- if (value === undefined || value === null || value === "")
505
- return false;
506
- // Verificar si el value coincide con el getOptionValue de alguna opción
507
- return options.some((option) => String(valueGetter(option)) === String(value));
508
- }, [value, options, valueGetter, isRegisterMode, multiple, selectedValuesArray]);
509
- // Función para limpiar el valor
510
- const handleClear = React.useCallback((event) => {
511
- if (readOnly)
512
- return;
513
- event.preventDefault();
514
- event.stopPropagation();
515
- // Marcar que acabamos de limpiar para prevenir que onFocus abra el diálogo
516
- justClearedRef.current = true;
517
- if (isRegisterMode) {
518
- // En modo register, limpiar el input nativo (hidden) y disparar eventos
519
- const targetInput = hiddenInputRef.current || inputRef.current;
520
- if (targetInput) {
521
- const nativeInput = targetInput;
522
- const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
523
- setter?.call(nativeInput, "");
524
- // Disparar eventos para que react-hook-form lo capture
525
- const inputEvent = new Event("input", { bubbles: true });
526
- nativeInput.dispatchEvent(inputEvent);
527
- const changeEvent = new Event("change", { bubbles: true });
528
- nativeInput.dispatchEvent(changeEvent);
529
- // Llamar al onChange de register
530
- if (onChange) {
531
- const changeEventReact = {
532
- target: nativeInput,
533
- currentTarget: nativeInput,
534
- };
535
- onChange(changeEventReact);
536
- }
537
- }
538
- // Limpiar el displayValue
539
- setDisplayValue("");
540
- }
541
- else {
542
- // Modo API personalizada
543
- if (value === undefined) {
544
- if (multiple) {
545
- setInternalValue([]);
546
- }
547
- else {
548
- setInternalValue("");
549
- }
550
- }
551
- if (onChange) {
552
- if (multiple) {
553
- onChange([]);
554
- }
555
- else {
556
- onChange("");
557
- }
558
- }
559
- setDisplayValue("");
560
- }
561
- setIsOpen(false);
562
- // Resetear el flag después de un pequeño delay para permitir que otros eventos se procesen
563
- setTimeout(() => {
564
- justClearedRef.current = false;
565
- }, 100);
566
- }, [value, onChange, isRegisterMode, readOnly]);
567
- // Determinar qué ícono mostrar: si hay valor seleccionado, mostrar "X", sino usar el ícono original
568
- // Si está en readOnly, no mostrar el ícono de limpiar ni permitir clicks
569
- const displayIcon = readOnly
570
- ? inputProps.icon
571
- : hasSelectedValue
572
- ? "fa-times"
573
- : inputProps.icon;
574
- const displayIconPosition = readOnly
575
- ? inputProps.iconPosition || "left"
576
- : hasSelectedValue
577
- ? "right"
578
- : inputProps.iconPosition || "left";
579
- const displayOnIconClick = readOnly
580
- ? undefined
581
- : hasSelectedValue
582
- ? handleClear
583
- : inputProps.onIconClick;
584
- // Refs separados: uno para el visible y otro para el hidden (registrado)
585
- const setHiddenRef = React.useCallback((node) => {
586
- hiddenInputRef.current = node;
587
- // Solo pasar el ref externo al hidden input en modo register
588
- if (isRegisterMode) {
589
- if (typeof ref === "function") {
590
- ref(node);
591
- }
592
- else if (ref) {
593
- ref.current = node;
594
- }
595
- // Sincronización inicial cuando el ref se monta
596
- if (node) {
597
- [0, 10, 50, 100, 200, 500].forEach((delay) => {
598
- setTimeout(() => {
599
- if (node && hiddenInputRef.current === node) {
600
- const formValue = node.value;
601
- if (formValue) {
602
- const matchingOption = options.find((option) => String(valueGetter(option)) === String(formValue));
603
- if (multiple) {
604
- try {
605
- const parsed = JSON.parse(formValue);
606
- if (Array.isArray(parsed)) {
607
- setDisplayValue(getMultipleDisplayValue(parsed));
608
- }
609
- }
610
- catch {
611
- setDisplayValue(getMultipleDisplayValue([formValue]));
612
- }
613
- }
614
- else {
615
- if (matchingOption) {
616
- setDisplayValue(labelGetter(matchingOption));
617
- }
618
- else {
619
- setDisplayValue(formValue);
620
- }
621
- }
622
- }
623
- }
624
- }, delay);
625
- });
626
- }
627
- }
628
- }, [ref, isRegisterMode, options, valueGetter, labelGetter, multiple, getMultipleDisplayValue]);
629
- const setVisibleRef = React.useCallback((node) => {
630
- inputRef.current = node;
631
- // En modo NO register, pasamos el ref al input visible
632
- if (!isRegisterMode) {
633
- if (typeof ref === "function") {
634
- ref(node);
635
- }
636
- else if (ref) {
637
- ref.current = node;
638
- }
639
- }
640
- }, [ref, isRegisterMode]);
641
- // Separar propiedades para input visible y hidden
642
- const { name: nameProp, ...visibleInputProps } = inputProps;
643
- return (_jsxs("div", { ref: containerRef, className: "relative w-full", children: [isRegisterMode && (_jsx("input", { type: "hidden", name: nameProp, ref: setHiddenRef, defaultValue: value })), _jsx(Input, { ...visibleInputProps, name: isRegisterMode ? undefined : nameProp, ref: setVisibleRef, value: multiple ? displayValue : inputValue, onChange: handleChange, onFocus: () => {
644
- if (!readOnly && !justClearedRef.current) {
645
- setIsOpen(true);
646
- }
647
- }, onKeyDown: handleKeyDown, className: className, icon: displayIcon, iconPosition: displayIconPosition, onIconClick: displayOnIconClick, readOnly: readOnly }), (() => {
648
- // Verificar de forma segura que document.body existe y es válido
649
- const bodyElement = typeof document !== "undefined" &&
650
- document.body &&
651
- document.body instanceof HTMLElement
652
- ? document.body
653
- : null;
654
- return (showDropdown &&
655
- dropdownPosition &&
656
- isMounted &&
657
- bodyElement &&
658
- createPortal(_jsx("div", { ref: dropdownRef, className: "fixed z-[2001] min-w-full w-max rounded-md border border-[var(--color-border-default)] \n bg-[var(--color-bg-default)] shadow-[var(--shadow-lg)] max-h-60 overflow-auto", style: {
659
- top: `${dropdownPosition.top}px`,
660
- left: `${dropdownPosition.left}px`,
661
- minWidth: `${dropdownPosition.width}px`,
662
- }, children: filteredOptions.length > 0 ? (_jsx("ul", { className: "py-1 list-none pl-0 m-0", children: filteredOptions.map((option, index) => {
663
- const label = labelGetter(option);
664
- const description = descriptionGetter(option);
665
- const anyOption = option;
666
- return (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-start gap-2 text-sm
667
- ${index === highlightedIndex
668
- ? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
669
- : "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (event) => {
670
- event.preventDefault();
671
- handleSelect(option);
672
- }, onMouseEnter: () => setHighlightedIndex(index), children: renderOption ? (renderOption(option)) : (_jsxs(_Fragment, { children: [multiple && (_jsx(Checkbox, { readOnly: true, checked: selectedValuesArray.includes(String(valueGetter(option) ?? "")), className: "mr-2 pointer-events-none" })), anyOption.icon && (_jsx("i", { className: `${normalizeIconClass(anyOption.icon)} mt-0.5 text-[var(--color-text-muted)] flex-shrink-0 mr-2` })), _jsxs("div", { className: "flex flex-col min-w-0", children: [_jsx("span", { className: "font-[var(--font-default)] whitespace-nowrap", children: label }), description !== undefined &&
673
- description !== null && (_jsx("span", { className: "text-xs text-[var(--color-text-secondary)] break-words", children: description }))] })] })) }, String(valueGetter(option) ?? label ?? index)));
674
- }) })) : (_jsx("div", { className: "px-3 py-2 text-sm text-[var(--color-text-secondary)]", children: noResultsText })) }), bodyElement));
675
- })()] }));
676
- });
677
- // Asignar displayName antes del cast genérico
678
- AutocompleteInputInner.displayName = "AutocompleteInput";
679
- // Exportar con el cast genérico
680
- export const AutocompleteInput = AutocompleteInputInner;