@adamosuiteservices/ui 1.2.5 → 1.3.5
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 +1 -1
- package/dist/accordion-rounded.js +1 -1
- package/dist/accordion.cjs +1 -1
- package/dist/accordion.js +1 -1
- package/dist/avatar.cjs +1 -1
- package/dist/avatar.js +1 -1
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/breadcrumb.cjs +1 -0
- package/dist/breadcrumb.js +105 -0
- package/dist/{button-C1n6snOY.js → button-2GdKenQI.js} +1 -1
- package/dist/{button-BV-_FVKZ.cjs → button-DEQVHMrX.cjs} +1 -1
- package/dist/button-group.cjs +1 -1
- package/dist/button-group.js +2 -2
- package/dist/button.cjs +1 -1
- package/dist/button.js +1 -1
- package/dist/calendar.cjs +1 -1
- package/dist/calendar.js +1 -1
- package/dist/{checkbox-BrmXPKTn.js → checkbox-Dr487kAg.js} +3 -3
- package/dist/{checkbox-Lq-HvSgc.cjs → checkbox-YWAnswaW.cjs} +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/collapsible.cjs +1 -1
- package/dist/collapsible.js +1 -1
- package/dist/combobox.cjs +1 -1
- package/dist/combobox.js +6 -6
- package/dist/components/ui/breadcrumb/breadcrumb.d.ts +11 -0
- package/dist/components/ui/breadcrumb/breadcrumb.stories.d.ts +26 -0
- package/dist/components/ui/breadcrumb/index.d.ts +1 -0
- package/dist/components/ui/dialog/dialog.d.ts +2 -1
- package/dist/context-menu.cjs +1 -1
- package/dist/context-menu.js +2 -2
- package/dist/custom-layered-styles.css +1 -1
- package/dist/dialog.cjs +1 -1
- package/dist/dialog.js +33 -19
- package/dist/dropdown-menu.cjs +1 -1
- package/dist/dropdown-menu.js +3 -3
- package/dist/ellipsis-CryjZKZn.js +15 -0
- package/dist/ellipsis-Ct9VTDOG.cjs +6 -0
- package/dist/field.cjs +1 -1
- package/dist/field.js +2 -2
- package/dist/hover-card.cjs +1 -1
- package/dist/hover-card.js +6 -6
- package/dist/{index-CAOY367Y.js → index-B0M7VOwp.js} +2 -2
- package/dist/{index-B-ZRqW0J.js → index-BBoIAjAs.js} +3 -3
- package/dist/{index-gO_QEiaK.cjs → index-BDs8lUfq.cjs} +1 -1
- package/dist/index-BFyr34mw.cjs +5 -0
- package/dist/index-BMWt1NBG.js +79 -0
- package/dist/{index-yR-v1A4G.js → index-BX9hz-JD.js} +1 -1
- package/dist/{index-BGiGvaq8.cjs → index-BcGMAmWE.cjs} +1 -1
- package/dist/{index-IKJMQref.cjs → index-Bd0gQB0k.cjs} +1 -1
- package/dist/{index-VIUqZjyP.cjs → index-BeWgla7c.cjs} +1 -1
- package/dist/{index-EUea2gfp.js → index-BpWB3aFK.js} +1 -1
- package/dist/index-BvLQnI56.js +59 -0
- package/dist/{index-CwUFT-GQ.js → index-C0YiLSjW.js} +4 -4
- package/dist/{index-o0sNTcKe.js → index-CBjZooac.js} +2 -2
- package/dist/{index-DnS_sBBe.cjs → index-COuvjZLM.cjs} +1 -1
- package/dist/index-CTjlbbt9.cjs +1 -0
- package/dist/index-CUWMxxKG.js +97 -0
- package/dist/{index-C329e3yQ.js → index-CZZ3llmi.js} +2 -2
- package/dist/index-CjyiloO7.cjs +1 -0
- package/dist/{index-D3wSWKST.cjs → index-Cmx9M9cZ.cjs} +1 -1
- package/dist/index-CocSS1YK.cjs +1 -0
- package/dist/index-CzRiuk60.cjs +1 -0
- package/dist/index-DFPDUUq7.js +658 -0
- package/dist/{index-D3S7dBDI.cjs → index-DIwmXz1u.cjs} +1 -1
- package/dist/index-DLcqcWxM.js +29 -0
- package/dist/index-DMLQL2aG.js +286 -0
- package/dist/{index-DXQ-7kNJ.cjs → index-DMs8RL3E.cjs} +1 -1
- package/dist/{index-Ce3QBKyj.cjs → index-Dbj9vHNq.cjs} +1 -1
- package/dist/{index-BRLtxFFr.cjs → index-DmGzwG2z.cjs} +1 -1
- package/dist/{index-P1sVIHE3.js → index-PYkEXTqJ.js} +1 -1
- package/dist/{index-DulPG3F9.js → index-Se4vRnIO.js} +3 -3
- package/dist/index-_XxjJPRD.cjs +1 -0
- package/dist/{index-B-cHTKrs.js → index-yWvyIlmA.js} +4 -4
- package/dist/input-group.cjs +1 -1
- package/dist/input-group.js +1 -1
- package/dist/{label-Cne2J57f.cjs → label-BjXORCBM.cjs} +1 -1
- package/dist/{label-Ky8qBEC3.js → label-CmwGvhy1.js} +1 -1
- package/dist/label.cjs +1 -1
- package/dist/label.js +1 -1
- package/dist/pagination.cjs +1 -6
- package/dist/pagination.js +58 -69
- package/dist/popover-3rIoNCXs.js +306 -0
- package/dist/popover-FCKBtFo-.cjs +1 -0
- package/dist/popover.cjs +1 -1
- package/dist/popover.js +1 -1
- package/dist/progress.cjs +1 -1
- package/dist/progress.js +1 -1
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +5 -5
- package/dist/select.cjs +2 -2
- package/dist/select.js +585 -542
- package/dist/{separator-CGnu_jIu.cjs → separator-BaZqZZ9R.cjs} +1 -1
- package/dist/{separator-BH73A90k.js → separator-DR7lQjv9.js} +1 -1
- package/dist/separator.cjs +1 -1
- package/dist/separator.js +1 -1
- package/dist/{sheet-CcxnJ6LH.cjs → sheet-CU-sFSaJ.cjs} +1 -1
- package/dist/{sheet-_DVpQIVF.js → sheet-UZWAbdXr.js} +1 -1
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sidebar.cjs +1 -1
- package/dist/sidebar.js +4 -4
- package/dist/slider.cjs +1 -1
- package/dist/slider.js +3 -3
- package/dist/styles.css +1 -1
- package/dist/switch.cjs +1 -1
- package/dist/switch.js +2 -2
- package/dist/tabs-underline.cjs +1 -1
- package/dist/tabs-underline.js +1 -1
- package/dist/tabs.cjs +1 -1
- package/dist/tabs.js +1 -1
- package/dist/toaster.cjs +1 -1
- package/dist/toaster.js +1 -1
- package/dist/toggle.cjs +1 -1
- package/dist/toggle.js +1 -1
- package/dist/tooltip.cjs +1 -1
- package/dist/tooltip.js +114 -108
- package/dist/typography.cjs +1 -1
- package/dist/typography.js +1 -1
- package/docs/AI-GUIDE.md +321 -0
- package/docs/components/layout/sidebar.md +330 -0
- package/docs/components/layout/toaster.md +436 -0
- package/docs/components/ui/accordion-rounded.md +583 -0
- package/docs/components/ui/accordion.md +267 -0
- package/docs/components/ui/alert.md +671 -0
- package/docs/components/ui/avatar.md +588 -0
- package/docs/components/ui/badge.md +1024 -0
- package/docs/components/ui/breadcrumb.md +614 -0
- package/docs/components/ui/button-group.md +1002 -0
- package/docs/components/ui/button.md +1078 -0
- package/docs/components/ui/calendar.md +1159 -0
- package/docs/components/ui/card.md +1265 -0
- package/docs/components/ui/checkbox.md +292 -0
- package/docs/components/ui/collapsible.md +320 -0
- package/docs/components/ui/combobox.md +328 -0
- package/docs/components/ui/command.md +454 -0
- package/docs/components/ui/context-menu.md +540 -0
- package/docs/components/ui/dialog.md +628 -0
- package/docs/components/ui/dropdown-menu.md +731 -0
- package/docs/components/ui/field.md +706 -0
- package/docs/components/ui/hover-card.md +446 -0
- package/docs/components/ui/input-group.md +509 -0
- package/docs/components/ui/input.md +362 -0
- package/docs/components/ui/kbd.md +434 -0
- package/docs/components/ui/label.md +359 -0
- package/docs/components/ui/pagination.md +650 -0
- package/docs/components/ui/popover.md +536 -0
- package/docs/components/ui/progress.md +182 -0
- package/docs/components/ui/radio-group.md +311 -0
- package/docs/components/ui/select.md +352 -0
- package/docs/components/ui/separator.md +214 -0
- package/docs/components/ui/sheet.md +142 -0
- package/docs/components/ui/skeleton.md +140 -0
- package/docs/components/ui/slider.md +341 -0
- package/docs/components/ui/spinner.md +170 -0
- package/docs/components/ui/switch.md +402 -0
- package/docs/components/ui/table.md +183 -0
- package/docs/components/ui/tabs-underline.md +106 -0
- package/docs/components/ui/tabs.md +122 -0
- package/docs/components/ui/textarea.md +243 -0
- package/docs/components/ui/toggle.md +243 -0
- package/docs/components/ui/tooltip.md +320 -0
- package/docs/components/ui/typography.md +191 -0
- package/package.json +11 -5
- package/dist/index-6oTEokEx.js +0 -82
- package/dist/index-B-NyefE0.js +0 -243
- package/dist/index-BKbK2GzY.cjs +0 -1
- package/dist/index-BMitW9UR.cjs +0 -1
- package/dist/index-BpvjJ_T6.cjs +0 -5
- package/dist/index-C5wjudc-.js +0 -36
- package/dist/index-CezwiPd_.js +0 -615
- package/dist/index-D02K8KOB.js +0 -54
- package/dist/index-D7hQvndv.cjs +0 -1
- package/dist/index-DQvx1rG_.cjs +0 -1
- package/dist/popover-BjdTqaB8.cjs +0 -1
- package/dist/popover-EnVfE0YA.js +0 -263
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Skeleton
|
|
2
|
+
|
|
3
|
+
Placeholder animado para contenido en carga. Simula la estructura del contenido final con bloques pulsantes.
|
|
4
|
+
|
|
5
|
+
## Descripción
|
|
6
|
+
|
|
7
|
+
El componente `Skeleton` muestra placeholders de carga para contenido que está siendo cargado.
|
|
8
|
+
|
|
9
|
+
## Importación
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Skeleton } from "@adamosuiteservices/ui/skeleton";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Anatomía
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
<Skeleton className="w-full h-12" />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Componentes**: 1 (Skeleton)
|
|
22
|
+
|
|
23
|
+
## Props
|
|
24
|
+
|
|
25
|
+
| Prop | Tipo | Descripción |
|
|
26
|
+
| ----------- | -------- | ------------------------------ |
|
|
27
|
+
| `className` | `string` | Clases CSS para tamaño y forma |
|
|
28
|
+
|
|
29
|
+
**Nota**: Acepta todas las props de `<div>`
|
|
30
|
+
|
|
31
|
+
## Patrones de Uso
|
|
32
|
+
|
|
33
|
+
### Básico
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<Skeleton className="h-4 w-[250px]" />
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Avatar + Text
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<div className="flex items-center space-x-4">
|
|
43
|
+
<Skeleton className="h-12 w-12 rounded-full" />
|
|
44
|
+
<div className="space-y-2">
|
|
45
|
+
<Skeleton className="h-4 w-[250px]" />
|
|
46
|
+
<Skeleton className="h-4 w-[200px]" />
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Card
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<div className="flex flex-col space-y-3">
|
|
55
|
+
<Skeleton className="h-[125px] w-[250px] rounded-xl" />
|
|
56
|
+
<div className="space-y-2">
|
|
57
|
+
<Skeleton className="h-4 w-[250px]" />
|
|
58
|
+
<Skeleton className="h-4 w-[200px]" />
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Text Lines
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<div className="space-y-2">
|
|
67
|
+
<Skeleton className="h-4 w-full" />
|
|
68
|
+
<Skeleton className="h-4 w-[90%]" />
|
|
69
|
+
<Skeleton className="h-4 w-[80%]" />
|
|
70
|
+
</div>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Form
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
<div className="space-y-4 max-w-md">
|
|
77
|
+
<div className="space-y-2">
|
|
78
|
+
<Skeleton className="h-4 w-16" />
|
|
79
|
+
<Skeleton className="h-10 w-full rounded-md" />
|
|
80
|
+
</div>
|
|
81
|
+
<div className="space-y-2">
|
|
82
|
+
<Skeleton className="h-4 w-20" />
|
|
83
|
+
<Skeleton className="h-10 w-full rounded-md" />
|
|
84
|
+
</div>
|
|
85
|
+
<Skeleton className="h-10 w-24 rounded-md" />
|
|
86
|
+
</div>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### List Items
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
<div className="space-y-4">
|
|
93
|
+
{Array.from({ length: 4 }).map((_, i) => (
|
|
94
|
+
<div key={i} className="flex items-center space-x-4">
|
|
95
|
+
<Skeleton className="h-10 w-10 rounded-full" />
|
|
96
|
+
<div className="space-y-2 flex-1">
|
|
97
|
+
<Skeleton className="h-4 w-[200px]" />
|
|
98
|
+
<Skeleton className="h-3 w-[150px]" />
|
|
99
|
+
</div>
|
|
100
|
+
<Skeleton className="h-8 w-16 rounded-md" />
|
|
101
|
+
</div>
|
|
102
|
+
))}
|
|
103
|
+
</div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Casos de Uso
|
|
107
|
+
|
|
108
|
+
**Loading states**: Placeholder mientras carga contenido
|
|
109
|
+
**Lazy loading**: Imágenes/contenido que carga progresivamente
|
|
110
|
+
**Optimistic UI**: Simular contenido antes de respuesta
|
|
111
|
+
**Infinite scroll**: Items mientras cargan más
|
|
112
|
+
|
|
113
|
+
## Estilos Base
|
|
114
|
+
|
|
115
|
+
- **Background**: `bg-accent`
|
|
116
|
+
- **Animation**: `animate-pulse`
|
|
117
|
+
- **Border radius**: `rounded-md` default
|
|
118
|
+
|
|
119
|
+
## Accesibilidad
|
|
120
|
+
|
|
121
|
+
- ✅ **ARIA**: Usa `aria-busy="true"` en contenedor padre
|
|
122
|
+
- ✅ **Screen readers**: Anuncia estado de carga en contenedor
|
|
123
|
+
- ⚠️ **Replace**: Reemplaza skeleton con contenido real al cargar
|
|
124
|
+
|
|
125
|
+
## Notas de Implementación
|
|
126
|
+
|
|
127
|
+
- **HTML nativo**: Simple `<div>` con estilos
|
|
128
|
+
- **Pulse animation**: Tailwind `animate-pulse`
|
|
129
|
+
- **Customizable**: Totalmente personalizable con className
|
|
130
|
+
- **No state**: Stateless, solo visual
|
|
131
|
+
|
|
132
|
+
## Troubleshooting
|
|
133
|
+
|
|
134
|
+
**No pulsa**: Verifica que `animate-pulse` esté aplicado
|
|
135
|
+
**Tamaño inconsistente**: Usa height/width específicos con className
|
|
136
|
+
**Forma incorrecta**: Ajusta `rounded-*` para avatars, cards, etc.
|
|
137
|
+
|
|
138
|
+
## Referencias
|
|
139
|
+
|
|
140
|
+
- **shadcn/ui Skeleton**: <https://ui.shadcn.com/docs/components/skeleton>
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# Slider
|
|
2
|
+
|
|
3
|
+
Control de rango con thumbs deslizables. Soporta valores simples y rangos. Basado en Radix UI.
|
|
4
|
+
|
|
5
|
+
## Descripción
|
|
6
|
+
|
|
7
|
+
El componente `Slider` permite seleccionar un valor arrastrando un control deslizante.
|
|
8
|
+
|
|
9
|
+
## Importación
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Slider } from "@adamosuiteservices/ui/slider";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Anatomía
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
<Slider defaultValue={[50]} max={100} step={1} />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Componentes**: 1 (Slider) con 3 partes internas (Root, Track, Range, Thumb)
|
|
22
|
+
|
|
23
|
+
## Props
|
|
24
|
+
|
|
25
|
+
| Prop | Tipo | Descripción |
|
|
26
|
+
| --------------- | ---------------------------- | ----------------------------------- |
|
|
27
|
+
| `defaultValue` | `number[]` | Valor inicial (uncontrolled) |
|
|
28
|
+
| `value` | `number[]` | Valor controlado (array de números) |
|
|
29
|
+
| `onValueChange` | `(value: number[]) => void` | Callback al cambiar valor |
|
|
30
|
+
| `min` | `number` | Valor mínimo (default: 0) |
|
|
31
|
+
| `max` | `number` | Valor máximo (default: 100) |
|
|
32
|
+
| `step` | `number` | Incremento (default: 1) |
|
|
33
|
+
| `disabled` | `boolean` | Deshabilita el slider |
|
|
34
|
+
| `orientation` | `"horizontal" \| "vertical"` | Orientación (default: horizontal) |
|
|
35
|
+
| `theme` | `Theme` | Tema personalizado |
|
|
36
|
+
| `className` | `string` | Clases CSS adicionales |
|
|
37
|
+
|
|
38
|
+
**Nota**: `value` y `defaultValue` siempre son arrays. Single value = `[50]`, range = `[20, 80]`
|
|
39
|
+
|
|
40
|
+
## Patrones de Uso
|
|
41
|
+
|
|
42
|
+
### Básico
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { Slider } from "@adamosuiteservices/ui/slider";
|
|
46
|
+
|
|
47
|
+
<Slider defaultValue={[33]} max={100} step={1} className="w-[60%]" />;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Con Label
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { Label } from "@adamosuiteservices/ui/label";
|
|
54
|
+
import { useState } from "react";
|
|
55
|
+
|
|
56
|
+
function App() {
|
|
57
|
+
const [value, setValue] = useState([50]);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="grid w-full max-w-sm items-center gap-2">
|
|
61
|
+
<Label htmlFor="volume">Volume: {value[0]}%</Label>
|
|
62
|
+
<Slider
|
|
63
|
+
id="volume"
|
|
64
|
+
max={100}
|
|
65
|
+
step={1}
|
|
66
|
+
value={value}
|
|
67
|
+
onValueChange={setValue}
|
|
68
|
+
className="w-full"
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Range (Dos Valores)
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
function App() {
|
|
79
|
+
const [value, setValue] = useState([20, 80]);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="grid w-full max-w-sm items-center gap-2">
|
|
83
|
+
<Label>
|
|
84
|
+
Price Range: ${value[0]} - ${value[1]}
|
|
85
|
+
</Label>
|
|
86
|
+
<Slider
|
|
87
|
+
max={100}
|
|
88
|
+
step={1}
|
|
89
|
+
value={value}
|
|
90
|
+
onValueChange={setValue}
|
|
91
|
+
className="w-full"
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Con Steps
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
function App() {
|
|
102
|
+
const [value, setValue] = useState([25]);
|
|
103
|
+
const stepSize = 25;
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div className="grid w-full max-w-sm items-center gap-2">
|
|
107
|
+
<Label>Progress: {value[0]}%</Label>
|
|
108
|
+
<Slider
|
|
109
|
+
max={100}
|
|
110
|
+
step={stepSize}
|
|
111
|
+
value={value}
|
|
112
|
+
onValueChange={setValue}
|
|
113
|
+
className="w-full"
|
|
114
|
+
/>
|
|
115
|
+
<div className="flex justify-between text-xs text-muted-foreground">
|
|
116
|
+
<span>0%</span>
|
|
117
|
+
<span>25%</span>
|
|
118
|
+
<span>50%</span>
|
|
119
|
+
<span>75%</span>
|
|
120
|
+
<span>100%</span>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Vertical
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
function App() {
|
|
131
|
+
const [value, setValue] = useState([60]);
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<div className="flex h-64 items-center space-x-6">
|
|
135
|
+
<div className="flex flex-col items-center space-y-2">
|
|
136
|
+
<Label>Volume</Label>
|
|
137
|
+
<Slider
|
|
138
|
+
orientation="vertical"
|
|
139
|
+
max={100}
|
|
140
|
+
step={1}
|
|
141
|
+
value={value}
|
|
142
|
+
onValueChange={setValue}
|
|
143
|
+
className="h-48"
|
|
144
|
+
/>
|
|
145
|
+
<span className="text-sm text-muted-foreground">{value[0]}%</span>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Con Botones
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { Button } from "@adamosuiteservices/ui/button";
|
|
156
|
+
|
|
157
|
+
function App() {
|
|
158
|
+
const [value, setValue] = useState([50]);
|
|
159
|
+
|
|
160
|
+
const decrease = () => setValue([Math.max(0, value[0] - 10)]);
|
|
161
|
+
const increase = () => setValue([Math.min(100, value[0] + 10)]);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className="grid w-full max-w-sm items-center gap-4">
|
|
165
|
+
<Label>Volume: {value[0]}%</Label>
|
|
166
|
+
<div className="flex items-center space-x-2">
|
|
167
|
+
<Button
|
|
168
|
+
variant="outline"
|
|
169
|
+
size="sm"
|
|
170
|
+
onClick={decrease}
|
|
171
|
+
disabled={value[0] === 0}
|
|
172
|
+
>
|
|
173
|
+
-
|
|
174
|
+
</Button>
|
|
175
|
+
<Slider
|
|
176
|
+
value={value}
|
|
177
|
+
onValueChange={setValue}
|
|
178
|
+
max={100}
|
|
179
|
+
step={1}
|
|
180
|
+
className="flex-1"
|
|
181
|
+
/>
|
|
182
|
+
<Button
|
|
183
|
+
variant="outline"
|
|
184
|
+
size="sm"
|
|
185
|
+
onClick={increase}
|
|
186
|
+
disabled={value[0] === 100}
|
|
187
|
+
>
|
|
188
|
+
+
|
|
189
|
+
</Button>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Price Filter
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import {
|
|
200
|
+
Card,
|
|
201
|
+
CardContent,
|
|
202
|
+
CardHeader,
|
|
203
|
+
CardTitle,
|
|
204
|
+
} from "@adamosuiteservices/ui/card";
|
|
205
|
+
import { Button } from "@adamosuiteservices/ui/button";
|
|
206
|
+
|
|
207
|
+
function PriceFilter() {
|
|
208
|
+
const [priceRange, setPriceRange] = useState([25, 75]);
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<Card className="w-full max-w-sm">
|
|
212
|
+
<CardHeader>
|
|
213
|
+
<CardTitle>Filter by Price</CardTitle>
|
|
214
|
+
</CardHeader>
|
|
215
|
+
<CardContent className="space-y-4">
|
|
216
|
+
<div className="space-y-2">
|
|
217
|
+
<Label>Price Range</Label>
|
|
218
|
+
<Slider
|
|
219
|
+
value={priceRange}
|
|
220
|
+
onValueChange={setPriceRange}
|
|
221
|
+
max={100}
|
|
222
|
+
step={1}
|
|
223
|
+
className="w-full"
|
|
224
|
+
/>
|
|
225
|
+
</div>
|
|
226
|
+
<div className="flex justify-between text-sm">
|
|
227
|
+
<span>${priceRange[0]}</span>
|
|
228
|
+
<span>${priceRange[1]}</span>
|
|
229
|
+
</div>
|
|
230
|
+
<Button className="w-full">Apply Filter</Button>
|
|
231
|
+
</CardContent>
|
|
232
|
+
</Card>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### RGB Color Picker
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
function ColorPicker() {
|
|
241
|
+
const [red, setRed] = useState([128]);
|
|
242
|
+
const [green, setGreen] = useState([200]);
|
|
243
|
+
const [blue, setBlue] = useState([75]);
|
|
244
|
+
|
|
245
|
+
const rgbColor = `rgb(${red[0]}, ${green[0]}, ${blue[0]})`;
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<Card className="w-full max-w-sm">
|
|
249
|
+
<CardHeader>
|
|
250
|
+
<CardTitle>RGB Color Picker</CardTitle>
|
|
251
|
+
</CardHeader>
|
|
252
|
+
<CardContent className="space-y-6">
|
|
253
|
+
<div
|
|
254
|
+
className="w-full h-20 rounded-lg border"
|
|
255
|
+
style={{ backgroundColor: rgbColor }}
|
|
256
|
+
/>
|
|
257
|
+
|
|
258
|
+
<div className="space-y-4">
|
|
259
|
+
<div className="space-y-2">
|
|
260
|
+
<div className="flex justify-between">
|
|
261
|
+
<Label>Red</Label>
|
|
262
|
+
<span className="text-sm text-muted-foreground">{red[0]}</span>
|
|
263
|
+
</div>
|
|
264
|
+
<Slider value={red} onValueChange={setRed} max={255} step={1} />
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div className="space-y-2">
|
|
268
|
+
<div className="flex justify-between">
|
|
269
|
+
<Label>Green</Label>
|
|
270
|
+
<span className="text-sm text-muted-foreground">{green[0]}</span>
|
|
271
|
+
</div>
|
|
272
|
+
<Slider value={green} onValueChange={setGreen} max={255} step={1} />
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
<div className="space-y-2">
|
|
276
|
+
<div className="flex justify-between">
|
|
277
|
+
<Label>Blue</Label>
|
|
278
|
+
<span className="text-sm text-muted-foreground">{blue[0]}</span>
|
|
279
|
+
</div>
|
|
280
|
+
<Slider value={blue} onValueChange={setBlue} max={255} step={1} />
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</CardContent>
|
|
284
|
+
</Card>
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Deshabilitado
|
|
290
|
+
|
|
291
|
+
```tsx
|
|
292
|
+
<Slider defaultValue={[50]} max={100} step={1} disabled className="w-full" />
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Casos de Uso
|
|
296
|
+
|
|
297
|
+
**Volume control**: Audio, música, efectos de sonido
|
|
298
|
+
**Price filters**: Rango de precios en e-commerce
|
|
299
|
+
**Color pickers**: RGB, HSL sliders
|
|
300
|
+
**Brightness/Contrast**: Ajustes de imagen
|
|
301
|
+
**Temperature**: Termostatos, controles de clima
|
|
302
|
+
**Range selection**: Filtros de fecha, edad, tamaño
|
|
303
|
+
|
|
304
|
+
## Estilos Base
|
|
305
|
+
|
|
306
|
+
- **Track height**: `h-1.5` (horizontal), `w-1.5` (vertical)
|
|
307
|
+
- **Track bg**: `bg-muted`
|
|
308
|
+
- **Range bg**: `bg-primary`
|
|
309
|
+
- **Thumb**: `size-4` con `border-primary`, `bg-white`, `shadow-sm`
|
|
310
|
+
- **Thumb hover/focus**: `ring-4` con `ring-ring/50`
|
|
311
|
+
- **Vertical**: `min-h-44` default, `flex-col`
|
|
312
|
+
|
|
313
|
+
## Accesibilidad
|
|
314
|
+
|
|
315
|
+
- ✅ **Role**: `role="slider"` con `aria-valuenow`, `aria-valuemin`, `aria-valuemax`
|
|
316
|
+
- ✅ **Keyboard**: Arrow keys para ajustar valor, Home/End para min/max
|
|
317
|
+
- ✅ **Focus**: Focus ring visible en thumbs
|
|
318
|
+
- ✅ **Label**: Asociar con `id` para screen readers
|
|
319
|
+
|
|
320
|
+
## Notas de Implementación
|
|
321
|
+
|
|
322
|
+
- **Radix UI**: Basado en `@radix-ui/react-slider`
|
|
323
|
+
- **Multiple thumbs**: Array length determina número de thumbs
|
|
324
|
+
- **Value format**: Siempre array, ej: `[50]` para single, `[20, 80]` para range
|
|
325
|
+
- **Auto-thumbs**: Genera thumbs automáticamente basado en `value.length`
|
|
326
|
+
- **Data attributes**: `data-orientation` para estilos horizontal/vertical
|
|
327
|
+
- **Theme support**: Prop `theme` para personalización
|
|
328
|
+
|
|
329
|
+
## Troubleshooting
|
|
330
|
+
|
|
331
|
+
**Thumb no se mueve**: Verifica `max`, `min` y `step` son números válidos
|
|
332
|
+
**Value no actualiza**: En modo controlado usa `value` + `onValueChange`, no `defaultValue`
|
|
333
|
+
**Range invertido**: Asegura `value[0] < value[1]` en ranges
|
|
334
|
+
**Vertical no funciona**: Agrega `className="h-[Xpx]"` para altura explícita
|
|
335
|
+
**Step no funciona**: `step` debe ser divisor válido del rango (max - min)
|
|
336
|
+
**Multiple thumbs**: `value={[10, 50, 90]}` crea 3 thumbs
|
|
337
|
+
|
|
338
|
+
## Referencias
|
|
339
|
+
|
|
340
|
+
- **Radix UI Slider**: <https://www.radix-ui.com/primitives/docs/components/slider>
|
|
341
|
+
- **shadcn/ui Slider**: <https://ui.shadcn.com/docs/components/slider>
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Spinner
|
|
2
|
+
|
|
3
|
+
Indicador de carga animado basado en Loader2 icon de Lucide. Icono giratorio para estados de loading.
|
|
4
|
+
|
|
5
|
+
## Descripción
|
|
6
|
+
|
|
7
|
+
El componente `Spinner` muestra un indicador de carga animado.
|
|
8
|
+
|
|
9
|
+
## Importación
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { Spinner } from "@adamosuiteservices/ui/spinner";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Anatomía
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
<Spinner />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Componentes**: 1 (Spinner)
|
|
22
|
+
|
|
23
|
+
## Props
|
|
24
|
+
|
|
25
|
+
| Prop | Tipo | Descripción |
|
|
26
|
+
| ----------- | -------- | ------------------------------ |
|
|
27
|
+
| `className` | `string` | Clases CSS para tamaño y color |
|
|
28
|
+
|
|
29
|
+
**Nota**: Acepta todas las props de `<svg>`
|
|
30
|
+
|
|
31
|
+
## Patrones de Uso
|
|
32
|
+
|
|
33
|
+
### Básico
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<Spinner />
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Tamaños
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<Spinner className="size-3" />
|
|
43
|
+
<Spinner className="size-4" /> {/* Default */}
|
|
44
|
+
<Spinner className="size-6" />
|
|
45
|
+
<Spinner className="size-8" />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Colores
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<Spinner className="text-primary" />
|
|
52
|
+
<Spinner className="text-destructive" />
|
|
53
|
+
<Spinner className="text-blue-500" />
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### En Botones
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { Button } from "@adamosuiteservices/ui/button";
|
|
60
|
+
|
|
61
|
+
<Button disabled>
|
|
62
|
+
<Spinner />
|
|
63
|
+
Loading...
|
|
64
|
+
</Button>
|
|
65
|
+
|
|
66
|
+
<Button variant="outline" disabled>
|
|
67
|
+
<Spinner />
|
|
68
|
+
Please wait
|
|
69
|
+
</Button>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Con Estado
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useState } from "react";
|
|
76
|
+
import { Button } from "@adamosuiteservices/ui/button";
|
|
77
|
+
|
|
78
|
+
function App() {
|
|
79
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
80
|
+
|
|
81
|
+
const handleClick = () => {
|
|
82
|
+
setIsLoading(true);
|
|
83
|
+
setTimeout(() => setIsLoading(false), 2000);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Button onClick={handleClick} disabled={isLoading}>
|
|
88
|
+
{isLoading ? (
|
|
89
|
+
<>
|
|
90
|
+
<Spinner />
|
|
91
|
+
Submitting...
|
|
92
|
+
</>
|
|
93
|
+
) : (
|
|
94
|
+
"Submit Form"
|
|
95
|
+
)}
|
|
96
|
+
</Button>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### En Badges
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
import { Badge } from "@adamosuiteservices/ui/badge";
|
|
105
|
+
|
|
106
|
+
<Badge>
|
|
107
|
+
<Spinner />
|
|
108
|
+
Syncing
|
|
109
|
+
</Badge>;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### En Cards
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
import { Card, CardContent } from "@adamosuiteservices/ui/card";
|
|
116
|
+
|
|
117
|
+
<Card>
|
|
118
|
+
<CardContent className="flex items-center space-x-3 p-6">
|
|
119
|
+
<Spinner className="size-5" />
|
|
120
|
+
<span>Processing your payment...</span>
|
|
121
|
+
</CardContent>
|
|
122
|
+
</Card>;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Inline
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
<p>
|
|
129
|
+
Loading data <Spinner className="inline size-4" />
|
|
130
|
+
</p>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Casos de Uso
|
|
134
|
+
|
|
135
|
+
**Button loading**: Estados de carga en botones
|
|
136
|
+
**Badge status**: Indicador de sincronización/procesamiento
|
|
137
|
+
**Inline loading**: Texto con loading inline
|
|
138
|
+
**Cards**: Contenido de cards en proceso
|
|
139
|
+
**Global loading**: Indicadores globales de app
|
|
140
|
+
|
|
141
|
+
## Estilos Base
|
|
142
|
+
|
|
143
|
+
- **Size**: `size-4` default
|
|
144
|
+
- **Animation**: `animate-spin`
|
|
145
|
+
- **Role**: `role="status"`
|
|
146
|
+
- **ARIA**: `aria-label="Loading"`
|
|
147
|
+
|
|
148
|
+
## Accesibilidad
|
|
149
|
+
|
|
150
|
+
- ✅ **Role**: `role="status"`
|
|
151
|
+
- ✅ **ARIA**: `aria-label="Loading"` para screen readers
|
|
152
|
+
- ✅ **Screen readers**: Anuncia estado de carga
|
|
153
|
+
|
|
154
|
+
## Notas de Implementación
|
|
155
|
+
|
|
156
|
+
- **Lucide React**: Usa `Loader2Icon` de lucide-react
|
|
157
|
+
- **Spin animation**: Tailwind `animate-spin`
|
|
158
|
+
- **SVG**: Componente SVG nativo
|
|
159
|
+
- **Customizable**: Tamaño y color via className
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
**No gira**: Verifica `animate-spin` aplicado
|
|
164
|
+
**Muy pequeño/grande**: Ajusta `size-*` en className
|
|
165
|
+
**Color incorrecto**: Usa `text-*` para cambiar color
|
|
166
|
+
**No se ve en button**: Asegúrate de espaciado con gap
|
|
167
|
+
|
|
168
|
+
## Referencias
|
|
169
|
+
|
|
170
|
+
- **Lucide Icons**: <https://lucide.dev/icons/loader-2>
|