@adamosuiteservices/ui 2.13.1 → 2.13.3

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 (46) hide show
  1. package/dist/components/ui/file-upload/file-upload.d.ts +11 -3
  2. package/dist/components/ui/slider/slider.d.ts +5 -2
  3. package/dist/components/ui/typography/typography.d.ts +1 -1
  4. package/dist/file-upload.cjs +6 -18
  5. package/dist/file-upload.js +264 -134
  6. package/dist/slider.cjs +6 -7
  7. package/dist/slider.js +191 -177
  8. package/dist/styles.css +1 -1
  9. package/dist/typography-Bj8oEDuE.cjs +1 -0
  10. package/dist/typography-MnY0LQoZ.js +50 -0
  11. package/dist/typography.cjs +1 -1
  12. package/dist/typography.js +1 -1
  13. package/docs/AI-GUIDE.md +321 -321
  14. package/docs/components/layout/sidebar.md +399 -399
  15. package/docs/components/layout/toaster.md +436 -436
  16. package/docs/components/ui/accordion-rounded.md +584 -584
  17. package/docs/components/ui/accordion.md +269 -269
  18. package/docs/components/ui/calendar.md +1159 -1159
  19. package/docs/components/ui/card.md +1455 -1455
  20. package/docs/components/ui/checkbox.md +292 -292
  21. package/docs/components/ui/collapsible.md +323 -323
  22. package/docs/components/ui/dialog.md +628 -628
  23. package/docs/components/ui/field.md +706 -706
  24. package/docs/components/ui/file-upload.md +475 -66
  25. package/docs/components/ui/hover-card.md +446 -446
  26. package/docs/components/ui/kbd.md +434 -434
  27. package/docs/components/ui/label.md +359 -359
  28. package/docs/components/ui/pagination.md +650 -650
  29. package/docs/components/ui/popover.md +536 -536
  30. package/docs/components/ui/progress.md +182 -182
  31. package/docs/components/ui/radio-group.md +311 -311
  32. package/docs/components/ui/separator.md +214 -214
  33. package/docs/components/ui/sheet.md +174 -174
  34. package/docs/components/ui/skeleton.md +140 -140
  35. package/docs/components/ui/slider.md +460 -341
  36. package/docs/components/ui/spinner.md +170 -170
  37. package/docs/components/ui/switch.md +408 -408
  38. package/docs/components/ui/tabs-underline.md +106 -106
  39. package/docs/components/ui/tabs.md +122 -122
  40. package/docs/components/ui/textarea.md +243 -243
  41. package/docs/components/ui/toggle.md +237 -237
  42. package/docs/components/ui/tooltip.md +317 -317
  43. package/docs/components/ui/typography.md +320 -280
  44. package/package.json +1 -1
  45. package/dist/typography-9EoV0kcN.js +0 -44
  46. package/dist/typography-DqQZZpkD.cjs +0 -1
@@ -1,292 +1,292 @@
1
- # Checkbox
2
-
3
- Checkbox basado en Radix UI con 3 estados (checked, unchecked, indeterminate), validación con `aria-invalid`, focus ring, y estado disabled.
4
-
5
- ## Importación
6
-
7
- ```tsx
8
- import { Checkbox } from "@adamosuiteservices/ui/checkbox";
9
- import { Label } from "@adamosuiteservices/ui/label";
10
- ```
11
-
12
- ## Anatomía
13
-
14
- ```tsx
15
- // Componente único, sin subcomponentes
16
- <Checkbox />
17
-
18
- // Con label (patrón recomendado)
19
- <div className="flex items-center gap-3">
20
- <Checkbox id="terms" />
21
- <Label htmlFor="terms">Accept terms</Label>
22
- </div>
23
- ```
24
-
25
- ## Props Principales
26
-
27
- | Prop | Tipo | Default | Descripción |
28
- | ----------------- | ----------------------------------------------- | ------- | -------------------------------------------- |
29
- | `checked` | `boolean \| "indeterminate"` | - | Estado controlado (true/false/indeterminate) |
30
- | `defaultChecked` | `boolean` | `false` | Estado inicial no controlado |
31
- | `onCheckedChange` | `(checked: boolean \| "indeterminate") => void` | - | Callback al cambiar estado |
32
- | `disabled` | `boolean` | `false` | Desactiva interacción |
33
- | `required` | `boolean` | `false` | Campo requerido (HTML5) |
34
- | `name` | `string` | - | Nombre para formularios |
35
- | `value` | `string` | `"on"` | Valor para formularios |
36
- | `aria-invalid` | `boolean` | `false` | Muestra estado error (border rojo + ring) |
37
- | `className` | `string` | - | Clases CSS adicionales |
38
-
39
- ## Estados del Checkbox
40
-
41
- ### 1. Unchecked (Default)
42
-
43
- ```tsx
44
- <Checkbox />
45
- ```
46
-
47
- ### 2. Checked
48
-
49
- ```tsx
50
- // No controlado
51
- <Checkbox defaultChecked />;
52
-
53
- // Controlado
54
- const [checked, setChecked] = useState(true);
55
- <Checkbox checked={checked} onCheckedChange={setChecked} />;
56
- ```
57
-
58
- ### 3. Indeterminate
59
-
60
- Estado especial para "select all" cuando algunos items están seleccionados.
61
-
62
- ```tsx
63
- <Checkbox checked="indeterminate" />;
64
-
65
- // Ejemplo práctico
66
- const allChecked = items.every(Boolean);
67
- const someChecked = items.some(Boolean) && !allChecked;
68
-
69
- <Checkbox
70
- checked={allChecked ? true : someChecked ? "indeterminate" : false}
71
- onCheckedChange={(checked) => setItems(items.map(() => checked === true))}
72
- />;
73
- ```
74
-
75
- **Visual**: Muestra un icono de guión (`MinusIcon`) en lugar de check.
76
-
77
- ### 4. Disabled
78
-
79
- ```tsx
80
- <Checkbox disabled />
81
- <Checkbox disabled defaultChecked />
82
- ```
83
-
84
- **Estilos**: `opacity-50` + `cursor-not-allowed`
85
-
86
- ### 5. Invalid (Error State)
87
-
88
- ```tsx
89
- <Checkbox aria-invalid />
90
- ```
91
-
92
- **Estilos**: Border rojo (`border-destructive`) + ring rojo (`ring-destructive/20`)
93
-
94
- ## Patrones de Uso
95
-
96
- ### Con Label Simple
97
-
98
- ```tsx
99
- <div className="flex items-center gap-3">
100
- <Checkbox id="notifications" />
101
- <Label htmlFor="notifications">Enable notifications</Label>
102
- </div>
103
- ```
104
-
105
- ### Con Label y Descripción
106
-
107
- ```tsx
108
- <div className="flex items-start gap-3">
109
- <Checkbox id="marketing" />
110
- <div className="grid gap-1">
111
- <Label htmlFor="marketing">Marketing emails</Label>
112
- <p className="text-sm text-muted-foreground">
113
- Receive updates about new products
114
- </p>
115
- </div>
116
- </div>
117
- ```
118
-
119
- ### Lista de Opciones
120
-
121
- ```tsx
122
- const options = ["Email", "SMS", "Push"];
123
-
124
- <div className="space-y-4">
125
- {options.map((option) => (
126
- <div key={option} className="flex items-center gap-3">
127
- <Checkbox id={option.toLowerCase()} />
128
- <Label htmlFor={option.toLowerCase()}>{option} notifications</Label>
129
- </div>
130
- ))}
131
- </div>;
132
- ```
133
-
134
- ### Select All con Indeterminate
135
-
136
- ```tsx
137
- const [items, setItems] = useState([false, true, false]);
138
- const allChecked = items.every(Boolean);
139
- const isIndeterminate = items.some(Boolean) && !allChecked;
140
-
141
- <div className="space-y-4">
142
- {/* Parent checkbox */}
143
- <div className="flex items-center gap-3">
144
- <Checkbox
145
- checked={allChecked ? true : isIndeterminate ? "indeterminate" : false}
146
- onCheckedChange={(checked) => setItems(items.map(() => checked === true))}
147
- />
148
- <Label className="font-medium">Select all</Label>
149
- </div>
150
-
151
- {/* Child checkboxes */}
152
- <div className="ml-6 space-y-3">
153
- {items.map((checked, i) => (
154
- <div key={i} className="flex items-center gap-3">
155
- <Checkbox
156
- checked={checked}
157
- onCheckedChange={(newChecked) => {
158
- const newItems = [...items];
159
- newItems[i] = newChecked as boolean;
160
- setItems(newItems);
161
- }}
162
- />
163
- <Label>Item {i + 1}</Label>
164
- </div>
165
- ))}
166
- </div>
167
- </div>;
168
- ```
169
-
170
- ### Card/Button Style
171
-
172
- Para checkboxes clickeables como botones.
173
-
174
- ```tsx
175
- <Label className="flex items-start gap-3 rounded-lg border p-4 cursor-pointer hover:bg-accent/50 has-aria-checked:border-primary has-aria-checked:bg-primary/5 transition-colors">
176
- <Checkbox id="card-option" />
177
- <div className="grid gap-1.5">
178
- <p className="text-sm font-medium">Enable feature</p>
179
- <p className="text-sm text-muted-foreground">Description</p>
180
- </div>
181
- </Label>
182
- ```
183
-
184
- **Nota**: `has-aria-checked` detecta cuando el checkbox está checked para estilos.
185
-
186
- ### Formulario de Preferencias
187
-
188
- ```tsx
189
- function PreferencesForm() {
190
- const [prefs, setPrefs] = useState({
191
- marketing: false,
192
- analytics: true,
193
- social: false,
194
- });
195
-
196
- return (
197
- <form className="space-y-4">
198
- {Object.entries(prefs).map(([key, value]) => (
199
- <div key={key} className="flex items-center gap-3">
200
- <Checkbox
201
- id={key}
202
- checked={value}
203
- onCheckedChange={(checked) =>
204
- setPrefs((prev) => ({ ...prev, [key]: checked as boolean }))
205
- }
206
- />
207
- <Label htmlFor={key}>{key} preferences</Label>
208
- </div>
209
- ))}
210
- <Button type="submit">Save</Button>
211
- </form>
212
- );
213
- }
214
- ```
215
-
216
- ### Terms & Conditions
217
-
218
- ```tsx
219
- const [agreed, setAgreed] = useState(false);
220
-
221
- <div className="flex items-start gap-3">
222
- <Checkbox
223
- id="terms"
224
- checked={agreed}
225
- onCheckedChange={(checked) => setAgreed(checked as boolean)}
226
- aria-invalid={!agreed}
227
- />
228
- <Label htmlFor="terms" className="text-sm">
229
- I agree to the{" "}
230
- <a href="/terms" className="underline">terms and conditions</a>
231
- </Label>
232
- </div>
233
- <Button disabled={!agreed}>Continue</Button>
234
- ```
235
-
236
- ## Estilos Internos (Data Attributes)
237
-
238
- ### Estados Visuales
239
-
240
- - **Checked**: `data-[state=checked]` → `bg-primary`, `text-primary-foreground`, `border-primary`
241
- - **Unchecked**: Default → `border-input`, `bg-transparent` (dark: `bg-input/30`)
242
- - **Indeterminate**: `data-[state=indeterminate]` → Muestra `MinusIcon` en lugar de `CheckIcon`
243
- - **Focus**: `focus-visible:ring-[3px]`, `focus-visible:ring-ring/50`, `focus-visible:border-ring`
244
- - **Invalid**: `aria-invalid:border-destructive`, `aria-invalid:ring-destructive/20`
245
-
246
- ### Iconos
247
-
248
- - **CheckIcon**: Se muestra cuando `state=checked` (oculto con `group-data-[state=indeterminate]:hidden`)
249
- - **MinusIcon**: Se muestra cuando `state=indeterminate` (oculto con `group-data-[state=checked]:hidden`)
250
- - Tamaño: `size-3.5`, color blanco (`text-white`) para check, primary para minus
251
-
252
- ## Casos de Uso Comunes
253
-
254
- **Términos y condiciones**: Single checkbox requerido para continuar
255
- **Preferencias de notificación**: Múltiples checkboxes independientes
256
- **Select all**: Checkbox parent con estado indeterminate
257
- **Filtros**: Checkboxes para filtrar listas/tablas
258
- **Permisos**: Grant/revoke permissions con checkboxes
259
- **Multi-select lists**: Selección múltiple en tablas/listas
260
-
261
- ## Accesibilidad
262
-
263
- - ✅ **Navegación teclado**: Space para toggle, Tab para navegar
264
- - ✅ **ARIA**: `role="checkbox"`, `aria-checked="true|false|mixed"` (mixed = indeterminate)
265
- - ✅ **Labels**: Siempre usar `<Label htmlFor="id">` para clickear label
266
- - ✅ **Focus visible**: Ring azul en focus con teclado
267
- - ✅ **Screen readers**: Anuncia estado checked/unchecked/indeterminate
268
- - ✅ **Peer class**: Permite estilos CSS basados en estado para labels
269
-
270
- ## Notas de Implementación
271
-
272
- - **Basado en Radix UI**: `@radix-ui/react-checkbox`
273
- - **Tamaño**: `size-5` (20px × 20px), no tiene variantes de tamaño
274
- - **Border radius**: `rounded-[6px]` fijo
275
- - **Shadow**: `shadow-xs` sutil
276
- - **Transition**: `transition-shadow` solo en shadow (no en background para performance)
277
- - **Peer utility**: Tiene clase `peer` para estilos con `peer-*:` en hermanos
278
- - **Data slots**: `data-slot="checkbox"` y `data-slot="checkbox-indicator"`
279
- - **Form integration**: Soporta `name` y `value` para formularios nativos
280
- - **RTL ready**: Funciona correctamente en right-to-left
281
-
282
- ## Troubleshooting
283
-
284
- **Label no clickeable**: Asegúrate de usar `id` en Checkbox y `htmlFor` en Label
285
- **Estado no cambia**: Verifica que uses `onCheckedChange` en modo controlado
286
- **Indeterminate no se ve**: El valor debe ser string `"indeterminate"`, no boolean
287
- **Focus ring no aparece**: Verifica que no haya `outline-none` sin `focus-visible:ring`
288
-
289
- ## Referencias
290
-
291
- - **Radix UI Checkbox**: https://www.radix-ui.com/primitives/docs/components/checkbox
292
- - **ARIA Checkbox**: https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/
1
+ # Checkbox
2
+
3
+ Checkbox basado en Radix UI con 3 estados (checked, unchecked, indeterminate), validación con `aria-invalid`, focus ring, y estado disabled.
4
+
5
+ ## Importación
6
+
7
+ ```tsx
8
+ import { Checkbox } from "@adamosuiteservices/ui/checkbox";
9
+ import { Label } from "@adamosuiteservices/ui/label";
10
+ ```
11
+
12
+ ## Anatomía
13
+
14
+ ```tsx
15
+ // Componente único, sin subcomponentes
16
+ <Checkbox />
17
+
18
+ // Con label (patrón recomendado)
19
+ <div className="flex items-center gap-3">
20
+ <Checkbox id="terms" />
21
+ <Label htmlFor="terms">Accept terms</Label>
22
+ </div>
23
+ ```
24
+
25
+ ## Props Principales
26
+
27
+ | Prop | Tipo | Default | Descripción |
28
+ | ----------------- | ----------------------------------------------- | ------- | -------------------------------------------- |
29
+ | `checked` | `boolean \| "indeterminate"` | - | Estado controlado (true/false/indeterminate) |
30
+ | `defaultChecked` | `boolean` | `false` | Estado inicial no controlado |
31
+ | `onCheckedChange` | `(checked: boolean \| "indeterminate") => void` | - | Callback al cambiar estado |
32
+ | `disabled` | `boolean` | `false` | Desactiva interacción |
33
+ | `required` | `boolean` | `false` | Campo requerido (HTML5) |
34
+ | `name` | `string` | - | Nombre para formularios |
35
+ | `value` | `string` | `"on"` | Valor para formularios |
36
+ | `aria-invalid` | `boolean` | `false` | Muestra estado error (border rojo + ring) |
37
+ | `className` | `string` | - | Clases CSS adicionales |
38
+
39
+ ## Estados del Checkbox
40
+
41
+ ### 1. Unchecked (Default)
42
+
43
+ ```tsx
44
+ <Checkbox />
45
+ ```
46
+
47
+ ### 2. Checked
48
+
49
+ ```tsx
50
+ // No controlado
51
+ <Checkbox defaultChecked />;
52
+
53
+ // Controlado
54
+ const [checked, setChecked] = useState(true);
55
+ <Checkbox checked={checked} onCheckedChange={setChecked} />;
56
+ ```
57
+
58
+ ### 3. Indeterminate
59
+
60
+ Estado especial para "select all" cuando algunos items están seleccionados.
61
+
62
+ ```tsx
63
+ <Checkbox checked="indeterminate" />;
64
+
65
+ // Ejemplo práctico
66
+ const allChecked = items.every(Boolean);
67
+ const someChecked = items.some(Boolean) && !allChecked;
68
+
69
+ <Checkbox
70
+ checked={allChecked ? true : someChecked ? "indeterminate" : false}
71
+ onCheckedChange={(checked) => setItems(items.map(() => checked === true))}
72
+ />;
73
+ ```
74
+
75
+ **Visual**: Muestra un icono de guión (`MinusIcon`) en lugar de check.
76
+
77
+ ### 4. Disabled
78
+
79
+ ```tsx
80
+ <Checkbox disabled />
81
+ <Checkbox disabled defaultChecked />
82
+ ```
83
+
84
+ **Estilos**: `opacity-50` + `cursor-not-allowed`
85
+
86
+ ### 5. Invalid (Error State)
87
+
88
+ ```tsx
89
+ <Checkbox aria-invalid />
90
+ ```
91
+
92
+ **Estilos**: Border rojo (`border-destructive`) + ring rojo (`ring-destructive/20`)
93
+
94
+ ## Patrones de Uso
95
+
96
+ ### Con Label Simple
97
+
98
+ ```tsx
99
+ <div className="flex items-center gap-3">
100
+ <Checkbox id="notifications" />
101
+ <Label htmlFor="notifications">Enable notifications</Label>
102
+ </div>
103
+ ```
104
+
105
+ ### Con Label y Descripción
106
+
107
+ ```tsx
108
+ <div className="flex items-start gap-3">
109
+ <Checkbox id="marketing" />
110
+ <div className="grid gap-1">
111
+ <Label htmlFor="marketing">Marketing emails</Label>
112
+ <p className="text-sm text-muted-foreground">
113
+ Receive updates about new products
114
+ </p>
115
+ </div>
116
+ </div>
117
+ ```
118
+
119
+ ### Lista de Opciones
120
+
121
+ ```tsx
122
+ const options = ["Email", "SMS", "Push"];
123
+
124
+ <div className="space-y-4">
125
+ {options.map((option) => (
126
+ <div key={option} className="flex items-center gap-3">
127
+ <Checkbox id={option.toLowerCase()} />
128
+ <Label htmlFor={option.toLowerCase()}>{option} notifications</Label>
129
+ </div>
130
+ ))}
131
+ </div>;
132
+ ```
133
+
134
+ ### Select All con Indeterminate
135
+
136
+ ```tsx
137
+ const [items, setItems] = useState([false, true, false]);
138
+ const allChecked = items.every(Boolean);
139
+ const isIndeterminate = items.some(Boolean) && !allChecked;
140
+
141
+ <div className="space-y-4">
142
+ {/* Parent checkbox */}
143
+ <div className="flex items-center gap-3">
144
+ <Checkbox
145
+ checked={allChecked ? true : isIndeterminate ? "indeterminate" : false}
146
+ onCheckedChange={(checked) => setItems(items.map(() => checked === true))}
147
+ />
148
+ <Label className="font-medium">Select all</Label>
149
+ </div>
150
+
151
+ {/* Child checkboxes */}
152
+ <div className="ml-6 space-y-3">
153
+ {items.map((checked, i) => (
154
+ <div key={i} className="flex items-center gap-3">
155
+ <Checkbox
156
+ checked={checked}
157
+ onCheckedChange={(newChecked) => {
158
+ const newItems = [...items];
159
+ newItems[i] = newChecked as boolean;
160
+ setItems(newItems);
161
+ }}
162
+ />
163
+ <Label>Item {i + 1}</Label>
164
+ </div>
165
+ ))}
166
+ </div>
167
+ </div>;
168
+ ```
169
+
170
+ ### Card/Button Style
171
+
172
+ Para checkboxes clickeables como botones.
173
+
174
+ ```tsx
175
+ <Label className="flex items-start gap-3 rounded-lg border p-4 cursor-pointer hover:bg-accent/50 has-aria-checked:border-primary has-aria-checked:bg-primary/5 transition-colors">
176
+ <Checkbox id="card-option" />
177
+ <div className="grid gap-1.5">
178
+ <p className="text-sm font-medium">Enable feature</p>
179
+ <p className="text-sm text-muted-foreground">Description</p>
180
+ </div>
181
+ </Label>
182
+ ```
183
+
184
+ **Nota**: `has-aria-checked` detecta cuando el checkbox está checked para estilos.
185
+
186
+ ### Formulario de Preferencias
187
+
188
+ ```tsx
189
+ function PreferencesForm() {
190
+ const [prefs, setPrefs] = useState({
191
+ marketing: false,
192
+ analytics: true,
193
+ social: false,
194
+ });
195
+
196
+ return (
197
+ <form className="space-y-4">
198
+ {Object.entries(prefs).map(([key, value]) => (
199
+ <div key={key} className="flex items-center gap-3">
200
+ <Checkbox
201
+ id={key}
202
+ checked={value}
203
+ onCheckedChange={(checked) =>
204
+ setPrefs((prev) => ({ ...prev, [key]: checked as boolean }))
205
+ }
206
+ />
207
+ <Label htmlFor={key}>{key} preferences</Label>
208
+ </div>
209
+ ))}
210
+ <Button type="submit">Save</Button>
211
+ </form>
212
+ );
213
+ }
214
+ ```
215
+
216
+ ### Terms & Conditions
217
+
218
+ ```tsx
219
+ const [agreed, setAgreed] = useState(false);
220
+
221
+ <div className="flex items-start gap-3">
222
+ <Checkbox
223
+ id="terms"
224
+ checked={agreed}
225
+ onCheckedChange={(checked) => setAgreed(checked as boolean)}
226
+ aria-invalid={!agreed}
227
+ />
228
+ <Label htmlFor="terms" className="text-sm">
229
+ I agree to the{" "}
230
+ <a href="/terms" className="underline">terms and conditions</a>
231
+ </Label>
232
+ </div>
233
+ <Button disabled={!agreed}>Continue</Button>
234
+ ```
235
+
236
+ ## Estilos Internos (Data Attributes)
237
+
238
+ ### Estados Visuales
239
+
240
+ - **Checked**: `data-[state=checked]` → `bg-primary`, `text-primary-foreground`, `border-primary`
241
+ - **Unchecked**: Default → `border-input`, `bg-transparent` (dark: `bg-input/30`)
242
+ - **Indeterminate**: `data-[state=indeterminate]` → Muestra `MinusIcon` en lugar de `CheckIcon`
243
+ - **Focus**: `focus-visible:ring-[3px]`, `focus-visible:ring-ring/50`, `focus-visible:border-ring`
244
+ - **Invalid**: `aria-invalid:border-destructive`, `aria-invalid:ring-destructive/20`
245
+
246
+ ### Iconos
247
+
248
+ - **CheckIcon**: Se muestra cuando `state=checked` (oculto con `group-data-[state=indeterminate]:hidden`)
249
+ - **MinusIcon**: Se muestra cuando `state=indeterminate` (oculto con `group-data-[state=checked]:hidden`)
250
+ - Tamaño: `size-3.5`, color blanco (`text-white`) para check, primary para minus
251
+
252
+ ## Casos de Uso Comunes
253
+
254
+ **Términos y condiciones**: Single checkbox requerido para continuar
255
+ **Preferencias de notificación**: Múltiples checkboxes independientes
256
+ **Select all**: Checkbox parent con estado indeterminate
257
+ **Filtros**: Checkboxes para filtrar listas/tablas
258
+ **Permisos**: Grant/revoke permissions con checkboxes
259
+ **Multi-select lists**: Selección múltiple en tablas/listas
260
+
261
+ ## Accesibilidad
262
+
263
+ - ✅ **Navegación teclado**: Space para toggle, Tab para navegar
264
+ - ✅ **ARIA**: `role="checkbox"`, `aria-checked="true|false|mixed"` (mixed = indeterminate)
265
+ - ✅ **Labels**: Siempre usar `<Label htmlFor="id">` para clickear label
266
+ - ✅ **Focus visible**: Ring azul en focus con teclado
267
+ - ✅ **Screen readers**: Anuncia estado checked/unchecked/indeterminate
268
+ - ✅ **Peer class**: Permite estilos CSS basados en estado para labels
269
+
270
+ ## Notas de Implementación
271
+
272
+ - **Basado en Radix UI**: `@radix-ui/react-checkbox`
273
+ - **Tamaño**: `size-5` (20px × 20px), no tiene variantes de tamaño
274
+ - **Border radius**: `rounded-[6px]` fijo
275
+ - **Shadow**: `shadow-xs` sutil
276
+ - **Transition**: `transition-shadow` solo en shadow (no en background para performance)
277
+ - **Peer utility**: Tiene clase `peer` para estilos con `peer-*:` en hermanos
278
+ - **Data slots**: `data-slot="checkbox"` y `data-slot="checkbox-indicator"`
279
+ - **Form integration**: Soporta `name` y `value` para formularios nativos
280
+ - **RTL ready**: Funciona correctamente en right-to-left
281
+
282
+ ## Troubleshooting
283
+
284
+ **Label no clickeable**: Asegúrate de usar `id` en Checkbox y `htmlFor` en Label
285
+ **Estado no cambia**: Verifica que uses `onCheckedChange` en modo controlado
286
+ **Indeterminate no se ve**: El valor debe ser string `"indeterminate"`, no boolean
287
+ **Focus ring no aparece**: Verifica que no haya `outline-none` sin `focus-visible:ring`
288
+
289
+ ## Referencias
290
+
291
+ - **Radix UI Checkbox**: https://www.radix-ui.com/primitives/docs/components/checkbox
292
+ - **ARIA Checkbox**: https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/