@adamosuiteservices/ui 2.10.13 → 2.11.13

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.
@@ -0,0 +1,376 @@
1
+ # Date Picker Selector
2
+
3
+ A comprehensive date range selector component combining preset date ranges with custom calendar selection.
4
+
5
+ ## Descripción
6
+
7
+ El componente `DatePickerSelector` proporciona una interfaz intuitiva para seleccionar rangos de fechas. Incluye opciones predefinidas (últimos 7, 30, 90 días) y un selector de calendario personalizado para rangos específicos.
8
+
9
+ ## Características
10
+
11
+ - ✅ Rangos predefinidos (7, 30, 90 días)
12
+ - ✅ Selector de calendario personalizado para rangos específicos
13
+ - ✅ Formato de fecha limpio (medianoche, sin horas)
14
+ - ✅ Labels personalizables para internacionalización
15
+ - ✅ Integración con Combobox y Calendar
16
+ - ✅ Props personalizables para Combobox y Calendar
17
+ - ✅ Estado controlado con callback onChange
18
+
19
+ ## Importación
20
+
21
+ ```typescript
22
+ import { DatePickerSelector } from "@adamosuiteservices/ui/date-picker-selector";
23
+ import type { DateRange } from "react-day-picker";
24
+ ```
25
+
26
+ ## Uso Básico
27
+
28
+ ```tsx
29
+ import { DatePickerSelector } from "@adamosuiteservices/ui/date-picker-selector";
30
+ import { useState } from "react";
31
+ import type { DateRange } from "react-day-picker";
32
+
33
+ function MyComponent() {
34
+ const [dateRange, setDateRange] = useState<DateRange>({
35
+ from: undefined,
36
+ to: undefined,
37
+ });
38
+
39
+ return (
40
+ <DatePickerSelector
41
+ dateRange={dateRange}
42
+ onDateRangeChange={setDateRange}
43
+ />
44
+ );
45
+ }
46
+ ```
47
+
48
+ ## Props
49
+
50
+ | Prop | Tipo | Default | Descripción |
51
+ | ------------------ | ------------------------ | ----------- | -------------------------------------------------------------- |
52
+ | `dateRange` | `DateRange` | - | **Requerido**. Rango de fechas actual |
53
+ | `onDateRangeChange`| `(dateRange: DateRange) => void` | - | **Requerido**. Callback al cambiar el rango |
54
+ | `labels` | `DatePickerSelectorLabels` | - | Labels personalizables para todos los textos de UI |
55
+ | `combobox` | `ComboboxProps` | - | Props adicionales para el componente Combobox |
56
+ | `calendar` | `CalendarProps` | - | Props adicionales para el componente Calendar |
57
+ | `className` | `string` | - | Clases CSS adicionales para el contenedor |
58
+ | ...props | `HTMLAttributes<HTMLDivElement>` | - | Props nativas de div |
59
+
60
+ ### DateRange Type
61
+
62
+ ```typescript
63
+ type DateRange = {
64
+ from: Date | undefined;
65
+ to: Date | undefined;
66
+ };
67
+ ```
68
+
69
+ ### DatePickerSelectorLabels Type
70
+
71
+ ```typescript
72
+ type DatePickerSelectorLabels = {
73
+ last30Days?: string; // Default: "Last 30 days"
74
+ last7Days?: string; // Default: "Last 7 days"
75
+ last90Days?: string; // Default: "Last 90 days"
76
+ custom?: string; // Default: "Custom"
77
+ placeholder?: string; // Default: "Date"
78
+ cancel?: string; // Default: "Cancel"
79
+ apply?: string; // Default: "Apply"
80
+ };
81
+ ```
82
+
83
+ ## Patrones de Uso
84
+
85
+ ### Con Valor Inicial
86
+
87
+ ```tsx
88
+ import { subDays, startOfDay } from "date-fns";
89
+
90
+ function MyComponent() {
91
+ const today = startOfDay(new Date());
92
+ const [dateRange, setDateRange] = useState<DateRange>({
93
+ from: subDays(today, 30),
94
+ to: today,
95
+ });
96
+
97
+ return (
98
+ <DatePickerSelector
99
+ dateRange={dateRange}
100
+ onDateRangeChange={setDateRange}
101
+ />
102
+ );
103
+ }
104
+ ```
105
+
106
+ ### Con Labels Personalizados (Internacionalización)
107
+
108
+ ```tsx
109
+ <DatePickerSelector
110
+ dateRange={dateRange}
111
+ onDateRangeChange={setDateRange}
112
+ labels={{
113
+ last7Days: "Últimos 7 días",
114
+ last30Days: "Últimos 30 días",
115
+ last90Days: "Últimos 90 días",
116
+ custom: "Personalizado",
117
+ placeholder: "Fecha",
118
+ cancel: "Cancelar",
119
+ apply: "Aplicar",
120
+ }}
121
+ />
122
+ ```
123
+
124
+ ### Con Props Personalizados del Combobox
125
+
126
+ ```tsx
127
+ <DatePickerSelector
128
+ dateRange={dateRange}
129
+ onDateRangeChange={setDateRange}
130
+ combobox={{
131
+ classNames: {
132
+ trigger: "w-[300px]",
133
+ },
134
+ }}
135
+ />
136
+ ```
137
+
138
+ ### Con Props Personalizados del Calendar
139
+
140
+ ```tsx
141
+ <DatePickerSelector
142
+ dateRange={dateRange}
143
+ onDateRangeChange={setDateRange}
144
+ calendar={{
145
+ fromYear: 2020,
146
+ toYear: 2030,
147
+ }}
148
+ />
149
+ ```
150
+
151
+ ### Formato de Fecha con date-fns
152
+
153
+ ```tsx
154
+ import { format } from "date-fns";
155
+
156
+ function MyComponent() {
157
+ const [dateRange, setDateRange] = useState<DateRange>({
158
+ from: undefined,
159
+ to: undefined,
160
+ });
161
+
162
+ const formatDateRange = () => {
163
+ if (!dateRange.from || !dateRange.to) return "No date selected";
164
+ return `${format(dateRange.from, "MMM d, yyyy")} - ${format(dateRange.to, "MMM d, yyyy")}`;
165
+ };
166
+
167
+ return (
168
+ <div>
169
+ <DatePickerSelector
170
+ dateRange={dateRange}
171
+ onDateRangeChange={setDateRange}
172
+ />
173
+ <p>Selected: {formatDateRange()}</p>
174
+ </div>
175
+ );
176
+ }
177
+ ```
178
+
179
+ ### Validación de Rango
180
+
181
+ ```tsx
182
+ function MyComponent() {
183
+ const [dateRange, setDateRange] = useState<DateRange>({
184
+ from: undefined,
185
+ to: undefined,
186
+ });
187
+
188
+ const handleDateRangeChange = (newRange: DateRange) => {
189
+ // Validate that both dates are selected
190
+ if (newRange.from && newRange.to) {
191
+ setDateRange(newRange);
192
+ }
193
+ };
194
+
195
+ const isValidRange = dateRange.from && dateRange.to;
196
+
197
+ return (
198
+ <div>
199
+ <DatePickerSelector
200
+ dateRange={dateRange}
201
+ onDateRangeChange={handleDateRangeChange}
202
+ />
203
+ {!isValidRange && (
204
+ <p className="text-destructive text-sm mt-2">
205
+ Please select a complete date range
206
+ </p>
207
+ )}
208
+ </div>
209
+ );
210
+ }
211
+ ```
212
+
213
+ ## Comportamiento
214
+
215
+ ### Rangos Predefinidos
216
+
217
+ El componente ofrece tres rangos predefinidos:
218
+
219
+ - **Last 7 days**: Desde hace 7 días hasta hoy
220
+ - **Last 30 days**: Desde hace 30 días hasta hoy
221
+ - **Last 90 days**: Desde hace 90 días hasta hoy
222
+
223
+ Todos los rangos predefinidos:
224
+ - Usan `date-fns` para cálculos precisos
225
+ - Establecen las fechas a medianoche (00:00:00)
226
+ - Se calculan dinámicamente basándose en la fecha actual
227
+
228
+ ### Rango Personalizado
229
+
230
+ Al seleccionar la opción "Custom":
231
+ 1. Se abre un popover con un calendario
232
+ 2. El usuario selecciona un rango de fechas
233
+ 3. Los botones "Cancel" y "Apply" permiten confirmar o descartar la selección
234
+ 4. El rango personalizado se mantiene independiente de los rangos predefinidos
235
+
236
+ ### Separación de Estados
237
+
238
+ - Los rangos predefinidos resetean cualquier selección personalizada previa
239
+ - El rango personalizado mantiene su valor hasta que se seleccione un rango predefinido
240
+ - Esto previene conflictos entre los dos modos de selección
241
+
242
+ ## Casos de Uso
243
+
244
+ **Filtros de reportes**: Seleccionar rango de fechas para generar reportes
245
+ **Dashboards**: Filtrar datos por períodos de tiempo
246
+ **Analytics**: Comparar métricas en diferentes rangos
247
+ **Búsquedas**: Filtrar resultados por rango de fechas
248
+ **Logs**: Visualizar registros en períodos específicos
249
+
250
+ ## Dependencias
251
+
252
+ Este componente utiliza internamente:
253
+
254
+ - **Combobox**: Para el selector de opciones con el ícono de calendario
255
+ - **Calendar**: Para la selección de rangos personalizados
256
+ - **Popover**: Para mostrar el calendario
257
+ - **Button**: Para las acciones "Cancel" y "Apply"
258
+ - **date-fns**: Para cálculos de fechas (`startOfDay`, `subDays`)
259
+ - **react-day-picker**: Para la gestión del calendario
260
+
261
+ ## Estilos Base
262
+
263
+ - **Contenedor**: `flex w-max flex-col`
264
+ - **Combobox**: Con placeholder siempre visible, ícono de calendario, feedback tipo check
265
+ - **Calendar**: Con `captionLayout="dropdown"` para navegación por años
266
+ - **Botones**: Estilo `variant="link"` para Cancel y Apply
267
+
268
+ ## Accesibilidad
269
+
270
+ - ✅ Labels descriptivos para todas las opciones
271
+ - ✅ Navegación por teclado en combobox y calendario
272
+ - ✅ Estados de selección claramente indicados
273
+ - ✅ Feedback visual en checkmarks
274
+ - ✅ Acciones claramente etiquetadas (Cancel/Apply)
275
+
276
+ ## Mejores Prácticas
277
+
278
+ ### Gestión del Estado
279
+
280
+ ```tsx
281
+ // ✅ Correcto - Estado controlado
282
+ const [dateRange, setDateRange] = useState<DateRange>({
283
+ from: undefined,
284
+ to: undefined,
285
+ });
286
+
287
+ <DatePickerSelector
288
+ dateRange={dateRange}
289
+ onDateRangeChange={setDateRange}
290
+ />
291
+
292
+ // ❌ Incorrecto - Estado no inicializado
293
+ const [dateRange, setDateRange] = useState();
294
+ ```
295
+
296
+ ### Validación
297
+
298
+ ```tsx
299
+ // ✅ Correcto - Validar rango completo
300
+ const handleChange = (range: DateRange) => {
301
+ if (range.from && range.to) {
302
+ // Procesar rango válido
303
+ setDateRange(range);
304
+ }
305
+ };
306
+
307
+ // ✅ Correcto - Mostrar feedback de validación
308
+ {!dateRange.from || !dateRange.to ? (
309
+ <p className="text-destructive">Please select both dates</p>
310
+ ) : null}
311
+ ```
312
+
313
+ ### Formateo de Fechas
314
+
315
+ ```tsx
316
+ import { format } from "date-fns";
317
+
318
+ // ✅ Correcto - Formatear con date-fns
319
+ const displayDate = dateRange.from
320
+ ? format(dateRange.from, "PP")
321
+ : "Not selected";
322
+
323
+ // ❌ Evitar - toString() no es user-friendly
324
+ const displayDate = dateRange.from?.toString();
325
+ ```
326
+
327
+ ### Internacionalización
328
+
329
+ ```tsx
330
+ // ✅ Correcto - Proporcionar todos los labels
331
+ <DatePickerSelector
332
+ labels={{
333
+ last7Days: t("dateRange.last7Days"),
334
+ last30Days: t("dateRange.last30Days"),
335
+ last90Days: t("dateRange.last90Days"),
336
+ custom: t("dateRange.custom"),
337
+ placeholder: t("dateRange.placeholder"),
338
+ cancel: t("actions.cancel"),
339
+ apply: t("actions.apply"),
340
+ }}
341
+ />
342
+ ```
343
+
344
+ ## Limitaciones
345
+
346
+ - ❌ Solo soporta rangos (no fechas individuales)
347
+ - ❌ Los rangos predefinidos son fijos (7, 30, 90 días)
348
+ - ❌ No incluye presets personalizables adicionales
349
+ - ❌ No soporta selección de hora (solo fechas)
350
+
351
+ ## Troubleshooting
352
+
353
+ **Problema**: Las fechas tienen horas no deseadas
354
+ **Solución**: El componente usa `startOfDay()` automáticamente. Si pasas fechas con horas, normalízalas antes:
355
+
356
+ ```tsx
357
+ import { startOfDay } from "date-fns";
358
+
359
+ const normalizedRange = {
360
+ from: dateRange.from ? startOfDay(dateRange.from) : undefined,
361
+ to: dateRange.to ? startOfDay(dateRange.to) : undefined,
362
+ };
363
+ ```
364
+
365
+ **Problema**: El calendario no se abre
366
+ **Solución**: Verifica que estás pasando las props correctamente y que el componente Calendar está importado.
367
+
368
+ **Problema**: Los rangos predefinidos no funcionan
369
+ **Solución**: Asegúrate de que `onDateRangeChange` esté actualizando el estado correctamente.
370
+
371
+ ## Referencias
372
+
373
+ - **Combobox**: [Ver documentación](./combobox.md)
374
+ - **Calendar**: [Ver documentación](./calendar.md)
375
+ - **date-fns**: https://date-fns.org/
376
+ - **react-day-picker**: https://react-day-picker.js.org/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamosuiteservices/ui",
3
- "version": "2.10.13",
3
+ "version": "2.11.13",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,6 +38,10 @@
38
38
  "types": "./dist/components/layout/toaster/index.d.ts",
39
39
  "import": "./dist/toaster.js"
40
40
  },
41
+ "./full-screen-loader": {
42
+ "types": "./dist/components/layout/full-screen-loader/index.d.ts",
43
+ "import": "./dist/full-screen-loader.js"
44
+ },
41
45
  "./accordion": {
42
46
  "types": "./dist/components/ui/accordion/accordion.d.ts",
43
47
  "import": "./dist/accordion.js"
@@ -94,6 +98,10 @@
94
98
  "types": "./dist/components/ui/context-menu/context-menu.d.ts",
95
99
  "import": "./dist/context-menu.js"
96
100
  },
101
+ "./date-picker-selector": {
102
+ "types": "./dist/components/ui/date-picker-selector/date-picker-selector.d.ts",
103
+ "import": "./dist/date-picker-selector.js"
104
+ },
97
105
  "./dialog": {
98
106
  "types": "./dist/components/ui/dialog/dialog.d.ts",
99
107
  "import": "./dist/dialog.js"