@adamosuiteservices/ui 2.13.3 → 2.14.0

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 (66) hide show
  1. package/dist/{button-Bn4LFAa9.js → button-B0lWuG-D.js} +27 -18
  2. package/dist/{button-Day6_fbu.cjs → button-DVrteFz9.cjs} +2 -2
  3. package/dist/button.cjs +1 -1
  4. package/dist/button.js +1 -1
  5. package/dist/{calendar-B1_ybTg0.js → calendar-CfqtuOWv.js} +1 -1
  6. package/dist/{calendar-CZkzHgYi.cjs → calendar-CpUN6BGK.cjs} +1 -1
  7. package/dist/calendar.cjs +1 -1
  8. package/dist/calendar.js +1 -1
  9. package/dist/{combobox-BOi7QzmO.js → combobox-B8HMlZy6.js} +1 -1
  10. package/dist/{combobox-0ndFo07_.cjs → combobox-Btj-hiBy.cjs} +1 -1
  11. package/dist/combobox.cjs +1 -1
  12. package/dist/combobox.js +1 -1
  13. package/dist/components/ui/alert/alert.d.ts +1 -1
  14. package/dist/components/ui/button/button.d.ts +3 -2
  15. package/dist/components/ui/card/card.d.ts +2 -2
  16. package/dist/components/ui/slider/slider.d.ts +2 -2
  17. package/dist/date-picker-selector.cjs +1 -1
  18. package/dist/date-picker-selector.js +3 -3
  19. package/dist/file-upload.cjs +1 -1
  20. package/dist/file-upload.js +1 -1
  21. package/dist/full-screen-loader.cjs +1 -1
  22. package/dist/full-screen-loader.js +1 -1
  23. package/dist/input-group.cjs +1 -1
  24. package/dist/input-group.js +1 -1
  25. package/dist/pagination.cjs +1 -1
  26. package/dist/pagination.js +1 -1
  27. package/dist/sidebar.cjs +1 -1
  28. package/dist/sidebar.js +1 -1
  29. package/dist/slider.cjs +3 -3
  30. package/dist/slider.js +2 -2
  31. package/dist/styles.css +1 -1
  32. package/dist/tabs.cjs +14 -16
  33. package/dist/tabs.js +17 -19
  34. package/docs/AI-GUIDE.md +321 -321
  35. package/docs/components/layout/full-screen-loader.md +2 -2
  36. package/docs/components/layout/sidebar.md +399 -399
  37. package/docs/components/layout/toaster.md +436 -436
  38. package/docs/components/ui/accordion-rounded.md +584 -584
  39. package/docs/components/ui/accordion.md +269 -269
  40. package/docs/components/ui/button.md +35 -23
  41. package/docs/components/ui/calendar.md +1159 -1159
  42. package/docs/components/ui/card.md +1455 -1455
  43. package/docs/components/ui/checkbox.md +292 -292
  44. package/docs/components/ui/collapsible.md +323 -323
  45. package/docs/components/ui/dialog.md +628 -628
  46. package/docs/components/ui/field.md +706 -706
  47. package/docs/components/ui/hover-card.md +446 -446
  48. package/docs/components/ui/kbd.md +434 -434
  49. package/docs/components/ui/label.md +359 -359
  50. package/docs/components/ui/pagination.md +650 -650
  51. package/docs/components/ui/popover.md +536 -536
  52. package/docs/components/ui/progress.md +182 -182
  53. package/docs/components/ui/radio-group.md +311 -311
  54. package/docs/components/ui/separator.md +214 -214
  55. package/docs/components/ui/sheet.md +174 -174
  56. package/docs/components/ui/skeleton.md +140 -140
  57. package/docs/components/ui/slider.md +8 -8
  58. package/docs/components/ui/spinner.md +170 -170
  59. package/docs/components/ui/switch.md +408 -408
  60. package/docs/components/ui/tabs-underline.md +106 -106
  61. package/docs/components/ui/tabs.md +125 -122
  62. package/docs/components/ui/textarea.md +243 -243
  63. package/docs/components/ui/toggle.md +237 -237
  64. package/docs/components/ui/tooltip.md +317 -317
  65. package/docs/components/ui/typography.md +320 -320
  66. package/package.json +1 -1
@@ -1,408 +1,408 @@
1
- # Switch
2
-
3
- Toggle binario on/off. Basado en Radix UI con animación de thumb.
4
-
5
- ## Descripción
6
-
7
- El componente `Switch` es un control de toggle que representa un estado booleano (on/off).
8
-
9
- ## Importación
10
-
11
- ```typescript
12
- import { Switch } from "@adamosuiteservices/ui/switch";
13
- ```
14
-
15
- ## Anatomía
16
-
17
- ```tsx
18
- <Switch />
19
- ```
20
-
21
- **Componentes**: 1 (Switch) con thumb interno
22
-
23
- ## Props
24
-
25
- | Prop | Tipo | Descripción |
26
- | ----------------- | ---------------------------- | ----------------------------- |
27
- | `defaultChecked` | `boolean` | Estado inicial (uncontrolled) |
28
- | `checked` | `boolean` | Estado controlado |
29
- | `onCheckedChange` | `(checked: boolean) => void` | Callback al cambiar |
30
- | `disabled` | `boolean` | Deshabilita el switch |
31
- | `required` | `boolean` | Campo requerido |
32
- | `name` | `string` | Nombre (formularios) |
33
- | `value` | `string` | Valor (formularios) |
34
- | `id` | `string` | ID para asociar con Label |
35
- | `className` | `string` | Clases CSS adicionales |
36
-
37
- **Nota**: Acepta todas las props de Radix UI Switch.Root
38
-
39
- ## Patrones de Uso
40
-
41
- ### Básico
42
-
43
- ```tsx
44
- import { Switch } from "@adamosuiteservices/ui/switch";
45
-
46
- <Switch />;
47
- ```
48
-
49
- ### Con Label
50
-
51
- ```tsx
52
- import { Label } from "@adamosuiteservices/ui/label";
53
-
54
- <div className="flex items-center space-x-2">
55
- <Switch id="airplane-mode" />
56
- <Label htmlFor="airplane-mode">Airplane Mode</Label>
57
- </div>;
58
- ```
59
-
60
- ### Controlado
61
-
62
- ```tsx
63
- import { useState } from "react";
64
-
65
- function App() {
66
- const [isChecked, setIsChecked] = useState(false);
67
-
68
- return (
69
- <div className="flex items-center space-x-2">
70
- <Switch
71
- id="controlled-switch"
72
- checked={isChecked}
73
- onCheckedChange={setIsChecked}
74
- />
75
- <Label htmlFor="controlled-switch">
76
- Notifications {isChecked ? "enabled" : "disabled"}
77
- </Label>
78
- </div>
79
- );
80
- }
81
- ```
82
-
83
- ### Con Iconos y Badges
84
-
85
- ```tsx
86
- import { Icon } from "@adamosuiteservices/ui/icon";
87
- import { Badge } from "@adamosuiteservices/ui/badge";
88
-
89
- function Settings() {
90
- const [settings, setSettings] = useState({
91
- notifications: true,
92
- darkMode: false,
93
- wifi: true,
94
- });
95
-
96
- return (
97
- <div className="space-y-4">
98
- <div className="flex items-center space-x-3">
99
- <Icon
100
- symbol="notifications"
101
- className="text-lg text-muted-foreground"
102
- />
103
- <Switch
104
- checked={settings.notifications}
105
- onCheckedChange={(checked) =>
106
- setSettings((prev) => ({ ...prev, notifications: checked }))
107
- }
108
- />
109
- <Label>Notifications</Label>
110
- <Badge variant={settings.notifications ? "default" : "secondary"}>
111
- {settings.notifications ? "On" : "Off"}
112
- </Badge>
113
- </div>
114
-
115
- <div className="flex items-center space-x-3">
116
- <Icon symbol="dark_mode" className="text-lg text-muted-foreground" />
117
- <Switch
118
- checked={settings.darkMode}
119
- onCheckedChange={(checked) =>
120
- setSettings((prev) => ({ ...prev, darkMode: checked }))
121
- }
122
- />
123
- <Label>Dark Mode</Label>
124
- <Badge variant={settings.darkMode ? "default" : "secondary"}>
125
- {settings.darkMode ? "On" : "Off"}
126
- </Badge>
127
- </div>
128
- </div>
129
- );
130
- }
131
- ```
132
-
133
- ### Device Controls
134
-
135
- ```tsx
136
- import {
137
- Card,
138
- CardContent,
139
- CardDescription,
140
- CardHeader,
141
- CardTitle,
142
- } from "@adamosuiteservices/ui/card";
143
- import { Icon } from "@adamosuiteservices/ui/icon";
144
-
145
- function ControlCenter() {
146
- const [deviceSettings, setDeviceSettings] = useState({
147
- airplaneMode: false,
148
- wifi: true,
149
- bluetooth: false,
150
- });
151
-
152
- const updateSetting = (key: keyof typeof deviceSettings) => {
153
- setDeviceSettings((prev) => ({ ...prev, [key]: !prev[key] }));
154
- };
155
-
156
- return (
157
- <Card className="w-full max-w-sm">
158
- <CardHeader>
159
- <CardTitle>Control Center</CardTitle>
160
- <CardDescription>Quick access to device settings</CardDescription>
161
- </CardHeader>
162
- <CardContent className="space-y-4">
163
- <div className="grid grid-cols-2 gap-4">
164
- <div className="flex flex-col items-center space-y-2 p-3 border rounded-lg">
165
- <Icon symbol="flight" className="text-2xl text-muted-foreground" />
166
- <span className="text-sm font-medium">Airplane</span>
167
- <Switch
168
- checked={deviceSettings.airplaneMode}
169
- onCheckedChange={() => updateSetting("airplaneMode")}
170
- className="scale-75"
171
- />
172
- </div>
173
-
174
- <div className="flex flex-col items-center space-y-2 p-3 border rounded-lg">
175
- <Icon symbol="wifi" className="text-2xl text-muted-foreground" />
176
- <span className="text-sm font-medium">Wi-Fi</span>
177
- <Switch
178
- checked={deviceSettings.wifi}
179
- onCheckedChange={() => updateSetting("wifi")}
180
- className="scale-75"
181
- />
182
- </div>
183
-
184
- <div className="flex flex-col items-center space-y-2 p-3 border rounded-lg">
185
- <Icon
186
- symbol="bluetooth"
187
- className="text-2xl text-muted-foreground"
188
- />
189
- <span className="text-sm font-medium">Bluetooth</span>
190
- <Switch
191
- checked={deviceSettings.bluetooth}
192
- onCheckedChange={() => updateSetting("bluetooth")}
193
- className="scale-75"
194
- />
195
- </div>
196
- </div>
197
- </CardContent>
198
- </Card>
199
- );
200
- }
201
- ```
202
-
203
- ### Privacy Settings
204
-
205
- ```tsx
206
- import { Icon } from "@adamosuiteservices/ui/icon";
207
- import { Button } from "@adamosuiteservices/ui/button";
208
-
209
- function PrivacySettings() {
210
- const [privacySettings, setPrivacySettings] = useState({
211
- locationServices: true,
212
- analyticsData: false,
213
- crashReports: true,
214
- personalizedAds: false,
215
- });
216
-
217
- return (
218
- <Card className="w-full max-w-lg">
219
- <CardHeader>
220
- <CardTitle className="flex items-center space-x-2">
221
- <Icon symbol="shield" className="text-xl" />
222
- <span>Privacy & Security</span>
223
- </CardTitle>
224
- <CardDescription>
225
- Control how your data is collected and used
226
- </CardDescription>
227
- </CardHeader>
228
- <CardContent className="space-y-6">
229
- <div className="space-y-4">
230
- <div className="flex items-start justify-between space-x-4">
231
- <div className="flex-1">
232
- <Label className="text-sm font-medium">Location Services</Label>
233
- <p className="text-xs text-muted-foreground mt-1">
234
- Allow apps to access your location for personalized experiences
235
- </p>
236
- </div>
237
- <Switch
238
- checked={privacySettings.locationServices}
239
- onCheckedChange={(checked) =>
240
- setPrivacySettings((prev) => ({
241
- ...prev,
242
- locationServices: checked,
243
- }))
244
- }
245
- />
246
- </div>
247
-
248
- <div className="flex items-start justify-between space-x-4">
249
- <div className="flex-1">
250
- <Label className="text-sm font-medium">
251
- Analytics & Diagnostics
252
- </Label>
253
- <p className="text-xs text-muted-foreground mt-1">
254
- Share analytics data to help improve our products
255
- </p>
256
- </div>
257
- <Switch
258
- checked={privacySettings.analyticsData}
259
- onCheckedChange={(checked) =>
260
- setPrivacySettings((prev) => ({
261
- ...prev,
262
- analyticsData: checked,
263
- }))
264
- }
265
- />
266
- </div>
267
- </div>
268
-
269
- <div className="flex justify-end space-x-2 pt-4 border-t">
270
- <Button variant="outline" size="sm">
271
- Reset to Defaults
272
- </Button>
273
- <Button size="sm">Save Changes</Button>
274
- </div>
275
- </CardContent>
276
- </Card>
277
- );
278
- }
279
- ```
280
-
281
- ### Feature Toggles
282
-
283
- ```tsx
284
- function FeatureToggles() {
285
- const [features, setFeatures] = useState({
286
- newDashboard: false,
287
- betaFeatures: false,
288
- experimentalUI: false,
289
- });
290
-
291
- const updateFeature = (key: keyof typeof features) => {
292
- setFeatures((prev) => ({ ...prev, [key]: !prev[key] }));
293
- };
294
-
295
- return (
296
- <Card className="w-full max-w-lg">
297
- <CardHeader>
298
- <CardTitle>Feature Toggles</CardTitle>
299
- <CardDescription>
300
- Enable or disable experimental features
301
- </CardDescription>
302
- </CardHeader>
303
- <CardContent className="space-y-4">
304
- <div className="flex items-start justify-between space-x-4 p-3 border rounded-lg">
305
- <div className="flex-1 space-y-1">
306
- <div className="flex items-center space-x-2">
307
- <Label className="text-sm font-medium">New Dashboard</Label>
308
- <Badge variant="default" className="text-xs">
309
- New
310
- </Badge>
311
- </div>
312
- <p className="text-xs text-muted-foreground">
313
- Try our redesigned dashboard interface
314
- </p>
315
- </div>
316
- <Switch
317
- checked={features.newDashboard}
318
- onCheckedChange={() => updateFeature("newDashboard")}
319
- />
320
- </div>
321
-
322
- <div className="flex items-start justify-between space-x-4 p-3 border rounded-lg">
323
- <div className="flex-1 space-y-1">
324
- <div className="flex items-center space-x-2">
325
- <Label className="text-sm font-medium">Beta Features</Label>
326
- <Badge variant="secondary" className="text-xs">
327
- Beta
328
- </Badge>
329
- </div>
330
- <p className="text-xs text-muted-foreground">
331
- Access features currently in beta testing
332
- </p>
333
- </div>
334
- <Switch
335
- checked={features.betaFeatures}
336
- onCheckedChange={() => updateFeature("betaFeatures")}
337
- />
338
- </div>
339
- </CardContent>
340
- </Card>
341
- );
342
- }
343
- ```
344
-
345
- ### Deshabilitado
346
-
347
- ```tsx
348
- <div className="space-y-4">
349
- <div className="flex items-center space-x-2">
350
- <Switch disabled />
351
- <Label className="text-muted-foreground">Disabled (off)</Label>
352
- </div>
353
- <div className="flex items-center space-x-2">
354
- <Switch disabled checked />
355
- <Label className="text-muted-foreground">Disabled (on)</Label>
356
- </div>
357
- </div>
358
- ```
359
-
360
- ## Casos de Uso
361
-
362
- **Settings**: On/off toggles para configuración
363
- **Feature flags**: Activar/desactivar features
364
- **Notifications**: Habilitar/deshabilitar notificaciones
365
- **Privacy**: Controles de privacidad y permisos
366
- **Device controls**: Wi-Fi, Bluetooth, Airplane mode
367
- **Filters**: Mostrar/ocultar contenido
368
-
369
- ## Estilos Base
370
-
371
- - **Size**: `h-5 w-8`
372
- - **Checked bg**: `bg-primary`
373
- - **Unchecked bg**: `bg-input` (dark: `bg-input/80`)
374
- - **Thumb**: `size-4` con `bg-background`
375
- - **Thumb checked**: `translate-x-[calc(100%-2px)]`
376
- - **Thumb unchecked**: `translate-x-0`
377
- - **Focus**: `ring-ring/50` con `ring-[3px]`
378
- - **Transition**: `transition-all` en thumb y background
379
-
380
- ## Accesibilidad
381
-
382
- - ✅ **Role**: `role="switch"` con `aria-checked`
383
- - ✅ **Keyboard**: Space/Enter para toggle
384
- - ✅ **Focus**: Focus ring visible
385
- - ✅ **Label**: Asociar con `htmlFor` e `id`
386
- - ✅ **State**: Screen readers anuncian checked/unchecked
387
-
388
- ## Notas de Implementación
389
-
390
- - **Radix UI**: Basado en `@radix-ui/react-switch`
391
- - **Peer class**: Usa `peer` para estilos relacionados con Label
392
- - **Data states**: `data-state="checked|unchecked"` para estilos
393
- - **Controlled**: Usa `checked` + `onCheckedChange`
394
- - **Uncontrolled**: Usa `defaultChecked`
395
- - **Dark mode**: Thumb color cambia automáticamente
396
-
397
- ## Troubleshooting
398
-
399
- **No cambia estado**: En modo controlado usa `checked` + `onCheckedChange`, no `defaultChecked`
400
- **Label no clickeable**: Asegura `htmlFor` en Label coincida con `id` del Switch
401
- **Thumb no anima**: Verifica que estilos de `transition-transform` no estén sobrescritos
402
- **Color incorrecto**: Switch usa `bg-primary` checked, `bg-input` unchecked
403
- **Disabled no funciona**: Prop `disabled` deshabilita interacción
404
-
405
- ## Referencias
406
-
407
- - **Radix UI Switch**: <https://www.radix-ui.com/primitives/docs/components/switch>
408
- - **shadcn/ui Switch**: <https://ui.shadcn.com/docs/components/switch>
1
+ # Switch
2
+
3
+ Toggle binario on/off. Basado en Radix UI con animación de thumb.
4
+
5
+ ## Descripción
6
+
7
+ El componente `Switch` es un control de toggle que representa un estado booleano (on/off).
8
+
9
+ ## Importación
10
+
11
+ ```typescript
12
+ import { Switch } from "@adamosuiteservices/ui/switch";
13
+ ```
14
+
15
+ ## Anatomía
16
+
17
+ ```tsx
18
+ <Switch />
19
+ ```
20
+
21
+ **Componentes**: 1 (Switch) con thumb interno
22
+
23
+ ## Props
24
+
25
+ | Prop | Tipo | Descripción |
26
+ | ----------------- | ---------------------------- | ----------------------------- |
27
+ | `defaultChecked` | `boolean` | Estado inicial (uncontrolled) |
28
+ | `checked` | `boolean` | Estado controlado |
29
+ | `onCheckedChange` | `(checked: boolean) => void` | Callback al cambiar |
30
+ | `disabled` | `boolean` | Deshabilita el switch |
31
+ | `required` | `boolean` | Campo requerido |
32
+ | `name` | `string` | Nombre (formularios) |
33
+ | `value` | `string` | Valor (formularios) |
34
+ | `id` | `string` | ID para asociar con Label |
35
+ | `className` | `string` | Clases CSS adicionales |
36
+
37
+ **Nota**: Acepta todas las props de Radix UI Switch.Root
38
+
39
+ ## Patrones de Uso
40
+
41
+ ### Básico
42
+
43
+ ```tsx
44
+ import { Switch } from "@adamosuiteservices/ui/switch";
45
+
46
+ <Switch />;
47
+ ```
48
+
49
+ ### Con Label
50
+
51
+ ```tsx
52
+ import { Label } from "@adamosuiteservices/ui/label";
53
+
54
+ <div className="flex items-center space-x-2">
55
+ <Switch id="airplane-mode" />
56
+ <Label htmlFor="airplane-mode">Airplane Mode</Label>
57
+ </div>;
58
+ ```
59
+
60
+ ### Controlado
61
+
62
+ ```tsx
63
+ import { useState } from "react";
64
+
65
+ function App() {
66
+ const [isChecked, setIsChecked] = useState(false);
67
+
68
+ return (
69
+ <div className="flex items-center space-x-2">
70
+ <Switch
71
+ id="controlled-switch"
72
+ checked={isChecked}
73
+ onCheckedChange={setIsChecked}
74
+ />
75
+ <Label htmlFor="controlled-switch">
76
+ Notifications {isChecked ? "enabled" : "disabled"}
77
+ </Label>
78
+ </div>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ### Con Iconos y Badges
84
+
85
+ ```tsx
86
+ import { Icon } from "@adamosuiteservices/ui/icon";
87
+ import { Badge } from "@adamosuiteservices/ui/badge";
88
+
89
+ function Settings() {
90
+ const [settings, setSettings] = useState({
91
+ notifications: true,
92
+ darkMode: false,
93
+ wifi: true,
94
+ });
95
+
96
+ return (
97
+ <div className="space-y-4">
98
+ <div className="flex items-center space-x-3">
99
+ <Icon
100
+ symbol="notifications"
101
+ className="text-lg text-muted-foreground"
102
+ />
103
+ <Switch
104
+ checked={settings.notifications}
105
+ onCheckedChange={(checked) =>
106
+ setSettings((prev) => ({ ...prev, notifications: checked }))
107
+ }
108
+ />
109
+ <Label>Notifications</Label>
110
+ <Badge variant={settings.notifications ? "default" : "secondary"}>
111
+ {settings.notifications ? "On" : "Off"}
112
+ </Badge>
113
+ </div>
114
+
115
+ <div className="flex items-center space-x-3">
116
+ <Icon symbol="dark_mode" className="text-lg text-muted-foreground" />
117
+ <Switch
118
+ checked={settings.darkMode}
119
+ onCheckedChange={(checked) =>
120
+ setSettings((prev) => ({ ...prev, darkMode: checked }))
121
+ }
122
+ />
123
+ <Label>Dark Mode</Label>
124
+ <Badge variant={settings.darkMode ? "default" : "secondary"}>
125
+ {settings.darkMode ? "On" : "Off"}
126
+ </Badge>
127
+ </div>
128
+ </div>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### Device Controls
134
+
135
+ ```tsx
136
+ import {
137
+ Card,
138
+ CardContent,
139
+ CardDescription,
140
+ CardHeader,
141
+ CardTitle,
142
+ } from "@adamosuiteservices/ui/card";
143
+ import { Icon } from "@adamosuiteservices/ui/icon";
144
+
145
+ function ControlCenter() {
146
+ const [deviceSettings, setDeviceSettings] = useState({
147
+ airplaneMode: false,
148
+ wifi: true,
149
+ bluetooth: false,
150
+ });
151
+
152
+ const updateSetting = (key: keyof typeof deviceSettings) => {
153
+ setDeviceSettings((prev) => ({ ...prev, [key]: !prev[key] }));
154
+ };
155
+
156
+ return (
157
+ <Card className="w-full max-w-sm">
158
+ <CardHeader>
159
+ <CardTitle>Control Center</CardTitle>
160
+ <CardDescription>Quick access to device settings</CardDescription>
161
+ </CardHeader>
162
+ <CardContent className="space-y-4">
163
+ <div className="grid grid-cols-2 gap-4">
164
+ <div className="flex flex-col items-center space-y-2 p-3 border rounded-lg">
165
+ <Icon symbol="flight" className="text-2xl text-muted-foreground" />
166
+ <span className="text-sm font-medium">Airplane</span>
167
+ <Switch
168
+ checked={deviceSettings.airplaneMode}
169
+ onCheckedChange={() => updateSetting("airplaneMode")}
170
+ className="scale-75"
171
+ />
172
+ </div>
173
+
174
+ <div className="flex flex-col items-center space-y-2 p-3 border rounded-lg">
175
+ <Icon symbol="wifi" className="text-2xl text-muted-foreground" />
176
+ <span className="text-sm font-medium">Wi-Fi</span>
177
+ <Switch
178
+ checked={deviceSettings.wifi}
179
+ onCheckedChange={() => updateSetting("wifi")}
180
+ className="scale-75"
181
+ />
182
+ </div>
183
+
184
+ <div className="flex flex-col items-center space-y-2 p-3 border rounded-lg">
185
+ <Icon
186
+ symbol="bluetooth"
187
+ className="text-2xl text-muted-foreground"
188
+ />
189
+ <span className="text-sm font-medium">Bluetooth</span>
190
+ <Switch
191
+ checked={deviceSettings.bluetooth}
192
+ onCheckedChange={() => updateSetting("bluetooth")}
193
+ className="scale-75"
194
+ />
195
+ </div>
196
+ </div>
197
+ </CardContent>
198
+ </Card>
199
+ );
200
+ }
201
+ ```
202
+
203
+ ### Privacy Settings
204
+
205
+ ```tsx
206
+ import { Icon } from "@adamosuiteservices/ui/icon";
207
+ import { Button } from "@adamosuiteservices/ui/button";
208
+
209
+ function PrivacySettings() {
210
+ const [privacySettings, setPrivacySettings] = useState({
211
+ locationServices: true,
212
+ analyticsData: false,
213
+ crashReports: true,
214
+ personalizedAds: false,
215
+ });
216
+
217
+ return (
218
+ <Card className="w-full max-w-lg">
219
+ <CardHeader>
220
+ <CardTitle className="flex items-center space-x-2">
221
+ <Icon symbol="shield" className="text-xl" />
222
+ <span>Privacy & Security</span>
223
+ </CardTitle>
224
+ <CardDescription>
225
+ Control how your data is collected and used
226
+ </CardDescription>
227
+ </CardHeader>
228
+ <CardContent className="space-y-6">
229
+ <div className="space-y-4">
230
+ <div className="flex items-start justify-between space-x-4">
231
+ <div className="flex-1">
232
+ <Label className="text-sm font-medium">Location Services</Label>
233
+ <p className="text-xs text-muted-foreground mt-1">
234
+ Allow apps to access your location for personalized experiences
235
+ </p>
236
+ </div>
237
+ <Switch
238
+ checked={privacySettings.locationServices}
239
+ onCheckedChange={(checked) =>
240
+ setPrivacySettings((prev) => ({
241
+ ...prev,
242
+ locationServices: checked,
243
+ }))
244
+ }
245
+ />
246
+ </div>
247
+
248
+ <div className="flex items-start justify-between space-x-4">
249
+ <div className="flex-1">
250
+ <Label className="text-sm font-medium">
251
+ Analytics & Diagnostics
252
+ </Label>
253
+ <p className="text-xs text-muted-foreground mt-1">
254
+ Share analytics data to help improve our products
255
+ </p>
256
+ </div>
257
+ <Switch
258
+ checked={privacySettings.analyticsData}
259
+ onCheckedChange={(checked) =>
260
+ setPrivacySettings((prev) => ({
261
+ ...prev,
262
+ analyticsData: checked,
263
+ }))
264
+ }
265
+ />
266
+ </div>
267
+ </div>
268
+
269
+ <div className="flex justify-end space-x-2 pt-4 border-t">
270
+ <Button variant="outline" size="sm">
271
+ Reset to Defaults
272
+ </Button>
273
+ <Button size="sm">Save Changes</Button>
274
+ </div>
275
+ </CardContent>
276
+ </Card>
277
+ );
278
+ }
279
+ ```
280
+
281
+ ### Feature Toggles
282
+
283
+ ```tsx
284
+ function FeatureToggles() {
285
+ const [features, setFeatures] = useState({
286
+ newDashboard: false,
287
+ betaFeatures: false,
288
+ experimentalUI: false,
289
+ });
290
+
291
+ const updateFeature = (key: keyof typeof features) => {
292
+ setFeatures((prev) => ({ ...prev, [key]: !prev[key] }));
293
+ };
294
+
295
+ return (
296
+ <Card className="w-full max-w-lg">
297
+ <CardHeader>
298
+ <CardTitle>Feature Toggles</CardTitle>
299
+ <CardDescription>
300
+ Enable or disable experimental features
301
+ </CardDescription>
302
+ </CardHeader>
303
+ <CardContent className="space-y-4">
304
+ <div className="flex items-start justify-between space-x-4 p-3 border rounded-lg">
305
+ <div className="flex-1 space-y-1">
306
+ <div className="flex items-center space-x-2">
307
+ <Label className="text-sm font-medium">New Dashboard</Label>
308
+ <Badge variant="default" className="text-xs">
309
+ New
310
+ </Badge>
311
+ </div>
312
+ <p className="text-xs text-muted-foreground">
313
+ Try our redesigned dashboard interface
314
+ </p>
315
+ </div>
316
+ <Switch
317
+ checked={features.newDashboard}
318
+ onCheckedChange={() => updateFeature("newDashboard")}
319
+ />
320
+ </div>
321
+
322
+ <div className="flex items-start justify-between space-x-4 p-3 border rounded-lg">
323
+ <div className="flex-1 space-y-1">
324
+ <div className="flex items-center space-x-2">
325
+ <Label className="text-sm font-medium">Beta Features</Label>
326
+ <Badge variant="secondary" className="text-xs">
327
+ Beta
328
+ </Badge>
329
+ </div>
330
+ <p className="text-xs text-muted-foreground">
331
+ Access features currently in beta testing
332
+ </p>
333
+ </div>
334
+ <Switch
335
+ checked={features.betaFeatures}
336
+ onCheckedChange={() => updateFeature("betaFeatures")}
337
+ />
338
+ </div>
339
+ </CardContent>
340
+ </Card>
341
+ );
342
+ }
343
+ ```
344
+
345
+ ### Deshabilitado
346
+
347
+ ```tsx
348
+ <div className="space-y-4">
349
+ <div className="flex items-center space-x-2">
350
+ <Switch disabled />
351
+ <Label className="text-muted-foreground">Disabled (off)</Label>
352
+ </div>
353
+ <div className="flex items-center space-x-2">
354
+ <Switch disabled checked />
355
+ <Label className="text-muted-foreground">Disabled (on)</Label>
356
+ </div>
357
+ </div>
358
+ ```
359
+
360
+ ## Casos de Uso
361
+
362
+ **Settings**: On/off toggles para configuración
363
+ **Feature flags**: Activar/desactivar features
364
+ **Notifications**: Habilitar/deshabilitar notificaciones
365
+ **Privacy**: Controles de privacidad y permisos
366
+ **Device controls**: Wi-Fi, Bluetooth, Airplane mode
367
+ **Filters**: Mostrar/ocultar contenido
368
+
369
+ ## Estilos Base
370
+
371
+ - **Size**: `h-5 w-8`
372
+ - **Checked bg**: `bg-primary`
373
+ - **Unchecked bg**: `bg-input` (dark: `bg-input/80`)
374
+ - **Thumb**: `size-4` con `bg-background`
375
+ - **Thumb checked**: `translate-x-[calc(100%-2px)]`
376
+ - **Thumb unchecked**: `translate-x-0`
377
+ - **Focus**: `ring-ring/50` con `ring-[3px]`
378
+ - **Transition**: `transition-all` en thumb y background
379
+
380
+ ## Accesibilidad
381
+
382
+ - ✅ **Role**: `role="switch"` con `aria-checked`
383
+ - ✅ **Keyboard**: Space/Enter para toggle
384
+ - ✅ **Focus**: Focus ring visible
385
+ - ✅ **Label**: Asociar con `htmlFor` e `id`
386
+ - ✅ **State**: Screen readers anuncian checked/unchecked
387
+
388
+ ## Notas de Implementación
389
+
390
+ - **Radix UI**: Basado en `@radix-ui/react-switch`
391
+ - **Peer class**: Usa `peer` para estilos relacionados con Label
392
+ - **Data states**: `data-state="checked|unchecked"` para estilos
393
+ - **Controlled**: Usa `checked` + `onCheckedChange`
394
+ - **Uncontrolled**: Usa `defaultChecked`
395
+ - **Dark mode**: Thumb color cambia automáticamente
396
+
397
+ ## Troubleshooting
398
+
399
+ **No cambia estado**: En modo controlado usa `checked` + `onCheckedChange`, no `defaultChecked`
400
+ **Label no clickeable**: Asegura `htmlFor` en Label coincida con `id` del Switch
401
+ **Thumb no anima**: Verifica que estilos de `transition-transform` no estén sobrescritos
402
+ **Color incorrecto**: Switch usa `bg-primary` checked, `bg-input` unchecked
403
+ **Disabled no funciona**: Prop `disabled` deshabilita interacción
404
+
405
+ ## Referencias
406
+
407
+ - **Radix UI Switch**: <https://www.radix-ui.com/primitives/docs/components/switch>
408
+ - **shadcn/ui Switch**: <https://ui.shadcn.com/docs/components/switch>