@adamosuiteservices/ui 1.2.4 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +4 -0
  2. package/dist/accordion-rounded.cjs +1 -1
  3. package/dist/accordion-rounded.js +1 -1
  4. package/dist/accordion.cjs +1 -1
  5. package/dist/accordion.js +1 -1
  6. package/dist/avatar.cjs +1 -1
  7. package/dist/avatar.js +1 -1
  8. package/dist/badge.cjs +1 -1
  9. package/dist/badge.js +1 -1
  10. package/dist/breadcrumb.cjs +1 -0
  11. package/dist/breadcrumb.js +105 -0
  12. package/dist/{button-C1n6snOY.js → button-2GdKenQI.js} +1 -1
  13. package/dist/{button-BV-_FVKZ.cjs → button-DEQVHMrX.cjs} +1 -1
  14. package/dist/button-group.cjs +1 -1
  15. package/dist/button-group.js +2 -2
  16. package/dist/button.cjs +1 -1
  17. package/dist/button.js +1 -1
  18. package/dist/calendar.cjs +1 -1
  19. package/dist/calendar.js +1 -1
  20. package/dist/{checkbox-BrmXPKTn.js → checkbox-Dr487kAg.js} +3 -3
  21. package/dist/{checkbox-Lq-HvSgc.cjs → checkbox-YWAnswaW.cjs} +1 -1
  22. package/dist/checkbox.cjs +1 -1
  23. package/dist/checkbox.js +1 -1
  24. package/dist/collapsible.cjs +1 -1
  25. package/dist/collapsible.js +1 -1
  26. package/dist/combobox.cjs +1 -1
  27. package/dist/combobox.js +6 -6
  28. package/dist/components/ui/breadcrumb/breadcrumb.d.ts +11 -0
  29. package/dist/components/ui/breadcrumb/breadcrumb.stories.d.ts +26 -0
  30. package/dist/components/ui/breadcrumb/index.d.ts +1 -0
  31. package/dist/components/ui/dialog/dialog.d.ts +2 -1
  32. package/dist/context-menu.cjs +1 -1
  33. package/dist/context-menu.js +2 -2
  34. package/dist/custom-layered-styles.css +1 -1
  35. package/dist/dialog.cjs +1 -1
  36. package/dist/dialog.js +33 -19
  37. package/dist/dropdown-menu.cjs +1 -1
  38. package/dist/dropdown-menu.js +3 -3
  39. package/dist/ellipsis-CryjZKZn.js +15 -0
  40. package/dist/ellipsis-Ct9VTDOG.cjs +6 -0
  41. package/dist/field.cjs +1 -1
  42. package/dist/field.js +2 -2
  43. package/dist/hover-card.cjs +1 -1
  44. package/dist/hover-card.js +6 -6
  45. package/dist/{index-CAOY367Y.js → index-B0M7VOwp.js} +2 -2
  46. package/dist/{index-B-ZRqW0J.js → index-BBoIAjAs.js} +3 -3
  47. package/dist/{index-gO_QEiaK.cjs → index-BDs8lUfq.cjs} +1 -1
  48. package/dist/index-BFyr34mw.cjs +5 -0
  49. package/dist/index-BMWt1NBG.js +79 -0
  50. package/dist/{index-yR-v1A4G.js → index-BX9hz-JD.js} +1 -1
  51. package/dist/{index-BGiGvaq8.cjs → index-BcGMAmWE.cjs} +1 -1
  52. package/dist/{index-IKJMQref.cjs → index-Bd0gQB0k.cjs} +1 -1
  53. package/dist/{index-VIUqZjyP.cjs → index-BeWgla7c.cjs} +1 -1
  54. package/dist/{index-EUea2gfp.js → index-BpWB3aFK.js} +1 -1
  55. package/dist/index-BvLQnI56.js +59 -0
  56. package/dist/{index-CwUFT-GQ.js → index-C0YiLSjW.js} +4 -4
  57. package/dist/{index-o0sNTcKe.js → index-CBjZooac.js} +2 -2
  58. package/dist/{index-DnS_sBBe.cjs → index-COuvjZLM.cjs} +1 -1
  59. package/dist/index-CTjlbbt9.cjs +1 -0
  60. package/dist/index-CUWMxxKG.js +97 -0
  61. package/dist/{index-C329e3yQ.js → index-CZZ3llmi.js} +2 -2
  62. package/dist/index-CjyiloO7.cjs +1 -0
  63. package/dist/{index-D3wSWKST.cjs → index-Cmx9M9cZ.cjs} +1 -1
  64. package/dist/index-CocSS1YK.cjs +1 -0
  65. package/dist/index-CzRiuk60.cjs +1 -0
  66. package/dist/index-DFPDUUq7.js +658 -0
  67. package/dist/{index-D3S7dBDI.cjs → index-DIwmXz1u.cjs} +1 -1
  68. package/dist/index-DLcqcWxM.js +29 -0
  69. package/dist/index-DMLQL2aG.js +286 -0
  70. package/dist/{index-DXQ-7kNJ.cjs → index-DMs8RL3E.cjs} +1 -1
  71. package/dist/{index-Ce3QBKyj.cjs → index-Dbj9vHNq.cjs} +1 -1
  72. package/dist/{index-BRLtxFFr.cjs → index-DmGzwG2z.cjs} +1 -1
  73. package/dist/{index-P1sVIHE3.js → index-PYkEXTqJ.js} +1 -1
  74. package/dist/{index-DulPG3F9.js → index-Se4vRnIO.js} +3 -3
  75. package/dist/index-_XxjJPRD.cjs +1 -0
  76. package/dist/{index-B-cHTKrs.js → index-yWvyIlmA.js} +4 -4
  77. package/dist/input-group.cjs +1 -1
  78. package/dist/input-group.js +1 -1
  79. package/dist/{label-Cne2J57f.cjs → label-BjXORCBM.cjs} +1 -1
  80. package/dist/{label-Ky8qBEC3.js → label-CmwGvhy1.js} +1 -1
  81. package/dist/label.cjs +1 -1
  82. package/dist/label.js +1 -1
  83. package/dist/pagination.cjs +1 -6
  84. package/dist/pagination.js +58 -69
  85. package/dist/popover-3rIoNCXs.js +306 -0
  86. package/dist/popover-FCKBtFo-.cjs +1 -0
  87. package/dist/popover.cjs +1 -1
  88. package/dist/popover.js +1 -1
  89. package/dist/progress.cjs +1 -1
  90. package/dist/progress.js +1 -1
  91. package/dist/radio-group.cjs +1 -1
  92. package/dist/radio-group.js +5 -5
  93. package/dist/select.cjs +2 -2
  94. package/dist/select.js +585 -542
  95. package/dist/{separator-CGnu_jIu.cjs → separator-BaZqZZ9R.cjs} +1 -1
  96. package/dist/{separator-BH73A90k.js → separator-DR7lQjv9.js} +1 -1
  97. package/dist/separator.cjs +1 -1
  98. package/dist/separator.js +1 -1
  99. package/dist/{sheet-CcxnJ6LH.cjs → sheet-CU-sFSaJ.cjs} +1 -1
  100. package/dist/{sheet-_DVpQIVF.js → sheet-UZWAbdXr.js} +1 -1
  101. package/dist/sheet.cjs +1 -1
  102. package/dist/sheet.js +1 -1
  103. package/dist/sidebar.cjs +1 -1
  104. package/dist/sidebar.js +4 -4
  105. package/dist/slider.cjs +1 -1
  106. package/dist/slider.js +3 -3
  107. package/dist/styles.css +1 -1
  108. package/dist/switch.cjs +1 -1
  109. package/dist/switch.js +2 -2
  110. package/dist/tabs-underline.cjs +1 -1
  111. package/dist/tabs-underline.js +1 -1
  112. package/dist/tabs.cjs +1 -1
  113. package/dist/tabs.js +1 -1
  114. package/dist/toaster.cjs +1 -1
  115. package/dist/toaster.js +1 -1
  116. package/dist/toggle.cjs +1 -1
  117. package/dist/toggle.js +1 -1
  118. package/dist/tooltip.cjs +1 -1
  119. package/dist/tooltip.js +114 -108
  120. package/dist/typography.cjs +1 -1
  121. package/dist/typography.js +16 -16
  122. package/docs/AI-GUIDE.md +321 -0
  123. package/docs/components/layout/sidebar.md +330 -0
  124. package/docs/components/layout/toaster.md +436 -0
  125. package/docs/components/ui/accordion-rounded.md +583 -0
  126. package/docs/components/ui/accordion.md +267 -0
  127. package/docs/components/ui/alert.md +671 -0
  128. package/docs/components/ui/avatar.md +588 -0
  129. package/docs/components/ui/badge.md +1024 -0
  130. package/docs/components/ui/breadcrumb.md +614 -0
  131. package/docs/components/ui/button-group.md +1002 -0
  132. package/docs/components/ui/button.md +1078 -0
  133. package/docs/components/ui/calendar.md +1159 -0
  134. package/docs/components/ui/card.md +1265 -0
  135. package/docs/components/ui/checkbox.md +292 -0
  136. package/docs/components/ui/collapsible.md +320 -0
  137. package/docs/components/ui/combobox.md +328 -0
  138. package/docs/components/ui/command.md +454 -0
  139. package/docs/components/ui/context-menu.md +540 -0
  140. package/docs/components/ui/dialog.md +628 -0
  141. package/docs/components/ui/dropdown-menu.md +731 -0
  142. package/docs/components/ui/field.md +706 -0
  143. package/docs/components/ui/hover-card.md +446 -0
  144. package/docs/components/ui/input-group.md +509 -0
  145. package/docs/components/ui/input.md +362 -0
  146. package/docs/components/ui/kbd.md +434 -0
  147. package/docs/components/ui/label.md +359 -0
  148. package/docs/components/ui/pagination.md +650 -0
  149. package/docs/components/ui/popover.md +536 -0
  150. package/docs/components/ui/progress.md +182 -0
  151. package/docs/components/ui/radio-group.md +311 -0
  152. package/docs/components/ui/select.md +352 -0
  153. package/docs/components/ui/separator.md +214 -0
  154. package/docs/components/ui/sheet.md +142 -0
  155. package/docs/components/ui/skeleton.md +140 -0
  156. package/docs/components/ui/slider.md +341 -0
  157. package/docs/components/ui/spinner.md +170 -0
  158. package/docs/components/ui/switch.md +402 -0
  159. package/docs/components/ui/table.md +183 -0
  160. package/docs/components/ui/tabs-underline.md +106 -0
  161. package/docs/components/ui/tabs.md +122 -0
  162. package/docs/components/ui/textarea.md +243 -0
  163. package/docs/components/ui/toggle.md +243 -0
  164. package/docs/components/ui/tooltip.md +320 -0
  165. package/docs/components/ui/typography.md +191 -0
  166. package/package.json +11 -5
  167. package/dist/index-6oTEokEx.js +0 -82
  168. package/dist/index-B-NyefE0.js +0 -243
  169. package/dist/index-BKbK2GzY.cjs +0 -1
  170. package/dist/index-BMitW9UR.cjs +0 -1
  171. package/dist/index-BpvjJ_T6.cjs +0 -5
  172. package/dist/index-C5wjudc-.js +0 -36
  173. package/dist/index-CezwiPd_.js +0 -615
  174. package/dist/index-D02K8KOB.js +0 -54
  175. package/dist/index-D7hQvndv.cjs +0 -1
  176. package/dist/index-DQvx1rG_.cjs +0 -1
  177. package/dist/popover-BjdTqaB8.cjs +0 -1
  178. package/dist/popover-EnVfE0YA.js +0 -263
@@ -0,0 +1,1078 @@
1
+ # Button Component
2
+
3
+ ## Descripción
4
+
5
+ Componente fundamental para **acciones e interacciones del usuario**. Ofrece 11 variantes visuales, 6 tamaños, estados automáticos (hover, focus, disabled, loading), iconos auto-dimensionados, y la capacidad de renderizarse como cualquier elemento usando `asChild`. Basado en CVA para variants y Radix UI Slot para composición.
6
+
7
+ ## Características
8
+
9
+ - ✅ 11 variantes: default, success (2), warning (2), destructive (2), secondary, outline, ghost, link
10
+ - ✅ 6 tamaños: sm, default, lg, icon, icon-sm, icon-lg
11
+ - ✅ Iconos auto-dimensionados (16px) con ajuste automático de padding
12
+ - ✅ Estados automáticos: hover, focus-visible, disabled, loading
13
+ - ✅ Prop `asChild` para renderizar como links u otros elementos
14
+ - ✅ Focus ring accesible con detección de teclado
15
+ - ✅ Soporte para aria-invalid con anillos de error
16
+ - ✅ Transiciones suaves en todos los estados
17
+ - ✅ Dark mode completo en todas las variantes
18
+
19
+ ## Importación
20
+
21
+ ```typescript
22
+ import { Button } from "@adamosuiteservices/ui/button";
23
+ ```
24
+
25
+ ## Uso Básico
26
+
27
+ ### Botón Simple
28
+
29
+ ```tsx
30
+ <Button>Click me</Button>
31
+ ```
32
+
33
+ ### Con Icono
34
+
35
+ ```tsx
36
+ import { PlusIcon } from "lucide-react";
37
+
38
+ <Button>
39
+ <PlusIcon />
40
+ Add Item
41
+ </Button>;
42
+ ```
43
+
44
+ **Nota**: El icono se auto-dimensiona a 16px y el padding se ajusta automáticamente con `has-[>svg]`.
45
+
46
+ ### Como Link (asChild)
47
+
48
+ ```tsx
49
+ <Button asChild>
50
+ <a href="/dashboard">Go to Dashboard</a>
51
+ </Button>
52
+ ```
53
+
54
+ **Uso de asChild**: Mantiene el estilo de Button pero renderiza el hijo (`<a>`) en lugar de `<button>`.
55
+
56
+ ## Variantes
57
+
58
+ ### default (Primary)
59
+
60
+ Botón principal con colores de marca para acciones primarias.
61
+
62
+ ```tsx
63
+ <Button variant="default">Default</Button>
64
+ ```
65
+
66
+ **Estilos**:
67
+
68
+ - Fondo: `bg-primary`
69
+ - Texto: `text-primary-foreground`
70
+ - Hover: `bg-primary-700`
71
+ - Uso: Acciones primarias, CTAs principales
72
+
73
+ ### success
74
+
75
+ Botón verde sólido para acciones exitosas o confirmaciones importantes.
76
+
77
+ ```tsx
78
+ <Button variant="success">Success</Button>
79
+ ```
80
+
81
+ **Estilos**:
82
+
83
+ - Fondo: `bg-success` (verde)
84
+ - Texto: `text-white`
85
+ - Hover: `bg-success-700`
86
+ - Focus ring: `ring-success/20`
87
+ - Dark mode: `bg-success/60`
88
+ - Uso: Guardar, aprobar, confirmar, completar
89
+
90
+ ### success-medium
91
+
92
+ Versión suave del botón success con fondo claro y texto verde.
93
+
94
+ ```tsx
95
+ <Button variant="success-medium">Success Medium</Button>
96
+ ```
97
+
98
+ **Estilos**:
99
+
100
+ - Fondo: `bg-success-50` (verde muy claro)
101
+ - Texto: `text-success` (verde)
102
+ - Hover: `bg-success/20`
103
+ - Uso: Acciones exitosas secundarias, estados de éxito menos enfáticos
104
+
105
+ ### warning
106
+
107
+ Botón naranja/amarillo sólido para acciones que requieren precaución.
108
+
109
+ ```tsx
110
+ <Button variant="warning">Warning</Button>
111
+ ```
112
+
113
+ **Estilos**:
114
+
115
+ - Fondo: `bg-warning` (naranja/amarillo)
116
+ - Texto: `text-white`
117
+ - Hover: `bg-warning-700`
118
+ - Focus ring: `ring-warning/20`
119
+ - Dark mode: `bg-warning/60`
120
+ - Uso: Acciones de advertencia, confirmaciones con riesgo moderado
121
+
122
+ ### warning-medium
123
+
124
+ Versión suave del botón warning con fondo claro.
125
+
126
+ ```tsx
127
+ <Button variant="warning-medium">Warning Medium</Button>
128
+ ```
129
+
130
+ **Estilos**:
131
+
132
+ - Fondo: `bg-warning-50` (naranja/amarillo muy claro)
133
+ - Texto: `text-warning`
134
+ - Hover: `bg-warning/20`
135
+ - Uso: Advertencias secundarias, alertas menos críticas
136
+
137
+ ### destructive
138
+
139
+ Botón rojo sólido para acciones destructivas o peligrosas.
140
+
141
+ ```tsx
142
+ <Button variant="destructive">Destructive</Button>
143
+ ```
144
+
145
+ **Estilos**:
146
+
147
+ - Fondo: `bg-destructive` (rojo)
148
+ - Texto: `text-white`
149
+ - Hover: `bg-destructive-700`
150
+ - Focus ring: `ring-destructive/20`
151
+ - Dark mode: `bg-destructive/60`
152
+ - Uso: Eliminar, cancelar suscripción, reset, acciones irreversibles
153
+
154
+ ### destructive-medium
155
+
156
+ Versión suave del botón destructive con fondo claro.
157
+
158
+ ```tsx
159
+ <Button variant="destructive-medium">Destructive Medium</Button>
160
+ ```
161
+
162
+ **Estilos**:
163
+
164
+ - Fondo: `bg-destructive-50` (rojo muy claro)
165
+ - Texto: `text-destructive`
166
+ - Hover: `bg-destructive/20`
167
+ - Uso: Acciones destructivas secundarias, advertencias de error
168
+
169
+ ### secondary
170
+
171
+ Botón secundario para acciones de menor importancia.
172
+
173
+ ```tsx
174
+ <Button variant="secondary">Secondary</Button>
175
+ ```
176
+
177
+ **Estilos**:
178
+
179
+ - Fondo: `bg-secondary`
180
+ - Texto: `text-secondary-foreground`
181
+ - Hover: `bg-primary-200`
182
+ - Uso: Acciones secundarias, botones de soporte
183
+
184
+ ### outline
185
+
186
+ Botón con borde y fondo transparente para acciones secundarias.
187
+
188
+ ```tsx
189
+ <Button variant="outline">Outline</Button>
190
+ ```
191
+
192
+ **Estilos**:
193
+
194
+ - Fondo: `bg-background` con `border`
195
+ - Shadow: `shadow-xs`
196
+ - Hover: `bg-accent`
197
+ - Dark mode: `bg-input/30`, `border-input`
198
+ - Uso: Cancelar, acciones alternativas, botones en grupos
199
+
200
+ ### ghost
201
+
202
+ Botón mínimo sin borde que solo aparece en hover.
203
+
204
+ ```tsx
205
+ <Button variant="ghost">Ghost</Button>
206
+ ```
207
+
208
+ **Estilos**:
209
+
210
+ - Fondo: Transparente
211
+ - Hover: `bg-accent`
212
+ - Dark mode: `hover:bg-accent/50`
213
+ - Uso: Acciones terciarias, iconos de herramientas, menús
214
+
215
+ ### link
216
+
217
+ Botón que se ve como un link con subrayado en hover.
218
+
219
+ ```tsx
220
+ <Button variant="link">Link</Button>
221
+ ```
222
+
223
+ **Estilos**:
224
+
225
+ - Color: `text-primary`
226
+ - Hover: `underline`
227
+ - Offset: `underline-offset-4`
228
+ - Uso: Navegación inline, acciones de bajo énfasis
229
+
230
+ ## Tamaños
231
+
232
+ ### sm (Small)
233
+
234
+ Botón compacto para espacios reducidos.
235
+
236
+ ```tsx
237
+ <Button size="sm">Small</Button>
238
+ ```
239
+
240
+ **Dimensiones**:
241
+
242
+ - Altura: `h-8` (32px)
243
+ - Padding horizontal: `px-3` (12px)
244
+ - Padding con icono: `px-2.5` (10px) con `has-[>svg]`
245
+ - Gap: `gap-1.5` (6px)
246
+ - Border radius: `rounded-md`
247
+
248
+ ### default
249
+
250
+ Tamaño estándar para la mayoría de casos.
251
+
252
+ ```tsx
253
+ <Button size="default">Default</Button>
254
+ ```
255
+
256
+ **Dimensiones**:
257
+
258
+ - Altura: `h-9` (36px)
259
+ - Padding horizontal: `px-4` (16px)
260
+ - Padding con icono: `px-3` (12px) con `has-[>svg]`
261
+ - Gap: `gap-2` (8px)
262
+ - Border radius: `rounded-md`
263
+
264
+ ### lg (Large)
265
+
266
+ Botón grande para CTAs prominentes.
267
+
268
+ ```tsx
269
+ <Button size="lg">Large</Button>
270
+ ```
271
+
272
+ **Dimensiones**:
273
+
274
+ - Altura: `h-10` (40px)
275
+ - Padding horizontal: `px-6` (24px)
276
+ - Padding con icono: `px-4` (16px) con `has-[>svg]`
277
+ - Gap: `gap-2` (8px)
278
+ - Border radius: `rounded-md`
279
+
280
+ ### icon (Icon Only - Default)
281
+
282
+ Botón cuadrado solo para iconos (tamaño medio).
283
+
284
+ ```tsx
285
+ <Button size="icon" aria-label="Settings">
286
+ <SettingsIcon />
287
+ </Button>
288
+ ```
289
+
290
+ **Dimensiones**:
291
+
292
+ - Tamaño: `size-9` (36x36px)
293
+ - **Importante**: Siempre incluye `aria-label` para accesibilidad
294
+
295
+ ### icon-sm (Icon Small)
296
+
297
+ Botón cuadrado pequeño para iconos.
298
+
299
+ ```tsx
300
+ <Button size="icon-sm" aria-label="Edit">
301
+ <EditIcon />
302
+ </Button>
303
+ ```
304
+
305
+ **Dimensiones**:
306
+
307
+ - Tamaño: `size-8` (32x32px)
308
+
309
+ ### icon-lg (Icon Large)
310
+
311
+ Botón cuadrado grande para iconos.
312
+
313
+ ```tsx
314
+ <Button size="icon-lg" aria-label="Search">
315
+ <SearchIcon />
316
+ </Button>
317
+ ```
318
+
319
+ **Dimensiones**:
320
+
321
+ - Tamaño: `size-10` (40x40px)
322
+
323
+ ## Estados
324
+
325
+ ### Normal (Default)
326
+
327
+ Estado por defecto con interacciones completas.
328
+
329
+ ```tsx
330
+ <Button>Normal State</Button>
331
+ ```
332
+
333
+ ### Disabled
334
+
335
+ Desactiva el botón y reduce opacidad.
336
+
337
+ ```tsx
338
+ <Button disabled>Disabled</Button>
339
+ ```
340
+
341
+ **Comportamiento**:
342
+
343
+ - `opacity-50`: Opacidad al 50%
344
+ - `pointer-events-none`: No acepta clicks ni hover
345
+ - Automático en todos los navegadores
346
+
347
+ ### Loading
348
+
349
+ Muestra spinner y desactiva interacciones.
350
+
351
+ ```tsx
352
+ import { Loader2Icon } from "lucide-react";
353
+
354
+ <Button disabled>
355
+ <Loader2Icon className="animate-spin" />
356
+ Loading...
357
+ </Button>;
358
+ ```
359
+
360
+ **Patrón recomendado**:
361
+
362
+ ```tsx
363
+ const [isLoading, setIsLoading] = useState(false);
364
+
365
+ <Button disabled={isLoading} onClick={handleSubmit}>
366
+ {isLoading && <Loader2Icon className="animate-spin" />}
367
+ {isLoading ? "Saving..." : "Save Changes"}
368
+ </Button>;
369
+ ```
370
+
371
+ ### Hover
372
+
373
+ Estado automático al pasar el mouse.
374
+
375
+ - Cada variante tiene su propio color de hover
376
+ - Transición suave con `transition-all`
377
+ - No afecta a botones disabled
378
+
379
+ ### Focus-Visible
380
+
381
+ Anillo visible solo al navegar con teclado.
382
+
383
+ ```tsx
384
+ <Button>Focus me with Tab key</Button>
385
+ ```
386
+
387
+ **Estilos aplicados**:
388
+
389
+ - `focus-visible:border-ring`: Borde del color del anillo
390
+ - `focus-visible:ring-ring/50`: Anillo exterior con 50% opacidad
391
+ - `focus-visible:ring-[3px]`: Anillo de 3px
392
+ - Solo visible con teclado (no con mouse)
393
+
394
+ ### Invalid (Error State)
395
+
396
+ Para formularios con validación.
397
+
398
+ ```tsx
399
+ <Button aria-invalid="true">Invalid Button</Button>
400
+ ```
401
+
402
+ **Estilos aplicados**:
403
+
404
+ - `aria-invalid:ring-destructive/20`: Anillo rojo claro
405
+ - `aria-invalid:border-destructive`: Borde rojo
406
+ - Dark mode: `ring-destructive/40`
407
+
408
+ ## Patrones Avanzados
409
+
410
+ ### Botón con Icono (Text + Icon)
411
+
412
+ ```tsx
413
+ import { SaveIcon, DownloadIcon, TrashIcon } from "lucide-react";
414
+
415
+ {
416
+ /* Icono a la izquierda */
417
+ }
418
+ <Button>
419
+ <SaveIcon />
420
+ Save Changes
421
+ </Button>;
422
+
423
+ {
424
+ /* Icono a la derecha */
425
+ }
426
+ <Button>
427
+ Download
428
+ <DownloadIcon />
429
+ </Button>;
430
+
431
+ {
432
+ /* Múltiples iconos */
433
+ }
434
+ <Button variant="destructive">
435
+ <TrashIcon />
436
+ Delete All
437
+ <span className="ml-auto text-xs">(5)</span>
438
+ </Button>;
439
+ ```
440
+
441
+ **Nota**: El gap (`gap-2`) se aplica automáticamente entre elementos.
442
+
443
+ ### Botón Redondeado (Pill)
444
+
445
+ ```tsx
446
+ <Button className="rounded-full">
447
+ <PlusIcon />
448
+ Add New
449
+ </Button>
450
+ ```
451
+
452
+ ### Botón de Ancho Completo
453
+
454
+ ```tsx
455
+ <Button className="w-full">Continue</Button>
456
+ ```
457
+
458
+ ### Grupo de Botones
459
+
460
+ ```tsx
461
+ <div className="flex gap-2">
462
+ <Button variant="outline">Cancel</Button>
463
+ <Button>Save</Button>
464
+ </div>
465
+ ```
466
+
467
+ ### Botón Interactivo con Estado
468
+
469
+ ```tsx
470
+ import { useState } from "react";
471
+ import { HeartIcon, StarIcon, PlayIcon, PauseIcon } from "lucide-react";
472
+
473
+ function LikeButton() {
474
+ const [liked, setLiked] = useState(false);
475
+
476
+ return (
477
+ <Button
478
+ variant={liked ? "default" : "outline"}
479
+ onClick={() => setLiked(!liked)}
480
+ >
481
+ <HeartIcon className={liked ? "fill-current" : ""} />
482
+ {liked ? "Liked" : "Like"}
483
+ </Button>
484
+ );
485
+ }
486
+
487
+ function SaveButton() {
488
+ const [saved, setSaved] = useState(false);
489
+
490
+ return (
491
+ <Button
492
+ variant={saved ? "secondary" : "outline"}
493
+ onClick={() => setSaved(!saved)}
494
+ >
495
+ <StarIcon className={saved ? "fill-current" : ""} />
496
+ {saved ? "Saved" : "Save"}
497
+ </Button>
498
+ );
499
+ }
500
+
501
+ function PlayButton() {
502
+ const [playing, setPlaying] = useState(false);
503
+
504
+ return (
505
+ <Button variant="outline" onClick={() => setPlaying(!playing)}>
506
+ {playing ? <PauseIcon /> : <PlayIcon />}
507
+ {playing ? "Pause" : "Play"}
508
+ </Button>
509
+ );
510
+ }
511
+ ```
512
+
513
+ ### asChild con Link (Next.js)
514
+
515
+ ```tsx
516
+ import Link from "next/link";
517
+ import { ExternalLinkIcon } from "lucide-react";
518
+
519
+ <Button asChild>
520
+ <Link href="/dashboard">
521
+ Go to Dashboard
522
+ </Link>
523
+ </Button>
524
+
525
+ <Button asChild variant="outline">
526
+ <a href="https://example.com" target="_blank" rel="noopener noreferrer">
527
+ <ExternalLinkIcon />
528
+ External Link
529
+ </a>
530
+ </Button>
531
+ ```
532
+
533
+ ### asChild con React Router
534
+
535
+ ```tsx
536
+ import { Link } from "react-router-dom";
537
+
538
+ <Button asChild>
539
+ <Link to="/profile">View Profile</Link>
540
+ </Button>;
541
+ ```
542
+
543
+ ### Botón con Badge
544
+
545
+ ```tsx
546
+ import { Badge } from "@adamosuiteservices/ui/badge";
547
+
548
+ <Button variant="outline" className="relative">
549
+ Notifications
550
+ <Badge
551
+ variant="destructive"
552
+ className="absolute -top-2 -right-2 h-5 w-5 rounded-full p-0 flex items-center justify-center text-xs"
553
+ >
554
+ 5
555
+ </Badge>
556
+ </Button>;
557
+ ```
558
+
559
+ ### Botón Dropdown Trigger
560
+
561
+ ```tsx
562
+ import { ChevronDownIcon } from "lucide-react";
563
+
564
+ <Button>
565
+ Options
566
+ <ChevronDownIcon className="ml-auto -mr-1" />
567
+ </Button>;
568
+ ```
569
+
570
+ ## Props
571
+
572
+ | Prop | Tipo | Default | Descripción |
573
+ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------- |
574
+ | variant | `"default" \| "success" \| "success-medium" \| "warning" \| "warning-medium" \| "destructive" \| "destructive-medium" \| "secondary" \| "outline" \| "ghost" \| "link"` | `"default"` | Variante visual del botón |
575
+ | size | `"default" \| "sm" \| "lg" \| "icon" \| "icon-sm" \| "icon-lg"` | `"default"` | Tamaño del botón |
576
+ | asChild | `boolean` | `false` | Renderiza el hijo en lugar de un `<button>`. Usa Radix UI Slot |
577
+ | disabled | `boolean` | `false` | Desactiva el botón (opacity 50%, pointer-events none) |
578
+ | className | `string` | - | Clases CSS adicionales |
579
+ | children | `ReactNode` | - | Contenido del botón (texto, iconos, etc.) |
580
+ | type | `"button" \| "submit" \| "reset"` | `"button"` | Tipo de botón HTML |
581
+ | onClick | `(e: MouseEvent) => void` | - | Handler de click |
582
+ | ...props | `ButtonHTMLAttributes` | - | Todas las props nativas de `<button>` |
583
+
584
+ **Nota sobre asChild**: Cuando es `true`, el componente usa `Slot` de Radix UI para transferir todas las props y estilos al hijo directo.
585
+
586
+ ## Estilos Base Automáticos
587
+
588
+ Todos los botones tienen estos estilos aplicados automáticamente:
589
+
590
+ ```css
591
+ inline-flex /* Display flex inline */
592
+ items-center /* Alinea verticalmente al centro */
593
+ justify-center /* Centra horizontalmente */
594
+ gap-2 /* Espacio de 8px entre hijos (varía por tamaño) */
595
+ whitespace-nowrap /* No rompe líneas */
596
+ rounded-md /* Border radius medium */
597
+ text-sm /* Tamaño de fuente 14px */
598
+ font-semibold /* Peso de fuente 600 */
599
+ transition-all /* Transiciones suaves */
600
+ shrink-0 /* No se encoge en flex/grid */
601
+ outline-none /* Sin outline por defecto */
602
+ ```
603
+
604
+ ### Iconos Auto-dimensionados
605
+
606
+ ```css
607
+ [&_svg]:pointer-events-none /* Iconos no capturan clicks */
608
+ [&_svg:not([class*=size-])]:size-4 /* SVG sin clase size-* → 16x16px */
609
+ [&_svg]:shrink-0 /* Iconos no se encogen */
610
+ ```
611
+
612
+ ### Padding Dinámico con Iconos
613
+
614
+ ```css
615
+ /* size="default" */
616
+ h-9 px-4 /* Sin icono: 16px padding horizontal */
617
+ has-[>svg]:px-3 /* Con icono: 12px padding horizontal */
618
+
619
+ /* size="sm" */
620
+ h-8 px-3
621
+ has-[>svg]:px-2.5
622
+
623
+ /* size="lg" */
624
+ h-10 px-6
625
+ has-[>svg]:px-4
626
+ ```
627
+
628
+ **Beneficio**: El padding se reduce automáticamente cuando hay iconos para mantener proporciones visuales.
629
+
630
+ ## Casos de Uso Comunes
631
+
632
+ ### Acciones Primarias
633
+
634
+ Para la acción más importante en la pantalla.
635
+
636
+ ```tsx
637
+ <div className="flex gap-2">
638
+ <Button>
639
+ <SaveIcon />
640
+ Save Changes
641
+ </Button>
642
+ <Button>
643
+ <PlusIcon />
644
+ Create New
645
+ </Button>
646
+ <Button>
647
+ <DownloadIcon />
648
+ Export Data
649
+ </Button>
650
+ </div>
651
+ ```
652
+
653
+ ### Acciones Secundarias
654
+
655
+ Para acciones alternativas o de menor prioridad.
656
+
657
+ ```tsx
658
+ <div className="flex gap-2">
659
+ <Button variant="outline">
660
+ <EditIcon />
661
+ Edit
662
+ </Button>
663
+ <Button variant="outline">
664
+ <CopyIcon />
665
+ Copy
666
+ </Button>
667
+ <Button variant="outline">
668
+ <ShareIcon />
669
+ Share
670
+ </Button>
671
+ </div>
672
+ ```
673
+
674
+ ### Acciones Destructivas/Peligrosas
675
+
676
+ Para acciones que requieren confirmación del usuario.
677
+
678
+ ```tsx
679
+ <div className="flex gap-2">
680
+ <Button variant="destructive">
681
+ <TrashIcon />
682
+ Delete Item
683
+ </Button>
684
+ <Button variant="destructive">Reset All Data</Button>
685
+ </div>
686
+ ```
687
+
688
+ ### Formularios
689
+
690
+ Combinación típica en formularios.
691
+
692
+ ```tsx
693
+ <form onSubmit={handleSubmit}>
694
+ {/* Campos del formulario */}
695
+
696
+ <div className="flex gap-2 justify-end mt-4">
697
+ <Button type="button" variant="outline" onClick={onCancel}>
698
+ Cancel
699
+ </Button>
700
+ <Button type="submit">
701
+ {isSubmitting ? (
702
+ <>
703
+ <Loader2Icon className="animate-spin" />
704
+ Saving...
705
+ </>
706
+ ) : (
707
+ <>
708
+ <SaveIcon />
709
+ Save
710
+ </>
711
+ )}
712
+ </Button>
713
+ </div>
714
+ </form>
715
+ ```
716
+
717
+ ### Dialogs y Modals
718
+
719
+ Acciones en footer de dialogs.
720
+
721
+ ```tsx
722
+ <DialogFooter>
723
+ <Button variant="outline" onClick={onClose}>
724
+ Cancel
725
+ </Button>
726
+ <Button onClick={onConfirm}>Confirm</Button>
727
+ </DialogFooter>
728
+ ```
729
+
730
+ ### Toolbars
731
+
732
+ Botones de herramientas con iconos.
733
+
734
+ ```tsx
735
+ <div className="flex gap-1 p-2 border rounded-lg">
736
+ <Button size="icon-sm" variant="ghost" aria-label="Bold">
737
+ <BoldIcon />
738
+ </Button>
739
+ <Button size="icon-sm" variant="ghost" aria-label="Italic">
740
+ <ItalicIcon />
741
+ </Button>
742
+ <Button size="icon-sm" variant="ghost" aria-label="Underline">
743
+ <UnderlineIcon />
744
+ </Button>
745
+ <div className="w-px bg-border mx-1" />
746
+ <Button size="icon-sm" variant="ghost" aria-label="Align left">
747
+ <AlignLeftIcon />
748
+ </Button>
749
+ <Button size="icon-sm" variant="ghost" aria-label="Align center">
750
+ <AlignCenterIcon />
751
+ </Button>
752
+ </div>
753
+ ```
754
+
755
+ ### Call to Action (CTA)
756
+
757
+ Botón prominente en landing pages.
758
+
759
+ ```tsx
760
+ <Button size="lg" className="text-base px-8">
761
+ Get Started Free
762
+ <ArrowRightIcon />
763
+ </Button>
764
+ ```
765
+
766
+ ### Navegación
767
+
768
+ Botones como links de navegación.
769
+
770
+ ```tsx
771
+ import { useNavigate } from "react-router-dom";
772
+
773
+ function Navigation() {
774
+ const navigate = useNavigate();
775
+
776
+ return (
777
+ <div className="flex gap-2">
778
+ <Button variant="ghost" onClick={() => navigate("/home")}>
779
+ Home
780
+ </Button>
781
+ <Button variant="ghost" onClick={() => navigate("/about")}>
782
+ About
783
+ </Button>
784
+ <Button variant="ghost" onClick={() => navigate("/contact")}>
785
+ Contact
786
+ </Button>
787
+ </div>
788
+ );
789
+ }
790
+ ```
791
+
792
+ ### Botones de Paginación
793
+
794
+ ```tsx
795
+ <div className="flex items-center gap-2">
796
+ <Button size="icon-sm" variant="outline" disabled={currentPage === 1}>
797
+ <ChevronLeftIcon />
798
+ </Button>
799
+ <span className="text-sm">
800
+ Page {currentPage} of {totalPages}
801
+ </span>
802
+ <Button
803
+ size="icon-sm"
804
+ variant="outline"
805
+ disabled={currentPage === totalPages}
806
+ >
807
+ <ChevronRightIcon />
808
+ </Button>
809
+ </div>
810
+ ```
811
+
812
+ ## Mejores Prácticas
813
+
814
+ ### Jerarquía Visual
815
+
816
+ ```tsx
817
+ {
818
+ /* ✅ Correcto - Jerarquía clara */
819
+ }
820
+ <div className="flex gap-2">
821
+ <Button variant="outline">Cancel</Button>
822
+ <Button>Save</Button> {/* Acción primaria más prominente */}
823
+ </div>;
824
+
825
+ {
826
+ /* ❌ Incorrecto - Todas las acciones con igual énfasis */
827
+ }
828
+ <div className="flex gap-2">
829
+ <Button>Cancel</Button>
830
+ <Button>Save</Button>
831
+ </div>;
832
+ ```
833
+
834
+ ### Textos Descriptivos
835
+
836
+ ```tsx
837
+ {/* ✅ Correcto - Texto claro */}
838
+ <Button>Save Changes</Button>
839
+ <Button variant="destructive">Delete Account</Button>
840
+
841
+ {/* ❌ Incorrecto - Texto genérico */}
842
+ <Button>OK</Button>
843
+ <Button>Submit</Button>
844
+ ```
845
+
846
+ ### aria-label en Botones de Icono
847
+
848
+ ```tsx
849
+ {
850
+ /* ✅ Correcto - Accesible */
851
+ }
852
+ <Button size="icon" aria-label="Settings">
853
+ <SettingsIcon />
854
+ </Button>;
855
+
856
+ {
857
+ /* ❌ Incorrecto - No accesible */
858
+ }
859
+ <Button size="icon">
860
+ <SettingsIcon />
861
+ </Button>;
862
+ ```
863
+
864
+ ### Loading State
865
+
866
+ ```tsx
867
+ {
868
+ /* ✅ Correcto - Estado de carga explícito */
869
+ }
870
+ <Button disabled={isLoading}>
871
+ {isLoading && <Loader2Icon className="animate-spin" />}
872
+ {isLoading ? "Saving..." : "Save"}
873
+ </Button>;
874
+
875
+ {
876
+ /* ❌ Incorrecto - Solo disabled sin feedback visual */
877
+ }
878
+ <Button disabled={isLoading}>Save</Button>;
879
+ ```
880
+
881
+ ### Variantes Semánticas
882
+
883
+ ```tsx
884
+ {/* ✅ Correcto - Variantes apropiadas */}
885
+ <Button variant="success">Approve</Button>
886
+ <Button variant="destructive">Delete</Button>
887
+ <Button variant="warning">Proceed with Caution</Button>
888
+
889
+ {/* ❌ Incorrecto - Variantes genéricas para acciones críticas */}
890
+ <Button>Delete All Data</Button> {/* Debería ser destructive */}
891
+ ```
892
+
893
+ ### Espaciado Consistente
894
+
895
+ ```tsx
896
+ {
897
+ /* ✅ Correcto - Gap consistente */
898
+ }
899
+ <div className="flex gap-2">
900
+ <Button variant="outline">Back</Button>
901
+ <Button variant="outline">Skip</Button>
902
+ <Button>Next</Button>
903
+ </div>;
904
+
905
+ {
906
+ /* ✅ También correcto - Separar acciones por importancia */
907
+ }
908
+ <div className="flex justify-between">
909
+ <Button variant="outline">Cancel</Button>
910
+ <div className="flex gap-2">
911
+ <Button variant="outline">Save as Draft</Button>
912
+ <Button>Publish</Button>
913
+ </div>
914
+ </div>;
915
+ ```
916
+
917
+ ## Notas de Implementación
918
+
919
+ - Basado en CVA (class-variance-authority) para variants system
920
+ - Usa Radix UI Slot para la prop `asChild`
921
+ - Los iconos SVG sin clase `size-*` se auto-dimensionan a 16px
922
+ - Padding horizontal se ajusta automáticamente con `has-[>svg]` selector
923
+ - Focus ring usa `focus-visible` (solo teclado, no mouse)
924
+ - Transiciones en `all` para suavidad en todos los cambios
925
+ - Sistema de slots con `data-slot="button"` para identificación
926
+ - Todos los botones son `inline-flex` para alineación perfecta
927
+ - `shrink-0` evita que botones se encojan en layouts flex
928
+
929
+ ## Accesibilidad
930
+
931
+ ### Navegación por Teclado
932
+
933
+ - ✅ **Tab**: Navega al botón
934
+ - ✅ **Space/Enter**: Activa el botón
935
+ - ✅ **Escape**: Sale del focus (en algunos contextos)
936
+
937
+ ### Estados Visuales Claros
938
+
939
+ - ✅ Focus ring visible solo con teclado (`focus-visible`)
940
+ - ✅ Disabled state con opacity reducida
941
+ - ✅ Hover state en todas las variantes
942
+ - ✅ Contraste de colores cumple WCAG AA
943
+
944
+ ### ARIA Best Practices
945
+
946
+ ```tsx
947
+ {/* ✅ Botón de icono con aria-label */}
948
+ <Button size="icon" aria-label="Delete item">
949
+ <TrashIcon />
950
+ </Button>
951
+
952
+ {/* ✅ Botón con estado de carga */}
953
+ <Button disabled={isLoading} aria-busy={isLoading}>
954
+ {isLoading && <Loader2Icon className="animate-spin" />}
955
+ {isLoading ? "Loading..." : "Submit"}
956
+ </Button>
957
+
958
+ {/* ✅ Botón con estado pressed (toggle) */}
959
+ <Button
960
+ variant={isActive ? "default" : "outline"}
961
+ aria-pressed={isActive}
962
+ onClick={() => setIsActive(!isActive)}
963
+ >
964
+ {isActive ? "Active" : "Inactive"}
965
+ </Button>
966
+
967
+ {/* ✅ Botón con descripción expandida */}
968
+ <Button aria-describedby="delete-description">
969
+ Delete Account
970
+ </Button>
971
+ <p id="delete-description" className="sr-only">
972
+ This action cannot be undone. All your data will be permanently deleted.
973
+ </p>
974
+ ```
975
+
976
+ ### Type en Formularios
977
+
978
+ ```tsx
979
+ {
980
+ /* ✅ Correcto - type explícito */
981
+ }
982
+ <form onSubmit={handleSubmit}>
983
+ <Button type="submit">Submit</Button>
984
+ <Button type="button" onClick={handleCancel}>
985
+ Cancel
986
+ </Button>
987
+ <Button type="reset">Reset Form</Button>
988
+ </form>;
989
+
990
+ {
991
+ /* ⚠️ Cuidado - sin type en form, default es submit */
992
+ }
993
+ <form>
994
+ <Button>Click me</Button> {/* Se comporta como submit */}
995
+ </form>;
996
+ ```
997
+
998
+ ### Screen Readers
999
+
1000
+ - ✅ Texto descriptivo en lugar de solo iconos
1001
+ - ✅ `aria-label` para botones de solo icono
1002
+ - ✅ `aria-busy` durante estados de carga
1003
+ - ✅ `aria-invalid` para estados de error
1004
+ - ✅ Disabled buttons se anuncian como "disabled" o "dimmed"
1005
+
1006
+ ## Troubleshooting
1007
+
1008
+ ### Botón No Se Ve Como Esperado
1009
+
1010
+ **Problema**: Los estilos no se aplican correctamente.
1011
+
1012
+ **Solución**:
1013
+
1014
+ ```tsx
1015
+ // ❌ Incorrecto - className sobrescribe variantes
1016
+ <Button className="bg-red-500">Click</Button>
1017
+
1018
+ // ✅ Correcto - Usa variantes predefinidas
1019
+ <Button variant="destructive">Click</Button>
1020
+
1021
+ // ✅ O combina correctamente
1022
+ <Button variant="destructive" className="rounded-full">Click</Button>
1023
+ ```
1024
+
1025
+ ### Icono No Se Auto-Dimensiona
1026
+
1027
+ **Problema**: El icono es muy grande o muy pequeño.
1028
+
1029
+ **Solución**:
1030
+
1031
+ ```tsx
1032
+ // ❌ Incorrecto - clase size-* evita auto-dimensionado
1033
+ <Button>
1034
+ <SaveIcon className="size-8" /> {/* Muy grande */}
1035
+ Save
1036
+ </Button>
1037
+
1038
+ // ✅ Correcto - sin clase size-*
1039
+ <Button>
1040
+ <SaveIcon /> {/* Auto-dimensionado a 16px */}
1041
+ Save
1042
+ </Button>
1043
+
1044
+ // ✅ O especifica tamaño personalizado si es necesario
1045
+ <Button>
1046
+ <SaveIcon className="h-5 w-5" />
1047
+ Save
1048
+ </Button>
1049
+ ```
1050
+
1051
+ ### asChild No Funciona
1052
+
1053
+ **Problema**: El hijo no recibe los estilos.
1054
+
1055
+ **Solución**:
1056
+
1057
+ ```tsx
1058
+ // ❌ Incorrecto - múltiples hijos
1059
+ <Button asChild>
1060
+ <a href="/link">Click</a>
1061
+ <span>Extra</span>
1062
+ </Button>
1063
+
1064
+ // ✅ Correcto - un solo hijo directo
1065
+ <Button asChild>
1066
+ <a href="/link">
1067
+ <LinkIcon />
1068
+ Click Me
1069
+ </a>
1070
+ </Button>
1071
+ ```
1072
+
1073
+ ## Referencias
1074
+
1075
+ - CVA (Class Variance Authority): https://cva.style/docs
1076
+ - Radix UI Slot: https://www.radix-ui.com/primitives/docs/utilities/slot
1077
+ - shadcn/ui Button: https://ui.shadcn.com/docs/components/button
1078
+ - WCAG 2.1 Button Guidelines: https://www.w3.org/WAI/ARIA/apg/patterns/button/