@adamosuiteservices/ui 1.2.5 → 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 (177) hide show
  1. package/dist/accordion-rounded.cjs +1 -1
  2. package/dist/accordion-rounded.js +1 -1
  3. package/dist/accordion.cjs +1 -1
  4. package/dist/accordion.js +1 -1
  5. package/dist/avatar.cjs +1 -1
  6. package/dist/avatar.js +1 -1
  7. package/dist/badge.cjs +1 -1
  8. package/dist/badge.js +1 -1
  9. package/dist/breadcrumb.cjs +1 -0
  10. package/dist/breadcrumb.js +105 -0
  11. package/dist/{button-C1n6snOY.js → button-2GdKenQI.js} +1 -1
  12. package/dist/{button-BV-_FVKZ.cjs → button-DEQVHMrX.cjs} +1 -1
  13. package/dist/button-group.cjs +1 -1
  14. package/dist/button-group.js +2 -2
  15. package/dist/button.cjs +1 -1
  16. package/dist/button.js +1 -1
  17. package/dist/calendar.cjs +1 -1
  18. package/dist/calendar.js +1 -1
  19. package/dist/{checkbox-BrmXPKTn.js → checkbox-Dr487kAg.js} +3 -3
  20. package/dist/{checkbox-Lq-HvSgc.cjs → checkbox-YWAnswaW.cjs} +1 -1
  21. package/dist/checkbox.cjs +1 -1
  22. package/dist/checkbox.js +1 -1
  23. package/dist/collapsible.cjs +1 -1
  24. package/dist/collapsible.js +1 -1
  25. package/dist/combobox.cjs +1 -1
  26. package/dist/combobox.js +6 -6
  27. package/dist/components/ui/breadcrumb/breadcrumb.d.ts +11 -0
  28. package/dist/components/ui/breadcrumb/breadcrumb.stories.d.ts +26 -0
  29. package/dist/components/ui/breadcrumb/index.d.ts +1 -0
  30. package/dist/components/ui/dialog/dialog.d.ts +2 -1
  31. package/dist/context-menu.cjs +1 -1
  32. package/dist/context-menu.js +2 -2
  33. package/dist/custom-layered-styles.css +1 -1
  34. package/dist/dialog.cjs +1 -1
  35. package/dist/dialog.js +33 -19
  36. package/dist/dropdown-menu.cjs +1 -1
  37. package/dist/dropdown-menu.js +3 -3
  38. package/dist/ellipsis-CryjZKZn.js +15 -0
  39. package/dist/ellipsis-Ct9VTDOG.cjs +6 -0
  40. package/dist/field.cjs +1 -1
  41. package/dist/field.js +2 -2
  42. package/dist/hover-card.cjs +1 -1
  43. package/dist/hover-card.js +6 -6
  44. package/dist/{index-CAOY367Y.js → index-B0M7VOwp.js} +2 -2
  45. package/dist/{index-B-ZRqW0J.js → index-BBoIAjAs.js} +3 -3
  46. package/dist/{index-gO_QEiaK.cjs → index-BDs8lUfq.cjs} +1 -1
  47. package/dist/index-BFyr34mw.cjs +5 -0
  48. package/dist/index-BMWt1NBG.js +79 -0
  49. package/dist/{index-yR-v1A4G.js → index-BX9hz-JD.js} +1 -1
  50. package/dist/{index-BGiGvaq8.cjs → index-BcGMAmWE.cjs} +1 -1
  51. package/dist/{index-IKJMQref.cjs → index-Bd0gQB0k.cjs} +1 -1
  52. package/dist/{index-VIUqZjyP.cjs → index-BeWgla7c.cjs} +1 -1
  53. package/dist/{index-EUea2gfp.js → index-BpWB3aFK.js} +1 -1
  54. package/dist/index-BvLQnI56.js +59 -0
  55. package/dist/{index-CwUFT-GQ.js → index-C0YiLSjW.js} +4 -4
  56. package/dist/{index-o0sNTcKe.js → index-CBjZooac.js} +2 -2
  57. package/dist/{index-DnS_sBBe.cjs → index-COuvjZLM.cjs} +1 -1
  58. package/dist/index-CTjlbbt9.cjs +1 -0
  59. package/dist/index-CUWMxxKG.js +97 -0
  60. package/dist/{index-C329e3yQ.js → index-CZZ3llmi.js} +2 -2
  61. package/dist/index-CjyiloO7.cjs +1 -0
  62. package/dist/{index-D3wSWKST.cjs → index-Cmx9M9cZ.cjs} +1 -1
  63. package/dist/index-CocSS1YK.cjs +1 -0
  64. package/dist/index-CzRiuk60.cjs +1 -0
  65. package/dist/index-DFPDUUq7.js +658 -0
  66. package/dist/{index-D3S7dBDI.cjs → index-DIwmXz1u.cjs} +1 -1
  67. package/dist/index-DLcqcWxM.js +29 -0
  68. package/dist/index-DMLQL2aG.js +286 -0
  69. package/dist/{index-DXQ-7kNJ.cjs → index-DMs8RL3E.cjs} +1 -1
  70. package/dist/{index-Ce3QBKyj.cjs → index-Dbj9vHNq.cjs} +1 -1
  71. package/dist/{index-BRLtxFFr.cjs → index-DmGzwG2z.cjs} +1 -1
  72. package/dist/{index-P1sVIHE3.js → index-PYkEXTqJ.js} +1 -1
  73. package/dist/{index-DulPG3F9.js → index-Se4vRnIO.js} +3 -3
  74. package/dist/index-_XxjJPRD.cjs +1 -0
  75. package/dist/{index-B-cHTKrs.js → index-yWvyIlmA.js} +4 -4
  76. package/dist/input-group.cjs +1 -1
  77. package/dist/input-group.js +1 -1
  78. package/dist/{label-Cne2J57f.cjs → label-BjXORCBM.cjs} +1 -1
  79. package/dist/{label-Ky8qBEC3.js → label-CmwGvhy1.js} +1 -1
  80. package/dist/label.cjs +1 -1
  81. package/dist/label.js +1 -1
  82. package/dist/pagination.cjs +1 -6
  83. package/dist/pagination.js +58 -69
  84. package/dist/popover-3rIoNCXs.js +306 -0
  85. package/dist/popover-FCKBtFo-.cjs +1 -0
  86. package/dist/popover.cjs +1 -1
  87. package/dist/popover.js +1 -1
  88. package/dist/progress.cjs +1 -1
  89. package/dist/progress.js +1 -1
  90. package/dist/radio-group.cjs +1 -1
  91. package/dist/radio-group.js +5 -5
  92. package/dist/select.cjs +2 -2
  93. package/dist/select.js +585 -542
  94. package/dist/{separator-CGnu_jIu.cjs → separator-BaZqZZ9R.cjs} +1 -1
  95. package/dist/{separator-BH73A90k.js → separator-DR7lQjv9.js} +1 -1
  96. package/dist/separator.cjs +1 -1
  97. package/dist/separator.js +1 -1
  98. package/dist/{sheet-CcxnJ6LH.cjs → sheet-CU-sFSaJ.cjs} +1 -1
  99. package/dist/{sheet-_DVpQIVF.js → sheet-UZWAbdXr.js} +1 -1
  100. package/dist/sheet.cjs +1 -1
  101. package/dist/sheet.js +1 -1
  102. package/dist/sidebar.cjs +1 -1
  103. package/dist/sidebar.js +4 -4
  104. package/dist/slider.cjs +1 -1
  105. package/dist/slider.js +3 -3
  106. package/dist/styles.css +1 -1
  107. package/dist/switch.cjs +1 -1
  108. package/dist/switch.js +2 -2
  109. package/dist/tabs-underline.cjs +1 -1
  110. package/dist/tabs-underline.js +1 -1
  111. package/dist/tabs.cjs +1 -1
  112. package/dist/tabs.js +1 -1
  113. package/dist/toaster.cjs +1 -1
  114. package/dist/toaster.js +1 -1
  115. package/dist/toggle.cjs +1 -1
  116. package/dist/toggle.js +1 -1
  117. package/dist/tooltip.cjs +1 -1
  118. package/dist/tooltip.js +114 -108
  119. package/dist/typography.cjs +1 -1
  120. package/dist/typography.js +1 -1
  121. package/docs/AI-GUIDE.md +321 -0
  122. package/docs/components/layout/sidebar.md +330 -0
  123. package/docs/components/layout/toaster.md +436 -0
  124. package/docs/components/ui/accordion-rounded.md +583 -0
  125. package/docs/components/ui/accordion.md +267 -0
  126. package/docs/components/ui/alert.md +671 -0
  127. package/docs/components/ui/avatar.md +588 -0
  128. package/docs/components/ui/badge.md +1024 -0
  129. package/docs/components/ui/breadcrumb.md +614 -0
  130. package/docs/components/ui/button-group.md +1002 -0
  131. package/docs/components/ui/button.md +1078 -0
  132. package/docs/components/ui/calendar.md +1159 -0
  133. package/docs/components/ui/card.md +1265 -0
  134. package/docs/components/ui/checkbox.md +292 -0
  135. package/docs/components/ui/collapsible.md +320 -0
  136. package/docs/components/ui/combobox.md +328 -0
  137. package/docs/components/ui/command.md +454 -0
  138. package/docs/components/ui/context-menu.md +540 -0
  139. package/docs/components/ui/dialog.md +628 -0
  140. package/docs/components/ui/dropdown-menu.md +731 -0
  141. package/docs/components/ui/field.md +706 -0
  142. package/docs/components/ui/hover-card.md +446 -0
  143. package/docs/components/ui/input-group.md +509 -0
  144. package/docs/components/ui/input.md +362 -0
  145. package/docs/components/ui/kbd.md +434 -0
  146. package/docs/components/ui/label.md +359 -0
  147. package/docs/components/ui/pagination.md +650 -0
  148. package/docs/components/ui/popover.md +536 -0
  149. package/docs/components/ui/progress.md +182 -0
  150. package/docs/components/ui/radio-group.md +311 -0
  151. package/docs/components/ui/select.md +352 -0
  152. package/docs/components/ui/separator.md +214 -0
  153. package/docs/components/ui/sheet.md +142 -0
  154. package/docs/components/ui/skeleton.md +140 -0
  155. package/docs/components/ui/slider.md +341 -0
  156. package/docs/components/ui/spinner.md +170 -0
  157. package/docs/components/ui/switch.md +402 -0
  158. package/docs/components/ui/table.md +183 -0
  159. package/docs/components/ui/tabs-underline.md +106 -0
  160. package/docs/components/ui/tabs.md +122 -0
  161. package/docs/components/ui/textarea.md +243 -0
  162. package/docs/components/ui/toggle.md +243 -0
  163. package/docs/components/ui/tooltip.md +320 -0
  164. package/docs/components/ui/typography.md +191 -0
  165. package/package.json +11 -5
  166. package/dist/index-6oTEokEx.js +0 -82
  167. package/dist/index-B-NyefE0.js +0 -243
  168. package/dist/index-BKbK2GzY.cjs +0 -1
  169. package/dist/index-BMitW9UR.cjs +0 -1
  170. package/dist/index-BpvjJ_T6.cjs +0 -5
  171. package/dist/index-C5wjudc-.js +0 -36
  172. package/dist/index-CezwiPd_.js +0 -615
  173. package/dist/index-D02K8KOB.js +0 -54
  174. package/dist/index-D7hQvndv.cjs +0 -1
  175. package/dist/index-DQvx1rG_.cjs +0 -1
  176. package/dist/popover-BjdTqaB8.cjs +0 -1
  177. package/dist/popover-EnVfE0YA.js +0 -263
@@ -0,0 +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/
@@ -0,0 +1,320 @@
1
+ # Collapsible
2
+
3
+ Componente interactivo basado en Radix UI para expandir/colapsar contenido con animaciones suaves. Útil para FAQs, menús de navegación, y secciones opcionales.
4
+
5
+ ## Importación
6
+
7
+ ```tsx
8
+ import {
9
+ Collapsible,
10
+ CollapsibleTrigger,
11
+ CollapsibleContent,
12
+ } from "@adamosuiteservices/ui/collapsible";
13
+ ```
14
+
15
+ ## Anatomía
16
+
17
+ ```tsx
18
+ <Collapsible>
19
+ <CollapsibleTrigger>Click to toggle</CollapsibleTrigger>
20
+ <CollapsibleContent>Hidden content that expands/collapses</CollapsibleContent>
21
+ </Collapsible>
22
+ ```
23
+
24
+ **Componentes**: 3 (Collapsible root, CollapsibleTrigger, CollapsibleContent)
25
+
26
+ ## Props Principales
27
+
28
+ ### Collapsible (Root)
29
+
30
+ | Prop | Tipo | Default | Descripción |
31
+ | -------------- | ------------------------- | ------- | ----------------------------------- |
32
+ | `open` | `boolean` | - | Estado controlado (abierto/cerrado) |
33
+ | `defaultOpen` | `boolean` | `false` | Estado inicial no controlado |
34
+ | `onOpenChange` | `(open: boolean) => void` | - | Callback al cambiar estado |
35
+ | `disabled` | `boolean` | `false` | Desactiva interacción |
36
+ | `className` | `string` | - | Clases CSS adicionales |
37
+
38
+ ### CollapsibleTrigger
39
+
40
+ | Prop | Tipo | Default | Descripción |
41
+ | ----------- | --------- | ------- | ----------------------------------- |
42
+ | `asChild` | `boolean` | `false` | Usa child como trigger (Radix Slot) |
43
+ | `className` | `string` | - | Clases CSS adicionales |
44
+
45
+ ### CollapsibleContent
46
+
47
+ | Prop | Tipo | Default | Descripción |
48
+ | ------------ | --------- | ------- | ----------------------------------------- |
49
+ | `forceMount` | `boolean` | `false` | Fuerza montaje en DOM aunque esté cerrado |
50
+ | `className` | `string` | - | Clases CSS adicionales |
51
+
52
+ ## Patrones de Uso
53
+
54
+ ### Básico (No Controlado)
55
+
56
+ ```tsx
57
+ <Collapsible>
58
+ <CollapsibleTrigger>Show details</CollapsibleTrigger>
59
+ <CollapsibleContent>
60
+ <p>Additional information here.</p>
61
+ </CollapsibleContent>
62
+ </Collapsible>
63
+ ```
64
+
65
+ ### Controlado con Estado
66
+
67
+ ```tsx
68
+ const [isOpen, setIsOpen] = useState(false);
69
+
70
+ <Collapsible open={isOpen} onOpenChange={setIsOpen}>
71
+ <CollapsibleTrigger>{isOpen ? "Hide" : "Show"} content</CollapsibleTrigger>
72
+ <CollapsibleContent>
73
+ <p>Controlled content</p>
74
+ </CollapsibleContent>
75
+ </Collapsible>;
76
+ ```
77
+
78
+ ### Con Botón Custom (asChild)
79
+
80
+ ```tsx
81
+ import { Button } from "@adamosuiteservices/ui/button";
82
+ import { ChevronsUpDownIcon } from "lucide-react";
83
+
84
+ <Collapsible>
85
+ <CollapsibleTrigger asChild>
86
+ <Button variant="outline" size="sm">
87
+ <ChevronsUpDownIcon />
88
+ Toggle
89
+ </Button>
90
+ </CollapsibleTrigger>
91
+ <CollapsibleContent>
92
+ <p>Content</p>
93
+ </CollapsibleContent>
94
+ </Collapsible>;
95
+ ```
96
+
97
+ ### Con Chevron Rotatorio
98
+
99
+ ```tsx
100
+ const [isOpen, setIsOpen] = useState(false);
101
+
102
+ <Collapsible open={isOpen} onOpenChange={setIsOpen}>
103
+ <CollapsibleTrigger className="flex w-full items-center justify-between p-4 border rounded-lg hover:bg-muted">
104
+ <span>Section Title</span>
105
+ <ChevronDownIcon
106
+ className={`h-4 w-4 transition-transform ${isOpen ? "rotate-180" : ""}`}
107
+ />
108
+ </CollapsibleTrigger>
109
+ <CollapsibleContent className="p-4">
110
+ <p>Expandable content</p>
111
+ </CollapsibleContent>
112
+ </Collapsible>;
113
+ ```
114
+
115
+ ### FAQ Pattern
116
+
117
+ ```tsx
118
+ <div className="space-y-4">
119
+ <Collapsible>
120
+ <CollapsibleTrigger className="flex w-full items-center justify-between border p-4 rounded-lg hover:bg-muted">
121
+ <span className="font-medium">What is this?</span>
122
+ <ChevronRightIcon className="h-4 w-4" />
123
+ </CollapsibleTrigger>
124
+ <CollapsibleContent className="px-4 pb-4">
125
+ <p className="text-sm text-muted-foreground">
126
+ This is a reusable UI component library.
127
+ </p>
128
+ </CollapsibleContent>
129
+ </Collapsible>
130
+
131
+ <Collapsible>
132
+ <CollapsibleTrigger className="flex w-full items-center justify-between border p-4 rounded-lg hover:bg-muted">
133
+ <span className="font-medium">How to install?</span>
134
+ <ChevronRightIcon className="h-4 w-4" />
135
+ </CollapsibleTrigger>
136
+ <CollapsibleContent className="px-4 pb-4">
137
+ <p className="text-sm text-muted-foreground">
138
+ Use: <code>npm install @adamosuiteservices/ui</code>
139
+ </p>
140
+ </CollapsibleContent>
141
+ </Collapsible>
142
+ </div>
143
+ ```
144
+
145
+ ### Navigation Menu
146
+
147
+ ```tsx
148
+ const [openSections, setOpenSections] = useState<string[]>(["settings"]);
149
+
150
+ const toggleSection = (id: string) => {
151
+ setOpenSections((prev) =>
152
+ prev.includes(id) ? prev.filter((s) => s !== id) : [...prev, id]
153
+ );
154
+ };
155
+
156
+ <div className="space-y-2">
157
+ <Collapsible
158
+ open={openSections.includes("settings")}
159
+ onOpenChange={() => toggleSection("settings")}
160
+ >
161
+ <CollapsibleTrigger className="flex w-full items-center gap-2 p-3 rounded-lg hover:bg-muted">
162
+ <SettingsIcon className="h-4 w-4" />
163
+ <span className="flex-1 font-medium">Settings</span>
164
+ <ChevronDownIcon
165
+ className={`h-4 w-4 transition-transform ${
166
+ openSections.includes("settings") ? "rotate-180" : ""
167
+ }`}
168
+ />
169
+ </CollapsibleTrigger>
170
+ <CollapsibleContent className="ml-6 space-y-1">
171
+ <a href="#" className="block px-3 py-2 text-sm rounded hover:bg-muted">
172
+ Profile
173
+ </a>
174
+ <a href="#" className="block px-3 py-2 text-sm rounded hover:bg-muted">
175
+ Security
176
+ </a>
177
+ </CollapsibleContent>
178
+ </Collapsible>
179
+
180
+ <Collapsible
181
+ open={openSections.includes("account")}
182
+ onOpenChange={() => toggleSection("account")}
183
+ >
184
+ <CollapsibleTrigger className="flex w-full items-center gap-2 p-3 rounded-lg hover:bg-muted">
185
+ <UserIcon className="h-4 w-4" />
186
+ <span className="flex-1 font-medium">Account</span>
187
+ <ChevronDownIcon
188
+ className={`h-4 w-4 transition-transform ${
189
+ openSections.includes("account") ? "rotate-180" : ""
190
+ }`}
191
+ />
192
+ </CollapsibleTrigger>
193
+ <CollapsibleContent className="ml-6 space-y-1">
194
+ <a href="#" className="block px-3 py-2 text-sm rounded hover:bg-muted">
195
+ Billing
196
+ </a>
197
+ <a href="#" className="block px-3 py-2 text-sm rounded hover:bg-muted">
198
+ API Keys
199
+ </a>
200
+ </CollapsibleContent>
201
+ </Collapsible>
202
+ </div>;
203
+ ```
204
+
205
+ ### Lista de Archivos
206
+
207
+ ```tsx
208
+ <Collapsible defaultOpen className="w-full space-y-2">
209
+ <CollapsibleTrigger className="w-full border p-3 rounded-lg text-left font-medium hover:bg-muted">
210
+ Recent Files
211
+ </CollapsibleTrigger>
212
+ <CollapsibleContent className="space-y-1">
213
+ <div className="border p-3 rounded text-sm">document.pdf</div>
214
+ <div className="border p-3 rounded text-sm">presentation.pptx</div>
215
+ <div className="border p-3 rounded text-sm">spreadsheet.xlsx</div>
216
+ </CollapsibleContent>
217
+ </Collapsible>
218
+ ```
219
+
220
+ ### Sección Deshabilitada
221
+
222
+ ```tsx
223
+ <Collapsible disabled>
224
+ <CollapsibleTrigger className="w-full border p-3 rounded-lg text-left font-medium opacity-50 cursor-not-allowed">
225
+ Coming Soon
226
+ </CollapsibleTrigger>
227
+ <CollapsibleContent>
228
+ <p className="p-3 text-sm text-muted-foreground">Not available yet.</p>
229
+ </CollapsibleContent>
230
+ </Collapsible>
231
+ ```
232
+
233
+ ### Con Layout de Tarjeta
234
+
235
+ ```tsx
236
+ <Collapsible className="border rounded-lg p-4">
237
+ <div className="flex items-center justify-between mb-2">
238
+ <h4 className="font-semibold">@user starred 3 repos</h4>
239
+ <CollapsibleTrigger asChild>
240
+ <Button variant="outline" size="sm">
241
+ <ChevronsUpDownIcon />
242
+ </Button>
243
+ </CollapsibleTrigger>
244
+ </div>
245
+
246
+ <div className="border px-4 py-2 rounded font-mono text-sm">
247
+ @radix-ui/primitives
248
+ </div>
249
+
250
+ <CollapsibleContent className="mt-2 space-y-2">
251
+ <div className="border px-4 py-2 rounded font-mono text-sm">
252
+ @radix-ui/colors
253
+ </div>
254
+ <div className="border px-4 py-2 rounded font-mono text-sm">
255
+ @stitches/react
256
+ </div>
257
+ </CollapsibleContent>
258
+ </Collapsible>
259
+ ```
260
+
261
+ ## Casos de Uso Comunes
262
+
263
+ **FAQ sections**: Lista de preguntas frecuentes expandibles
264
+ **Navigation menus**: Menús colapsables con subsecciones
265
+ **Details/Summary**: Información adicional opcional
266
+ **File browsers**: Estructuras de carpetas expandibles
267
+ **Settings panels**: Grupos de configuraciones organizadas
268
+ **Table rows**: Filas de tabla con detalles expandibles
269
+
270
+ ## Estilos y Animaciones
271
+
272
+ ### Data States
273
+
274
+ - **Abierto**: `data-state="open"` en todos los componentes
275
+ - **Cerrado**: `data-state="closed"` en todos los componentes
276
+ - **Disabled**: `data-disabled` cuando `disabled={true}`
277
+
278
+ ### Animación Suave
279
+
280
+ El contenido usa animaciones CSS automáticas (height, opacity) al expandir/colapsar. No requiere configuración adicional.
281
+
282
+ ### Custom Animations
283
+
284
+ ```tsx
285
+ <CollapsibleContent className="data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp">
286
+ Content with custom animations
287
+ </CollapsibleContent>
288
+ ```
289
+
290
+ ## Accesibilidad
291
+
292
+ - ✅ **Navegación teclado**: Enter/Space para toggle en trigger, Tab para navegar
293
+ - ✅ **ARIA**: `aria-expanded`, `aria-controls` automáticos en trigger
294
+ - ✅ **Screen readers**: Anuncia estado expandido/colapsado
295
+ - ✅ **Focus visible**: Trigger recibe focus del teclado
296
+ - ✅ **Disabled state**: `aria-disabled` cuando disabled
297
+
298
+ ## Notas de Implementación
299
+
300
+ - **Basado en Radix UI**: `@radix-ui/react-collapsible`
301
+ - **No tiene estilos propios**: Wrapper limpio, agrega tus propios estilos
302
+ - **Data slots**: `data-slot="collapsible"`, `data-slot="collapsible-trigger"`, `data-slot="collapsible-content"`
303
+ - **asChild pattern**: CollapsibleTrigger soporta `asChild` para usar componentes custom
304
+ - **Animaciones automáticas**: Radix maneja transiciones de height/opacity
305
+ - **forceMount**: Útil para animaciones custom o cuando necesitas el DOM montado siempre
306
+ - **Multiple instances**: Puedes tener múltiples Collapsibles independientes
307
+ - **Accordion vs Collapsible**: Usa Accordion cuando solo uno debe estar abierto, Collapsible para control independiente
308
+
309
+ ## Troubleshooting
310
+
311
+ **Animación no suave**: Radix maneja animaciones automáticamente, si no se ve suave verifica que no haya `transition` conflictivos en CSS
312
+ **Trigger no clickeable**: Verifica que esté dentro de `<Collapsible>`, no como hermano
313
+ **asChild no funciona**: Asegúrate que el child acepta props `onClick` y `aria-*`
314
+ **Content siempre visible**: Verifica que no tengas `forceMount` activado sin intención
315
+ **Estado no sincroniza**: En modo controlado, asegúrate de usar ambos `open` y `onOpenChange`
316
+
317
+ ## Referencias
318
+
319
+ - **Radix UI Collapsible**: https://www.radix-ui.com/primitives/docs/components/collapsible
320
+ - **ARIA Disclosure**: https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/