@adamosuiteservices/ui 1.7.12 → 1.8.13
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.
- package/dist/accordion-rounded.cjs +24 -2
- package/dist/accordion-rounded.js +46 -8
- package/dist/accordion.cjs +20 -1
- package/dist/accordion.js +29 -5
- package/dist/alert.cjs +26 -1
- package/dist/alert.js +33 -8
- package/dist/avatar.cjs +7 -1
- package/dist/avatar.js +8 -2
- package/dist/badge.cjs +83 -1
- package/dist/badge.js +106 -24
- package/dist/breadcrumb.cjs +8 -1
- package/dist/breadcrumb.js +11 -4
- package/dist/button-B7ZP4LZN.js +127 -0
- package/dist/button-D-qFRXiM.cjs +70 -0
- package/dist/button-group.cjs +25 -1
- package/dist/button-group.js +33 -9
- package/dist/button.cjs +1 -1
- package/dist/button.js +1 -1
- package/dist/calendar.cjs +74 -1
- package/dist/calendar.js +114 -35
- package/dist/card.cjs +35 -1
- package/dist/card.js +45 -11
- package/dist/{checkbox-YWAnswaW.cjs → checkbox-CdnZ8VFJ.cjs} +21 -1
- package/dist/{checkbox-Dr487kAg.js → checkbox-DhBcmKze.js} +34 -4
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/combobox.cjs +36 -2
- package/dist/combobox.js +302 -253
- package/dist/components/icons/account-balance-icon.d.ts +3 -0
- package/dist/components/icons/account-icon.d.ts +3 -0
- package/dist/components/icons/add-circle-icon.d.ts +3 -0
- package/dist/components/icons/alarm-icon.d.ts +3 -0
- package/dist/components/icons/archive-icon.d.ts +3 -0
- package/dist/components/icons/arrow-back-icon.d.ts +3 -0
- package/dist/components/icons/arrow-circle-up-icon.d.ts +3 -0
- package/dist/components/icons/arrow-forward-icon.d.ts +3 -0
- package/dist/components/icons/arrow-outward-icon.d.ts +3 -0
- package/dist/components/icons/article-icon.d.ts +3 -0
- package/dist/components/icons/attach-file-icon.d.ts +3 -0
- package/dist/components/icons/autorenew-icon.d.ts +3 -0
- package/dist/components/icons/bookmark-icon.d.ts +3 -0
- package/dist/components/icons/calculate-icon.d.ts +3 -0
- package/dist/components/icons/calendar-today-icon.d.ts +3 -0
- package/dist/components/icons/call-split-icon.d.ts +3 -0
- package/dist/components/icons/cancel-filled-icon.d.ts +3 -0
- package/dist/components/icons/cancel-icon.d.ts +3 -0
- package/dist/components/icons/check-circle-icon.d.ts +3 -0
- package/dist/components/icons/check-icon.d.ts +3 -0
- package/dist/components/icons/chevron-back-icon.d.ts +3 -0
- package/dist/components/icons/chevron-down-icon.d.ts +3 -0
- package/dist/components/icons/chevron-forward-icon.d.ts +3 -0
- package/dist/components/icons/chevron-up-icon.d.ts +3 -0
- package/dist/components/icons/clarify-icon.d.ts +3 -0
- package/dist/components/icons/clock-icon.d.ts +3 -0
- package/dist/components/icons/close-icon.d.ts +3 -0
- package/dist/components/icons/confirmation-number-icon.d.ts +3 -0
- package/dist/components/icons/contacts-icon.d.ts +3 -0
- package/dist/components/icons/contract-delete-icon.d.ts +3 -0
- package/dist/components/icons/copy-icon.d.ts +3 -0
- package/dist/components/icons/do-not-touch-icon.d.ts +3 -0
- package/dist/components/icons/download-icon.d.ts +3 -0
- package/dist/components/icons/dragger-icon.d.ts +3 -0
- package/dist/components/icons/edit-icon.d.ts +3 -0
- package/dist/components/icons/edit-square-icon.d.ts +3 -0
- package/dist/components/icons/exclamation-icon.d.ts +3 -0
- package/dist/components/icons/expand-circle-right-icon.d.ts +3 -0
- package/dist/components/icons/feature-search-icon.d.ts +3 -0
- package/dist/components/icons/filter-icon.d.ts +3 -0
- package/dist/components/icons/folder-icon.d.ts +3 -0
- package/dist/components/icons/folder-open-icon.d.ts +3 -0
- package/dist/components/icons/format-list-bulleted-icon.d.ts +3 -0
- package/dist/components/icons/hamburger-menu-icon.d.ts +3 -0
- package/dist/components/icons/help-icon.d.ts +3 -0
- package/dist/components/icons/hide-pass-icon.d.ts +3 -0
- package/dist/components/icons/home-icon.d.ts +3 -0
- package/dist/components/icons/id-card-icon.d.ts +3 -0
- package/dist/components/icons/index.d.ts +88 -0
- package/dist/components/icons/info-icon.d.ts +3 -0
- package/dist/components/icons/kid-star-icon.d.ts +3 -0
- package/dist/components/icons/language-icon.d.ts +3 -0
- package/dist/components/icons/last-page-icon.d.ts +3 -0
- package/dist/components/icons/layers-icon.d.ts +3 -0
- package/dist/components/icons/location-icon.d.ts +3 -0
- package/dist/components/icons/mail-icon.d.ts +3 -0
- package/dist/components/icons/manage-search-icon.d.ts +3 -0
- package/dist/components/icons/menu-icon.d.ts +3 -0
- package/dist/components/icons/message-icon.d.ts +3 -0
- package/dist/components/icons/metrics-icon.d.ts +3 -0
- package/dist/components/icons/mic-icon.d.ts +3 -0
- package/dist/components/icons/minus-icon.d.ts +3 -0
- package/dist/components/icons/mode-comment-icon.d.ts +3 -0
- package/dist/components/icons/money-icon.d.ts +3 -0
- package/dist/components/icons/monitoring-icon.d.ts +3 -0
- package/dist/components/icons/more-icon.d.ts +3 -0
- package/dist/components/icons/notifications-icon.d.ts +3 -0
- package/dist/components/icons/open-in-new-icon.d.ts +3 -0
- package/dist/components/icons/palette-icon.d.ts +3 -0
- package/dist/components/icons/password-icon.d.ts +3 -0
- package/dist/components/icons/pending-icon.d.ts +3 -0
- package/dist/components/icons/person-add-icon.d.ts +3 -0
- package/dist/components/icons/person-search-icon.d.ts +3 -0
- package/dist/components/icons/photo-icon.d.ts +3 -0
- package/dist/components/icons/plus-icon.d.ts +3 -0
- package/dist/components/icons/policy-icon.d.ts +3 -0
- package/dist/components/icons/publish-icon.d.ts +3 -0
- package/dist/components/icons/ready-icon.d.ts +3 -0
- package/dist/components/icons/receipt-icon.d.ts +3 -0
- package/dist/components/icons/receive-icon.d.ts +3 -0
- package/dist/components/icons/refresh-icon.d.ts +3 -0
- package/dist/components/icons/search-icon.d.ts +3 -0
- package/dist/components/icons/see-icon.d.ts +3 -0
- package/dist/components/icons/send-icon.d.ts +3 -0
- package/dist/components/icons/settings-icon.d.ts +3 -0
- package/dist/components/icons/shield-icon.d.ts +3 -0
- package/dist/components/icons/swap-horiz-icon.d.ts +3 -0
- package/dist/components/icons/tag-icon.d.ts +3 -0
- package/dist/components/icons/trash-icon.d.ts +3 -0
- package/dist/components/layout/toaster/toaster.d.ts +1 -1
- package/dist/components/layout/toaster/toaster.stories.d.ts +1 -1
- package/dist/components/ui/accordion/accordion.d.ts +1 -1
- package/dist/components/ui/accordion/accordion.stories.d.ts +1 -1
- package/dist/components/ui/accordion-rounded/accordion-rounded.d.ts +1 -1
- package/dist/components/ui/accordion-rounded/accordion-rounded.stories.d.ts +1 -1
- package/dist/components/ui/alert/alert.stories.d.ts +1 -1
- package/dist/components/ui/avatar/avatar.d.ts +1 -1
- package/dist/components/ui/avatar/avatar.stories.d.ts +1 -1
- package/dist/components/ui/badge/badge.stories.d.ts +1 -1
- package/dist/components/ui/breadcrumb/breadcrumb.stories.d.ts +1 -1
- package/dist/components/ui/button/button.stories.d.ts +1 -1
- package/dist/components/ui/button-group/button-group.d.ts +1 -1
- package/dist/components/ui/button-group/button-group.stories.d.ts +1 -1
- package/dist/components/ui/calendar/calendar.d.ts +1 -1
- package/dist/components/ui/calendar/calendar.stories.d.ts +1 -1
- package/dist/components/ui/card/card.stories.d.ts +1 -1
- package/dist/components/ui/checkbox/checkbox.d.ts +1 -1
- package/dist/components/ui/checkbox/checkbox.stories.d.ts +1 -1
- package/dist/components/ui/collapsible/collapsible.stories.d.ts +1 -1
- package/dist/components/ui/combobox/combobox.stories.d.ts +1 -1
- package/dist/components/ui/command/command.d.ts +1 -1
- package/dist/components/ui/context-menu/context-menu.d.ts +1 -1
- package/dist/components/ui/context-menu/context-menu.stories.d.ts +1 -1
- package/dist/components/ui/dialog/dialog.d.ts +1 -1
- package/dist/components/ui/dialog/dialog.stories.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu.stories.d.ts +1 -1
- package/dist/components/ui/field/field.d.ts +1 -1
- package/dist/components/ui/field/field.stories.d.ts +1 -1
- package/dist/components/ui/hover-card/hover-card.d.ts +1 -1
- package/dist/components/ui/hover-card/hover-card.stories.d.ts +1 -1
- package/dist/components/ui/input/input.stories.d.ts +1 -1
- package/dist/components/ui/input-group/Input-group.stories.d.ts +1 -1
- package/dist/components/ui/input-group/input-group.d.ts +1 -1
- package/dist/components/ui/kbd/kbd.stories.d.ts +1 -1
- package/dist/components/ui/label/label.d.ts +1 -1
- package/dist/components/ui/label/label.stories.d.ts +1 -1
- package/dist/components/ui/pagination/pagination.stories.d.ts +1 -1
- package/dist/components/ui/popover/popover.d.ts +1 -1
- package/dist/components/ui/popover/popover.stories.d.ts +1 -1
- package/dist/components/ui/progress/progress.d.ts +1 -1
- package/dist/components/ui/progress/progress.stories.d.ts +1 -1
- package/dist/components/ui/radio-group/radio-group.d.ts +1 -1
- package/dist/components/ui/radio-group/radio-group.stories.d.ts +1 -1
- package/dist/components/ui/scroll-area/scroll-area.d.ts +1 -1
- package/dist/components/ui/scroll-area/scroll-area.stories.d.ts +1 -1
- package/dist/components/ui/select/select.d.ts +1 -1
- package/dist/components/ui/select/select.stories.d.ts +1 -1
- package/dist/components/ui/separator/separator.d.ts +1 -1
- package/dist/components/ui/separator/separator.stories.d.ts +1 -1
- package/dist/components/ui/sheet/sheet.d.ts +1 -1
- package/dist/components/ui/sheet/sheet.stories.d.ts +1 -1
- package/dist/components/ui/skeleton/skeleton.stories.d.ts +1 -1
- package/dist/components/ui/slider/slider.d.ts +1 -1
- package/dist/components/ui/slider/slider.stories.d.ts +1 -1
- package/dist/components/ui/spinner/spinner.stories.d.ts +1 -1
- package/dist/components/ui/switch/switch.d.ts +1 -1
- package/dist/components/ui/switch/switch.stories.d.ts +1 -1
- package/dist/components/ui/tabs/tabs.d.ts +1 -1
- package/dist/components/ui/tabs/tabs.stories.d.ts +1 -1
- package/dist/components/ui/tabs-underline/tabs-underline.d.ts +1 -1
- package/dist/components/ui/tabs-underline/tabs-underline.stories.d.ts +1 -1
- package/dist/components/ui/textarea/textarea.stories.d.ts +1 -1
- package/dist/components/ui/toggle/toggle.d.ts +1 -1
- package/dist/components/ui/toggle/toggle.stories.d.ts +1 -1
- package/dist/components/ui/tooltip/tooltip.d.ts +1 -1
- package/dist/components/ui/tooltip/tooltip.stories.d.ts +1 -1
- package/dist/context-menu.cjs +79 -1
- package/dist/context-menu.js +101 -11
- package/dist/custom-layered-styles.css +1 -1
- package/dist/dialog.cjs +30 -1
- package/dist/dialog.js +35 -6
- package/dist/dropdown-menu.cjs +79 -1
- package/dist/dropdown-menu.js +101 -11
- package/dist/field.cjs +66 -1
- package/dist/field.js +91 -26
- package/dist/hover-card.cjs +15 -1
- package/dist/hover-card.js +15 -1
- package/dist/icons.cjs +1 -0
- package/dist/icons.js +1507 -0
- package/dist/input-BQZUpTEY.js +42 -0
- package/dist/input-DSmxdfq5.cjs +21 -0
- package/dist/input-group.cjs +76 -1
- package/dist/input-group.js +99 -24
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/kbd.cjs +10 -1
- package/dist/kbd.js +11 -2
- package/dist/{label-CmwGvhy1.js → label-BJ8Yf6Ft.js} +7 -1
- package/dist/{label-BjXORCBM.cjs → label-CNGQhi5L.cjs} +7 -1
- package/dist/label.cjs +1 -1
- package/dist/label.js +1 -1
- package/dist/pagination.cjs +13 -1
- package/dist/pagination.js +30 -6
- package/dist/{popover-FCKBtFo-.cjs → popover-CYbik-H4.cjs} +15 -1
- package/dist/{popover-3rIoNCXs.js → popover-DAwH8jUh.js} +15 -1
- package/dist/popover.cjs +1 -1
- package/dist/popover.js +1 -1
- package/dist/radio-group.cjs +14 -1
- package/dist/radio-group.js +20 -2
- package/dist/select.cjs +68 -1
- package/dist/select.js +83 -10
- package/dist/{separator-BaZqZZ9R.cjs → separator-Brpax0EI.cjs} +7 -1
- package/dist/{separator-DR7lQjv9.js → separator-DVypR3Qf.js} +7 -1
- package/dist/separator.cjs +1 -1
- package/dist/separator.js +1 -1
- package/dist/sheet-CGahUP7F.cjs +41 -0
- package/dist/sheet-Q3dBOQG-.js +174 -0
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sidebar.cjs +20 -2
- package/dist/sidebar.js +58 -26
- package/dist/skeleton.cjs +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/slider.cjs +27 -1
- package/dist/slider.js +30 -4
- package/dist/space.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/switch.cjs +18 -1
- package/dist/switch.js +19 -2
- package/dist/table.cjs +20 -1
- package/dist/table.js +26 -7
- package/dist/tabs-underline.cjs +21 -1
- package/dist/tabs-underline.js +23 -3
- package/dist/tabs.cjs +22 -1
- package/dist/tabs.js +24 -3
- package/dist/textarea-CG7iQcb3.cjs +14 -0
- package/dist/textarea-CUPWKl-S.js +32 -0
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.js +1 -1
- package/dist/toaster.cjs +4 -1
- package/dist/toaster.js +9 -6
- package/dist/toggle.cjs +17 -1
- package/dist/toggle.js +25 -9
- package/dist/tooltip.cjs +16 -1
- package/dist/tooltip.js +22 -2
- package/dist/typography.cjs +1 -1
- package/dist/typography.js +6 -6
- package/docs/AI-GUIDE.md +321 -321
- package/docs/components/layout/sidebar.md +404 -404
- package/docs/components/layout/toaster.md +436 -436
- package/docs/components/ui/accordion-rounded.md +583 -583
- package/docs/components/ui/accordion.md +267 -267
- package/docs/components/ui/alert.md +671 -671
- package/docs/components/ui/avatar.md +588 -588
- package/docs/components/ui/badge.md +1024 -1024
- package/docs/components/ui/button-group.md +1002 -1002
- package/docs/components/ui/button.md +1078 -1078
- package/docs/components/ui/calendar.md +1159 -1159
- package/docs/components/ui/card.md +1265 -1265
- package/docs/components/ui/checkbox.md +292 -292
- package/docs/components/ui/collapsible.md +320 -320
- package/docs/components/ui/command.md +454 -454
- package/docs/components/ui/context-menu.md +540 -540
- package/docs/components/ui/dialog.md +628 -628
- package/docs/components/ui/dropdown-menu.md +731 -731
- package/docs/components/ui/field.md +706 -706
- package/docs/components/ui/hover-card.md +446 -446
- package/docs/components/ui/input-group.md +509 -509
- package/docs/components/ui/input.md +362 -362
- package/docs/components/ui/kbd.md +434 -434
- package/docs/components/ui/label.md +359 -359
- package/docs/components/ui/pagination.md +650 -650
- package/docs/components/ui/popover.md +536 -536
- package/docs/components/ui/progress.md +182 -182
- package/docs/components/ui/radio-group.md +311 -311
- package/docs/components/ui/select.md +352 -352
- package/docs/components/ui/separator.md +214 -214
- package/docs/components/ui/sheet.md +142 -142
- package/docs/components/ui/skeleton.md +140 -140
- package/docs/components/ui/slider.md +341 -341
- package/docs/components/ui/spinner.md +170 -170
- package/docs/components/ui/switch.md +402 -402
- package/docs/components/ui/table.md +183 -183
- package/docs/components/ui/tabs-underline.md +106 -106
- package/docs/components/ui/tabs.md +122 -122
- package/docs/components/ui/textarea.md +243 -243
- package/docs/components/ui/toggle.md +243 -243
- package/docs/components/ui/tooltip.md +320 -320
- package/docs/components/ui/typography.md +191 -191
- package/package.json +7 -1
- package/dist/button-2GdKenQI.js +0 -58
- package/dist/button-DEQVHMrX.cjs +0 -1
- package/dist/input-BF73maXg.cjs +0 -1
- package/dist/input-C04hsVXE.js +0 -22
- package/dist/sheet-B-9YHdR5.js +0 -128
- package/dist/sheet-CU-sFSaJ.cjs +0 -1
- package/dist/textarea-3ZdbFRDN.cjs +0 -1
- package/dist/textarea-BZbcAAAu.js +0 -19
|
@@ -1,509 +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>
|
|
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>
|