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