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
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import dayjs, {} from "dayjs";
|
|
5
|
+
import { useFormContext } from "react-hook-form";
|
|
3
6
|
import { Input } from "./Input";
|
|
4
7
|
import { DatePicker } from "./DatePicker";
|
|
5
8
|
const pad = (value) => value.toString().padStart(2, "0");
|
|
9
|
+
const isDayjs = (value) => {
|
|
10
|
+
return (value !== null &&
|
|
11
|
+
value !== undefined &&
|
|
12
|
+
typeof value === "object" &&
|
|
13
|
+
"isValid" in value &&
|
|
14
|
+
typeof value.isValid === "function");
|
|
15
|
+
};
|
|
16
|
+
const normalizeToDayjs = (value) => {
|
|
17
|
+
if (value === null || value === undefined)
|
|
18
|
+
return null;
|
|
19
|
+
if (isDayjs(value))
|
|
20
|
+
return value;
|
|
21
|
+
// Si no es Dayjs, intentar convertirlo
|
|
22
|
+
if (typeof value === "string" ||
|
|
23
|
+
typeof value === "number" ||
|
|
24
|
+
value instanceof Date) {
|
|
25
|
+
const d = dayjs(value);
|
|
26
|
+
return d.isValid() ? d : null;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
};
|
|
6
30
|
const formatDateToString = (date, format) => {
|
|
7
|
-
|
|
31
|
+
const normalized = normalizeToDayjs(date);
|
|
32
|
+
if (!normalized || !normalized.isValid())
|
|
8
33
|
return "";
|
|
9
|
-
const day = pad(date
|
|
10
|
-
const month = pad(
|
|
11
|
-
const year =
|
|
34
|
+
const day = pad(normalized.date());
|
|
35
|
+
const month = pad(normalized.month() + 1);
|
|
36
|
+
const year = normalized.year().toString();
|
|
12
37
|
if (format === "mm/dd/yyyy") {
|
|
13
38
|
return `${month}/${day}/${year}`;
|
|
14
39
|
}
|
|
@@ -33,11 +58,15 @@ const parseDateFromString = (value, format) => {
|
|
|
33
58
|
month <= 12 &&
|
|
34
59
|
year >= 1000 &&
|
|
35
60
|
year <= 9999) {
|
|
36
|
-
const date =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
date
|
|
40
|
-
|
|
61
|
+
const date = dayjs()
|
|
62
|
+
.year(year)
|
|
63
|
+
.month(month - 1)
|
|
64
|
+
.date(day);
|
|
65
|
+
if (date.isValid() &&
|
|
66
|
+
date.year() === year &&
|
|
67
|
+
date.month() === month - 1 &&
|
|
68
|
+
date.date() === day) {
|
|
69
|
+
return date.startOf("day");
|
|
41
70
|
}
|
|
42
71
|
}
|
|
43
72
|
}
|
|
@@ -57,100 +86,426 @@ const parseDateFromString = (value, format) => {
|
|
|
57
86
|
month > 12) {
|
|
58
87
|
return null;
|
|
59
88
|
}
|
|
60
|
-
const date =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
date
|
|
89
|
+
const date = dayjs()
|
|
90
|
+
.year(year)
|
|
91
|
+
.month(month - 1)
|
|
92
|
+
.date(day);
|
|
93
|
+
if (!date.isValid() ||
|
|
94
|
+
date.year() !== year ||
|
|
95
|
+
date.month() !== month - 1 ||
|
|
96
|
+
date.date() !== day) {
|
|
64
97
|
return null;
|
|
65
98
|
}
|
|
66
|
-
return date;
|
|
99
|
+
return date.startOf("day");
|
|
67
100
|
};
|
|
68
|
-
export const DateInput = ({ value, onChange, format = "dd/mm/yyyy", datePickerProps, icon = "fa-calendar-alt", iconPosition = "right", className = "", ...inputProps }) => {
|
|
69
|
-
|
|
70
|
-
const
|
|
101
|
+
export const DateInput = React.forwardRef(({ value, onChange, format = "dd/mm/yyyy", datePickerProps, icon = "fa-calendar-alt", iconPosition = "right", className = "", readOnly = false, ...inputProps }, ref) => {
|
|
102
|
+
// Extraer onBlur de inputProps para manejarlo por separado
|
|
103
|
+
const { onBlur: registerOnBlur, ...restInputProps } = inputProps;
|
|
104
|
+
// Detectar si estamos en modo register: si viene 'name' de register, estamos en modo register
|
|
105
|
+
// register siempre pasa 'name', 'onChange', 'onBlur', y 'ref'
|
|
106
|
+
const isRegisterMode = React.useMemo(() => {
|
|
107
|
+
// Si viene 'name' en inputProps, es porque viene de register
|
|
108
|
+
return "name" in inputProps && inputProps.name !== undefined;
|
|
109
|
+
}, [inputProps]);
|
|
110
|
+
const fieldName = isRegisterMode && "name" in restInputProps
|
|
111
|
+
? restInputProps.name
|
|
112
|
+
: undefined;
|
|
113
|
+
// Obtener setValue del contexto del formulario
|
|
114
|
+
// Para usar objetos Dayjs con register, el formulario debe estar dentro de FormProvider
|
|
115
|
+
// useFormContext debe llamarse incondicionalmente (requisito de React Hooks)
|
|
116
|
+
// Si no hay FormProvider y se usa en modo register, useFormContext lanzará un error
|
|
117
|
+
// Para usar sin FormProvider, usar Controller en lugar de register
|
|
118
|
+
const formContext = useFormContext();
|
|
119
|
+
const setValue = formContext?.setValue;
|
|
120
|
+
const [internalDate, setInternalDate] = React.useState(null);
|
|
121
|
+
const [displayValue, setDisplayValue] = React.useState("");
|
|
71
122
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
123
|
+
const [pickerPosition, setPickerPosition] = React.useState(null);
|
|
72
124
|
const containerRef = React.useRef(null);
|
|
73
|
-
const
|
|
74
|
-
const
|
|
125
|
+
const pickerRef = React.useRef(null);
|
|
126
|
+
const inputRef = React.useRef(null);
|
|
127
|
+
const isTypingRef = React.useRef(false);
|
|
128
|
+
// Función helper para sincronizar displayValue con el valor del formulario en modo register
|
|
129
|
+
const syncDisplayValue = React.useCallback(() => {
|
|
130
|
+
if (isRegisterMode && inputRef.current) {
|
|
131
|
+
const formValue = inputRef.current.value;
|
|
132
|
+
if (formValue) {
|
|
133
|
+
// Parsear el string de fecha del formulario
|
|
134
|
+
const parsed = parseDateFromString(formValue, format);
|
|
135
|
+
if (parsed) {
|
|
136
|
+
setDisplayValue(formatDateToString(parsed, format));
|
|
137
|
+
setInternalDate(parsed);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Si hay un valor pero no se puede parsear, mostrarlo tal cual
|
|
142
|
+
setDisplayValue(formValue);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
setDisplayValue("");
|
|
148
|
+
setInternalDate(null);
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}, [isRegisterMode, format]);
|
|
154
|
+
// Sincronizar displayValue con el valor del formulario en modo register
|
|
75
155
|
React.useEffect(() => {
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
156
|
+
if (isRegisterMode) {
|
|
157
|
+
let attempts = 0;
|
|
158
|
+
const maxAttempts = 50; // Intentar durante ~5 segundos (50 * 100ms)
|
|
159
|
+
const trySync = () => {
|
|
160
|
+
if (inputRef.current) {
|
|
161
|
+
const formValue = inputRef.current.value;
|
|
162
|
+
if (formValue) {
|
|
163
|
+
const parsed = parseDateFromString(formValue, format);
|
|
164
|
+
if (parsed) {
|
|
165
|
+
setDisplayValue(formatDateToString(parsed, format));
|
|
166
|
+
setInternalDate(parsed);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
setDisplayValue(formValue);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
setDisplayValue("");
|
|
176
|
+
setInternalDate(null);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
};
|
|
181
|
+
// Intentar inmediatamente
|
|
182
|
+
if (trySync()) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Si no encontramos el valor, usar un intervalo
|
|
186
|
+
const intervalId = window.setInterval(() => {
|
|
187
|
+
attempts++;
|
|
188
|
+
if (trySync() || attempts >= maxAttempts) {
|
|
189
|
+
clearInterval(intervalId);
|
|
190
|
+
}
|
|
191
|
+
}, 100);
|
|
192
|
+
// También usar timeouts como fallback
|
|
193
|
+
const timeouts = [];
|
|
194
|
+
[0, 50, 100, 200, 500, 1000].forEach((delay) => {
|
|
195
|
+
const timeoutId = window.setTimeout(() => {
|
|
196
|
+
trySync();
|
|
197
|
+
}, delay);
|
|
198
|
+
timeouts.push(timeoutId);
|
|
199
|
+
});
|
|
200
|
+
return () => {
|
|
201
|
+
clearInterval(intervalId);
|
|
202
|
+
timeouts.forEach(clearTimeout);
|
|
203
|
+
};
|
|
79
204
|
}
|
|
80
|
-
}, [
|
|
81
|
-
//
|
|
205
|
+
}, [isRegisterMode, format]);
|
|
206
|
+
// También escuchar cambios en el input nativo para sincronizar cuando cambie
|
|
82
207
|
React.useEffect(() => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
208
|
+
if (isRegisterMode && inputRef.current) {
|
|
209
|
+
const input = inputRef.current;
|
|
210
|
+
const handleInputSync = () => {
|
|
211
|
+
syncDisplayValue();
|
|
212
|
+
};
|
|
213
|
+
input.addEventListener("input", handleInputSync);
|
|
214
|
+
input.addEventListener("change", handleInputSync);
|
|
215
|
+
const observer = new MutationObserver(() => {
|
|
216
|
+
syncDisplayValue();
|
|
217
|
+
});
|
|
218
|
+
observer.observe(input, {
|
|
219
|
+
attributes: true,
|
|
220
|
+
attributeFilter: ["value"],
|
|
221
|
+
});
|
|
222
|
+
return () => {
|
|
223
|
+
input.removeEventListener("input", handleInputSync);
|
|
224
|
+
input.removeEventListener("change", handleInputSync);
|
|
225
|
+
observer.disconnect();
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}, [isRegisterMode, syncDisplayValue]);
|
|
229
|
+
// Sincronizar con el valor del formulario
|
|
230
|
+
React.useEffect(() => {
|
|
231
|
+
if (!isTypingRef.current) {
|
|
232
|
+
if (isRegisterMode) {
|
|
233
|
+
// En modo register con setValue, leer del formulario
|
|
234
|
+
if (formContext && fieldName) {
|
|
235
|
+
const formValue = formContext.watch(fieldName);
|
|
236
|
+
const normalized = normalizeToDayjs(formValue);
|
|
237
|
+
setInternalDate(normalized);
|
|
238
|
+
if (normalized) {
|
|
239
|
+
setDisplayValue(formatDateToString(normalized, format));
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
setDisplayValue("");
|
|
243
|
+
}
|
|
94
244
|
}
|
|
245
|
+
// Si no hay setValue, syncDisplayValue se encarga de sincronizar desde el input nativo
|
|
95
246
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
247
|
+
else {
|
|
248
|
+
// Modo Controller, sincronizar con el valor Dayjs
|
|
249
|
+
const normalized = normalizeToDayjs(value);
|
|
250
|
+
setInternalDate(normalized);
|
|
251
|
+
if (normalized) {
|
|
252
|
+
setDisplayValue(formatDateToString(normalized, format));
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
setDisplayValue("");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}, [value, format, isRegisterMode, setValue, fieldName, formContext]);
|
|
260
|
+
// Determinar el valor a mostrar en el input
|
|
261
|
+
const inputValue = isRegisterMode ? displayValue : displayValue;
|
|
105
262
|
const handleDateChange = (date) => {
|
|
106
|
-
if (
|
|
263
|
+
if (readOnly)
|
|
264
|
+
return;
|
|
265
|
+
const dateString = formatDateToString(date, format);
|
|
266
|
+
if (isRegisterMode) {
|
|
267
|
+
// En modo register, usar setValue si está disponible para guardar el objeto Dayjs
|
|
268
|
+
// Si no está disponible, guardar como string (comportamiento por defecto)
|
|
269
|
+
if (setValue && fieldName) {
|
|
270
|
+
// Usar setValue para guardar el objeto Dayjs directamente
|
|
271
|
+
setValue(fieldName, date, {
|
|
272
|
+
shouldValidate: true,
|
|
273
|
+
shouldDirty: true,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// Fallback: actualizar el input nativo con el string de fecha
|
|
278
|
+
if (inputRef.current) {
|
|
279
|
+
const nativeInput = inputRef.current;
|
|
280
|
+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
|
|
281
|
+
if (nativeInputValueSetter) {
|
|
282
|
+
nativeInputValueSetter.call(nativeInput, dateString);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
nativeInput.value = dateString;
|
|
286
|
+
}
|
|
287
|
+
// Llamar al onChange de register
|
|
288
|
+
if (onChange) {
|
|
289
|
+
const changeEvent = {
|
|
290
|
+
target: nativeInput,
|
|
291
|
+
currentTarget: nativeInput,
|
|
292
|
+
};
|
|
293
|
+
onChange(changeEvent);
|
|
294
|
+
}
|
|
295
|
+
// Disparar eventos nativos
|
|
296
|
+
const inputEvent = new Event("input", {
|
|
297
|
+
bubbles: true,
|
|
298
|
+
cancelable: true,
|
|
299
|
+
});
|
|
300
|
+
nativeInput.dispatchEvent(inputEvent);
|
|
301
|
+
const changeEventNative = new Event("change", {
|
|
302
|
+
bubbles: true,
|
|
303
|
+
cancelable: true,
|
|
304
|
+
});
|
|
305
|
+
nativeInput.dispatchEvent(changeEventNative);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Actualizar el displayValue
|
|
309
|
+
setDisplayValue(dateString);
|
|
107
310
|
setInternalDate(date);
|
|
108
|
-
setInputValue(formatDateToString(date, format));
|
|
109
311
|
}
|
|
110
|
-
|
|
312
|
+
else {
|
|
313
|
+
// Modo Controller - comportamiento original
|
|
314
|
+
setInternalDate(date);
|
|
315
|
+
setDisplayValue(dateString);
|
|
316
|
+
if (onChange) {
|
|
317
|
+
const dayjsHandler = onChange;
|
|
318
|
+
dayjsHandler(date);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
111
321
|
setIsOpen(false);
|
|
112
322
|
};
|
|
113
323
|
const handleInputChange = (event) => {
|
|
324
|
+
if (readOnly)
|
|
325
|
+
return;
|
|
114
326
|
const newValue = event.target.value;
|
|
115
|
-
|
|
116
|
-
|
|
327
|
+
isTypingRef.current = true;
|
|
328
|
+
if (isRegisterMode) {
|
|
329
|
+
// En modo register, actualizar el displayValue mientras el usuario escribe
|
|
330
|
+
setDisplayValue(newValue);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
// Modo Controller
|
|
334
|
+
setDisplayValue(newValue);
|
|
335
|
+
}
|
|
117
336
|
};
|
|
118
337
|
const handleInputBlur = (event) => {
|
|
338
|
+
isTypingRef.current = false;
|
|
119
339
|
const newValue = event.target.value.trim();
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
340
|
+
if (isRegisterMode) {
|
|
341
|
+
// En modo register, validar y actualizar el input nativo
|
|
342
|
+
if (!newValue) {
|
|
343
|
+
// Limpiar el valor
|
|
344
|
+
if (inputRef.current) {
|
|
345
|
+
const nativeInput = inputRef.current;
|
|
346
|
+
const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value")?.set;
|
|
347
|
+
setter?.call(nativeInput, "");
|
|
348
|
+
if (onChange) {
|
|
349
|
+
const changeEvent = {
|
|
350
|
+
target: nativeInput,
|
|
351
|
+
currentTarget: nativeInput,
|
|
352
|
+
};
|
|
353
|
+
onChange(changeEvent);
|
|
354
|
+
}
|
|
355
|
+
const inputEvent = new Event("input", { bubbles: true });
|
|
356
|
+
nativeInput.dispatchEvent(inputEvent);
|
|
357
|
+
const changeEventNative = new Event("change", { bubbles: true });
|
|
358
|
+
nativeInput.dispatchEvent(changeEventNative);
|
|
359
|
+
}
|
|
360
|
+
setDisplayValue("");
|
|
361
|
+
setInternalDate(null);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
const parsed = parseDateFromString(newValue, format);
|
|
365
|
+
if (parsed) {
|
|
366
|
+
handleDateChange(parsed);
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
// Si no es válida, restaurar el valor anterior
|
|
370
|
+
const previousValue = inputRef.current?.value || "";
|
|
371
|
+
setDisplayValue(previousValue);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Llamar al onBlur de register si existe
|
|
375
|
+
if (registerOnBlur) {
|
|
376
|
+
registerOnBlur(event);
|
|
377
|
+
}
|
|
127
378
|
}
|
|
128
379
|
else {
|
|
129
|
-
//
|
|
130
|
-
|
|
380
|
+
// Modo Controller
|
|
381
|
+
if (!newValue) {
|
|
382
|
+
handleDateChange(null);
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
const parsed = parseDateFromString(newValue, format);
|
|
386
|
+
if (parsed) {
|
|
387
|
+
handleDateChange(parsed);
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
// Si no es válida, restaurar el valor anterior formateado
|
|
391
|
+
setDisplayValue(formatDateToString(internalDate, format));
|
|
392
|
+
}
|
|
393
|
+
}
|
|
131
394
|
}
|
|
132
395
|
};
|
|
133
396
|
const handleIconClick = (event) => {
|
|
397
|
+
if (readOnly)
|
|
398
|
+
return;
|
|
134
399
|
event.preventDefault();
|
|
135
400
|
setIsOpen((prev) => !prev);
|
|
136
401
|
};
|
|
137
402
|
React.useEffect(() => {
|
|
403
|
+
if (!isOpen)
|
|
404
|
+
return;
|
|
138
405
|
const handleClickOutside = (event) => {
|
|
139
|
-
|
|
140
|
-
|
|
406
|
+
const target = event.target;
|
|
407
|
+
const isClickInsideContainer = containerRef.current?.contains(target);
|
|
408
|
+
const isClickInsidePicker = pickerRef.current?.contains(target);
|
|
409
|
+
if (!isClickInsideContainer && !isClickInsidePicker) {
|
|
141
410
|
setIsOpen(false);
|
|
142
411
|
}
|
|
143
412
|
};
|
|
144
|
-
|
|
413
|
+
// Pequeño delay para asegurar que el portal esté montado
|
|
414
|
+
const timer = setTimeout(() => {
|
|
415
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
416
|
+
}, 0);
|
|
145
417
|
return () => {
|
|
418
|
+
clearTimeout(timer);
|
|
146
419
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
147
420
|
};
|
|
148
|
-
}, []);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
421
|
+
}, [isOpen]);
|
|
422
|
+
// Combinar refs: el ref del componente y el ref interno
|
|
423
|
+
const combinedRef = React.useCallback((node) => {
|
|
424
|
+
inputRef.current = node;
|
|
425
|
+
if (typeof ref === "function") {
|
|
426
|
+
ref(node);
|
|
427
|
+
}
|
|
428
|
+
else if (ref) {
|
|
429
|
+
ref.current = node;
|
|
430
|
+
}
|
|
431
|
+
// Cuando el ref se establece en modo register, sincronizar el displayValue
|
|
432
|
+
if (isRegisterMode && node) {
|
|
433
|
+
[0, 10, 50, 100, 200, 500].forEach((delay) => {
|
|
434
|
+
setTimeout(() => {
|
|
435
|
+
if (node && inputRef.current === node) {
|
|
436
|
+
const formValue = node.value;
|
|
437
|
+
if (formValue) {
|
|
438
|
+
const parsed = parseDateFromString(formValue, format);
|
|
439
|
+
if (parsed) {
|
|
440
|
+
setDisplayValue(formatDateToString(parsed, format));
|
|
441
|
+
setInternalDate(parsed);
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
setDisplayValue(formValue);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}, delay);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}, [ref, isRegisterMode, format]);
|
|
452
|
+
const datePickerInitialViewDate = internalDate ?? datePickerProps?.initialViewDate ?? dayjs();
|
|
453
|
+
// Ocultar el ícono cuando está en modo readOnly
|
|
454
|
+
const displayIcon = readOnly ? undefined : icon;
|
|
455
|
+
const displayIconPosition = readOnly ? undefined : iconPosition;
|
|
456
|
+
const displayOnIconClick = readOnly ? undefined : handleIconClick;
|
|
457
|
+
// Verificar que estamos en el navegador
|
|
458
|
+
// Inicializar isMounted de forma síncrona si es posible
|
|
459
|
+
const [isMounted, setIsMounted] = React.useState(() => {
|
|
460
|
+
return typeof document !== "undefined" && !!document.body;
|
|
461
|
+
});
|
|
462
|
+
React.useEffect(() => {
|
|
463
|
+
if (!isMounted && typeof document !== "undefined" && document.body) {
|
|
464
|
+
setIsMounted(true);
|
|
465
|
+
}
|
|
466
|
+
}, [isMounted]);
|
|
467
|
+
// Actualizar posición del picker cuando se abre
|
|
468
|
+
React.useEffect(() => {
|
|
469
|
+
if (isOpen && !readOnly && containerRef.current && isMounted) {
|
|
470
|
+
const updatePosition = () => {
|
|
471
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
472
|
+
if (rect) {
|
|
473
|
+
setPickerPosition({
|
|
474
|
+
top: rect.bottom + window.scrollY + 4,
|
|
475
|
+
left: rect.right + window.scrollX - 280, // Alinear a la derecha
|
|
476
|
+
width: rect.width,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
updatePosition();
|
|
481
|
+
window.addEventListener("scroll", updatePosition, true);
|
|
482
|
+
window.addEventListener("resize", updatePosition);
|
|
483
|
+
return () => {
|
|
484
|
+
window.removeEventListener("scroll", updatePosition, true);
|
|
485
|
+
window.removeEventListener("resize", updatePosition);
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
setPickerPosition(null);
|
|
490
|
+
}
|
|
491
|
+
}, [isOpen, readOnly, isMounted]);
|
|
492
|
+
return (_jsxs("div", { ref: containerRef, className: "relative w-full", children: [_jsx(Input, { ...restInputProps, ref: combinedRef, type: "text", value: inputValue, onChange: handleInputChange, onBlur: handleInputBlur, icon: displayIcon, iconPosition: displayIconPosition, onIconClick: displayOnIconClick, placeholder: restInputProps.placeholder ??
|
|
493
|
+
(format === "mm/dd/yyyy" ? "mm/dd/yyyy" : "dd/mm/yyyy"), className: className, readOnly: readOnly }), (() => {
|
|
494
|
+
// Verificar de forma segura que document.body existe y es válido
|
|
495
|
+
const bodyElement = typeof document !== "undefined" &&
|
|
496
|
+
document.body &&
|
|
497
|
+
document.body instanceof HTMLElement
|
|
498
|
+
? document.body
|
|
499
|
+
: null;
|
|
500
|
+
return (!readOnly &&
|
|
501
|
+
isOpen &&
|
|
502
|
+
pickerPosition &&
|
|
503
|
+
isMounted &&
|
|
504
|
+
bodyElement &&
|
|
505
|
+
createPortal(_jsx("div", { ref: pickerRef, className: "fixed z-[2001] min-w-[280px] w-max", style: {
|
|
506
|
+
top: `${pickerPosition.top}px`,
|
|
507
|
+
left: `${pickerPosition.left}px`,
|
|
508
|
+
}, children: _jsx(DatePicker, { ...datePickerProps, value: internalDate ?? datePickerInitialViewDate, onChange: (date) => handleDateChange(date) }) }), bodyElement));
|
|
509
|
+
})()] }));
|
|
510
|
+
});
|
|
511
|
+
DateInput.displayName = "DateInput";
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { type Dayjs } from "dayjs";
|
|
2
3
|
export type DatePickerView = {
|
|
3
4
|
month: number;
|
|
4
5
|
year: number;
|
|
5
6
|
};
|
|
6
7
|
export interface DatePickerProps {
|
|
7
|
-
value?:
|
|
8
|
-
onChange?: (date:
|
|
9
|
-
initialViewDate?:
|
|
8
|
+
value?: Dayjs | null;
|
|
9
|
+
onChange?: (date: Dayjs) => void;
|
|
10
|
+
initialViewDate?: Dayjs;
|
|
10
11
|
startWeekOn?: "monday" | "sunday";
|
|
11
12
|
className?: string;
|
|
12
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/DatePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/form-controls/DatePicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAc,EAAE,KAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAG1C,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,eAAe,CAAC,EAAE,KAAK,CAAC;IACxB,WAAW,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA8OhD,CAAC"}
|