@adamosuiteservices/ui 2.10.12 → 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.
- package/dist/accordion-rounded.cjs +7 -7
- package/dist/accordion-rounded.js +1 -1
- package/dist/calendar-Bapd0vmU.js +2949 -0
- package/dist/calendar-DMvGcwMp.cjs +76 -0
- package/dist/calendar.cjs +1 -76
- package/dist/calendar.js +3 -2945
- package/dist/colors.css +1 -1
- package/dist/combobox-CW07jN3o.cjs +37 -0
- package/dist/combobox-CtdzWxGX.js +598 -0
- package/dist/combobox.cjs +1 -37
- package/dist/combobox.js +2 -596
- package/dist/components/layout/full-screen-loader/full-screen-loader-manager.d.ts +6 -0
- package/dist/components/layout/full-screen-loader/full-screen-loader-observable.d.ts +8 -0
- package/dist/components/layout/full-screen-loader/full-screen-loader.d.ts +4 -0
- package/dist/components/layout/full-screen-loader/index.d.ts +3 -0
- package/dist/components/ui/date-picker-selector/date-picker-selector.d.ts +21 -0
- package/dist/components/ui/date-picker-selector/index.d.ts +1 -0
- package/dist/date-picker-selector.cjs +1 -0
- package/dist/date-picker-selector.js +105 -0
- package/dist/full-screen-loader.cjs +4 -0
- package/dist/full-screen-loader.js +50 -0
- package/dist/spinner-B-sC3DVC.cjs +1 -0
- package/dist/spinner-DvrliN2E.js +19 -0
- package/dist/spinner.cjs +1 -1
- package/dist/spinner.js +1 -16
- package/dist/styles.css +1 -1
- package/dist/table.cjs +5 -5
- package/dist/table.js +2 -2
- package/dist/tailwind-colors.css +1 -1
- package/dist/tailwind-theme.css +1 -1
- package/dist/themes.css +1 -1
- package/dist/tooltip.cjs +5 -4
- package/dist/tooltip.js +4 -3
- package/dist/types/theme.type.d.ts +1 -1
- package/docs/components/layout/full-screen-loader.md +500 -0
- package/docs/components/ui/accordion-rounded.md +7 -7
- package/docs/components/ui/accordion.md +2 -2
- package/docs/components/ui/alert.md +3 -3
- package/docs/components/ui/avatar.md +10 -10
- package/docs/components/ui/badge.md +10 -53
- package/docs/components/ui/button.md +1 -1
- package/docs/components/ui/calendar.md +1 -1
- package/docs/components/ui/combobox.md +7 -7
- package/docs/components/ui/date-picker-selector.md +376 -0
- package/docs/components/ui/hover-card.md +1 -1
- package/docs/components/ui/icon.md +12 -12
- package/docs/components/ui/input-group.md +9 -14
- package/docs/components/ui/popover.md +2 -2
- package/docs/components/ui/spinner.md +1 -1
- package/docs/components/ui/table.md +1 -1
- package/docs/components/ui/tooltip.md +3 -3
- package/docs/components/ui/typography.md +1 -1
- package/package.json +9 -1
|
@@ -499,29 +499,11 @@ Para etiquetas promocionales.
|
|
|
499
499
|
```tsx
|
|
500
500
|
import { Icon } from "@adamosuiteservices/ui/icon";
|
|
501
501
|
|
|
502
|
-
<div className="
|
|
503
|
-
|
|
504
|
-
<
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
<Badge variant="secondary">Bestseller</Badge>
|
|
508
|
-
<Badge variant="outline">Limited</Badge>
|
|
509
|
-
</div>
|
|
510
|
-
|
|
511
|
-
{/* Badges personalizados */}
|
|
512
|
-
<div className="flex gap-2">
|
|
513
|
-
<Badge className="bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
|
|
514
|
-
Free Shipping
|
|
515
|
-
</Badge>
|
|
516
|
-
<Badge className="bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200">
|
|
517
|
-
<Icon symbol="star" />
|
|
518
|
-
Premium
|
|
519
|
-
</Badge>
|
|
520
|
-
<Badge className="bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200">
|
|
521
|
-
<Icon symbol="redeem" />
|
|
522
|
-
Bundle Deal
|
|
523
|
-
</Badge>
|
|
524
|
-
</div>
|
|
502
|
+
<div className="flex gap-2">
|
|
503
|
+
<Badge variant="destructive">Sale</Badge>
|
|
504
|
+
<Badge variant="default">New</Badge>
|
|
505
|
+
<Badge variant="secondary">Bestseller</Badge>
|
|
506
|
+
<Badge variant="outline">Limited</Badge>
|
|
525
507
|
</div>;
|
|
526
508
|
```
|
|
527
509
|
|
|
@@ -548,12 +530,10 @@ import { Icon } from "@adamosuiteservices/ui/icon";
|
|
|
548
530
|
|
|
549
531
|
<div className="flex items-center gap-2">
|
|
550
532
|
<Avatar className="size-6">
|
|
551
|
-
<
|
|
533
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
534
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
552
535
|
</Avatar>
|
|
553
|
-
<Badge variant="
|
|
554
|
-
<Icon symbol="verified" />
|
|
555
|
-
maxleiter
|
|
556
|
-
</Badge>
|
|
536
|
+
<Badge variant="secondary">shadcn</Badge>
|
|
557
537
|
</div>
|
|
558
538
|
</div>;
|
|
559
539
|
```
|
|
@@ -578,32 +558,9 @@ import { Icon } from "@adamosuiteservices/ui/icon";
|
|
|
578
558
|
Best Value
|
|
579
559
|
</Badge>
|
|
580
560
|
<Badge variant="outline">Free Trial</Badge>
|
|
581
|
-
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
### Colores Personalizados
|
|
585
|
-
|
|
586
|
-
Para casos especiales de branding.
|
|
587
|
-
|
|
588
|
-
```tsx
|
|
589
|
-
import { Icon } from "@adamosuiteservices/ui/icon";
|
|
590
|
-
|
|
591
|
-
<div className="flex gap-2">
|
|
592
|
-
<Badge className="bg-blue-500 text-white dark:bg-blue-600">
|
|
593
|
-
<Icon symbol="verified" />
|
|
594
|
-
Verified
|
|
595
|
-
</Badge>
|
|
596
|
-
<Badge className="bg-green-500 text-white dark:bg-green-600">
|
|
561
|
+
<Badge variant="success-medium">
|
|
597
562
|
<Icon symbol="check" />
|
|
598
|
-
|
|
599
|
-
</Badge>
|
|
600
|
-
<Badge className="bg-purple-500 text-white dark:bg-purple-600">
|
|
601
|
-
<Icon symbol="star" />
|
|
602
|
-
Premium
|
|
603
|
-
</Badge>
|
|
604
|
-
<Badge className="bg-orange-500 text-white dark:bg-orange-600">
|
|
605
|
-
<Icon symbol="trending_up" />
|
|
606
|
-
Trending
|
|
563
|
+
Money Back Guarantee
|
|
607
564
|
</Badge>
|
|
608
565
|
</div>;
|
|
609
566
|
```
|
|
@@ -1072,7 +1072,7 @@ function Navigation() {
|
|
|
1072
1072
|
|
|
1073
1073
|
```tsx
|
|
1074
1074
|
// ❌ Incorrecto - className sobrescribe variantes
|
|
1075
|
-
<Button className="bg-
|
|
1075
|
+
<Button className="bg-destructive">Click</Button>
|
|
1076
1076
|
|
|
1077
1077
|
// ✅ Correcto - Usa variantes predefinidas
|
|
1078
1078
|
<Button variant="destructive">Click</Button>
|
|
@@ -270,10 +270,10 @@ const options = [
|
|
|
270
270
|
searchable
|
|
271
271
|
options={frameworks}
|
|
272
272
|
classNames={{
|
|
273
|
-
trigger: "border-2 border-
|
|
274
|
-
popover: "border-
|
|
275
|
-
item: "rounded px-3 py-2 hover:bg-
|
|
276
|
-
check: "text-
|
|
273
|
+
trigger: "border-2 border-primary w-64",
|
|
274
|
+
popover: "border-border shadow-lg",
|
|
275
|
+
item: "rounded px-3 py-2 hover:bg-accent",
|
|
276
|
+
check: "text-primary",
|
|
277
277
|
}}
|
|
278
278
|
/>
|
|
279
279
|
```
|
|
@@ -335,7 +335,7 @@ const [values, setValues] = useState<string[]>([]);
|
|
|
335
335
|
{values.length > 0 && (
|
|
336
336
|
<button
|
|
337
337
|
onClick={() => setValues([])}
|
|
338
|
-
className="text-xs text-
|
|
338
|
+
className="text-xs text-primary hover:text-primary/80 underline"
|
|
339
339
|
>
|
|
340
340
|
Clear all
|
|
341
341
|
</button>
|
|
@@ -390,7 +390,7 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
390
390
|
<div className="flex items-center gap-2">
|
|
391
391
|
<span>{text}</span>
|
|
392
392
|
{text && (
|
|
393
|
-
<span className="px-1.5 py-0.5 text-xs bg-
|
|
393
|
+
<span className="px-1.5 py-0.5 text-xs bg-success/10 text-success rounded font-medium">
|
|
394
394
|
Active
|
|
395
395
|
</span>
|
|
396
396
|
)}
|
|
@@ -411,7 +411,7 @@ El prop `renders` permite personalizar completamente la UI usando el patrón ren
|
|
|
411
411
|
renders={{
|
|
412
412
|
optionLabel: ({ option }) => (
|
|
413
413
|
<div className="flex items-center gap-2">
|
|
414
|
-
<span className="font-semibold text-
|
|
414
|
+
<span className="font-semibold text-primary">🚀</span>
|
|
415
415
|
<span>{option.label}</span>
|
|
416
416
|
</div>
|
|
417
417
|
),
|
|
@@ -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/
|
|
@@ -192,7 +192,7 @@ import { Icon } from "@adamosuiteservices/ui/icon";
|
|
|
192
192
|
<span>4.1k</span>
|
|
193
193
|
</div>
|
|
194
194
|
<div className="flex items-center gap-1">
|
|
195
|
-
<div className="h-3 w-3 rounded-full bg-
|
|
195
|
+
<div className="h-3 w-3 rounded-full bg-primary" />
|
|
196
196
|
<span>TypeScript</span>
|
|
197
197
|
</div>
|
|
198
198
|
</div>
|
|
@@ -84,7 +84,7 @@ Usa clases de texto Tailwind para controlar el tamaño del icono. Se pueden comb
|
|
|
84
84
|
<Icon symbol="star" className="adm:text-5xl" /> {/* ~48px */}
|
|
85
85
|
|
|
86
86
|
// Combinando tamaño con color
|
|
87
|
-
<Icon symbol="star" className="adm:text-2xl adm:text-
|
|
87
|
+
<Icon symbol="star" className="adm:text-2xl adm:text-warning" />
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
### fill
|
|
@@ -190,7 +190,7 @@ function FavoriteButton() {
|
|
|
190
190
|
fill={isFavorite ? 1 : 0}
|
|
191
191
|
className={cn(
|
|
192
192
|
"adm:text-lg",
|
|
193
|
-
isFavorite ? "adm:text-
|
|
193
|
+
isFavorite ? "adm:text-destructive" : "adm:text-muted-foreground"
|
|
194
194
|
)}
|
|
195
195
|
/>
|
|
196
196
|
{isFavorite ? "Liked" : "Like"}
|
|
@@ -261,7 +261,7 @@ const commonIcons = [
|
|
|
261
261
|
<Icon
|
|
262
262
|
symbol="notification"
|
|
263
263
|
weight={300}
|
|
264
|
-
className="adm:text-2xl adm:text-
|
|
264
|
+
className="adm:text-2xl adm:text-primary adm:drop-shadow-sm"
|
|
265
265
|
/>
|
|
266
266
|
```
|
|
267
267
|
|
|
@@ -270,7 +270,7 @@ const commonIcons = [
|
|
|
270
270
|
```tsx
|
|
271
271
|
<Icon
|
|
272
272
|
symbol="refresh"
|
|
273
|
-
className="adm:text-2xl adm:animate-spin adm:text-
|
|
273
|
+
className="adm:text-2xl adm:animate-spin adm:text-primary"
|
|
274
274
|
/>
|
|
275
275
|
```
|
|
276
276
|
|
|
@@ -291,7 +291,7 @@ const commonIcons = [
|
|
|
291
291
|
<Card>
|
|
292
292
|
<CardHeader>
|
|
293
293
|
<div className="adm:flex adm:items-center adm:gap-2">
|
|
294
|
-
<Icon symbol="folder" className="adm:text-2xl adm:text-
|
|
294
|
+
<Icon symbol="folder" className="adm:text-2xl adm:text-primary" />
|
|
295
295
|
<CardTitle>Documents</CardTitle>
|
|
296
296
|
</div>
|
|
297
297
|
</CardHeader>
|
|
@@ -311,17 +311,17 @@ const commonIcons = [
|
|
|
311
311
|
|
|
312
312
|
```tsx
|
|
313
313
|
<div className="adm:flex adm:items-center adm:gap-2">
|
|
314
|
-
<Icon symbol="check_circle" fill={1} className="adm:text-
|
|
314
|
+
<Icon symbol="check_circle" fill={1} className="adm:text-success" />
|
|
315
315
|
<span>Completed</span>
|
|
316
316
|
</div>
|
|
317
317
|
|
|
318
318
|
<div className="adm:flex adm:items-center adm:gap-2">
|
|
319
|
-
<Icon symbol="error" fill={1} className="adm:text-
|
|
319
|
+
<Icon symbol="error" fill={1} className="adm:text-destructive" />
|
|
320
320
|
<span>Error</span>
|
|
321
321
|
</div>
|
|
322
322
|
|
|
323
323
|
<div className="adm:flex adm:items-center adm:gap-2">
|
|
324
|
-
<Icon symbol="schedule" fill={1} className="adm:text-
|
|
324
|
+
<Icon symbol="schedule" fill={1} className="adm:text-warning" />
|
|
325
325
|
<span>Pending</span>
|
|
326
326
|
</div>
|
|
327
327
|
```
|
|
@@ -396,7 +396,7 @@ const commonIcons = [
|
|
|
396
396
|
{
|
|
397
397
|
/* ✅ Correcto - Peso mayor para énfasis */
|
|
398
398
|
}
|
|
399
|
-
<Icon symbol="warning" weight={500} fill={1} className="adm:text-
|
|
399
|
+
<Icon symbol="warning" weight={500} fill={1} className="adm:text-warning" />;
|
|
400
400
|
|
|
401
401
|
{
|
|
402
402
|
/* ❌ Evitar - Peso muy pesado sin propósito */
|
|
@@ -408,9 +408,9 @@ const commonIcons = [
|
|
|
408
408
|
|
|
409
409
|
```tsx
|
|
410
410
|
{/* ✅ Correcto - Estados con significado claro */}
|
|
411
|
-
<Icon symbol="check_circle" fill={1} className="adm:text-
|
|
412
|
-
<Icon symbol="error" fill={1} className="adm:text-
|
|
413
|
-
<Icon symbol="info" fill={1} className="adm:text-
|
|
411
|
+
<Icon symbol="check_circle" fill={1} className="adm:text-success" /> {/* Éxito */}
|
|
412
|
+
<Icon symbol="error" fill={1} className="adm:text-destructive" /> {/* Error */}
|
|
413
|
+
<Icon symbol="info" fill={1} className="adm:text-primary" /> {/* Info */}
|
|
414
414
|
|
|
415
415
|
{/* ✅ Correcto - Estados interactivos */}
|
|
416
416
|
<Icon symbol="favorite" fill={liked ? 1 : 0} />
|
|
@@ -79,12 +79,12 @@ import {
|
|
|
79
79
|
|
|
80
80
|
### InputGroupButton
|
|
81
81
|
|
|
82
|
-
| Prop | Tipo | Default
|
|
83
|
-
| --------- | ---------------------------------------- |
|
|
84
|
-
| `size` | `"xs" \| "sm" \| "icon-xs" \| "icon-sm"` | `"xs"`
|
|
85
|
-
| `variant` | Button variants | `"ghost"`
|
|
86
|
-
| `type` | `string` | `"button"`
|
|
87
|
-
| ...rest | - | -
|
|
82
|
+
| Prop | Tipo | Default | Descripción |
|
|
83
|
+
| --------- | ---------------------------------------- | ----------------- | ---------------------------------------- |
|
|
84
|
+
| `size` | `"xs" \| "sm" \| "icon-xs" \| "icon-sm"` | `"xs"` | Tamaño del botón |
|
|
85
|
+
| `variant` | Button variants | `"ghost-neutral"` | Variante del botón |
|
|
86
|
+
| `type` | `string` | `"button"` | Tipo HTML del botón |
|
|
87
|
+
| ...rest | - | - | Todas las props de Button excepto `size` |
|
|
88
88
|
|
|
89
89
|
**Sizes**:
|
|
90
90
|
|
|
@@ -235,7 +235,7 @@ import {
|
|
|
235
235
|
<InputGroupAddon align="inline-end">
|
|
236
236
|
<Tooltip>
|
|
237
237
|
<TooltipTrigger asChild>
|
|
238
|
-
<InputGroupButton
|
|
238
|
+
<InputGroupButton size="icon-xs">
|
|
239
239
|
<Icon symbol="info" className="text-base" />
|
|
240
240
|
</InputGroupButton>
|
|
241
241
|
</TooltipTrigger>
|
|
@@ -268,7 +268,6 @@ function App() {
|
|
|
268
268
|
/>
|
|
269
269
|
<InputGroupAddon align="inline-end">
|
|
270
270
|
<InputGroupButton
|
|
271
|
-
variant="ghost"
|
|
272
271
|
size="icon-xs"
|
|
273
272
|
onClick={() => setShowPassword(!showPassword)}
|
|
274
273
|
aria-label={showPassword ? "Hide password" : "Show password"}
|
|
@@ -315,7 +314,7 @@ import {
|
|
|
315
314
|
<InputGroupAddon align="inline-end">
|
|
316
315
|
<DropdownMenu>
|
|
317
316
|
<DropdownMenuTrigger asChild>
|
|
318
|
-
<InputGroupButton
|
|
317
|
+
<InputGroupButton size="icon-xs">
|
|
319
318
|
<Icon symbol="more_horiz" className="text-base" />
|
|
320
319
|
</InputGroupButton>
|
|
321
320
|
</DropdownMenuTrigger>
|
|
@@ -362,11 +361,7 @@ import { Label } from "@adamosuiteservices/ui/label";
|
|
|
362
361
|
</Label>
|
|
363
362
|
<Tooltip>
|
|
364
363
|
<TooltipTrigger asChild>
|
|
365
|
-
<InputGroupButton
|
|
366
|
-
variant="ghost"
|
|
367
|
-
className="ml-auto rounded-full"
|
|
368
|
-
size="icon-xs"
|
|
369
|
-
>
|
|
364
|
+
<InputGroupButton className="ml-auto rounded-full" size="icon-xs">
|
|
370
365
|
<Icon symbol="info" className="text-base" />
|
|
371
366
|
</InputGroupButton>
|
|
372
367
|
</TooltipTrigger>
|