@adamosuiteservices/ui 2.11.14 → 2.11.16

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.
Files changed (41) hide show
  1. package/dist/colors.css +1 -1
  2. package/dist/styles.css +1 -1
  3. package/dist/themes.css +1 -1
  4. package/docs/AI-GUIDE.md +321 -321
  5. package/docs/components/layout/sidebar.md +399 -399
  6. package/docs/components/layout/toaster.md +436 -436
  7. package/docs/components/ui/accordion-rounded.md +584 -584
  8. package/docs/components/ui/accordion.md +269 -269
  9. package/docs/components/ui/button-group.md +984 -984
  10. package/docs/components/ui/button.md +1137 -1137
  11. package/docs/components/ui/calendar.md +1159 -1159
  12. package/docs/components/ui/card.md +1455 -1455
  13. package/docs/components/ui/checkbox.md +292 -292
  14. package/docs/components/ui/collapsible.md +323 -323
  15. package/docs/components/ui/command.md +454 -454
  16. package/docs/components/ui/context-menu.md +540 -540
  17. package/docs/components/ui/dialog.md +628 -628
  18. package/docs/components/ui/dropdown-menu.md +709 -709
  19. package/docs/components/ui/field.md +706 -706
  20. package/docs/components/ui/hover-card.md +446 -446
  21. package/docs/components/ui/input.md +362 -362
  22. package/docs/components/ui/kbd.md +434 -434
  23. package/docs/components/ui/label.md +359 -359
  24. package/docs/components/ui/pagination.md +650 -650
  25. package/docs/components/ui/popover.md +536 -536
  26. package/docs/components/ui/progress.md +182 -182
  27. package/docs/components/ui/radio-group.md +311 -311
  28. package/docs/components/ui/select.md +352 -352
  29. package/docs/components/ui/separator.md +214 -214
  30. package/docs/components/ui/sheet.md +142 -142
  31. package/docs/components/ui/skeleton.md +140 -140
  32. package/docs/components/ui/slider.md +341 -341
  33. package/docs/components/ui/spinner.md +170 -170
  34. package/docs/components/ui/switch.md +408 -408
  35. package/docs/components/ui/tabs-underline.md +106 -106
  36. package/docs/components/ui/tabs.md +122 -122
  37. package/docs/components/ui/textarea.md +243 -243
  38. package/docs/components/ui/toggle.md +237 -237
  39. package/docs/components/ui/tooltip.md +317 -317
  40. package/docs/components/ui/typography.md +280 -280
  41. package/package.json +1 -1
@@ -1,341 +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>
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>