flysoft-react-ui 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_CONTEXT.md +1400 -217
- package/AI_INTEGRATION_GUIDE.md +343 -0
- package/INTEGRATION_GUIDE.md +60 -0
- package/README.md +5 -3
- package/dist/components/form-controls/Input.d.ts.map +1 -1
- package/dist/components/layout/Accordion.d.ts +1 -0
- package/dist/components/layout/Accordion.d.ts.map +1 -1
- package/dist/components/layout/DataTable.d.ts.map +1 -1
- package/dist/components/layout/DropdownMenu.d.ts +2 -1
- package/dist/components/layout/DropdownMenu.d.ts.map +1 -1
- package/dist/components/layout/DropdownPanel.d.ts +2 -1
- package/dist/components/layout/DropdownPanel.d.ts.map +1 -1
- package/dist/components/layout/Filter.d.ts +1 -0
- package/dist/components/layout/Filter.d.ts.map +1 -1
- package/dist/components/layout/Menu.d.ts +2 -1
- package/dist/components/layout/Menu.d.ts.map +1 -1
- package/dist/components/layout/TabsGroup.d.ts +1 -0
- package/dist/components/layout/TabsGroup.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11190 -24
- package/dist/index.js.map +1 -1
- package/dist/templates/forms/ContactForm.d.ts +1 -0
- package/dist/templates/forms/ContactForm.d.ts.map +1 -1
- package/dist/templates/forms/LoginForm.d.ts +1 -0
- package/dist/templates/forms/LoginForm.d.ts.map +1 -1
- package/dist/templates/forms/RegistrationForm.d.ts +1 -0
- package/dist/templates/forms/RegistrationForm.d.ts.map +1 -1
- package/dist/templates/layouts/DashboardLayout.d.ts +1 -0
- package/dist/templates/layouts/DashboardLayout.d.ts.map +1 -1
- package/dist/templates/layouts/SidebarLayout.d.ts +1 -0
- package/dist/templates/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/templates/patterns/FormPattern.d.ts +1 -0
- package/dist/templates/patterns/FormPattern.d.ts.map +1 -1
- package/dist/templates/patterns/ListPattern.d.ts +77 -0
- package/dist/templates/patterns/ListPattern.d.ts.map +1 -0
- package/package.json +8 -4
- package/dist/App.d.ts +0 -4
- package/dist/App.d.ts.map +0 -1
- package/dist/App.js +0 -30
- package/dist/components/ThemeSwitcher.js +0 -12
- package/dist/components/form-controls/AutocompleteInput.js +0 -680
- package/dist/components/form-controls/Button.js +0 -211
- package/dist/components/form-controls/Checkbox.js +0 -79
- package/dist/components/form-controls/CurrencyInput.js +0 -106
- package/dist/components/form-controls/DateInput.js +0 -578
- package/dist/components/form-controls/DatePicker.js +0 -144
- package/dist/components/form-controls/Input.js +0 -35
- package/dist/components/form-controls/LinkButton.js +0 -248
- package/dist/components/form-controls/Pagination.js +0 -23
- package/dist/components/form-controls/RadioButtonGroup.js +0 -220
- package/dist/components/form-controls/SearchSelectInput.js +0 -336
- package/dist/components/form-controls/index.js +0 -11
- package/dist/components/index.js +0 -7
- package/dist/components/layout/Accordion.js +0 -67
- package/dist/components/layout/AppLayout.js +0 -230
- package/dist/components/layout/Card.js +0 -54
- package/dist/components/layout/Collection.js +0 -18
- package/dist/components/layout/DataField.js +0 -38
- package/dist/components/layout/DataTable.js +0 -164
- package/dist/components/layout/DropdownMenu.js +0 -176
- package/dist/components/layout/DropdownPanel.js +0 -162
- package/dist/components/layout/Filter.js +0 -629
- package/dist/components/layout/Menu.js +0 -21
- package/dist/components/layout/TabPanel.js +0 -11
- package/dist/components/layout/TabsGroup.js +0 -52
- package/dist/components/layout/index.js +0 -12
- package/dist/components/utils/Avatar.js +0 -77
- package/dist/components/utils/Badge.js +0 -151
- package/dist/components/utils/Dialog.js +0 -44
- package/dist/components/utils/FiltersDialog.js +0 -104
- package/dist/components/utils/Loader.js +0 -44
- package/dist/components/utils/RoadMap.js +0 -139
- package/dist/components/utils/Skeleton.js +0 -10
- package/dist/components/utils/Snackbar.js +0 -136
- package/dist/components/utils/SnackbarContainer.js +0 -26
- package/dist/components/utils/iconUtils.js +0 -40
- package/dist/components/utils/index.js +0 -9
- package/dist/contexts/AppLayoutContext.js +0 -104
- package/dist/contexts/AuthContext.js +0 -224
- package/dist/contexts/CrudContext.js +0 -333
- package/dist/contexts/SnackbarContext.js +0 -41
- package/dist/contexts/ThemeContext.js +0 -197
- package/dist/contexts/index.js +0 -13
- package/dist/contexts/presets.js +0 -311
- package/dist/contexts/types.js +0 -1
- package/dist/docs/AccordionDocs.d.ts +0 -4
- package/dist/docs/AccordionDocs.d.ts.map +0 -1
- package/dist/docs/AccordionDocs.js +0 -21
- package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts +0 -13
- package/dist/docs/AuthDocs.tsx/AuthDocs.d.ts.map +0 -1
- package/dist/docs/AuthDocs.tsx/AuthDocs.js +0 -18
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts +0 -2
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.d.ts.map +0 -1
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +0 -22
- package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts +0 -24
- package/dist/docs/AuthDocs.tsx/mockAuthService.d.ts.map +0 -1
- package/dist/docs/AuthDocs.tsx/mockAuthService.js +0 -78
- package/dist/docs/AutocompleteInputDocs.d.ts +0 -4
- package/dist/docs/AutocompleteInputDocs.d.ts.map +0 -1
- package/dist/docs/AutocompleteInputDocs.js +0 -84
- package/dist/docs/AvatarDocs.d.ts +0 -4
- package/dist/docs/AvatarDocs.d.ts.map +0 -1
- package/dist/docs/AvatarDocs.js +0 -7
- package/dist/docs/BadgeDocs.d.ts +0 -4
- package/dist/docs/BadgeDocs.d.ts.map +0 -1
- package/dist/docs/BadgeDocs.js +0 -9
- package/dist/docs/ButtonDocs.d.ts +0 -4
- package/dist/docs/ButtonDocs.d.ts.map +0 -1
- package/dist/docs/ButtonDocs.js +0 -7
- package/dist/docs/CardDocs.d.ts +0 -4
- package/dist/docs/CardDocs.d.ts.map +0 -1
- package/dist/docs/CardDocs.js +0 -22
- package/dist/docs/CheckboxDocs.d.ts +0 -4
- package/dist/docs/CheckboxDocs.d.ts.map +0 -1
- package/dist/docs/CheckboxDocs.js +0 -7
- package/dist/docs/CurrencyInputDocs.d.ts +0 -4
- package/dist/docs/CurrencyInputDocs.d.ts.map +0 -1
- package/dist/docs/CurrencyInputDocs.js +0 -22
- package/dist/docs/DataFieldDocs.d.ts +0 -4
- package/dist/docs/DataFieldDocs.d.ts.map +0 -1
- package/dist/docs/DataFieldDocs.js +0 -7
- package/dist/docs/DataTableDocs.d.ts +0 -4
- package/dist/docs/DataTableDocs.d.ts.map +0 -1
- package/dist/docs/DataTableDocs.js +0 -244
- package/dist/docs/DateInputDocs.d.ts +0 -5
- package/dist/docs/DateInputDocs.d.ts.map +0 -1
- package/dist/docs/DateInputDocs.js +0 -19
- package/dist/docs/DatePickerDocs.d.ts +0 -5
- package/dist/docs/DatePickerDocs.d.ts.map +0 -1
- package/dist/docs/DatePickerDocs.js +0 -16
- package/dist/docs/DialogDocs.d.ts +0 -4
- package/dist/docs/DialogDocs.d.ts.map +0 -1
- package/dist/docs/DialogDocs.js +0 -13
- package/dist/docs/DocAdmin.d.ts +0 -4
- package/dist/docs/DocAdmin.d.ts.map +0 -1
- package/dist/docs/DocAdmin.js +0 -68
- package/dist/docs/DocsMenu.d.ts +0 -2
- package/dist/docs/DocsMenu.d.ts.map +0 -1
- package/dist/docs/DocsMenu.js +0 -5
- package/dist/docs/DocsRouter.d.ts +0 -4
- package/dist/docs/DocsRouter.d.ts.map +0 -1
- package/dist/docs/DocsRouter.js +0 -39
- package/dist/docs/DropdownMenuDocs.d.ts +0 -4
- package/dist/docs/DropdownMenuDocs.d.ts.map +0 -1
- package/dist/docs/DropdownMenuDocs.js +0 -66
- package/dist/docs/DropdownPanelDocs.d.ts +0 -4
- package/dist/docs/DropdownPanelDocs.d.ts.map +0 -1
- package/dist/docs/DropdownPanelDocs.js +0 -7
- package/dist/docs/ExampleFormDocs.d.ts +0 -4
- package/dist/docs/ExampleFormDocs.d.ts.map +0 -1
- package/dist/docs/ExampleFormDocs.js +0 -153
- package/dist/docs/FilterDocs.d.ts +0 -4
- package/dist/docs/FilterDocs.d.ts.map +0 -1
- package/dist/docs/FilterDocs.js +0 -130
- package/dist/docs/InputDocs.d.ts +0 -4
- package/dist/docs/InputDocs.d.ts.map +0 -1
- package/dist/docs/InputDocs.js +0 -17
- package/dist/docs/LinkButtonDocs.d.ts +0 -4
- package/dist/docs/LinkButtonDocs.d.ts.map +0 -1
- package/dist/docs/LinkButtonDocs.js +0 -7
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +0 -47
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaPersonas.js +0 -34
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresaSingle.js +0 -66
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresas.js +0 -7
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts +0 -10
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentEmpresasPersonasEditDialog.js +0 -39
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +0 -2
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +0 -57
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts +0 -9
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.d.ts.map +0 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsEditDialog.js +0 -30
- package/dist/docs/LoaderDocs.d.ts +0 -4
- package/dist/docs/LoaderDocs.d.ts.map +0 -1
- package/dist/docs/LoaderDocs.js +0 -33
- package/dist/docs/MenuDocs.d.ts +0 -4
- package/dist/docs/MenuDocs.d.ts.map +0 -1
- package/dist/docs/MenuDocs.js +0 -26
- package/dist/docs/PaginationDocs.d.ts +0 -4
- package/dist/docs/PaginationDocs.d.ts.map +0 -1
- package/dist/docs/PaginationDocs.js +0 -38
- package/dist/docs/RadioButtonGroupDocs.d.ts +0 -4
- package/dist/docs/RadioButtonGroupDocs.d.ts.map +0 -1
- package/dist/docs/RadioButtonGroupDocs.js +0 -46
- package/dist/docs/RoadMapDocs.d.ts +0 -4
- package/dist/docs/RoadMapDocs.d.ts.map +0 -1
- package/dist/docs/RoadMapDocs.js +0 -171
- package/dist/docs/SearchSelectInputDocs.d.ts +0 -4
- package/dist/docs/SearchSelectInputDocs.d.ts.map +0 -1
- package/dist/docs/SearchSelectInputDocs.js +0 -168
- package/dist/docs/SkeletonDocs.d.ts +0 -4
- package/dist/docs/SkeletonDocs.d.ts.map +0 -1
- package/dist/docs/SkeletonDocs.js +0 -7
- package/dist/docs/SnackbarDocs.d.ts +0 -4
- package/dist/docs/SnackbarDocs.d.ts.map +0 -1
- package/dist/docs/SnackbarDocs.js +0 -69
- package/dist/docs/TabsGroupDocs.d.ts +0 -4
- package/dist/docs/TabsGroupDocs.d.ts.map +0 -1
- package/dist/docs/TabsGroupDocs.js +0 -38
- package/dist/docs/ThemeSwitcherDocs.d.ts +0 -4
- package/dist/docs/ThemeSwitcherDocs.d.ts.map +0 -1
- package/dist/docs/ThemeSwitcherDocs.js +0 -11
- package/dist/docs/docMockServices/empresaService.d.ts +0 -38
- package/dist/docs/docMockServices/empresaService.d.ts.map +0 -1
- package/dist/docs/docMockServices/empresaService.js +0 -125
- package/dist/docs/docMockServices/index.d.ts +0 -9
- package/dist/docs/docMockServices/index.d.ts.map +0 -1
- package/dist/docs/docMockServices/index.js +0 -8
- package/dist/docs/docMockServices/initialData.d.ts +0 -6
- package/dist/docs/docMockServices/initialData.d.ts.map +0 -1
- package/dist/docs/docMockServices/initialData.js +0 -132
- package/dist/docs/docMockServices/interfaces.d.ts +0 -38
- package/dist/docs/docMockServices/interfaces.d.ts.map +0 -1
- package/dist/docs/docMockServices/interfaces.js +0 -1
- package/dist/docs/docMockServices/personaEmpresaService.d.ts +0 -43
- package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +0 -1
- package/dist/docs/docMockServices/personaEmpresaService.js +0 -151
- package/dist/docs/docMockServices/personaService.d.ts +0 -39
- package/dist/docs/docMockServices/personaService.d.ts.map +0 -1
- package/dist/docs/docMockServices/personaService.js +0 -190
- package/dist/helpers/currencyFormat.js +0 -3
- package/dist/helpers/getErrorMessage.js +0 -13
- package/dist/helpers/getInitialLetters.js +0 -5
- package/dist/helpers/getQueryString.js +0 -13
- package/dist/helpers/index.js +0 -9
- package/dist/helpers/mappers.js +0 -27
- package/dist/helpers/nameValueArrayToObject.js +0 -3
- package/dist/helpers/objectToQueryString.js +0 -3
- package/dist/helpers/queryStringToObject.js +0 -13
- package/dist/helpers/regularExpressions.js +0 -5
- package/dist/hooks/index.js +0 -6
- package/dist/hooks/useAsyncRequest.js +0 -53
- package/dist/hooks/useBreakpoint.js +0 -59
- package/dist/hooks/useElementScroll.js +0 -58
- package/dist/hooks/useEnum.js +0 -21
- package/dist/hooks/useGlobalThemeStyles.js +0 -40
- package/dist/hooks/useThemeOverride.js +0 -99
- package/dist/interfaces/index.js +0 -1
- package/dist/interfaces/name-value.interface.js +0 -1
- package/dist/interfaces/pagination.interface.js +0 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js +0 -6
- package/dist/services/apiClient.js +0 -216
- package/dist/services/index.js +0 -1
- package/dist/styles.d.ts +0 -2
- package/dist/styles.d.ts.map +0 -1
- package/dist/styles.js +0 -3
- package/dist/templates/forms/ContactForm.js +0 -58
- package/dist/templates/forms/LoginForm.js +0 -36
- package/dist/templates/forms/RegistrationForm.js +0 -54
- package/dist/templates/layouts/DashboardLayout.js +0 -26
- package/dist/templates/layouts/SidebarLayout.js +0 -28
- package/dist/templates/patterns/FormPattern.js +0 -68
|
@@ -1,629 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useState, useEffect, useRef } from "react";
|
|
3
|
-
import { createPortal } from "react-dom";
|
|
4
|
-
import { useSearchParams } from "react-router-dom";
|
|
5
|
-
import dayjs, {} from "dayjs";
|
|
6
|
-
import { Button } from "../form-controls/Button";
|
|
7
|
-
import { Input } from "../form-controls/Input";
|
|
8
|
-
import { DateInput } from "../form-controls/DateInput";
|
|
9
|
-
import { AutocompleteInput } from "../form-controls/AutocompleteInput";
|
|
10
|
-
import { SearchSelectInput } from "../form-controls/SearchSelectInput";
|
|
11
|
-
import { DataField } from "./DataField";
|
|
12
|
-
import { normalizeIconClass } from "../utils/iconUtils";
|
|
13
|
-
export const Filter = (props) => {
|
|
14
|
-
const { paramName, label, staticOptions, inputWidth, value: propValue, onChange, hideEmpty = false, disabled = false, } = props;
|
|
15
|
-
const filterType = props.filterType || "text";
|
|
16
|
-
// Calcular el ancho por defecto según el tipo de filtro
|
|
17
|
-
const defaultInputWidth = filterType === "date" || filterType === "autocomplete" ? "160px" : "200px";
|
|
18
|
-
const finalInputWidth = inputWidth || defaultInputWidth;
|
|
19
|
-
const [searchParams, setSearchParams] = useSearchParams();
|
|
20
|
-
const urlValue = paramName
|
|
21
|
-
? searchParams.get(paramName) || undefined
|
|
22
|
-
: undefined;
|
|
23
|
-
// Usar propValue si está presente, sino usar urlValue
|
|
24
|
-
const currentValue = propValue !== undefined ? propValue : urlValue;
|
|
25
|
-
const [inputValue, setInputValue] = useState(currentValue || "");
|
|
26
|
-
const [searchValue, setSearchValue] = useState(currentValue || "");
|
|
27
|
-
const [dateValue, setDateValue] = useState(null);
|
|
28
|
-
const [autocompleteValue, setAutocompleteValue] = useState(currentValue ?
|
|
29
|
-
(props.filterType === "autocomplete" && props.multiple ? currentValue.split("|") : currentValue)
|
|
30
|
-
: "");
|
|
31
|
-
const [searchSelectValue, setSearchSelectValue] = useState(currentValue || undefined);
|
|
32
|
-
const [searchSelectLabel, setSearchSelectLabel] = useState("");
|
|
33
|
-
const [isUserTyping, setIsUserTyping] = useState(false);
|
|
34
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
35
|
-
const [panelPosition, setPanelPosition] = useState(null);
|
|
36
|
-
const containerRef = useRef(null);
|
|
37
|
-
const panelRef = useRef(null);
|
|
38
|
-
const inputRef = useRef(null);
|
|
39
|
-
const searchInputRef = useRef(null);
|
|
40
|
-
const searchSelectInputRef = useRef(null);
|
|
41
|
-
const dateInputRef = useRef(null);
|
|
42
|
-
const autocompleteInputRef = useRef(null);
|
|
43
|
-
// Sincronizar el input con el valor actual (propValue o urlValue)
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
if (filterType !== "autocomplete" &&
|
|
46
|
-
filterType !== "search" &&
|
|
47
|
-
filterType !== "searchSelect") {
|
|
48
|
-
setInputValue(currentValue || "");
|
|
49
|
-
}
|
|
50
|
-
}, [currentValue, filterType]);
|
|
51
|
-
// Sincronizar el searchValue con el valor actual (propValue o urlValue)
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
if (filterType === "search") {
|
|
54
|
-
setSearchValue(currentValue || "");
|
|
55
|
-
}
|
|
56
|
-
}, [currentValue, filterType]);
|
|
57
|
-
// Sincronizar el searchSelectValue con el valor actual (propValue o urlValue)
|
|
58
|
-
// y buscar el label si no está disponible
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (filterType === "searchSelect" && currentValue) {
|
|
61
|
-
const searchSelectProps = props;
|
|
62
|
-
const getOptionLabel = searchSelectProps.getOptionLabel || ((item) => item.label || "");
|
|
63
|
-
const getOptionValue = searchSelectProps.getOptionValue || ((item) => item.value || "");
|
|
64
|
-
const onSingleSearchPromiseFn = searchSelectProps.onSingleSearchPromiseFn;
|
|
65
|
-
// Si searchSelectValue es un objeto, extraer el label directamente
|
|
66
|
-
if (searchSelectValue && typeof searchSelectValue === "object") {
|
|
67
|
-
const label = getOptionLabel(searchSelectValue);
|
|
68
|
-
const value = String(getOptionValue(searchSelectValue));
|
|
69
|
-
if (value === String(currentValue)) {
|
|
70
|
-
setSearchSelectLabel(label);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Si no tenemos el objeto completo, usar onSingleSearchPromiseFn para obtenerlo
|
|
75
|
-
if (onSingleSearchPromiseFn) {
|
|
76
|
-
onSingleSearchPromiseFn(currentValue)
|
|
77
|
-
.then((option) => {
|
|
78
|
-
if (option) {
|
|
79
|
-
setSearchSelectValue(option);
|
|
80
|
-
setSearchSelectLabel(getOptionLabel(option));
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
setSearchSelectLabel(String(currentValue));
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
.catch(() => {
|
|
87
|
-
setSearchSelectLabel(String(currentValue));
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
setSearchSelectLabel(String(currentValue));
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else if (filterType === "searchSelect" && !currentValue) {
|
|
95
|
-
setSearchSelectValue(undefined);
|
|
96
|
-
setSearchSelectLabel("");
|
|
97
|
-
}
|
|
98
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
99
|
-
}, [currentValue, filterType]);
|
|
100
|
-
// Sincronizar el dateValue con el valor actual (propValue o urlValue)
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
if (filterType === "date") {
|
|
103
|
-
if (currentValue) {
|
|
104
|
-
const date = dayjs(currentValue, "YYYY-MM-DD");
|
|
105
|
-
setDateValue(date.isValid() ? date : null);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
setDateValue(null);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}, [currentValue, filterType]);
|
|
112
|
-
// Sincronizar el autocompleteValue con el valor actual (propValue o urlValue)
|
|
113
|
-
// Para autocomplete, mantener el value (no el label) para que AutocompleteInput pueda encontrar la opción
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
if (filterType === "autocomplete") {
|
|
116
|
-
const isMultiple = props.multiple;
|
|
117
|
-
// Mantener el value, el AutocompleteInput se encargará de mostrar el label
|
|
118
|
-
setAutocompleteValue(currentValue ? (isMultiple ? currentValue.split("|") : currentValue) : (isMultiple ? [] : ""));
|
|
119
|
-
setIsUserTyping(false);
|
|
120
|
-
}
|
|
121
|
-
}, [currentValue, filterType, props]);
|
|
122
|
-
// Cerrar el panel al hacer clic fuera
|
|
123
|
-
useEffect(() => {
|
|
124
|
-
if (!isOpen)
|
|
125
|
-
return;
|
|
126
|
-
const handleClickOutside = (event) => {
|
|
127
|
-
const target = event.target;
|
|
128
|
-
const isClickInsideContainer = containerRef.current?.contains(target);
|
|
129
|
-
const isClickInsidePanel = panelRef.current?.contains(target);
|
|
130
|
-
// Verificar si el click está dentro de un elemento con portal (DatePicker, AutocompleteInput, etc.)
|
|
131
|
-
// Estos elementos tienen z-[2001] y están posicionados fixed
|
|
132
|
-
let isClickInsidePortal = false;
|
|
133
|
-
if (target instanceof Element) {
|
|
134
|
-
let element = target;
|
|
135
|
-
// Subir por el árbol DOM buscando elementos con z-index alto que sean portales
|
|
136
|
-
while (element && element !== document.body) {
|
|
137
|
-
const computedStyle = window.getComputedStyle(element);
|
|
138
|
-
const zIndex = computedStyle.zIndex;
|
|
139
|
-
const position = computedStyle.position;
|
|
140
|
-
// Si encontramos un elemento fixed con z-index alto, probablemente es un portal
|
|
141
|
-
if (position === "fixed" &&
|
|
142
|
-
(zIndex === "2001" || parseInt(zIndex) >= 2001)) {
|
|
143
|
-
isClickInsidePortal = true;
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
element = element.parentElement;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
if (!isClickInsideContainer &&
|
|
150
|
-
!isClickInsidePanel &&
|
|
151
|
-
!isClickInsidePortal) {
|
|
152
|
-
setIsOpen(false);
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
// Pequeño delay para asegurar que el portal esté montado
|
|
156
|
-
const timer = setTimeout(() => {
|
|
157
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
158
|
-
}, 0);
|
|
159
|
-
return () => {
|
|
160
|
-
clearTimeout(timer);
|
|
161
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
162
|
-
};
|
|
163
|
-
}, [isOpen]);
|
|
164
|
-
// Cerrar el panel si el componente se deshabilita
|
|
165
|
-
useEffect(() => {
|
|
166
|
-
if (disabled) {
|
|
167
|
-
setIsOpen(false);
|
|
168
|
-
}
|
|
169
|
-
}, [disabled]);
|
|
170
|
-
const handleSetFilter = () => {
|
|
171
|
-
const newValue = inputValue.trim() || undefined;
|
|
172
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
173
|
-
if (onChange) {
|
|
174
|
-
onChange(newValue);
|
|
175
|
-
}
|
|
176
|
-
// Si hay paramName, actualizar el query param
|
|
177
|
-
if (paramName) {
|
|
178
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
179
|
-
if (newValue) {
|
|
180
|
-
newSearchParams.set(paramName, newValue);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
newSearchParams.delete(paramName);
|
|
184
|
-
}
|
|
185
|
-
// Usar replace: true para reemplazar la URL sin agregar una nueva entrada al historial
|
|
186
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
187
|
-
}
|
|
188
|
-
setIsOpen(false);
|
|
189
|
-
};
|
|
190
|
-
const handleSearchChange = (e) => {
|
|
191
|
-
setSearchValue(e.target.value);
|
|
192
|
-
};
|
|
193
|
-
const handleSearchKeyDown = (e) => {
|
|
194
|
-
if (e.key === "Enter") {
|
|
195
|
-
handleSearchSubmit();
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
const handleSearchSubmit = () => {
|
|
199
|
-
const newValue = searchValue.trim() || undefined;
|
|
200
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
201
|
-
if (onChange) {
|
|
202
|
-
onChange(newValue);
|
|
203
|
-
}
|
|
204
|
-
// Si hay paramName, actualizar el query param
|
|
205
|
-
if (paramName) {
|
|
206
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
207
|
-
if (newValue) {
|
|
208
|
-
newSearchParams.set(paramName, newValue);
|
|
209
|
-
}
|
|
210
|
-
else {
|
|
211
|
-
newSearchParams.delete(paramName);
|
|
212
|
-
}
|
|
213
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
const handleSearchIconClick = () => {
|
|
217
|
-
// Verificar si el texto actual coincide con el valor actual
|
|
218
|
-
const valueMatches = currentValue && searchValue.trim() === currentValue;
|
|
219
|
-
if (valueMatches) {
|
|
220
|
-
// Si coincide, limpiar
|
|
221
|
-
const newValue = undefined;
|
|
222
|
-
// Si hay onChange, llamarlo con undefined
|
|
223
|
-
if (onChange) {
|
|
224
|
-
onChange(newValue);
|
|
225
|
-
}
|
|
226
|
-
// Si hay paramName, actualizar el query param
|
|
227
|
-
if (paramName) {
|
|
228
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
229
|
-
newSearchParams.delete(paramName);
|
|
230
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
231
|
-
}
|
|
232
|
-
setSearchValue("");
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
// Si no coincide, hacer submit
|
|
236
|
-
handleSearchSubmit();
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
const handleAutocompleteChange = (val) => {
|
|
240
|
-
// Si viene undefined pero estamos en múltiple, podría ser por limpieza
|
|
241
|
-
if (val !== undefined && Array.isArray(val) && props.multiple) {
|
|
242
|
-
setAutocompleteValue(val);
|
|
243
|
-
// En múltiple no manejamos "free text" que no sea opción
|
|
244
|
-
setIsUserTyping(false);
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
// Marcar que el usuario está escribiendo libremente (input manual simple mode)
|
|
248
|
-
setIsUserTyping(true);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
const handleAutocompleteSelect = () => {
|
|
252
|
-
// Obtener el valor actual del input del AutocompleteInput
|
|
253
|
-
const currentInputValue = autocompleteInputRef.current?.value || "";
|
|
254
|
-
// Buscar si el texto actual coincide con alguna opción
|
|
255
|
-
if (filterType === "autocomplete") {
|
|
256
|
-
const autocompleteProps = props;
|
|
257
|
-
const getOptionLabel = autocompleteProps.getOptionLabel || ((item) => item.label || "");
|
|
258
|
-
const getOptionValue = autocompleteProps.getOptionValue || ((item) => item.value || "");
|
|
259
|
-
// Buscar opción por label
|
|
260
|
-
const matchingOption = autocompleteProps.options.find((opt) => getOptionLabel(opt).toLowerCase() === currentInputValue.toLowerCase());
|
|
261
|
-
let newValue;
|
|
262
|
-
if (autocompleteProps.multiple) {
|
|
263
|
-
// Extraemos del estado que ya contiene el arreglo
|
|
264
|
-
newValue = Array.isArray(autocompleteValue) && autocompleteValue.length > 0 ? autocompleteValue.join("|") : undefined;
|
|
265
|
-
setIsUserTyping(false);
|
|
266
|
-
}
|
|
267
|
-
else {
|
|
268
|
-
if (matchingOption) {
|
|
269
|
-
newValue = String(getOptionValue(matchingOption));
|
|
270
|
-
setAutocompleteValue(newValue);
|
|
271
|
-
setIsUserTyping(false);
|
|
272
|
-
}
|
|
273
|
-
else if (currentInputValue.trim()) {
|
|
274
|
-
// Si no coincide con ninguna opción, guardar el texto tal cual
|
|
275
|
-
newValue = currentInputValue.trim();
|
|
276
|
-
setAutocompleteValue(newValue);
|
|
277
|
-
setIsUserTyping(false);
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
newValue = undefined;
|
|
281
|
-
setAutocompleteValue("");
|
|
282
|
-
setIsUserTyping(false);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
286
|
-
if (onChange) {
|
|
287
|
-
onChange(newValue);
|
|
288
|
-
}
|
|
289
|
-
// Si hay paramName, actualizar el query param
|
|
290
|
-
if (paramName) {
|
|
291
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
292
|
-
if (newValue) {
|
|
293
|
-
newSearchParams.set(paramName, newValue);
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
newSearchParams.delete(paramName);
|
|
297
|
-
}
|
|
298
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
299
|
-
}
|
|
300
|
-
setIsOpen(false);
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
const handleAutocompleteOptionSelect = (option) => {
|
|
304
|
-
if (filterType === "autocomplete") {
|
|
305
|
-
const autocompleteProps = props;
|
|
306
|
-
const getOptionValue = autocompleteProps.getOptionValue || ((item) => item.value || "");
|
|
307
|
-
const optionValueStr = String(getOptionValue(option));
|
|
308
|
-
let newValueToEmit;
|
|
309
|
-
if (autocompleteProps.multiple) {
|
|
310
|
-
// El onChange directo del AutocompleteInput ya maneja el arreglo,
|
|
311
|
-
// pero si por alguna razón onSelect atrapa esto, actualizamos el array (aunque lo hace en setAutocompleteValue arriba)
|
|
312
|
-
// El array completo actual deberia estar en `autocompleteValue` pero asíncronamente;
|
|
313
|
-
// mejor confiamos en la lógica de `AutocompleteInput` de toggle.
|
|
314
|
-
// En modo onSelect individual (cuando se clickea una recien), solo la disparamos o dejamos que HandleAutoCompleteChange actúe.
|
|
315
|
-
return; // Para múltiple dejamos que submit o el Autocomplete lo haga, o lo sincronizamos a nivel onChange general de autComplete y en Confirm.
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
newValueToEmit = optionValueStr;
|
|
319
|
-
setAutocompleteValue(newValueToEmit);
|
|
320
|
-
setIsUserTyping(false);
|
|
321
|
-
}
|
|
322
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
323
|
-
if (onChange) {
|
|
324
|
-
onChange(newValueToEmit);
|
|
325
|
-
}
|
|
326
|
-
// Si hay paramName, actualizar el query param
|
|
327
|
-
if (paramName) {
|
|
328
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
329
|
-
newSearchParams.set(paramName, newValueToEmit);
|
|
330
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
331
|
-
}
|
|
332
|
-
setIsOpen(false);
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
const handleSearchSelectChange = (value) => {
|
|
336
|
-
if (filterType === "searchSelect") {
|
|
337
|
-
const searchSelectProps = props;
|
|
338
|
-
const getOptionValue = searchSelectProps.getOptionValue || ((item) => item.value || "");
|
|
339
|
-
const getOptionLabel = searchSelectProps.getOptionLabel || ((item) => item.label || "");
|
|
340
|
-
// Si value es un objeto, extraer el valor usando getOptionValue
|
|
341
|
-
// Si value es un string/number, usarlo directamente
|
|
342
|
-
let newValue;
|
|
343
|
-
if (value === undefined || value === null) {
|
|
344
|
-
newValue = undefined;
|
|
345
|
-
setSearchSelectValue(undefined);
|
|
346
|
-
setSearchSelectLabel("");
|
|
347
|
-
}
|
|
348
|
-
else if (typeof value === "object") {
|
|
349
|
-
newValue = String(getOptionValue(value));
|
|
350
|
-
setSearchSelectValue(value);
|
|
351
|
-
setSearchSelectLabel(getOptionLabel(value));
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
newValue = String(value);
|
|
355
|
-
setSearchSelectValue(value);
|
|
356
|
-
// Si solo tenemos el valor, el useEffect se encargará de buscar el label
|
|
357
|
-
setSearchSelectLabel("");
|
|
358
|
-
}
|
|
359
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
360
|
-
if (onChange) {
|
|
361
|
-
onChange(newValue);
|
|
362
|
-
}
|
|
363
|
-
// Si hay paramName, actualizar el query param
|
|
364
|
-
if (paramName) {
|
|
365
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
366
|
-
if (newValue) {
|
|
367
|
-
newSearchParams.set(paramName, newValue);
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
newSearchParams.delete(paramName);
|
|
371
|
-
}
|
|
372
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
373
|
-
}
|
|
374
|
-
setIsOpen(false);
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
const handleDateChange = (date) => {
|
|
378
|
-
// Solo actualizar el estado temporal, no setear en la URL
|
|
379
|
-
setDateValue(date);
|
|
380
|
-
};
|
|
381
|
-
const handleSetDateFilter = () => {
|
|
382
|
-
let newValue;
|
|
383
|
-
if (dateValue && dateValue.isValid()) {
|
|
384
|
-
// Guardar como yyyy-mm-dd
|
|
385
|
-
newValue = dateValue.format("YYYY-MM-DD");
|
|
386
|
-
}
|
|
387
|
-
else {
|
|
388
|
-
newValue = undefined;
|
|
389
|
-
}
|
|
390
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
391
|
-
if (onChange) {
|
|
392
|
-
onChange(newValue);
|
|
393
|
-
}
|
|
394
|
-
// Si hay paramName, actualizar el query param
|
|
395
|
-
if (paramName) {
|
|
396
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
397
|
-
if (newValue) {
|
|
398
|
-
newSearchParams.set(paramName, newValue);
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
newSearchParams.delete(paramName);
|
|
402
|
-
}
|
|
403
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
404
|
-
}
|
|
405
|
-
setIsOpen(false);
|
|
406
|
-
};
|
|
407
|
-
const handleStaticOptionSelect = (option) => {
|
|
408
|
-
const newValue = option.value;
|
|
409
|
-
// Si hay onChange, llamarlo con el nuevo valor
|
|
410
|
-
if (onChange) {
|
|
411
|
-
onChange(newValue);
|
|
412
|
-
}
|
|
413
|
-
// Si hay paramName, actualizar el query param
|
|
414
|
-
if (paramName) {
|
|
415
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
416
|
-
newSearchParams.set(paramName, newValue);
|
|
417
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
418
|
-
}
|
|
419
|
-
setIsOpen(false);
|
|
420
|
-
};
|
|
421
|
-
// Para staticOptions: mostrar el texto de la opción si el valor coincide (prioridad)
|
|
422
|
-
// Para date: convertir yyyy-mm-dd a Dayjs y formatear para mostrar como dd/mm/yyyy
|
|
423
|
-
// Para autocomplete: mostrar el label de la opción si el valor coincide
|
|
424
|
-
const getDisplayValue = () => {
|
|
425
|
-
// Primero verificar si el valor coincide con alguna opción estática
|
|
426
|
-
if (staticOptions && currentValue) {
|
|
427
|
-
const option = staticOptions.find((opt) => opt.value === currentValue);
|
|
428
|
-
if (option) {
|
|
429
|
-
return option.text;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
// Para autocomplete, buscar el label de la opción
|
|
433
|
-
if (filterType === "autocomplete" && currentValue) {
|
|
434
|
-
const autocompleteProps = props;
|
|
435
|
-
if (autocompleteProps.options) {
|
|
436
|
-
const getOptionLabel = autocompleteProps.getOptionLabel || ((item) => item.label || "");
|
|
437
|
-
const getOptionValue = autocompleteProps.getOptionValue || ((item) => item.value || "");
|
|
438
|
-
if (autocompleteProps.multiple) {
|
|
439
|
-
const valuesArray = currentValue.split("|");
|
|
440
|
-
const labels = valuesArray.map((val) => {
|
|
441
|
-
const option = autocompleteProps.options.find((opt) => String(getOptionValue(opt)) === String(val));
|
|
442
|
-
return option ? getOptionLabel(option) : val;
|
|
443
|
-
});
|
|
444
|
-
return labels.join(", ");
|
|
445
|
-
}
|
|
446
|
-
else {
|
|
447
|
-
const option = autocompleteProps.options.find((opt) => String(getOptionValue(opt)) === String(currentValue));
|
|
448
|
-
if (option) {
|
|
449
|
-
return getOptionLabel(option);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
// Para searchSelect, mostrar el label guardado o buscar el label del objeto
|
|
455
|
-
if (filterType === "searchSelect" && currentValue) {
|
|
456
|
-
if (searchSelectLabel) {
|
|
457
|
-
return searchSelectLabel;
|
|
458
|
-
}
|
|
459
|
-
// Si tenemos el objeto completo, extraer el label
|
|
460
|
-
if (searchSelectValue && typeof searchSelectValue === "object") {
|
|
461
|
-
const searchSelectProps = props;
|
|
462
|
-
const getOptionLabel = searchSelectProps.getOptionLabel || ((item) => item.label || "");
|
|
463
|
-
return getOptionLabel(searchSelectValue);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
// Si no hay opción estática que coincida, formatear según el tipo
|
|
467
|
-
if (filterType === "date" && currentValue) {
|
|
468
|
-
const date = dayjs(currentValue, "YYYY-MM-DD");
|
|
469
|
-
if (date.isValid()) {
|
|
470
|
-
return date.format("DD/MM/YYYY");
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return currentValue || "";
|
|
474
|
-
};
|
|
475
|
-
const handleClearFilter = (e) => {
|
|
476
|
-
e.stopPropagation();
|
|
477
|
-
// Si hay onChange, llamarlo con undefined para limpiar
|
|
478
|
-
if (onChange) {
|
|
479
|
-
onChange(undefined);
|
|
480
|
-
}
|
|
481
|
-
// Si hay paramName, actualizar el query param
|
|
482
|
-
if (paramName) {
|
|
483
|
-
const newSearchParams = new URLSearchParams(searchParams);
|
|
484
|
-
newSearchParams.delete(paramName);
|
|
485
|
-
setSearchParams(newSearchParams, { replace: true });
|
|
486
|
-
}
|
|
487
|
-
};
|
|
488
|
-
const handleTogglePanel = () => {
|
|
489
|
-
if (disabled)
|
|
490
|
-
return;
|
|
491
|
-
if (!isOpen) {
|
|
492
|
-
// Calcular posición antes de abrir
|
|
493
|
-
if (containerRef.current) {
|
|
494
|
-
const rect = containerRef.current.getBoundingClientRect();
|
|
495
|
-
setPanelPosition({
|
|
496
|
-
top: rect.bottom + window.scrollY + 4,
|
|
497
|
-
left: rect.left + window.scrollX,
|
|
498
|
-
width: rect.width,
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
setIsOpen(!isOpen);
|
|
503
|
-
};
|
|
504
|
-
// Actualizar posición cuando se abre o cuando cambia el scroll
|
|
505
|
-
useEffect(() => {
|
|
506
|
-
if (isOpen && containerRef.current) {
|
|
507
|
-
const updatePosition = () => {
|
|
508
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
509
|
-
if (rect) {
|
|
510
|
-
setPanelPosition({
|
|
511
|
-
top: rect.bottom + window.scrollY + 4,
|
|
512
|
-
left: rect.left + window.scrollX,
|
|
513
|
-
width: rect.width,
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
updatePosition();
|
|
518
|
-
window.addEventListener("scroll", updatePosition, true);
|
|
519
|
-
window.addEventListener("resize", updatePosition);
|
|
520
|
-
return () => {
|
|
521
|
-
window.removeEventListener("scroll", updatePosition, true);
|
|
522
|
-
window.removeEventListener("resize", updatePosition);
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
}, [isOpen]);
|
|
526
|
-
// Hacer foco en el input cuando se abre el panel
|
|
527
|
-
useEffect(() => {
|
|
528
|
-
if (isOpen) {
|
|
529
|
-
// Pequeño delay para asegurar que el DOM esté actualizado
|
|
530
|
-
const timer = setTimeout(() => {
|
|
531
|
-
if (filterType === "text" || filterType === "number") {
|
|
532
|
-
inputRef.current?.focus();
|
|
533
|
-
}
|
|
534
|
-
else if (filterType === "date") {
|
|
535
|
-
dateInputRef.current?.focus();
|
|
536
|
-
}
|
|
537
|
-
else if (filterType === "autocomplete") {
|
|
538
|
-
autocompleteInputRef.current?.focus();
|
|
539
|
-
}
|
|
540
|
-
// searchSelect no necesita focus porque usa un Dialog interno
|
|
541
|
-
}, 50);
|
|
542
|
-
return () => clearTimeout(timer);
|
|
543
|
-
}
|
|
544
|
-
}, [isOpen, filterType]);
|
|
545
|
-
// Si hideEmpty es true y no hay valor, no renderizar el componente
|
|
546
|
-
if (hideEmpty && !currentValue) {
|
|
547
|
-
return null;
|
|
548
|
-
}
|
|
549
|
-
// Contenedor tipo badge con diseño similar al Input
|
|
550
|
-
// Altura ajustada para coincidir con input sm: py-1.5 (6px arriba y abajo) + text-sm (14px línea) = ~26px total
|
|
551
|
-
const badgeContainer = (_jsxs("div", { className: "inline-flex items-center gap-2 px-3 py-1.5 h-[2.1rem] rounded-lg border border-[var(--color-border-default)] bg-[var(--color-bg-default)] text-[var(--color-text-primary)] font-[var(--font-default)] cursor-pointer text-sm transition-colors", onClick: handleTogglePanel, children: [_jsx("span", { className: "text-sm min-w-[1rem]", children: getDisplayValue() || "\u00A0" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "p-0.5 hover:bg-[var(--color-bg-secondary)] rounded transition-colors flex items-center justify-center", children: _jsx("i", { className: `${normalizeIconClass("fa-chevron-down")} text-xs text-[var(--color-text-muted)] hover:text-[var(--color-primary)] transition-all ${isOpen ? "rotate-180" : ""}` }) }), currentValue && (_jsx("button", { onClick: handleClearFilter, className: "p-0.5 hover:bg-[var(--color-bg-secondary)] rounded transition-colors flex items-center justify-center cursor-pointer", "aria-label": "Borrar filtro", type: "button", children: _jsx("i", { className: `${normalizeIconClass("fa-times")} text-xs text-[var(--color-text-muted)] hover:text-[var(--color-primary)] transition-colors` }) }))] })] }));
|
|
552
|
-
// Renderizar según el tipo de filtro
|
|
553
|
-
if (filterType === "autocomplete") {
|
|
554
|
-
return (_jsxs("div", { ref: containerRef, className: `relative inline-block ${disabled ? "opacity-50 pointer-events-none" : ""}`, children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
555
|
-
panelPosition &&
|
|
556
|
-
typeof document !== "undefined" &&
|
|
557
|
-
document.body &&
|
|
558
|
-
createPortal(_jsx("div", { ref: panelRef, className: "fixed z-[2001] w-fit rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-default)] shadow-[var(--shadow-lg)] p-4", style: {
|
|
559
|
-
top: `${panelPosition.top}px`,
|
|
560
|
-
left: `${panelPosition.left}px`,
|
|
561
|
-
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto list-none pl-0", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center justify-start text-left gap-2 text-sm rounded transition-colors ${currentValue === option.value
|
|
562
|
-
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
563
|
-
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
564
|
-
e.preventDefault();
|
|
565
|
-
handleStaticOptionSelect(option);
|
|
566
|
-
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsxs("div", { className: "flex items-center justify-start gap-2", children: [_jsx("div", { style: { width: finalInputWidth }, children: _jsx(AutocompleteInput, { ref: autocompleteInputRef, options: props.options, value: isUserTyping ? undefined : autocompleteValue, onChange: handleAutocompleteChange, getOptionLabel: props.getOptionLabel, getOptionValue: props.getOptionValue, renderOption: props.renderOption, noResultsText: props.noResultsText, multiple: props.multiple, onSelectOption: handleAutocompleteOptionSelect, disabled: disabled }) }), _jsx(Button, { onClick: handleAutocompleteSelect, icon: props.multiple ? "fa-check" : "fa-arrow-right", variant: "ghost" })] })] }) }), document.body)] }));
|
|
567
|
-
}
|
|
568
|
-
if (filterType === "date") {
|
|
569
|
-
return (_jsxs("div", { ref: containerRef, className: `relative inline-block ${disabled ? "opacity-50 pointer-events-none" : ""}`, children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
570
|
-
panelPosition &&
|
|
571
|
-
typeof document !== "undefined" &&
|
|
572
|
-
document.body &&
|
|
573
|
-
createPortal(_jsx("div", { ref: panelRef, className: "fixed z-[2001] w-fit rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-default)] shadow-[var(--shadow-lg)] p-4", style: {
|
|
574
|
-
top: `${panelPosition.top}px`,
|
|
575
|
-
left: `${panelPosition.left}px`,
|
|
576
|
-
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto list-none pl-0", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center justify-start text-left gap-2 text-sm rounded transition-colors ${currentValue === option.value
|
|
577
|
-
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
578
|
-
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
579
|
-
e.preventDefault();
|
|
580
|
-
handleStaticOptionSelect(option);
|
|
581
|
-
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsxs("div", { className: "flex items-center justify-start gap-2", children: [_jsx("div", { style: { width: finalInputWidth }, children: _jsx(DateInput, { ref: dateInputRef, value: dateValue, onChange: handleDateChange, format: "dd/mm/yyyy" }) }), _jsx(Button, { onClick: handleSetDateFilter, icon: "fa-arrow-right", variant: "ghost" })] })] }) }), document.body)] }));
|
|
582
|
-
}
|
|
583
|
-
// Para searchSelect
|
|
584
|
-
if (filterType === "searchSelect") {
|
|
585
|
-
const searchSelectProps = props;
|
|
586
|
-
return (_jsxs("div", { ref: containerRef, className: `relative inline-block ${disabled ? "opacity-50 pointer-events-none" : ""}`, children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
587
|
-
panelPosition &&
|
|
588
|
-
typeof document !== "undefined" &&
|
|
589
|
-
document.body &&
|
|
590
|
-
createPortal(_jsx("div", { ref: panelRef, className: "fixed z-[2001] w-fit rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-default)] shadow-[var(--shadow-lg)] p-4", style: {
|
|
591
|
-
top: `${panelPosition.top}px`,
|
|
592
|
-
left: `${panelPosition.left}px`,
|
|
593
|
-
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto list-none pl-0", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center justify-start text-left gap-2 text-sm rounded transition-colors ${currentValue === option.value
|
|
594
|
-
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
595
|
-
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
596
|
-
e.preventDefault();
|
|
597
|
-
handleStaticOptionSelect(option);
|
|
598
|
-
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsx("div", { style: { width: finalInputWidth }, children: _jsx(SearchSelectInput, { ref: searchSelectInputRef, value: searchSelectValue, onChange: handleSearchSelectChange, onSearchPromiseFn: searchSelectProps.onSearchPromiseFn, onSingleSearchPromiseFn: searchSelectProps.onSingleSearchPromiseFn, getOptionLabel: searchSelectProps.getOptionLabel, getOptionValue: searchSelectProps.getOptionValue, renderOption: searchSelectProps.renderOption, dialogTitle: searchSelectProps.dialogTitle, noResultsText: searchSelectProps.noResultsText }) })] }) }), document.body)] }));
|
|
599
|
-
}
|
|
600
|
-
// Para search
|
|
601
|
-
if (filterType === "search") {
|
|
602
|
-
// Mostrar X solo si hay un valor actual Y el texto del input coincide con ese valor
|
|
603
|
-
const hasValue = !!currentValue;
|
|
604
|
-
const valueMatches = hasValue && searchValue.trim() === currentValue;
|
|
605
|
-
return (_jsx("div", { ref: containerRef, className: `relative inline-block ${disabled ? "opacity-50 pointer-events-none" : ""}`, children: _jsx(DataField, { label: label, value: _jsx("div", { style: { width: finalInputWidth }, children: _jsx(Input, { ref: searchInputRef, type: "text", value: searchValue, onChange: handleSearchChange, onKeyDown: handleSearchKeyDown, icon: valueMatches ? "fa-times" : "fa-search", iconPosition: "right", onIconClick: handleSearchIconClick, placeholder: "Buscar...", size: "sm", disabled: disabled }) }), className: "inline-block" }) }));
|
|
606
|
-
}
|
|
607
|
-
// Para text y number
|
|
608
|
-
return (_jsxs("div", { ref: containerRef, className: `relative inline-block ${disabled ? "opacity-50 pointer-events-none" : ""}`, children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
609
|
-
panelPosition &&
|
|
610
|
-
typeof document !== "undefined" &&
|
|
611
|
-
document.body &&
|
|
612
|
-
createPortal(_jsx("div", { ref: panelRef, className: "fixed z-[2001] w-fit rounded-md border border-[var(--color-border-default)] bg-[var(--color-bg-default)] shadow-[var(--shadow-lg)] p-4", style: {
|
|
613
|
-
top: `${panelPosition.top}px`,
|
|
614
|
-
left: `${panelPosition.left}px`,
|
|
615
|
-
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto list-none pl-0", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center justify-start text-left gap-2 text-sm rounded transition-colors ${urlValue === option.value
|
|
616
|
-
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
617
|
-
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
618
|
-
e.preventDefault();
|
|
619
|
-
handleStaticOptionSelect(option);
|
|
620
|
-
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsxs("div", { className: "flex items-center justify-start gap-2", children: [_jsx("div", { style: { width: finalInputWidth }, children: _jsx(Input, { ref: inputRef, type: filterType === "number" ? "number" : "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), placeholder: "Ingresa un valor", min: filterType === "number"
|
|
621
|
-
? props.min
|
|
622
|
-
: undefined, max: filterType === "number"
|
|
623
|
-
? props.max
|
|
624
|
-
: undefined, onKeyDown: (e) => {
|
|
625
|
-
if (e.key === "Enter") {
|
|
626
|
-
handleSetFilter();
|
|
627
|
-
}
|
|
628
|
-
} }) }), _jsx(Button, { onClick: handleSetFilter, icon: "fa-arrow-right", variant: "ghost" })] })] }) }), document.body)] }));
|
|
629
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React, { useCallback } from "react";
|
|
3
|
-
import { twMerge } from "tailwind-merge";
|
|
4
|
-
export const Menu = ({ options, onOptionSelected, getOptionLabel, renderOption, className, style, itemClassName, }) => {
|
|
5
|
-
const labelGetter = useCallback((item) => {
|
|
6
|
-
if (getOptionLabel)
|
|
7
|
-
return getOptionLabel(item);
|
|
8
|
-
const anyItem = item;
|
|
9
|
-
return (anyItem.label ?? "").toString();
|
|
10
|
-
}, [getOptionLabel]);
|
|
11
|
-
const handleOptionClick = (item) => {
|
|
12
|
-
onOptionSelected(item);
|
|
13
|
-
};
|
|
14
|
-
const mergedClassName = twMerge("bg-[var(--color-bg-default)] border border-[var(--color-border-default)] rounded-md shadow-[var(--shadow-sm)] py-1 min-w-[160px] font-[var(--font-default)] inline-block", className);
|
|
15
|
-
return (_jsx("div", { className: mergedClassName, style: style, children: options.map((option, index) => {
|
|
16
|
-
const key = String(option?.id ??
|
|
17
|
-
labelGetter(option) ??
|
|
18
|
-
index);
|
|
19
|
-
return (_jsx("div", { onClick: () => handleOptionClick(option), className: twMerge("px-4 py-2 text-sm text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)] cursor-pointer transition-colors flex items-center", itemClassName), children: renderOption ? renderOption(option) : labelGetter(option) }, key));
|
|
20
|
-
}) }));
|
|
21
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { useTabsContext } from "./TabsGroup";
|
|
4
|
-
export const TabPanel = ({ children, tabId }) => {
|
|
5
|
-
const { activeTab } = useTabsContext();
|
|
6
|
-
const isActive = activeTab.toString() === tabId.toString();
|
|
7
|
-
if (!isActive) {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
return (_jsx("div", { role: "tabpanel", className: "w-full font-[var(--font-default)]", children: children }));
|
|
11
|
-
};
|