@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,509 @@
1
+ # Input Group Component
2
+
3
+ Combina inputs/textareas con addons (texto, iconos, botones). Perfecto para campos con unidades, prefijos, acciones integradas o información contextual adicional.
4
+
5
+ ## Descripción
6
+
7
+ El componente `InputGroup` combina inputs con prefijos, sufijos y addons.
8
+
9
+ ## Importación
10
+
11
+ ```typescript
12
+ import {
13
+ InputGroup,
14
+ InputGroupAddon,
15
+ InputGroupButton,
16
+ InputGroupText,
17
+ InputGroupInput,
18
+ InputGroupTextarea,
19
+ } from "@adamosuiteservices/ui/input-group";
20
+ ```
21
+
22
+ ## Uso Básico
23
+
24
+ ```tsx
25
+ <InputGroup>
26
+ <InputGroup.Addon>https://</InputGroup.Addon>
27
+ <Input placeholder="example.com" />
28
+ </InputGroup>
29
+ ```
30
+
31
+ ## Con Icono
32
+
33
+ ```tsx
34
+ <InputGroup>
35
+ <InputGroup.Icon>
36
+ <SearchIcon />
37
+ </InputGroup.Icon>
38
+ <Input placeholder="Search..." />
39
+ </InputGroup>
40
+ ```
41
+
42
+ ## Con Botón
43
+
44
+ ```tsx
45
+ <InputGroup>
46
+ <Input placeholder="Enter email" />
47
+ <InputGroup.Button>
48
+ <Button>Subscribe</Button>
49
+ </InputGroup.Button>
50
+ </InputGroup>
51
+ ```
52
+
53
+ **Componentes**: 6 (InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea)
54
+
55
+ ## Props Principales
56
+
57
+ ### InputGroup (Root)
58
+
59
+ | Prop | Tipo | Descripción |
60
+ | --------------- | --------- | ------------------------------------- |
61
+ | `data-disabled` | `boolean` | Marca el grupo como disabled (visual) |
62
+ | `className` | `string` | Clases CSS adicionales |
63
+
64
+ **Nota**: Acepta todas las props de `<div>`
65
+
66
+ ### InputGroupAddon
67
+
68
+ | Prop | Tipo | Default | Descripción |
69
+ | ----------- | ---------------------------------------------------------------- | ---------------- | ---------------------- |
70
+ | `align` | `"inline-start" \| "inline-end" \| "block-start" \| "block-end"` | `"inline-start"` | Posición del addon |
71
+ | `className` | `string` | - | Clases CSS adicionales |
72
+
73
+ **Positions**:
74
+
75
+ - `inline-start`: Izquierda (horizontal)
76
+ - `inline-end`: Derecha (horizontal)
77
+ - `block-start`: Arriba (vertical)
78
+ - `block-end`: Abajo (vertical)
79
+
80
+ ### InputGroupButton
81
+
82
+ | Prop | Tipo | Default | Descripción |
83
+ | --------- | ---------------------------------------- | ---------- | ---------------------------------------- |
84
+ | `size` | `"xs" \| "sm" \| "icon-xs" \| "icon-sm"` | `"xs"` | Tamaño del botón |
85
+ | `variant` | Button variants | `"ghost"` | Variante del botón |
86
+ | `type` | `string` | `"button"` | Tipo HTML del botón |
87
+ | ...rest | - | - | Todas las props de Button excepto `size` |
88
+
89
+ **Sizes**:
90
+
91
+ - `xs`: h-6, px-2
92
+ - `sm`: h-8, px-2.5
93
+ - `icon-xs`: size-6 (solo icono)
94
+ - `icon-sm`: size-8 (solo icono)
95
+
96
+ ### InputGroupText
97
+
98
+ | Prop | Tipo | Descripción |
99
+ | ----------- | -------- | ---------------------- |
100
+ | `className` | `string` | Clases CSS adicionales |
101
+
102
+ **Uso**: Wrapper para texto estático, iconos, labels, etc.
103
+
104
+ ### InputGroupInput
105
+
106
+ | Prop | Tipo | Descripción |
107
+ | ----------- | -------- | ------------------------------------ |
108
+ | ...props | - | Todas las props nativas de `<input>` |
109
+ | `className` | `string` | Clases CSS adicionales |
110
+
111
+ **Nota**: Estilos internos: sin border, sin shadow, bg-transparent
112
+
113
+ ### InputGroupTextarea
114
+
115
+ | Prop | Tipo | Descripción |
116
+ | ----------- | -------- | --------------------------------------- |
117
+ | ...props | - | Todas las props nativas de `<textarea>` |
118
+ | `className` | `string` | Clases CSS adicionales |
119
+
120
+ **Nota**: Estilos internos: sin border, sin shadow, bg-transparent, resize-none, py-3
121
+
122
+ ## Patrones de Uso
123
+
124
+ ### Básico con Icono
125
+
126
+ ```tsx
127
+ import { Search } from "lucide-react";
128
+
129
+ <InputGroup>
130
+ <InputGroupInput placeholder="Search..." />
131
+ <InputGroupAddon>
132
+ <Search />
133
+ </InputGroupAddon>
134
+ </InputGroup>;
135
+ ```
136
+
137
+ ### Con Texto (Precio)
138
+
139
+ ```tsx
140
+ <InputGroup>
141
+ <InputGroupAddon>
142
+ <InputGroupText>$</InputGroupText>
143
+ </InputGroupAddon>
144
+ <InputGroupInput placeholder="0.00" type="number" />
145
+ <InputGroupAddon align="inline-end">
146
+ <InputGroupText>USD</InputGroupText>
147
+ </InputGroupAddon>
148
+ </InputGroup>
149
+ ```
150
+
151
+ ### Con Prefijo URL
152
+
153
+ ```tsx
154
+ <InputGroup>
155
+ <InputGroupAddon>
156
+ <InputGroupText>https://</InputGroupText>
157
+ </InputGroupAddon>
158
+ <InputGroupInput placeholder="example.com" />
159
+ <InputGroupAddon align="inline-end">
160
+ <InputGroupText>.com</InputGroupText>
161
+ </InputGroupAddon>
162
+ </InputGroup>
163
+ ```
164
+
165
+ ### Con Email Domain
166
+
167
+ ```tsx
168
+ <InputGroup>
169
+ <InputGroupInput placeholder="Enter your username" />
170
+ <InputGroupAddon align="inline-end">
171
+ <InputGroupText>@company.com</InputGroupText>
172
+ </InputGroupAddon>
173
+ </InputGroup>
174
+ ```
175
+
176
+ ### Con Botón Copy
177
+
178
+ ```tsx
179
+ import { useState } from "react";
180
+ import { Copy, Check } from "lucide-react";
181
+
182
+ function App() {
183
+ const [isCopied, setIsCopied] = useState(false);
184
+
185
+ const handleCopy = () => {
186
+ navigator.clipboard.writeText("https://x.com/shadcn");
187
+ setIsCopied(true);
188
+ setTimeout(() => setIsCopied(false), 2000);
189
+ };
190
+
191
+ return (
192
+ <InputGroup>
193
+ <InputGroupInput
194
+ placeholder="https://x.com/shadcn"
195
+ readOnly
196
+ defaultValue="https://x.com/shadcn"
197
+ />
198
+ <InputGroupAddon align="inline-end">
199
+ <InputGroupButton aria-label="Copy" size="icon-xs" onClick={handleCopy}>
200
+ {isCopied ? <Check /> : <Copy />}
201
+ </InputGroupButton>
202
+ </InputGroupAddon>
203
+ </InputGroup>
204
+ );
205
+ }
206
+ ```
207
+
208
+ ### Con Botón Search
209
+
210
+ ```tsx
211
+ <InputGroup>
212
+ <InputGroupInput placeholder="Type to search..." />
213
+ <InputGroupAddon align="inline-end">
214
+ <InputGroupButton variant="secondary">Search</InputGroupButton>
215
+ </InputGroupAddon>
216
+ </InputGroup>
217
+ ```
218
+
219
+ ### Con Tooltip
220
+
221
+ ```tsx
222
+ import { Info } from "lucide-react";
223
+ import {
224
+ Tooltip,
225
+ TooltipContent,
226
+ TooltipTrigger,
227
+ } from "@adamosuiteservices/ui/tooltip";
228
+
229
+ <InputGroup>
230
+ <InputGroupInput placeholder="Enter password" type="password" />
231
+ <InputGroupAddon align="inline-end">
232
+ <Tooltip>
233
+ <TooltipTrigger asChild>
234
+ <InputGroupButton variant="ghost" size="icon-xs">
235
+ <Info />
236
+ </InputGroupButton>
237
+ </TooltipTrigger>
238
+ <TooltipContent>
239
+ <p>Password must be at least 8 characters</p>
240
+ </TooltipContent>
241
+ </Tooltip>
242
+ </InputGroupAddon>
243
+ </InputGroup>;
244
+ ```
245
+
246
+ ### Password Toggle
247
+
248
+ ```tsx
249
+ import { useState } from "react";
250
+ import { Eye, EyeOff } from "lucide-react";
251
+ import { Label } from "@adamosuiteservices/ui/label";
252
+
253
+ function App() {
254
+ const [showPassword, setShowPassword] = useState(false);
255
+
256
+ return (
257
+ <div className="w-full max-w-sm">
258
+ <Label htmlFor="password">Password</Label>
259
+ <InputGroup className="mt-2">
260
+ <InputGroupInput
261
+ id="password"
262
+ type={showPassword ? "text" : "password"}
263
+ placeholder="Enter your password"
264
+ />
265
+ <InputGroupAddon align="inline-end">
266
+ <InputGroupButton
267
+ variant="ghost"
268
+ size="icon-xs"
269
+ onClick={() => setShowPassword(!showPassword)}
270
+ aria-label={showPassword ? "Hide password" : "Show password"}
271
+ >
272
+ {showPassword ? <EyeOff /> : <Eye />}
273
+ </InputGroupButton>
274
+ </InputGroupAddon>
275
+ </InputGroup>
276
+ </div>
277
+ );
278
+ }
279
+ ```
280
+
281
+ ### Con Spinner (Loading)
282
+
283
+ ```tsx
284
+ import { Spinner } from "@adamosuiteservices/ui/spinner";
285
+
286
+ <InputGroup data-disabled>
287
+ <InputGroupInput placeholder="Searching..." disabled />
288
+ <InputGroupAddon align="inline-end">
289
+ <Spinner />
290
+ </InputGroupAddon>
291
+ </InputGroup>;
292
+ ```
293
+
294
+ ### Con Dropdown
295
+
296
+ ```tsx
297
+ import { MoreHorizontal } from "lucide-react";
298
+ import {
299
+ DropdownMenu,
300
+ DropdownMenuContent,
301
+ DropdownMenuItem,
302
+ DropdownMenuTrigger,
303
+ } from "@adamosuiteservices/ui/dropdown-menu";
304
+
305
+ <InputGroup>
306
+ <InputGroupInput placeholder="Enter file name" />
307
+ <InputGroupAddon align="inline-end">
308
+ <DropdownMenu>
309
+ <DropdownMenuTrigger asChild>
310
+ <InputGroupButton variant="ghost" size="icon-xs">
311
+ <MoreHorizontal />
312
+ </InputGroupButton>
313
+ </DropdownMenuTrigger>
314
+ <DropdownMenuContent align="end">
315
+ <DropdownMenuItem>Settings</DropdownMenuItem>
316
+ <DropdownMenuItem>Copy path</DropdownMenuItem>
317
+ <DropdownMenuItem>Open location</DropdownMenuItem>
318
+ </DropdownMenuContent>
319
+ </DropdownMenu>
320
+ </InputGroupAddon>
321
+ </InputGroup>;
322
+ ```
323
+
324
+ ### Con Textarea
325
+
326
+ ```tsx
327
+ <InputGroup>
328
+ <InputGroupTextarea
329
+ placeholder="console.log('Hello, world!');"
330
+ className="min-h-[200px]"
331
+ />
332
+ <InputGroupAddon align="block-end" className="border-t">
333
+ <InputGroupText>Line 1, Column 1</InputGroupText>
334
+ <InputGroupButton size="sm" className="ml-auto" variant="default">
335
+ Run <Send />
336
+ </InputGroupButton>
337
+ </InputGroupAddon>
338
+ </InputGroup>
339
+ ```
340
+
341
+ ### Con Label (Block Start)
342
+
343
+ ```tsx
344
+ import { Label } from "@adamosuiteservices/ui/label";
345
+ import { Info } from "lucide-react";
346
+
347
+ <InputGroup>
348
+ <InputGroupInput id="email" placeholder="shadcn@vercel.com" />
349
+ <InputGroupAddon align="block-start">
350
+ <Label htmlFor="email" className="text-foreground">
351
+ Email
352
+ </Label>
353
+ <Tooltip>
354
+ <TooltipTrigger asChild>
355
+ <InputGroupButton
356
+ variant="ghost"
357
+ className="ml-auto rounded-full"
358
+ size="icon-xs"
359
+ >
360
+ <Info />
361
+ </InputGroupButton>
362
+ </TooltipTrigger>
363
+ <TooltipContent>
364
+ <p>We'll use this to send you notifications</p>
365
+ </TooltipContent>
366
+ </Tooltip>
367
+ </InputGroupAddon>
368
+ </InputGroup>;
369
+ ```
370
+
371
+ ### Chat Input Complex
372
+
373
+ ```tsx
374
+ import { useState } from "react";
375
+ import { Plus, Forward } from "lucide-react";
376
+ import { Spinner } from "@adamosuiteservices/ui/spinner";
377
+
378
+ function App() {
379
+ const [message, setMessage] = useState("");
380
+ const [isLoading, setIsLoading] = useState(false);
381
+
382
+ const handleSend = () => {
383
+ if (!message.trim()) return;
384
+ setIsLoading(true);
385
+ setTimeout(() => {
386
+ setMessage("");
387
+ setIsLoading(false);
388
+ }, 1000);
389
+ };
390
+
391
+ return (
392
+ <InputGroup>
393
+ <InputGroupTextarea
394
+ placeholder="Ask, Search or Chat..."
395
+ value={message}
396
+ onChange={(e) => setMessage(e.target.value)}
397
+ className="min-h-[60px]"
398
+ />
399
+ <InputGroupAddon align="block-end">
400
+ <InputGroupButton
401
+ variant="outline"
402
+ className="rounded-full"
403
+ size="icon-xs"
404
+ >
405
+ <Plus />
406
+ </InputGroupButton>
407
+
408
+ <InputGroupText className="ml-auto">
409
+ {message.length}/280
410
+ </InputGroupText>
411
+
412
+ <InputGroupButton
413
+ variant="default"
414
+ className="rounded-full"
415
+ size="icon-xs"
416
+ onClick={handleSend}
417
+ disabled={!message.trim() || isLoading}
418
+ >
419
+ {isLoading ? <Spinner /> : <Forward />}
420
+ </InputGroupButton>
421
+ </InputGroupAddon>
422
+ </InputGroup>
423
+ );
424
+ }
425
+ ```
426
+
427
+ ## Casos de Uso Comunes
428
+
429
+ **Price inputs**: Con $ prefix y USD suffix
430
+ **URL inputs**: Con https:// prefix y dominio suffix
431
+ **Email inputs**: Con @domain.com suffix
432
+ **Search bars**: Con icono search y resultados count
433
+ **Copy fields**: Con botón copy integrado
434
+ **Password fields**: Con toggle show/hide
435
+ **Chat inputs**: Con múltiples controles y contador
436
+ **Code editors**: Con textarea y toolbars en block-start/end
437
+
438
+ ## Estados y Data Attributes
439
+
440
+ ### InputGroup States
441
+
442
+ - **Disabled**: `data-disabled` → `opacity-50` en addons
443
+ - **Focus**: `has-[input:focus-visible]` → ring y border aplicados al grupo
444
+ - **Invalid**: `has-[input[aria-invalid=true]]` → ring destructive y border
445
+
446
+ ### Focus Behavior
447
+
448
+ El grupo aplica estilos focus cuando el input/textarea interno recibe focus, no el grupo en sí.
449
+
450
+ ### Click Behavior (Addon)
451
+
452
+ Los addons hacen focus al input cuando se hace click en el addon (no en botones).
453
+
454
+ ## Interacción
455
+
456
+ - ✅ **Click addon**: Focus automático en el input (excepto botones)
457
+ - ✅ **Keyboard**: Navegación normal del input/textarea
458
+ - ✅ **Disabled**: Visual `data-disabled`, input debe estar `disabled` también
459
+ - ✅ **Auto-height**: Con textarea, el grupo ajusta altura automáticamente
460
+
461
+ ## Accesibilidad
462
+
463
+ - ✅ **Role**: `role="group"` en InputGroup y InputGroupAddon
464
+ - ✅ **Labels**: Usa Label dentro de InputGroupAddon o externo con `htmlFor`
465
+ - ✅ **ARIA**: Input/textarea maneja `aria-invalid`, `aria-describedby`
466
+ - ✅ **Focus**: Focus visible en el grupo cuando input interno tiene focus
467
+ - ✅ **Keyboard**: Navegación nativa del input/textarea
468
+ - ⚠️ **Buttons**: Usa `aria-label` en InputGroupButton para iconos
469
+
470
+ ## Notas de Implementación
471
+
472
+ - **Container**: InputGroup es el wrapper con border, shadow, focus ring
473
+ - **Input/Textarea**: Sin border, sin shadow, sin focus ring (aplicado al grupo)
474
+ - **Auto-height**: Grupo tiene `has-[>textarea]:h-auto` para textareas
475
+ - **Alignment**: CVA con 4 posiciones (inline-start, inline-end, block-start, block-end)
476
+ - **Click delegation**: Addon hace focus al input al click (excepto en botones)
477
+ - **Variants**: InputGroupButton usa CVA para 4 tamaños custom
478
+ - **Order**: Addon usa `order-first` o `order-last` para posicionamiento
479
+ - **Focus detection**: CSS `:has()` para aplicar focus ring al grupo
480
+ - **Portal**: No usa portal, todo inline
481
+
482
+ ## Alineamiento Detallado
483
+
484
+ ### Inline (Horizontal)
485
+
486
+ - **inline-start**: `pl-3`, botones con `ml-[-0.45rem]`, orden `order-first`
487
+ - **inline-end**: `pr-3`, botones con `mr-[-0.45rem]`, orden `order-last`
488
+
489
+ ### Block (Vertical)
490
+
491
+ - **block-start**: `w-full`, `px-3 pt-3`, `order-first`, borders con `border-b`
492
+ - **block-end**: `w-full`, `px-3 pb-3`, `order-last`, borders con `border-t`
493
+
494
+ ## Troubleshooting
495
+
496
+ **Addon no clickea al input**: Verifica que InputGroupAddon tenga el onClick handler (default)
497
+ **Focus ring no aparece**: El input interno debe tener `data-slot="input-group-control"`
498
+ **Textarea no ajusta altura**: Verifica que uses `InputGroupTextarea` no `InputGroupInput`
499
+ **Botón muy grande**: Usa `size="xs"` o `size="icon-xs"` en InputGroupButton
500
+ **Addon mal posicionado**: Verifica `align` prop (inline-start/end, block-start/end)
501
+ **Border doble**: InputGroupInput/Textarea tienen `border-0`, no uses Input/Textarea directamente
502
+ **Invalid state no funciona**: El input interno necesita `aria-invalid`, grupo detecta con `:has()`
503
+ **Disabled no funciona**: Aplica `disabled` al input Y `data-disabled` al InputGroup
504
+ **Spacing inconsistente**: Addon usa padding específico por align, no modifiques sin CVA
505
+
506
+ ## Referencias
507
+
508
+ - **shadcn/ui Input**: <https://ui.shadcn.com/docs/components/input>
509
+ - **Radix UI Label**: <https://www.radix-ui.com/primitives/docs/components/label>