flysoft-react-ui 0.4.0 → 0.5.2
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/dist/App.d.ts.map +1 -1
- package/dist/App.js +20 -4
- package/dist/components/form-controls/AutocompleteInput.d.ts +11 -3
- package/dist/components/form-controls/AutocompleteInput.d.ts.map +1 -1
- package/dist/components/form-controls/AutocompleteInput.js +410 -31
- package/dist/components/form-controls/Button.js +1 -1
- package/dist/components/form-controls/Checkbox.d.ts +14 -0
- package/dist/components/form-controls/Checkbox.d.ts.map +1 -0
- package/dist/components/form-controls/Checkbox.js +77 -0
- package/dist/components/form-controls/DateInput.d.ts +20 -4
- package/dist/components/form-controls/DateInput.d.ts.map +1 -1
- package/dist/components/form-controls/DateInput.js +425 -70
- package/dist/components/form-controls/DatePicker.d.ts +4 -3
- package/dist/components/form-controls/DatePicker.d.ts.map +1 -1
- package/dist/components/form-controls/DatePicker.js +26 -30
- package/dist/components/form-controls/Input.d.ts +10 -1
- package/dist/components/form-controls/Input.d.ts.map +1 -1
- package/dist/components/form-controls/Input.js +16 -10
- package/dist/components/form-controls/Pagination.d.ts +1 -0
- package/dist/components/form-controls/Pagination.d.ts.map +1 -1
- package/dist/components/form-controls/Pagination.js +3 -40
- package/dist/components/form-controls/RadioButtonGroup.d.ts +62 -0
- package/dist/components/form-controls/RadioButtonGroup.d.ts.map +1 -0
- package/dist/components/form-controls/RadioButtonGroup.js +220 -0
- package/dist/components/form-controls/SearchSelectInput-OLD.d.ts +68 -0
- package/dist/components/form-controls/SearchSelectInput-OLD.d.ts.map +1 -0
- package/dist/components/form-controls/SearchSelectInput-OLD.js +962 -0
- package/dist/components/form-controls/SearchSelectInput.d.ts +70 -0
- package/dist/components/form-controls/SearchSelectInput.d.ts.map +1 -0
- package/dist/components/form-controls/SearchSelectInput.js +335 -0
- package/dist/components/form-controls/index.d.ts +7 -1
- package/dist/components/form-controls/index.d.ts.map +1 -1
- package/dist/components/form-controls/index.js +3 -0
- package/dist/components/layout/AppLayout.d.ts +3 -2
- package/dist/components/layout/AppLayout.d.ts.map +1 -1
- package/dist/components/layout/AppLayout.js +104 -31
- package/dist/components/layout/Card.d.ts +4 -1
- package/dist/components/layout/Card.d.ts.map +1 -1
- package/dist/components/layout/Card.js +30 -1
- package/dist/components/layout/Collection.js +1 -1
- package/dist/components/layout/DataTable.d.ts +29 -0
- package/dist/components/layout/DataTable.d.ts.map +1 -0
- package/dist/components/layout/DataTable.js +165 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +1 -0
- package/dist/components/utils/Avatar.d.ts +49 -0
- package/dist/components/utils/Avatar.d.ts.map +1 -0
- package/dist/components/utils/Avatar.js +93 -0
- package/dist/components/utils/Badge.d.ts +3 -0
- package/dist/components/utils/Badge.d.ts.map +1 -1
- package/dist/components/utils/Badge.js +130 -26
- package/dist/components/utils/Dialog.d.ts.map +1 -1
- package/dist/components/utils/Dialog.js +5 -1
- package/dist/components/utils/DropdownMenu.d.ts +25 -0
- package/dist/components/utils/DropdownMenu.d.ts.map +1 -0
- package/dist/components/utils/DropdownMenu.js +145 -0
- package/dist/components/utils/Filter.d.ts +57 -0
- package/dist/components/utils/Filter.d.ts.map +1 -0
- package/dist/components/utils/Filter.js +580 -0
- package/dist/components/utils/FiltersDialog.d.ts +21 -0
- package/dist/components/utils/FiltersDialog.d.ts.map +1 -0
- package/dist/components/utils/FiltersDialog.js +104 -0
- package/dist/components/utils/Loader.js +1 -1
- package/dist/components/utils/RoadMap.d.ts +59 -0
- package/dist/components/utils/RoadMap.d.ts.map +1 -0
- package/dist/components/utils/RoadMap.js +138 -0
- package/dist/components/utils/Snackbar.d.ts +13 -0
- package/dist/components/utils/Snackbar.d.ts.map +1 -0
- package/dist/components/utils/Snackbar.js +121 -0
- package/dist/components/utils/SnackbarContainer.d.ts +7 -0
- package/dist/components/utils/SnackbarContainer.d.ts.map +1 -0
- package/dist/components/utils/SnackbarContainer.js +25 -0
- package/dist/components/utils/index.d.ts +12 -0
- package/dist/components/utils/index.d.ts.map +1 -1
- package/dist/components/utils/index.js +6 -0
- package/dist/contexts/AppLayoutContext.d.ts +40 -0
- package/dist/contexts/AppLayoutContext.d.ts.map +1 -0
- package/dist/contexts/AppLayoutContext.js +98 -0
- package/dist/contexts/ListCrudContext.d.ts +29 -0
- package/dist/contexts/ListCrudContext.d.ts.map +1 -0
- package/dist/contexts/ListCrudContext.js +209 -0
- package/dist/contexts/SnackbarContext.d.ts +26 -0
- package/dist/contexts/SnackbarContext.d.ts.map +1 -0
- package/dist/contexts/SnackbarContext.js +34 -0
- package/dist/contexts/index.d.ts +6 -0
- package/dist/contexts/index.d.ts.map +1 -1
- package/dist/contexts/index.js +6 -0
- package/dist/contexts/presets.js +6 -6
- package/dist/docs/AuthDocs.tsx/AuthDocsContent.js +3 -1
- package/dist/docs/AvatarDocs.d.ts +4 -0
- package/dist/docs/AvatarDocs.d.ts.map +1 -0
- package/dist/docs/AvatarDocs.js +7 -0
- package/dist/docs/BadgeDocs.d.ts.map +1 -1
- package/dist/docs/BadgeDocs.js +4 -2
- package/dist/docs/CardDocs.d.ts.map +1 -1
- package/dist/docs/CardDocs.js +7 -1
- package/dist/docs/CheckboxDocs.d.ts +4 -0
- package/dist/docs/CheckboxDocs.d.ts.map +1 -0
- package/dist/docs/CheckboxDocs.js +7 -0
- package/dist/docs/DataTableDocs.d.ts +4 -0
- package/dist/docs/DataTableDocs.d.ts.map +1 -0
- package/dist/docs/DataTableDocs.js +244 -0
- package/dist/docs/DateInputDocs.d.ts +1 -0
- package/dist/docs/DateInputDocs.d.ts.map +1 -1
- package/dist/docs/DateInputDocs.js +7 -9
- package/dist/docs/DatePickerDocs.d.ts +1 -0
- package/dist/docs/DatePickerDocs.d.ts.map +1 -1
- package/dist/docs/DatePickerDocs.js +6 -8
- package/dist/docs/DocAdmin.d.ts +4 -0
- package/dist/docs/DocAdmin.d.ts.map +1 -0
- package/dist/docs/DocAdmin.js +68 -0
- package/dist/docs/DocsMenu.d.ts.map +1 -1
- package/dist/docs/DocsMenu.js +1 -1
- package/dist/docs/DocsRouter.d.ts.map +1 -1
- package/dist/docs/DocsRouter.js +13 -1
- package/dist/docs/DropdownMenuDocs.d.ts +4 -0
- package/dist/docs/DropdownMenuDocs.d.ts.map +1 -0
- package/dist/docs/DropdownMenuDocs.js +66 -0
- package/dist/docs/ExampleFormDocs.d.ts +4 -0
- package/dist/docs/ExampleFormDocs.d.ts.map +1 -0
- package/dist/docs/ExampleFormDocs.js +148 -0
- package/dist/docs/FilterDocs.d.ts +4 -0
- package/dist/docs/FilterDocs.d.ts.map +1 -0
- package/dist/docs/FilterDocs.js +112 -0
- package/dist/docs/InputDocs.d.ts.map +1 -1
- package/dist/docs/InputDocs.js +11 -1
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts +11 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.d.ts.map +1 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocs.js +25 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts +2 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.d.ts.map +1 -0
- package/dist/docs/ListCrudDocs.tsx/ListCrudDocsContentPersonas.js +51 -0
- package/dist/docs/PaginationDocs.js +6 -6
- package/dist/docs/RadioButtonGroupDocs.d.ts +4 -0
- package/dist/docs/RadioButtonGroupDocs.d.ts.map +1 -0
- package/dist/docs/RadioButtonGroupDocs.js +46 -0
- package/dist/docs/RoadMapDocs.d.ts +4 -0
- package/dist/docs/RoadMapDocs.d.ts.map +1 -0
- package/dist/docs/RoadMapDocs.js +171 -0
- package/dist/docs/SearchSelectInputDocs.d.ts +4 -0
- package/dist/docs/SearchSelectInputDocs.d.ts.map +1 -0
- package/dist/docs/SearchSelectInputDocs.js +168 -0
- package/dist/docs/SnackbarDocs.d.ts +4 -0
- package/dist/docs/SnackbarDocs.d.ts.map +1 -0
- package/dist/docs/SnackbarDocs.js +50 -0
- package/dist/docs/TabsGroupDocs.d.ts.map +1 -1
- package/dist/docs/TabsGroupDocs.js +12 -1
- package/dist/docs/docMockServices/empresaService.d.ts +38 -0
- package/dist/docs/docMockServices/empresaService.d.ts.map +1 -0
- package/dist/docs/docMockServices/empresaService.js +116 -0
- package/dist/docs/docMockServices/index.d.ts +9 -0
- package/dist/docs/docMockServices/index.d.ts.map +1 -0
- package/dist/docs/docMockServices/index.js +8 -0
- package/dist/docs/docMockServices/initialData.d.ts +6 -0
- package/dist/docs/docMockServices/initialData.d.ts.map +1 -0
- package/dist/docs/docMockServices/initialData.js +132 -0
- package/dist/docs/docMockServices/interfaces.d.ts +26 -0
- package/dist/docs/docMockServices/interfaces.d.ts.map +1 -0
- package/dist/docs/docMockServices/interfaces.js +1 -0
- package/dist/docs/docMockServices/personaEmpresaService.d.ts +43 -0
- package/dist/docs/docMockServices/personaEmpresaService.d.ts.map +1 -0
- package/dist/docs/docMockServices/personaEmpresaService.js +113 -0
- package/dist/docs/docMockServices/personaService.d.ts +39 -0
- package/dist/docs/docMockServices/personaService.d.ts.map +1 -0
- package/dist/docs/docMockServices/personaService.js +180 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useAsyncRequest.d.ts +17 -0
- package/dist/hooks/useAsyncRequest.d.ts.map +1 -0
- package/dist/hooks/useAsyncRequest.js +70 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,580 @@
|
|
|
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 "../layout/DataField";
|
|
12
|
+
export const Filter = (props) => {
|
|
13
|
+
const { paramName, label, staticOptions, inputWidth, value: propValue, onChange, hideEmpty = false, } = props;
|
|
14
|
+
const filterType = props.filterType || "text";
|
|
15
|
+
// Calcular el ancho por defecto según el tipo de filtro
|
|
16
|
+
const defaultInputWidth = filterType === "date" || filterType === "autocomplete" ? "160px" : "200px";
|
|
17
|
+
const finalInputWidth = inputWidth || defaultInputWidth;
|
|
18
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
19
|
+
const urlValue = paramName
|
|
20
|
+
? searchParams.get(paramName) || undefined
|
|
21
|
+
: undefined;
|
|
22
|
+
// Usar propValue si está presente, sino usar urlValue
|
|
23
|
+
const currentValue = propValue !== undefined ? propValue : urlValue;
|
|
24
|
+
const [inputValue, setInputValue] = useState(currentValue || "");
|
|
25
|
+
const [searchValue, setSearchValue] = useState(currentValue || "");
|
|
26
|
+
const [dateValue, setDateValue] = useState(null);
|
|
27
|
+
const [autocompleteValue, setAutocompleteValue] = useState(currentValue || "");
|
|
28
|
+
const [searchSelectValue, setSearchSelectValue] = useState(currentValue || undefined);
|
|
29
|
+
const [searchSelectLabel, setSearchSelectLabel] = useState("");
|
|
30
|
+
const [isUserTyping, setIsUserTyping] = useState(false);
|
|
31
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
32
|
+
const [panelPosition, setPanelPosition] = useState(null);
|
|
33
|
+
const containerRef = useRef(null);
|
|
34
|
+
const panelRef = useRef(null);
|
|
35
|
+
const inputRef = useRef(null);
|
|
36
|
+
const searchInputRef = useRef(null);
|
|
37
|
+
const searchSelectInputRef = useRef(null);
|
|
38
|
+
const dateInputRef = useRef(null);
|
|
39
|
+
const autocompleteInputRef = useRef(null);
|
|
40
|
+
// Sincronizar el input con el valor actual (propValue o urlValue)
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (filterType !== "autocomplete" &&
|
|
43
|
+
filterType !== "search" &&
|
|
44
|
+
filterType !== "searchSelect") {
|
|
45
|
+
setInputValue(currentValue || "");
|
|
46
|
+
}
|
|
47
|
+
}, [currentValue, filterType]);
|
|
48
|
+
// Sincronizar el searchValue con el valor actual (propValue o urlValue)
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (filterType === "search") {
|
|
51
|
+
setSearchValue(currentValue || "");
|
|
52
|
+
}
|
|
53
|
+
}, [currentValue, filterType]);
|
|
54
|
+
// Sincronizar el searchSelectValue con el valor actual (propValue o urlValue)
|
|
55
|
+
// y buscar el label si no está disponible
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (filterType === "searchSelect" && currentValue) {
|
|
58
|
+
const searchSelectProps = props;
|
|
59
|
+
const getOptionLabel = searchSelectProps.getOptionLabel || ((item) => item.label || "");
|
|
60
|
+
const getOptionValue = searchSelectProps.getOptionValue || ((item) => item.value || "");
|
|
61
|
+
const onSingleSearchPromiseFn = searchSelectProps.onSingleSearchPromiseFn;
|
|
62
|
+
// Si searchSelectValue es un objeto, extraer el label directamente
|
|
63
|
+
if (searchSelectValue && typeof searchSelectValue === "object") {
|
|
64
|
+
const label = getOptionLabel(searchSelectValue);
|
|
65
|
+
const value = String(getOptionValue(searchSelectValue));
|
|
66
|
+
if (value === String(currentValue)) {
|
|
67
|
+
setSearchSelectLabel(label);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Si no tenemos el objeto completo, usar onSingleSearchPromiseFn para obtenerlo
|
|
72
|
+
if (onSingleSearchPromiseFn) {
|
|
73
|
+
onSingleSearchPromiseFn(currentValue)
|
|
74
|
+
.then((option) => {
|
|
75
|
+
if (option) {
|
|
76
|
+
setSearchSelectValue(option);
|
|
77
|
+
setSearchSelectLabel(getOptionLabel(option));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
setSearchSelectLabel(String(currentValue));
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
.catch(() => {
|
|
84
|
+
setSearchSelectLabel(String(currentValue));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
setSearchSelectLabel(String(currentValue));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (filterType === "searchSelect" && !currentValue) {
|
|
92
|
+
setSearchSelectValue(undefined);
|
|
93
|
+
setSearchSelectLabel("");
|
|
94
|
+
}
|
|
95
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
96
|
+
}, [currentValue, filterType]);
|
|
97
|
+
// Sincronizar el dateValue con el valor actual (propValue o urlValue)
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (filterType === "date") {
|
|
100
|
+
if (currentValue) {
|
|
101
|
+
const date = dayjs(currentValue, "YYYY-MM-DD");
|
|
102
|
+
setDateValue(date.isValid() ? date : null);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
setDateValue(null);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, [currentValue, filterType]);
|
|
109
|
+
// Sincronizar el autocompleteValue con el valor actual (propValue o urlValue)
|
|
110
|
+
// Para autocomplete, mantener el value (no el label) para que AutocompleteInput pueda encontrar la opción
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (filterType === "autocomplete") {
|
|
113
|
+
// Mantener el value, el AutocompleteInput se encargará de mostrar el label
|
|
114
|
+
setAutocompleteValue(currentValue || "");
|
|
115
|
+
setIsUserTyping(false);
|
|
116
|
+
}
|
|
117
|
+
}, [currentValue, filterType]);
|
|
118
|
+
// Cerrar el panel al hacer clic fuera
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (!isOpen)
|
|
121
|
+
return;
|
|
122
|
+
const handleClickOutside = (event) => {
|
|
123
|
+
const target = event.target;
|
|
124
|
+
const isClickInsideContainer = containerRef.current?.contains(target);
|
|
125
|
+
const isClickInsidePanel = panelRef.current?.contains(target);
|
|
126
|
+
// Verificar si el click está dentro de un elemento con portal (DatePicker, AutocompleteInput, etc.)
|
|
127
|
+
// Estos elementos tienen z-[2001] y están posicionados fixed
|
|
128
|
+
let isClickInsidePortal = false;
|
|
129
|
+
if (target instanceof Element) {
|
|
130
|
+
let element = target;
|
|
131
|
+
// Subir por el árbol DOM buscando elementos con z-index alto que sean portales
|
|
132
|
+
while (element && element !== document.body) {
|
|
133
|
+
const computedStyle = window.getComputedStyle(element);
|
|
134
|
+
const zIndex = computedStyle.zIndex;
|
|
135
|
+
const position = computedStyle.position;
|
|
136
|
+
// Si encontramos un elemento fixed con z-index alto, probablemente es un portal
|
|
137
|
+
if (position === "fixed" &&
|
|
138
|
+
(zIndex === "2001" || parseInt(zIndex) >= 2001)) {
|
|
139
|
+
isClickInsidePortal = true;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
element = element.parentElement;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!isClickInsideContainer &&
|
|
146
|
+
!isClickInsidePanel &&
|
|
147
|
+
!isClickInsidePortal) {
|
|
148
|
+
setIsOpen(false);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
// Pequeño delay para asegurar que el portal esté montado
|
|
152
|
+
const timer = setTimeout(() => {
|
|
153
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
154
|
+
}, 0);
|
|
155
|
+
return () => {
|
|
156
|
+
clearTimeout(timer);
|
|
157
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
158
|
+
};
|
|
159
|
+
}, [isOpen]);
|
|
160
|
+
const handleSetFilter = () => {
|
|
161
|
+
const newValue = inputValue.trim() || undefined;
|
|
162
|
+
// Si hay onChange, llamarlo con el nuevo valor
|
|
163
|
+
if (onChange) {
|
|
164
|
+
onChange(newValue);
|
|
165
|
+
}
|
|
166
|
+
// Si hay paramName, actualizar el query param
|
|
167
|
+
if (paramName) {
|
|
168
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
169
|
+
if (newValue) {
|
|
170
|
+
newSearchParams.set(paramName, newValue);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
newSearchParams.delete(paramName);
|
|
174
|
+
}
|
|
175
|
+
// Usar replace: true para reemplazar la URL sin agregar una nueva entrada al historial
|
|
176
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
177
|
+
}
|
|
178
|
+
setIsOpen(false);
|
|
179
|
+
};
|
|
180
|
+
const handleSearchChange = (e) => {
|
|
181
|
+
setSearchValue(e.target.value);
|
|
182
|
+
};
|
|
183
|
+
const handleSearchKeyDown = (e) => {
|
|
184
|
+
if (e.key === "Enter") {
|
|
185
|
+
handleSearchSubmit();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const handleSearchSubmit = () => {
|
|
189
|
+
const newValue = searchValue.trim() || undefined;
|
|
190
|
+
// Si hay onChange, llamarlo con el nuevo valor
|
|
191
|
+
if (onChange) {
|
|
192
|
+
onChange(newValue);
|
|
193
|
+
}
|
|
194
|
+
// Si hay paramName, actualizar el query param
|
|
195
|
+
if (paramName) {
|
|
196
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
197
|
+
if (newValue) {
|
|
198
|
+
newSearchParams.set(paramName, newValue);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
newSearchParams.delete(paramName);
|
|
202
|
+
}
|
|
203
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
const handleSearchIconClick = () => {
|
|
207
|
+
// Verificar si el texto actual coincide con el valor actual
|
|
208
|
+
const valueMatches = currentValue && searchValue.trim() === currentValue;
|
|
209
|
+
if (valueMatches) {
|
|
210
|
+
// Si coincide, limpiar
|
|
211
|
+
const newValue = undefined;
|
|
212
|
+
// Si hay onChange, llamarlo con undefined
|
|
213
|
+
if (onChange) {
|
|
214
|
+
onChange(newValue);
|
|
215
|
+
}
|
|
216
|
+
// Si hay paramName, actualizar el query param
|
|
217
|
+
if (paramName) {
|
|
218
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
219
|
+
newSearchParams.delete(paramName);
|
|
220
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
221
|
+
}
|
|
222
|
+
setSearchValue("");
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// Si no coincide, hacer submit
|
|
226
|
+
handleSearchSubmit();
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const handleAutocompleteChange = () => {
|
|
230
|
+
// Marcar que el usuario está escribiendo para que el AutocompleteInput pueda manejar el texto libremente
|
|
231
|
+
setIsUserTyping(true);
|
|
232
|
+
};
|
|
233
|
+
const handleAutocompleteSelect = () => {
|
|
234
|
+
// Obtener el valor actual del input del AutocompleteInput
|
|
235
|
+
const currentInputValue = autocompleteInputRef.current?.value || "";
|
|
236
|
+
// Buscar si el texto actual coincide con alguna opción
|
|
237
|
+
if (filterType === "autocomplete") {
|
|
238
|
+
const autocompleteProps = props;
|
|
239
|
+
const getOptionLabel = autocompleteProps.getOptionLabel || ((item) => item.label || "");
|
|
240
|
+
const getOptionValue = autocompleteProps.getOptionValue || ((item) => item.value || "");
|
|
241
|
+
// Buscar opción por label
|
|
242
|
+
const matchingOption = autocompleteProps.options.find((opt) => getOptionLabel(opt).toLowerCase() === currentInputValue.toLowerCase());
|
|
243
|
+
let newValue;
|
|
244
|
+
if (matchingOption) {
|
|
245
|
+
newValue = String(getOptionValue(matchingOption));
|
|
246
|
+
setAutocompleteValue(newValue);
|
|
247
|
+
setIsUserTyping(false);
|
|
248
|
+
}
|
|
249
|
+
else if (currentInputValue.trim()) {
|
|
250
|
+
// Si no coincide con ninguna opción, guardar el texto tal cual
|
|
251
|
+
newValue = currentInputValue.trim();
|
|
252
|
+
setAutocompleteValue(newValue);
|
|
253
|
+
setIsUserTyping(false);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
newValue = undefined;
|
|
257
|
+
setAutocompleteValue("");
|
|
258
|
+
setIsUserTyping(false);
|
|
259
|
+
}
|
|
260
|
+
// Si hay onChange, llamarlo con el nuevo valor
|
|
261
|
+
if (onChange) {
|
|
262
|
+
onChange(newValue);
|
|
263
|
+
}
|
|
264
|
+
// Si hay paramName, actualizar el query param
|
|
265
|
+
if (paramName) {
|
|
266
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
267
|
+
if (newValue) {
|
|
268
|
+
newSearchParams.set(paramName, newValue);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
newSearchParams.delete(paramName);
|
|
272
|
+
}
|
|
273
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
274
|
+
}
|
|
275
|
+
setIsOpen(false);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const handleAutocompleteOptionSelect = (option) => {
|
|
279
|
+
if (filterType === "autocomplete") {
|
|
280
|
+
const autocompleteProps = props;
|
|
281
|
+
const getOptionValue = autocompleteProps.getOptionValue || ((item) => item.value || "");
|
|
282
|
+
const newValue = String(getOptionValue(option));
|
|
283
|
+
setAutocompleteValue(newValue);
|
|
284
|
+
setIsUserTyping(false);
|
|
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
|
+
newSearchParams.set(paramName, newValue);
|
|
293
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
294
|
+
}
|
|
295
|
+
setIsOpen(false);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const handleSearchSelectChange = (value) => {
|
|
299
|
+
if (filterType === "searchSelect") {
|
|
300
|
+
const searchSelectProps = props;
|
|
301
|
+
const getOptionValue = searchSelectProps.getOptionValue || ((item) => item.value || "");
|
|
302
|
+
const getOptionLabel = searchSelectProps.getOptionLabel || ((item) => item.label || "");
|
|
303
|
+
// Si value es un objeto, extraer el valor usando getOptionValue
|
|
304
|
+
// Si value es un string/number, usarlo directamente
|
|
305
|
+
let newValue;
|
|
306
|
+
if (value === undefined || value === null) {
|
|
307
|
+
newValue = undefined;
|
|
308
|
+
setSearchSelectValue(undefined);
|
|
309
|
+
setSearchSelectLabel("");
|
|
310
|
+
}
|
|
311
|
+
else if (typeof value === "object") {
|
|
312
|
+
newValue = String(getOptionValue(value));
|
|
313
|
+
setSearchSelectValue(value);
|
|
314
|
+
setSearchSelectLabel(getOptionLabel(value));
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
newValue = String(value);
|
|
318
|
+
setSearchSelectValue(value);
|
|
319
|
+
// Si solo tenemos el valor, el useEffect se encargará de buscar el label
|
|
320
|
+
setSearchSelectLabel("");
|
|
321
|
+
}
|
|
322
|
+
// Si hay onChange, llamarlo con el nuevo valor
|
|
323
|
+
if (onChange) {
|
|
324
|
+
onChange(newValue);
|
|
325
|
+
}
|
|
326
|
+
// Si hay paramName, actualizar el query param
|
|
327
|
+
if (paramName) {
|
|
328
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
329
|
+
if (newValue) {
|
|
330
|
+
newSearchParams.set(paramName, newValue);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
newSearchParams.delete(paramName);
|
|
334
|
+
}
|
|
335
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
336
|
+
}
|
|
337
|
+
setIsOpen(false);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const handleDateChange = (date) => {
|
|
341
|
+
// Solo actualizar el estado temporal, no setear en la URL
|
|
342
|
+
setDateValue(date);
|
|
343
|
+
};
|
|
344
|
+
const handleSetDateFilter = () => {
|
|
345
|
+
let newValue;
|
|
346
|
+
if (dateValue && dateValue.isValid()) {
|
|
347
|
+
// Guardar como yyyy-mm-dd
|
|
348
|
+
newValue = dateValue.format("YYYY-MM-DD");
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
newValue = undefined;
|
|
352
|
+
}
|
|
353
|
+
// Si hay onChange, llamarlo con el nuevo valor
|
|
354
|
+
if (onChange) {
|
|
355
|
+
onChange(newValue);
|
|
356
|
+
}
|
|
357
|
+
// Si hay paramName, actualizar el query param
|
|
358
|
+
if (paramName) {
|
|
359
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
360
|
+
if (newValue) {
|
|
361
|
+
newSearchParams.set(paramName, newValue);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
newSearchParams.delete(paramName);
|
|
365
|
+
}
|
|
366
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
367
|
+
}
|
|
368
|
+
setIsOpen(false);
|
|
369
|
+
};
|
|
370
|
+
const handleStaticOptionSelect = (option) => {
|
|
371
|
+
const newValue = option.value;
|
|
372
|
+
// Si hay onChange, llamarlo con el nuevo valor
|
|
373
|
+
if (onChange) {
|
|
374
|
+
onChange(newValue);
|
|
375
|
+
}
|
|
376
|
+
// Si hay paramName, actualizar el query param
|
|
377
|
+
if (paramName) {
|
|
378
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
379
|
+
newSearchParams.set(paramName, newValue);
|
|
380
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
381
|
+
}
|
|
382
|
+
setIsOpen(false);
|
|
383
|
+
};
|
|
384
|
+
// Para staticOptions: mostrar el texto de la opción si el valor coincide (prioridad)
|
|
385
|
+
// Para date: convertir yyyy-mm-dd a Dayjs y formatear para mostrar como dd/mm/yyyy
|
|
386
|
+
// Para autocomplete: mostrar el label de la opción si el valor coincide
|
|
387
|
+
const getDisplayValue = () => {
|
|
388
|
+
// Primero verificar si el valor coincide con alguna opción estática
|
|
389
|
+
if (staticOptions && currentValue) {
|
|
390
|
+
const option = staticOptions.find((opt) => opt.value === currentValue);
|
|
391
|
+
if (option) {
|
|
392
|
+
return option.text;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// Para autocomplete, buscar el label de la opción
|
|
396
|
+
if (filterType === "autocomplete" && currentValue) {
|
|
397
|
+
const autocompleteProps = props;
|
|
398
|
+
if (autocompleteProps.options) {
|
|
399
|
+
const getOptionLabel = autocompleteProps.getOptionLabel || ((item) => item.label || "");
|
|
400
|
+
const getOptionValue = autocompleteProps.getOptionValue || ((item) => item.value || "");
|
|
401
|
+
const option = autocompleteProps.options.find((opt) => String(getOptionValue(opt)) === String(currentValue));
|
|
402
|
+
if (option) {
|
|
403
|
+
return getOptionLabel(option);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Para searchSelect, mostrar el label guardado o buscar el label del objeto
|
|
408
|
+
if (filterType === "searchSelect" && currentValue) {
|
|
409
|
+
if (searchSelectLabel) {
|
|
410
|
+
return searchSelectLabel;
|
|
411
|
+
}
|
|
412
|
+
// Si tenemos el objeto completo, extraer el label
|
|
413
|
+
if (searchSelectValue && typeof searchSelectValue === "object") {
|
|
414
|
+
const searchSelectProps = props;
|
|
415
|
+
const getOptionLabel = searchSelectProps.getOptionLabel || ((item) => item.label || "");
|
|
416
|
+
return getOptionLabel(searchSelectValue);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// Si no hay opción estática que coincida, formatear según el tipo
|
|
420
|
+
if (filterType === "date" && currentValue) {
|
|
421
|
+
const date = dayjs(currentValue, "YYYY-MM-DD");
|
|
422
|
+
if (date.isValid()) {
|
|
423
|
+
return date.format("DD/MM/YYYY");
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return currentValue || "";
|
|
427
|
+
};
|
|
428
|
+
const handleClearFilter = (e) => {
|
|
429
|
+
e.stopPropagation();
|
|
430
|
+
// Si hay onChange, llamarlo con undefined para limpiar
|
|
431
|
+
if (onChange) {
|
|
432
|
+
onChange(undefined);
|
|
433
|
+
}
|
|
434
|
+
// Si hay paramName, actualizar el query param
|
|
435
|
+
if (paramName) {
|
|
436
|
+
const newSearchParams = new URLSearchParams(searchParams);
|
|
437
|
+
newSearchParams.delete(paramName);
|
|
438
|
+
setSearchParams(newSearchParams, { replace: true });
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
const handleTogglePanel = () => {
|
|
442
|
+
if (!isOpen) {
|
|
443
|
+
// Calcular posición antes de abrir
|
|
444
|
+
if (containerRef.current) {
|
|
445
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
446
|
+
setPanelPosition({
|
|
447
|
+
top: rect.bottom + window.scrollY + 4,
|
|
448
|
+
left: rect.left + window.scrollX,
|
|
449
|
+
width: rect.width,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
setIsOpen(!isOpen);
|
|
454
|
+
};
|
|
455
|
+
// Actualizar posición cuando se abre o cuando cambia el scroll
|
|
456
|
+
useEffect(() => {
|
|
457
|
+
if (isOpen && containerRef.current) {
|
|
458
|
+
const updatePosition = () => {
|
|
459
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
460
|
+
if (rect) {
|
|
461
|
+
setPanelPosition({
|
|
462
|
+
top: rect.bottom + window.scrollY + 4,
|
|
463
|
+
left: rect.left + window.scrollX,
|
|
464
|
+
width: rect.width,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
updatePosition();
|
|
469
|
+
window.addEventListener("scroll", updatePosition, true);
|
|
470
|
+
window.addEventListener("resize", updatePosition);
|
|
471
|
+
return () => {
|
|
472
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
473
|
+
window.removeEventListener("resize", updatePosition);
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}, [isOpen]);
|
|
477
|
+
// Hacer foco en el input cuando se abre el panel
|
|
478
|
+
useEffect(() => {
|
|
479
|
+
if (isOpen) {
|
|
480
|
+
// Pequeño delay para asegurar que el DOM esté actualizado
|
|
481
|
+
const timer = setTimeout(() => {
|
|
482
|
+
if (filterType === "text" || filterType === "number") {
|
|
483
|
+
inputRef.current?.focus();
|
|
484
|
+
}
|
|
485
|
+
else if (filterType === "date") {
|
|
486
|
+
dateInputRef.current?.focus();
|
|
487
|
+
}
|
|
488
|
+
else if (filterType === "autocomplete") {
|
|
489
|
+
autocompleteInputRef.current?.focus();
|
|
490
|
+
}
|
|
491
|
+
// searchSelect no necesita focus porque usa un Dialog interno
|
|
492
|
+
}, 50);
|
|
493
|
+
return () => clearTimeout(timer);
|
|
494
|
+
}
|
|
495
|
+
}, [isOpen, filterType]);
|
|
496
|
+
// Si hideEmpty es true y no hay valor, no renderizar el componente
|
|
497
|
+
if (hideEmpty && !currentValue) {
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
// Contenedor tipo badge con diseño similar al Input
|
|
501
|
+
// Altura ajustada para coincidir con input sm: py-1.5 (6px arriba y abajo) + text-sm (14px línea) = ~26px total
|
|
502
|
+
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: `fa 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", "aria-label": "Borrar filtro", type: "button", children: _jsx("i", { className: "fa fa-times text-xs text-[var(--color-text-muted)] hover:text-[var(--color-primary)] transition-colors" }) }))] })] }));
|
|
503
|
+
// Renderizar según el tipo de filtro
|
|
504
|
+
if (filterType === "autocomplete") {
|
|
505
|
+
return (_jsxs("div", { ref: containerRef, className: "relative inline-block", children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
506
|
+
panelPosition &&
|
|
507
|
+
typeof document !== "undefined" &&
|
|
508
|
+
document.body &&
|
|
509
|
+
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: {
|
|
510
|
+
top: `${panelPosition.top}px`,
|
|
511
|
+
left: `${panelPosition.left}px`,
|
|
512
|
+
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center gap-2 text-sm rounded transition-colors ${currentValue === option.value
|
|
513
|
+
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
514
|
+
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
515
|
+
e.preventDefault();
|
|
516
|
+
handleStaticOptionSelect(option);
|
|
517
|
+
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsxs("div", { className: "flex items-center 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, onSelectOption: handleAutocompleteOptionSelect }) }), _jsx(Button, { onClick: handleAutocompleteSelect, icon: "fa-arrow-right", variant: "ghost" })] })] }) }), document.body)] }));
|
|
518
|
+
}
|
|
519
|
+
if (filterType === "date") {
|
|
520
|
+
return (_jsxs("div", { ref: containerRef, className: "relative inline-block", children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
521
|
+
panelPosition &&
|
|
522
|
+
typeof document !== "undefined" &&
|
|
523
|
+
document.body &&
|
|
524
|
+
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: {
|
|
525
|
+
top: `${panelPosition.top}px`,
|
|
526
|
+
left: `${panelPosition.left}px`,
|
|
527
|
+
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center gap-2 text-sm rounded transition-colors ${currentValue === option.value
|
|
528
|
+
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
529
|
+
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
530
|
+
e.preventDefault();
|
|
531
|
+
handleStaticOptionSelect(option);
|
|
532
|
+
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsxs("div", { className: "flex items-center 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)] }));
|
|
533
|
+
}
|
|
534
|
+
// Para searchSelect
|
|
535
|
+
if (filterType === "searchSelect") {
|
|
536
|
+
const searchSelectProps = props;
|
|
537
|
+
return (_jsxs("div", { ref: containerRef, className: "relative inline-block", children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
538
|
+
panelPosition &&
|
|
539
|
+
typeof document !== "undefined" &&
|
|
540
|
+
document.body &&
|
|
541
|
+
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: {
|
|
542
|
+
top: `${panelPosition.top}px`,
|
|
543
|
+
left: `${panelPosition.left}px`,
|
|
544
|
+
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center gap-2 text-sm rounded transition-colors ${currentValue === option.value
|
|
545
|
+
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
546
|
+
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
547
|
+
e.preventDefault();
|
|
548
|
+
handleStaticOptionSelect(option);
|
|
549
|
+
}, 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)] }));
|
|
550
|
+
}
|
|
551
|
+
// Para search
|
|
552
|
+
if (filterType === "search") {
|
|
553
|
+
// Mostrar X solo si hay un valor actual Y el texto del input coincide con ese valor
|
|
554
|
+
const hasValue = !!currentValue;
|
|
555
|
+
const valueMatches = hasValue && searchValue.trim() === currentValue;
|
|
556
|
+
return (_jsx("div", { ref: containerRef, className: "relative inline-block", 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" }) }), className: "inline-block" }) }));
|
|
557
|
+
}
|
|
558
|
+
// Para text y number
|
|
559
|
+
return (_jsxs("div", { ref: containerRef, className: "relative inline-block", children: [_jsx(DataField, { label: label, value: badgeContainer, className: "inline-block" }), isOpen &&
|
|
560
|
+
panelPosition &&
|
|
561
|
+
typeof document !== "undefined" &&
|
|
562
|
+
document.body &&
|
|
563
|
+
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: {
|
|
564
|
+
top: `${panelPosition.top}px`,
|
|
565
|
+
left: `${panelPosition.left}px`,
|
|
566
|
+
}, children: _jsxs("div", { className: "space-y-3", children: [staticOptions && staticOptions.length > 0 && (_jsx("ul", { className: "py-1 max-h-60 overflow-auto", children: staticOptions.map((option) => (_jsx("li", { className: `px-3 py-2 cursor-pointer flex items-center gap-2 text-sm rounded transition-colors ${urlValue === option.value
|
|
567
|
+
? "bg-[var(--color-primary-soft)] text-[var(--color-primary)]"
|
|
568
|
+
: "text-[var(--color-text-primary)] hover:bg-[var(--color-bg-secondary)]"}`, onMouseDown: (e) => {
|
|
569
|
+
e.preventDefault();
|
|
570
|
+
handleStaticOptionSelect(option);
|
|
571
|
+
}, children: _jsx("span", { className: "font-[var(--font-default)]", children: option.text }) }, option.value))) })), _jsxs("div", { className: "flex items-center 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"
|
|
572
|
+
? props.min
|
|
573
|
+
: undefined, max: filterType === "number"
|
|
574
|
+
? props.max
|
|
575
|
+
: undefined, onKeyDown: (e) => {
|
|
576
|
+
if (e.key === "Enter") {
|
|
577
|
+
handleSetFilter();
|
|
578
|
+
}
|
|
579
|
+
} }) }), _jsx(Button, { onClick: handleSetFilter, icon: "fa-arrow-right", variant: "ghost" })] })] }) }), document.body)] }));
|
|
580
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type FilterProps } from "./Filter";
|
|
3
|
+
export interface FilterConfig {
|
|
4
|
+
filterType: FilterProps["filterType"];
|
|
5
|
+
paramName: string;
|
|
6
|
+
label?: string;
|
|
7
|
+
staticOptions?: FilterProps["staticOptions"];
|
|
8
|
+
inputWidth?: string;
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
options?: any[];
|
|
12
|
+
getOptionLabel?: (item: any) => string;
|
|
13
|
+
getOptionValue?: (item: any) => any;
|
|
14
|
+
renderOption?: (item: any) => React.ReactNode;
|
|
15
|
+
noResultsText?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface FiltersDialogProps {
|
|
18
|
+
filters: FilterConfig[];
|
|
19
|
+
}
|
|
20
|
+
export declare const FiltersDialog: React.FC<FiltersDialogProps>;
|
|
21
|
+
//# sourceMappingURL=FiltersDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FiltersDialog.d.ts","sourceRoot":"","sources":["../../../src/components/utils/FiltersDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAGpD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,WAAW,CAAC,eAAe,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;IACvC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAG,CAAC;IACpC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAgJtD,CAAC"}
|