@adamosuiteservices/ui 1.7.13 → 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 +62 -22
- 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,588 +1,588 @@
|
|
|
1
|
-
# Avatar Component
|
|
2
|
-
|
|
3
|
-
## Descripción
|
|
4
|
-
|
|
5
|
-
Componente para mostrar **imágenes de perfil de usuario** con sistema de fallback automático a iniciales o iconos cuando la imagen no está disponible o falla al cargar. Basado en Radix UI Avatar primitives con carga lazy, estado de error manejado, y diseño circular responsive.
|
|
6
|
-
|
|
7
|
-
## Características
|
|
8
|
-
|
|
9
|
-
- ✅ Fallback automático si la imagen falla
|
|
10
|
-
- ✅ Carga lazy de imágenes
|
|
11
|
-
- ✅ Soporte para iniciales o iconos como fallback
|
|
12
|
-
- ✅ Tamaños personalizables
|
|
13
|
-
- ✅ Formas: circular (default) o cuadrado/rectangular
|
|
14
|
-
- ✅ Grupos de avatares con solapamiento
|
|
15
|
-
- ✅ Integración con Tooltip
|
|
16
|
-
- ✅ Accesibilidad: alt text y ARIA
|
|
17
|
-
- ✅ Diseño responsive y flexible
|
|
18
|
-
|
|
19
|
-
## Importación
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
import {
|
|
23
|
-
Avatar,
|
|
24
|
-
AvatarImage,
|
|
25
|
-
AvatarFallback,
|
|
26
|
-
} from "@adamosuiteservices/ui/avatar";
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Uso Básico
|
|
30
|
-
|
|
31
|
-
### Avatar con Imagen y Fallback
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
<Avatar>
|
|
35
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
36
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
37
|
-
</Avatar>
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Comportamiento**:
|
|
41
|
-
|
|
42
|
-
1. Intenta cargar la imagen del `src`
|
|
43
|
-
2. Si falla o no carga, muestra el `AvatarFallback` automáticamente
|
|
44
|
-
3. Radix UI maneja el estado de carga internamente
|
|
45
|
-
|
|
46
|
-
### Solo Fallback (Sin Imagen)
|
|
47
|
-
|
|
48
|
-
```tsx
|
|
49
|
-
<Avatar>
|
|
50
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
51
|
-
</Avatar>
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Uso**: Cuando no hay imagen disponible o solo quieres mostrar iniciales.
|
|
55
|
-
|
|
56
|
-
### Imagen Rota (Graceful Degradation)
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
<Avatar>
|
|
60
|
-
<AvatarImage src="https://broken-link.com/image.jpg" alt="Broken" />
|
|
61
|
-
<AvatarFallback>BK</AvatarFallback>
|
|
62
|
-
</Avatar>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Resultado**: Automáticamente muestra "BK" si la imagen no carga.
|
|
66
|
-
|
|
67
|
-
## Props
|
|
68
|
-
|
|
69
|
-
### Avatar (Root)
|
|
70
|
-
|
|
71
|
-
Contenedor principal del avatar.
|
|
72
|
-
|
|
73
|
-
| Prop | Tipo | Descripción |
|
|
74
|
-
| --------- | -------------------------- | --------------------------- |
|
|
75
|
-
| className | `string` | Clases CSS adicionales |
|
|
76
|
-
| ...props | Props de Radix Avatar.Root | Props nativas del primitivo |
|
|
77
|
-
|
|
78
|
-
**Estilos por defecto**:
|
|
79
|
-
|
|
80
|
-
- `size-8`: 2rem (32x32px) - tamaño base
|
|
81
|
-
- `rounded-full`: Forma circular
|
|
82
|
-
- `shrink-0`: No se encoge en flex/grid
|
|
83
|
-
- `overflow-hidden`: Recorta contenido fuera del círculo
|
|
84
|
-
- `relative`: Para posicionamiento interno
|
|
85
|
-
- `flex`: Contenedor flex
|
|
86
|
-
|
|
87
|
-
**Atributos automáticos**:
|
|
88
|
-
|
|
89
|
-
- `data-slot="avatar"`: Para identificación interna
|
|
90
|
-
|
|
91
|
-
### AvatarImage
|
|
92
|
-
|
|
93
|
-
Imagen del avatar con carga lazy.
|
|
94
|
-
|
|
95
|
-
| Prop | Tipo | Descripción |
|
|
96
|
-
| --------- | --------------------------- | --------------------------------------------------- |
|
|
97
|
-
| src | `string` | **Requerido**. URL de la imagen |
|
|
98
|
-
| alt | `string` | **Requerido**. Texto alternativo para accesibilidad |
|
|
99
|
-
| className | `string` | Clases CSS adicionales |
|
|
100
|
-
| ...props | Props de Radix Avatar.Image | Props nativas del primitivo |
|
|
101
|
-
|
|
102
|
-
**Estilos aplicados**:
|
|
103
|
-
|
|
104
|
-
- `aspect-square`: Mantiene aspecto cuadrado
|
|
105
|
-
- `size-full`: Ocupa todo el contenedor (100% width/height)
|
|
106
|
-
|
|
107
|
-
**Comportamiento**:
|
|
108
|
-
|
|
109
|
-
- Carga lazy automática
|
|
110
|
-
- Emite eventos `onLoadingStatusChange`
|
|
111
|
-
- Estados: `idle`, `loading`, `loaded`, `error`
|
|
112
|
-
- Si falla, muestra AvatarFallback automáticamente
|
|
113
|
-
|
|
114
|
-
**Atributos automáticos**:
|
|
115
|
-
|
|
116
|
-
- `data-slot="avatar-image"`: Para identificación interna
|
|
117
|
-
|
|
118
|
-
### AvatarFallback
|
|
119
|
-
|
|
120
|
-
Contenido mostrado cuando la imagen no carga o no existe.
|
|
121
|
-
|
|
122
|
-
| Prop | Tipo | Descripción |
|
|
123
|
-
| --------- | ------------------------------ | ------------------------------------------------------ |
|
|
124
|
-
| children | `ReactNode` | **Requerido**. Iniciales, icono, o cualquier contenido |
|
|
125
|
-
| delayMs | `number` | Delay antes de mostrar el fallback (ms) |
|
|
126
|
-
| className | `string` | Clases CSS adicionales |
|
|
127
|
-
| ...props | Props de Radix Avatar.Fallback | Props nativas del primitivo |
|
|
128
|
-
|
|
129
|
-
**Estilos por defecto**:
|
|
130
|
-
|
|
131
|
-
- `bg-muted`: Fondo gris claro
|
|
132
|
-
- `rounded-full`: Forma circular (coincide con el contenedor)
|
|
133
|
-
- `size-full`: Ocupa todo el espacio
|
|
134
|
-
- `flex items-center justify-center`: Centra el contenido
|
|
135
|
-
|
|
136
|
-
**Contenido común**:
|
|
137
|
-
|
|
138
|
-
- Iniciales (2 letras): "JD", "AB", "CN"
|
|
139
|
-
- Iconos: `<UserIcon />`, `<PersonIcon />`
|
|
140
|
-
- Texto: "+5" (para grupos)
|
|
141
|
-
|
|
142
|
-
**Atributos automáticos**:
|
|
143
|
-
|
|
144
|
-
- `data-slot="avatar-fallback"`: Para identificación interna
|
|
145
|
-
|
|
146
|
-
## Tamaños Personalizados
|
|
147
|
-
|
|
148
|
-
El tamaño por defecto es `size-8` (32px). Personaliza con className:
|
|
149
|
-
|
|
150
|
-
### Tamaños Predefinidos
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
{
|
|
154
|
-
/* Extra Small - 24px */
|
|
155
|
-
}
|
|
156
|
-
<Avatar className="size-6">
|
|
157
|
-
<AvatarImage src={url} alt="User" />
|
|
158
|
-
<AvatarFallback className="text-xs">CN</AvatarFallback>
|
|
159
|
-
</Avatar>;
|
|
160
|
-
|
|
161
|
-
{
|
|
162
|
-
/* Small - 32px (default) */
|
|
163
|
-
}
|
|
164
|
-
<Avatar className="size-8">
|
|
165
|
-
<AvatarImage src={url} alt="User" />
|
|
166
|
-
<AvatarFallback>ER</AvatarFallback>
|
|
167
|
-
</Avatar>;
|
|
168
|
-
|
|
169
|
-
{
|
|
170
|
-
/* Medium - 48px */
|
|
171
|
-
}
|
|
172
|
-
<Avatar className="size-12">
|
|
173
|
-
<AvatarImage src={url} alt="User" />
|
|
174
|
-
<AvatarFallback>ML</AvatarFallback>
|
|
175
|
-
</Avatar>;
|
|
176
|
-
|
|
177
|
-
{
|
|
178
|
-
/* Large - 64px */
|
|
179
|
-
}
|
|
180
|
-
<Avatar className="size-16">
|
|
181
|
-
<AvatarImage src={url} alt="User" />
|
|
182
|
-
<AvatarFallback className="text-lg">VC</AvatarFallback>
|
|
183
|
-
</Avatar>;
|
|
184
|
-
|
|
185
|
-
{
|
|
186
|
-
/* Extra Large - 80px */
|
|
187
|
-
}
|
|
188
|
-
<Avatar className="size-20">
|
|
189
|
-
<AvatarImage src={url} alt="User" />
|
|
190
|
-
<AvatarFallback className="text-xl">NJ</AvatarFallback>
|
|
191
|
-
</Avatar>;
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**Nota**: Ajusta el tamaño del texto del fallback según el tamaño del avatar para mantener proporciones.
|
|
195
|
-
|
|
196
|
-
### Tamaño Personalizado
|
|
197
|
-
|
|
198
|
-
```tsx
|
|
199
|
-
<Avatar className="h-24 w-24">
|
|
200
|
-
<AvatarImage src={url} alt="User" />
|
|
201
|
-
<AvatarFallback className="text-2xl">AB</AvatarFallback>
|
|
202
|
-
</Avatar>
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
## Formas Personalizadas
|
|
206
|
-
|
|
207
|
-
### Avatar Cuadrado
|
|
208
|
-
|
|
209
|
-
```tsx
|
|
210
|
-
{
|
|
211
|
-
/* Rounded large */
|
|
212
|
-
}
|
|
213
|
-
<Avatar className="rounded-lg">
|
|
214
|
-
<AvatarImage src={url} alt="User" />
|
|
215
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
216
|
-
</Avatar>;
|
|
217
|
-
|
|
218
|
-
{
|
|
219
|
-
/* Rounded medium */
|
|
220
|
-
}
|
|
221
|
-
<Avatar className="rounded-md">
|
|
222
|
-
<AvatarImage src={url} alt="User" />
|
|
223
|
-
<AvatarFallback>ER</AvatarFallback>
|
|
224
|
-
</Avatar>;
|
|
225
|
-
|
|
226
|
-
{
|
|
227
|
-
/* Rounded small */
|
|
228
|
-
}
|
|
229
|
-
<Avatar className="rounded-sm">
|
|
230
|
-
<AvatarImage src={url} alt="User" />
|
|
231
|
-
<AvatarFallback>ML</AvatarFallback>
|
|
232
|
-
</Avatar>;
|
|
233
|
-
|
|
234
|
-
{
|
|
235
|
-
/* Completamente cuadrado */
|
|
236
|
-
}
|
|
237
|
-
<Avatar className="rounded-none">
|
|
238
|
-
<AvatarFallback>SQ</AvatarFallback>
|
|
239
|
-
</Avatar>;
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
**Uso**: Avatares cuadrados son comunes para logos de empresas o aplicaciones.
|
|
243
|
-
|
|
244
|
-
## Patrones Avanzados
|
|
245
|
-
|
|
246
|
-
### Grupo de Avatares (Overlapping)
|
|
247
|
-
|
|
248
|
-
Para mostrar múltiples usuarios con solapamiento:
|
|
249
|
-
|
|
250
|
-
```tsx
|
|
251
|
-
<div className="flex -space-x-2">
|
|
252
|
-
<Avatar className="ring-2 ring-background">
|
|
253
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
254
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
255
|
-
</Avatar>
|
|
256
|
-
<Avatar className="ring-2 ring-background">
|
|
257
|
-
<AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" />
|
|
258
|
-
<AvatarFallback>ER</AvatarFallback>
|
|
259
|
-
</Avatar>
|
|
260
|
-
<Avatar className="ring-2 ring-background">
|
|
261
|
-
<AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" />
|
|
262
|
-
<AvatarFallback>ML</AvatarFallback>
|
|
263
|
-
</Avatar>
|
|
264
|
-
<Avatar className="ring-2 ring-background bg-muted">
|
|
265
|
-
<AvatarFallback>+2</AvatarFallback>
|
|
266
|
-
</Avatar>
|
|
267
|
-
</div>
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
**Técnicas**:
|
|
271
|
-
|
|
272
|
-
- `-space-x-2`: Espacio negativo para solapar
|
|
273
|
-
- `ring-2 ring-background`: Borde blanco para separación visual
|
|
274
|
-
- Último avatar muestra contador "+N" para usuarios adicionales
|
|
275
|
-
|
|
276
|
-
### Avatar con Tooltip
|
|
277
|
-
|
|
278
|
-
Para mostrar información adicional al hover:
|
|
279
|
-
|
|
280
|
-
```tsx
|
|
281
|
-
import {
|
|
282
|
-
Tooltip,
|
|
283
|
-
TooltipContent,
|
|
284
|
-
TooltipProvider,
|
|
285
|
-
TooltipTrigger,
|
|
286
|
-
} from "@adamosuiteservices/ui/tooltip";
|
|
287
|
-
|
|
288
|
-
<TooltipProvider>
|
|
289
|
-
<Tooltip>
|
|
290
|
-
<TooltipTrigger asChild>
|
|
291
|
-
<Avatar className="cursor-pointer">
|
|
292
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
293
|
-
<AvatarFallback>CN</AvatarFallback>
|
|
294
|
-
</Avatar>
|
|
295
|
-
</TooltipTrigger>
|
|
296
|
-
<TooltipContent>
|
|
297
|
-
<p>shadcn - UI Engineer</p>
|
|
298
|
-
</TooltipContent>
|
|
299
|
-
</Tooltip>
|
|
300
|
-
</TooltipProvider>;
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
**Nota**: Agrega `cursor-pointer` para indicar interactividad.
|
|
304
|
-
|
|
305
|
-
### Card de Perfil de Usuario
|
|
306
|
-
|
|
307
|
-
Avatar como parte de un perfil completo:
|
|
308
|
-
|
|
309
|
-
```tsx
|
|
310
|
-
import { Badge } from "@adamosuiteservices/ui/badge";
|
|
311
|
-
import { Button } from "@adamosuiteservices/ui/button";
|
|
312
|
-
|
|
313
|
-
<div className="flex items-center gap-4 p-6 rounded-lg border max-w-md">
|
|
314
|
-
<Avatar className="size-16">
|
|
315
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
316
|
-
<AvatarFallback className="text-lg">CN</AvatarFallback>
|
|
317
|
-
</Avatar>
|
|
318
|
-
<div className="flex-1">
|
|
319
|
-
<h3 className="text-lg font-semibold">Colin Northcott</h3>
|
|
320
|
-
<p className="text-sm text-muted-foreground">@shadcn • UI Engineer</p>
|
|
321
|
-
<div className="flex gap-2 mt-2">
|
|
322
|
-
<Badge variant="secondary">React</Badge>
|
|
323
|
-
<Badge variant="secondary">TypeScript</Badge>
|
|
324
|
-
</div>
|
|
325
|
-
</div>
|
|
326
|
-
<Button size="sm">Follow</Button>
|
|
327
|
-
</div>;
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### Sistema de Comentarios
|
|
331
|
-
|
|
332
|
-
Avatares en un layout de conversación:
|
|
333
|
-
|
|
334
|
-
```tsx
|
|
335
|
-
const comments = [
|
|
336
|
-
{
|
|
337
|
-
id: 1,
|
|
338
|
-
author: "John Doe",
|
|
339
|
-
avatar: "https://github.com/shadcn.png",
|
|
340
|
-
fallback: "JD",
|
|
341
|
-
time: "2 hours ago",
|
|
342
|
-
content:
|
|
343
|
-
"This looks great! Really excited to see this feature in production.",
|
|
344
|
-
},
|
|
345
|
-
// ... más comentarios
|
|
346
|
-
];
|
|
347
|
-
|
|
348
|
-
<div className="space-y-4 max-w-2xl">
|
|
349
|
-
{comments.map((comment) => (
|
|
350
|
-
<div key={comment.id} className="flex gap-3">
|
|
351
|
-
<Avatar>
|
|
352
|
-
{comment.avatar && (
|
|
353
|
-
<AvatarImage src={comment.avatar} alt={comment.author} />
|
|
354
|
-
)}
|
|
355
|
-
<AvatarFallback>{comment.fallback}</AvatarFallback>
|
|
356
|
-
</Avatar>
|
|
357
|
-
<div className="flex-1 space-y-1">
|
|
358
|
-
<div className="flex items-center gap-2">
|
|
359
|
-
<span className="text-sm font-medium">{comment.author}</span>
|
|
360
|
-
<span className="text-xs text-muted-foreground">{comment.time}</span>
|
|
361
|
-
</div>
|
|
362
|
-
<p className="text-sm">{comment.content}</p>
|
|
363
|
-
</div>
|
|
364
|
-
</div>
|
|
365
|
-
))}
|
|
366
|
-
</div>;
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### Avatar con Indicador de Estado
|
|
370
|
-
|
|
371
|
-
Para mostrar estado online/offline/busy:
|
|
372
|
-
|
|
373
|
-
```tsx
|
|
374
|
-
<div className="relative inline-block">
|
|
375
|
-
<Avatar>
|
|
376
|
-
<AvatarImage src={url} alt="User" />
|
|
377
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
378
|
-
</Avatar>
|
|
379
|
-
{/* Indicador de estado */}
|
|
380
|
-
<span className="absolute bottom-0 right-0 block h-3 w-3 rounded-full bg-green-500 ring-2 ring-background" />
|
|
381
|
-
</div>
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
**Variantes de estado**:
|
|
385
|
-
|
|
386
|
-
- `bg-green-500`: Online
|
|
387
|
-
- `bg-gray-400`: Offline
|
|
388
|
-
- `bg-yellow-500`: Away/Idle
|
|
389
|
-
- `bg-red-500`: Busy/Do Not Disturb
|
|
390
|
-
|
|
391
|
-
### Avatar con Badge
|
|
392
|
-
|
|
393
|
-
Para notificaciones o roles:
|
|
394
|
-
|
|
395
|
-
```tsx
|
|
396
|
-
import { Badge } from "@adamosuiteservices/ui/badge";
|
|
397
|
-
|
|
398
|
-
<div className="relative inline-block">
|
|
399
|
-
<Avatar className="size-12">
|
|
400
|
-
<AvatarImage src={url} alt="User" />
|
|
401
|
-
<AvatarFallback>AD</AvatarFallback>
|
|
402
|
-
</Avatar>
|
|
403
|
-
<Badge
|
|
404
|
-
variant="destructive"
|
|
405
|
-
className="absolute -top-1 -right-1 h-5 w-5 rounded-full p-0 flex items-center justify-center text-xs"
|
|
406
|
-
>
|
|
407
|
-
5
|
|
408
|
-
</Badge>
|
|
409
|
-
</div>;
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
### Avatar con Icono de Fallback
|
|
413
|
-
|
|
414
|
-
Para usuarios sin nombre o genéricos:
|
|
415
|
-
|
|
416
|
-
```tsx
|
|
417
|
-
import { UserIcon } from "lucide-react";
|
|
418
|
-
|
|
419
|
-
<Avatar>
|
|
420
|
-
<AvatarImage src={url} alt="User" />
|
|
421
|
-
<AvatarFallback>
|
|
422
|
-
<UserIcon className="h-4 w-4" />
|
|
423
|
-
</AvatarFallback>
|
|
424
|
-
</Avatar>;
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
## Casos de Uso Comunes
|
|
428
|
-
|
|
429
|
-
### Lista de Miembros del Equipo
|
|
430
|
-
|
|
431
|
-
```tsx
|
|
432
|
-
const team = [
|
|
433
|
-
{ name: "John Doe", image: url1, initials: "JD" },
|
|
434
|
-
{ name: "Jane Smith", image: url2, initials: "JS" },
|
|
435
|
-
// ...
|
|
436
|
-
];
|
|
437
|
-
|
|
438
|
-
<div className="grid grid-cols-3 gap-4">
|
|
439
|
-
{team.map((member) => (
|
|
440
|
-
<div key={member.name} className="flex flex-col items-center gap-2">
|
|
441
|
-
<Avatar className="size-16">
|
|
442
|
-
<AvatarImage src={member.image} alt={member.name} />
|
|
443
|
-
<AvatarFallback className="text-lg">{member.initials}</AvatarFallback>
|
|
444
|
-
</Avatar>
|
|
445
|
-
<span className="text-sm font-medium">{member.name}</span>
|
|
446
|
-
</div>
|
|
447
|
-
))}
|
|
448
|
-
</div>;
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
### Chat de Mensajería
|
|
452
|
-
|
|
453
|
-
```tsx
|
|
454
|
-
<div className="flex items-start gap-3">
|
|
455
|
-
<Avatar>
|
|
456
|
-
<AvatarImage src={senderAvatar} alt={senderName} />
|
|
457
|
-
<AvatarFallback>{senderInitials}</AvatarFallback>
|
|
458
|
-
</Avatar>
|
|
459
|
-
<div className="flex-1">
|
|
460
|
-
<div className="flex items-center gap-2">
|
|
461
|
-
<span className="font-medium text-sm">{senderName}</span>
|
|
462
|
-
<span className="text-xs text-muted-foreground">{timestamp}</span>
|
|
463
|
-
</div>
|
|
464
|
-
<p className="text-sm mt-1">{messageContent}</p>
|
|
465
|
-
</div>
|
|
466
|
-
</div>
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### Selector de Usuario
|
|
470
|
-
|
|
471
|
-
```tsx
|
|
472
|
-
<div className="flex items-center gap-3 p-2 rounded-lg hover:bg-muted cursor-pointer">
|
|
473
|
-
<Avatar className="size-10">
|
|
474
|
-
<AvatarImage src={userAvatar} alt={userName} />
|
|
475
|
-
<AvatarFallback>{userInitials}</AvatarFallback>
|
|
476
|
-
</Avatar>
|
|
477
|
-
<div className="flex-1">
|
|
478
|
-
<p className="text-sm font-medium">{userName}</p>
|
|
479
|
-
<p className="text-xs text-muted-foreground">{userEmail}</p>
|
|
480
|
-
</div>
|
|
481
|
-
</div>
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
## Mejores Prácticas
|
|
485
|
-
|
|
486
|
-
### Generación de Iniciales
|
|
487
|
-
|
|
488
|
-
```typescript
|
|
489
|
-
function getInitials(name: string): string {
|
|
490
|
-
return name
|
|
491
|
-
.split(" ")
|
|
492
|
-
.map((part) => part[0])
|
|
493
|
-
.join("")
|
|
494
|
-
.toUpperCase()
|
|
495
|
-
.slice(0, 2);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Uso
|
|
499
|
-
<AvatarFallback>{getInitials("John Doe")}</AvatarFallback>; // "JD"
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
### Prop alt Descriptiva
|
|
503
|
-
|
|
504
|
-
```tsx
|
|
505
|
-
// ✅ Correcto - descriptivo
|
|
506
|
-
<AvatarImage src={url} alt="John Doe" />
|
|
507
|
-
<AvatarImage src={url} alt="@johndoe profile picture" />
|
|
508
|
-
|
|
509
|
-
// ❌ Incorrecto - genérico
|
|
510
|
-
<AvatarImage src={url} alt="avatar" />
|
|
511
|
-
<AvatarImage src={url} alt="user" />
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
### Consistencia de Tamaños
|
|
515
|
-
|
|
516
|
-
Mantén tamaños consistentes por contexto:
|
|
517
|
-
|
|
518
|
-
- **Listas pequeñas**: `size-8` (32px)
|
|
519
|
-
- **Perfiles**: `size-16` (64px)
|
|
520
|
-
- **Headers/Nav**: `size-10` (40px)
|
|
521
|
-
- **Comentarios**: `size-8` o `size-10`
|
|
522
|
-
- **Grupos**: `size-8` o más pequeños
|
|
523
|
-
|
|
524
|
-
### Colores de Fallback Personalizados
|
|
525
|
-
|
|
526
|
-
```tsx
|
|
527
|
-
<Avatar>
|
|
528
|
-
<AvatarImage src={url} alt="User" />
|
|
529
|
-
<AvatarFallback className="bg-blue-500 text-white">AB</AvatarFallback>
|
|
530
|
-
</Avatar>
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
**Patrón común**: Asignar colores basados en el nombre del usuario:
|
|
534
|
-
|
|
535
|
-
```typescript
|
|
536
|
-
function getAvatarColor(name: string): string {
|
|
537
|
-
const colors = [
|
|
538
|
-
"bg-red-500",
|
|
539
|
-
"bg-blue-500",
|
|
540
|
-
"bg-green-500",
|
|
541
|
-
"bg-yellow-500",
|
|
542
|
-
"bg-purple-500",
|
|
543
|
-
];
|
|
544
|
-
const index = name.charCodeAt(0) % colors.length;
|
|
545
|
-
return colors[index];
|
|
546
|
-
}
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
## Notas de Implementación
|
|
550
|
-
|
|
551
|
-
- Basado en Radix UI Avatar primitives
|
|
552
|
-
- Lazy loading de imágenes por defecto
|
|
553
|
-
- Fallback se muestra automáticamente en error de carga
|
|
554
|
-
- `aspect-square` mantiene proporción 1:1
|
|
555
|
-
- `overflow-hidden` con `rounded-full` crea forma circular
|
|
556
|
-
- `shrink-0` evita que el avatar se encoja en layouts flex
|
|
557
|
-
- Sistema de slots con `data-slot` para composición
|
|
558
|
-
- Tamaño por defecto: 32x32px (`size-8`)
|
|
559
|
-
|
|
560
|
-
## Accesibilidad
|
|
561
|
-
|
|
562
|
-
- ✅ **SIEMPRE** incluye prop `alt` en `AvatarImage` con texto descriptivo
|
|
563
|
-
- ✅ Radix UI maneja ARIA attributes automáticamente
|
|
564
|
-
- ✅ El fallback es accesible por screen readers
|
|
565
|
-
- ✅ Usa texto real en fallback (no iconos decorativos solos) cuando sea posible
|
|
566
|
-
- ✅ Si el avatar es clickeable, agrégalo dentro de un `<button>` o `<a>` con aria-label
|
|
567
|
-
- ⚠️ No uses solo color para indicar estado (combina con iconos/texto)
|
|
568
|
-
|
|
569
|
-
### Avatar Clickeable Accesible
|
|
570
|
-
|
|
571
|
-
```tsx
|
|
572
|
-
<button
|
|
573
|
-
type="button"
|
|
574
|
-
aria-label="View John Doe's profile"
|
|
575
|
-
className="rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2"
|
|
576
|
-
>
|
|
577
|
-
<Avatar>
|
|
578
|
-
<AvatarImage src={url} alt="John Doe" />
|
|
579
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
580
|
-
</Avatar>
|
|
581
|
-
</button>
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
## Referencias
|
|
585
|
-
|
|
586
|
-
- Radix UI Avatar: https://www.radix-ui.com/primitives/docs/components/avatar
|
|
587
|
-
- shadcn/ui Avatar: https://ui.shadcn.com/docs/components/avatar
|
|
588
|
-
- WCAG Image Alternative Text: https://www.w3.org/WAI/tutorials/images/
|
|
1
|
+
# Avatar Component
|
|
2
|
+
|
|
3
|
+
## Descripción
|
|
4
|
+
|
|
5
|
+
Componente para mostrar **imágenes de perfil de usuario** con sistema de fallback automático a iniciales o iconos cuando la imagen no está disponible o falla al cargar. Basado en Radix UI Avatar primitives con carga lazy, estado de error manejado, y diseño circular responsive.
|
|
6
|
+
|
|
7
|
+
## Características
|
|
8
|
+
|
|
9
|
+
- ✅ Fallback automático si la imagen falla
|
|
10
|
+
- ✅ Carga lazy de imágenes
|
|
11
|
+
- ✅ Soporte para iniciales o iconos como fallback
|
|
12
|
+
- ✅ Tamaños personalizables
|
|
13
|
+
- ✅ Formas: circular (default) o cuadrado/rectangular
|
|
14
|
+
- ✅ Grupos de avatares con solapamiento
|
|
15
|
+
- ✅ Integración con Tooltip
|
|
16
|
+
- ✅ Accesibilidad: alt text y ARIA
|
|
17
|
+
- ✅ Diseño responsive y flexible
|
|
18
|
+
|
|
19
|
+
## Importación
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import {
|
|
23
|
+
Avatar,
|
|
24
|
+
AvatarImage,
|
|
25
|
+
AvatarFallback,
|
|
26
|
+
} from "@adamosuiteservices/ui/avatar";
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Uso Básico
|
|
30
|
+
|
|
31
|
+
### Avatar con Imagen y Fallback
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<Avatar>
|
|
35
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
36
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
37
|
+
</Avatar>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Comportamiento**:
|
|
41
|
+
|
|
42
|
+
1. Intenta cargar la imagen del `src`
|
|
43
|
+
2. Si falla o no carga, muestra el `AvatarFallback` automáticamente
|
|
44
|
+
3. Radix UI maneja el estado de carga internamente
|
|
45
|
+
|
|
46
|
+
### Solo Fallback (Sin Imagen)
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Avatar>
|
|
50
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
51
|
+
</Avatar>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Uso**: Cuando no hay imagen disponible o solo quieres mostrar iniciales.
|
|
55
|
+
|
|
56
|
+
### Imagen Rota (Graceful Degradation)
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<Avatar>
|
|
60
|
+
<AvatarImage src="https://broken-link.com/image.jpg" alt="Broken" />
|
|
61
|
+
<AvatarFallback>BK</AvatarFallback>
|
|
62
|
+
</Avatar>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Resultado**: Automáticamente muestra "BK" si la imagen no carga.
|
|
66
|
+
|
|
67
|
+
## Props
|
|
68
|
+
|
|
69
|
+
### Avatar (Root)
|
|
70
|
+
|
|
71
|
+
Contenedor principal del avatar.
|
|
72
|
+
|
|
73
|
+
| Prop | Tipo | Descripción |
|
|
74
|
+
| --------- | -------------------------- | --------------------------- |
|
|
75
|
+
| className | `string` | Clases CSS adicionales |
|
|
76
|
+
| ...props | Props de Radix Avatar.Root | Props nativas del primitivo |
|
|
77
|
+
|
|
78
|
+
**Estilos por defecto**:
|
|
79
|
+
|
|
80
|
+
- `size-8`: 2rem (32x32px) - tamaño base
|
|
81
|
+
- `rounded-full`: Forma circular
|
|
82
|
+
- `shrink-0`: No se encoge en flex/grid
|
|
83
|
+
- `overflow-hidden`: Recorta contenido fuera del círculo
|
|
84
|
+
- `relative`: Para posicionamiento interno
|
|
85
|
+
- `flex`: Contenedor flex
|
|
86
|
+
|
|
87
|
+
**Atributos automáticos**:
|
|
88
|
+
|
|
89
|
+
- `data-slot="avatar"`: Para identificación interna
|
|
90
|
+
|
|
91
|
+
### AvatarImage
|
|
92
|
+
|
|
93
|
+
Imagen del avatar con carga lazy.
|
|
94
|
+
|
|
95
|
+
| Prop | Tipo | Descripción |
|
|
96
|
+
| --------- | --------------------------- | --------------------------------------------------- |
|
|
97
|
+
| src | `string` | **Requerido**. URL de la imagen |
|
|
98
|
+
| alt | `string` | **Requerido**. Texto alternativo para accesibilidad |
|
|
99
|
+
| className | `string` | Clases CSS adicionales |
|
|
100
|
+
| ...props | Props de Radix Avatar.Image | Props nativas del primitivo |
|
|
101
|
+
|
|
102
|
+
**Estilos aplicados**:
|
|
103
|
+
|
|
104
|
+
- `aspect-square`: Mantiene aspecto cuadrado
|
|
105
|
+
- `size-full`: Ocupa todo el contenedor (100% width/height)
|
|
106
|
+
|
|
107
|
+
**Comportamiento**:
|
|
108
|
+
|
|
109
|
+
- Carga lazy automática
|
|
110
|
+
- Emite eventos `onLoadingStatusChange`
|
|
111
|
+
- Estados: `idle`, `loading`, `loaded`, `error`
|
|
112
|
+
- Si falla, muestra AvatarFallback automáticamente
|
|
113
|
+
|
|
114
|
+
**Atributos automáticos**:
|
|
115
|
+
|
|
116
|
+
- `data-slot="avatar-image"`: Para identificación interna
|
|
117
|
+
|
|
118
|
+
### AvatarFallback
|
|
119
|
+
|
|
120
|
+
Contenido mostrado cuando la imagen no carga o no existe.
|
|
121
|
+
|
|
122
|
+
| Prop | Tipo | Descripción |
|
|
123
|
+
| --------- | ------------------------------ | ------------------------------------------------------ |
|
|
124
|
+
| children | `ReactNode` | **Requerido**. Iniciales, icono, o cualquier contenido |
|
|
125
|
+
| delayMs | `number` | Delay antes de mostrar el fallback (ms) |
|
|
126
|
+
| className | `string` | Clases CSS adicionales |
|
|
127
|
+
| ...props | Props de Radix Avatar.Fallback | Props nativas del primitivo |
|
|
128
|
+
|
|
129
|
+
**Estilos por defecto**:
|
|
130
|
+
|
|
131
|
+
- `bg-muted`: Fondo gris claro
|
|
132
|
+
- `rounded-full`: Forma circular (coincide con el contenedor)
|
|
133
|
+
- `size-full`: Ocupa todo el espacio
|
|
134
|
+
- `flex items-center justify-center`: Centra el contenido
|
|
135
|
+
|
|
136
|
+
**Contenido común**:
|
|
137
|
+
|
|
138
|
+
- Iniciales (2 letras): "JD", "AB", "CN"
|
|
139
|
+
- Iconos: `<UserIcon />`, `<PersonIcon />`
|
|
140
|
+
- Texto: "+5" (para grupos)
|
|
141
|
+
|
|
142
|
+
**Atributos automáticos**:
|
|
143
|
+
|
|
144
|
+
- `data-slot="avatar-fallback"`: Para identificación interna
|
|
145
|
+
|
|
146
|
+
## Tamaños Personalizados
|
|
147
|
+
|
|
148
|
+
El tamaño por defecto es `size-8` (32px). Personaliza con className:
|
|
149
|
+
|
|
150
|
+
### Tamaños Predefinidos
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
{
|
|
154
|
+
/* Extra Small - 24px */
|
|
155
|
+
}
|
|
156
|
+
<Avatar className="size-6">
|
|
157
|
+
<AvatarImage src={url} alt="User" />
|
|
158
|
+
<AvatarFallback className="text-xs">CN</AvatarFallback>
|
|
159
|
+
</Avatar>;
|
|
160
|
+
|
|
161
|
+
{
|
|
162
|
+
/* Small - 32px (default) */
|
|
163
|
+
}
|
|
164
|
+
<Avatar className="size-8">
|
|
165
|
+
<AvatarImage src={url} alt="User" />
|
|
166
|
+
<AvatarFallback>ER</AvatarFallback>
|
|
167
|
+
</Avatar>;
|
|
168
|
+
|
|
169
|
+
{
|
|
170
|
+
/* Medium - 48px */
|
|
171
|
+
}
|
|
172
|
+
<Avatar className="size-12">
|
|
173
|
+
<AvatarImage src={url} alt="User" />
|
|
174
|
+
<AvatarFallback>ML</AvatarFallback>
|
|
175
|
+
</Avatar>;
|
|
176
|
+
|
|
177
|
+
{
|
|
178
|
+
/* Large - 64px */
|
|
179
|
+
}
|
|
180
|
+
<Avatar className="size-16">
|
|
181
|
+
<AvatarImage src={url} alt="User" />
|
|
182
|
+
<AvatarFallback className="text-lg">VC</AvatarFallback>
|
|
183
|
+
</Avatar>;
|
|
184
|
+
|
|
185
|
+
{
|
|
186
|
+
/* Extra Large - 80px */
|
|
187
|
+
}
|
|
188
|
+
<Avatar className="size-20">
|
|
189
|
+
<AvatarImage src={url} alt="User" />
|
|
190
|
+
<AvatarFallback className="text-xl">NJ</AvatarFallback>
|
|
191
|
+
</Avatar>;
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Nota**: Ajusta el tamaño del texto del fallback según el tamaño del avatar para mantener proporciones.
|
|
195
|
+
|
|
196
|
+
### Tamaño Personalizado
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
<Avatar className="h-24 w-24">
|
|
200
|
+
<AvatarImage src={url} alt="User" />
|
|
201
|
+
<AvatarFallback className="text-2xl">AB</AvatarFallback>
|
|
202
|
+
</Avatar>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Formas Personalizadas
|
|
206
|
+
|
|
207
|
+
### Avatar Cuadrado
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
{
|
|
211
|
+
/* Rounded large */
|
|
212
|
+
}
|
|
213
|
+
<Avatar className="rounded-lg">
|
|
214
|
+
<AvatarImage src={url} alt="User" />
|
|
215
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
216
|
+
</Avatar>;
|
|
217
|
+
|
|
218
|
+
{
|
|
219
|
+
/* Rounded medium */
|
|
220
|
+
}
|
|
221
|
+
<Avatar className="rounded-md">
|
|
222
|
+
<AvatarImage src={url} alt="User" />
|
|
223
|
+
<AvatarFallback>ER</AvatarFallback>
|
|
224
|
+
</Avatar>;
|
|
225
|
+
|
|
226
|
+
{
|
|
227
|
+
/* Rounded small */
|
|
228
|
+
}
|
|
229
|
+
<Avatar className="rounded-sm">
|
|
230
|
+
<AvatarImage src={url} alt="User" />
|
|
231
|
+
<AvatarFallback>ML</AvatarFallback>
|
|
232
|
+
</Avatar>;
|
|
233
|
+
|
|
234
|
+
{
|
|
235
|
+
/* Completamente cuadrado */
|
|
236
|
+
}
|
|
237
|
+
<Avatar className="rounded-none">
|
|
238
|
+
<AvatarFallback>SQ</AvatarFallback>
|
|
239
|
+
</Avatar>;
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Uso**: Avatares cuadrados son comunes para logos de empresas o aplicaciones.
|
|
243
|
+
|
|
244
|
+
## Patrones Avanzados
|
|
245
|
+
|
|
246
|
+
### Grupo de Avatares (Overlapping)
|
|
247
|
+
|
|
248
|
+
Para mostrar múltiples usuarios con solapamiento:
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
<div className="flex -space-x-2">
|
|
252
|
+
<Avatar className="ring-2 ring-background">
|
|
253
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
254
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
255
|
+
</Avatar>
|
|
256
|
+
<Avatar className="ring-2 ring-background">
|
|
257
|
+
<AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" />
|
|
258
|
+
<AvatarFallback>ER</AvatarFallback>
|
|
259
|
+
</Avatar>
|
|
260
|
+
<Avatar className="ring-2 ring-background">
|
|
261
|
+
<AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" />
|
|
262
|
+
<AvatarFallback>ML</AvatarFallback>
|
|
263
|
+
</Avatar>
|
|
264
|
+
<Avatar className="ring-2 ring-background bg-muted">
|
|
265
|
+
<AvatarFallback>+2</AvatarFallback>
|
|
266
|
+
</Avatar>
|
|
267
|
+
</div>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Técnicas**:
|
|
271
|
+
|
|
272
|
+
- `-space-x-2`: Espacio negativo para solapar
|
|
273
|
+
- `ring-2 ring-background`: Borde blanco para separación visual
|
|
274
|
+
- Último avatar muestra contador "+N" para usuarios adicionales
|
|
275
|
+
|
|
276
|
+
### Avatar con Tooltip
|
|
277
|
+
|
|
278
|
+
Para mostrar información adicional al hover:
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
import {
|
|
282
|
+
Tooltip,
|
|
283
|
+
TooltipContent,
|
|
284
|
+
TooltipProvider,
|
|
285
|
+
TooltipTrigger,
|
|
286
|
+
} from "@adamosuiteservices/ui/tooltip";
|
|
287
|
+
|
|
288
|
+
<TooltipProvider>
|
|
289
|
+
<Tooltip>
|
|
290
|
+
<TooltipTrigger asChild>
|
|
291
|
+
<Avatar className="cursor-pointer">
|
|
292
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
293
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
294
|
+
</Avatar>
|
|
295
|
+
</TooltipTrigger>
|
|
296
|
+
<TooltipContent>
|
|
297
|
+
<p>shadcn - UI Engineer</p>
|
|
298
|
+
</TooltipContent>
|
|
299
|
+
</Tooltip>
|
|
300
|
+
</TooltipProvider>;
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Nota**: Agrega `cursor-pointer` para indicar interactividad.
|
|
304
|
+
|
|
305
|
+
### Card de Perfil de Usuario
|
|
306
|
+
|
|
307
|
+
Avatar como parte de un perfil completo:
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
import { Badge } from "@adamosuiteservices/ui/badge";
|
|
311
|
+
import { Button } from "@adamosuiteservices/ui/button";
|
|
312
|
+
|
|
313
|
+
<div className="flex items-center gap-4 p-6 rounded-lg border max-w-md">
|
|
314
|
+
<Avatar className="size-16">
|
|
315
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
316
|
+
<AvatarFallback className="text-lg">CN</AvatarFallback>
|
|
317
|
+
</Avatar>
|
|
318
|
+
<div className="flex-1">
|
|
319
|
+
<h3 className="text-lg font-semibold">Colin Northcott</h3>
|
|
320
|
+
<p className="text-sm text-muted-foreground">@shadcn • UI Engineer</p>
|
|
321
|
+
<div className="flex gap-2 mt-2">
|
|
322
|
+
<Badge variant="secondary">React</Badge>
|
|
323
|
+
<Badge variant="secondary">TypeScript</Badge>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
<Button size="sm">Follow</Button>
|
|
327
|
+
</div>;
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Sistema de Comentarios
|
|
331
|
+
|
|
332
|
+
Avatares en un layout de conversación:
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
const comments = [
|
|
336
|
+
{
|
|
337
|
+
id: 1,
|
|
338
|
+
author: "John Doe",
|
|
339
|
+
avatar: "https://github.com/shadcn.png",
|
|
340
|
+
fallback: "JD",
|
|
341
|
+
time: "2 hours ago",
|
|
342
|
+
content:
|
|
343
|
+
"This looks great! Really excited to see this feature in production.",
|
|
344
|
+
},
|
|
345
|
+
// ... más comentarios
|
|
346
|
+
];
|
|
347
|
+
|
|
348
|
+
<div className="space-y-4 max-w-2xl">
|
|
349
|
+
{comments.map((comment) => (
|
|
350
|
+
<div key={comment.id} className="flex gap-3">
|
|
351
|
+
<Avatar>
|
|
352
|
+
{comment.avatar && (
|
|
353
|
+
<AvatarImage src={comment.avatar} alt={comment.author} />
|
|
354
|
+
)}
|
|
355
|
+
<AvatarFallback>{comment.fallback}</AvatarFallback>
|
|
356
|
+
</Avatar>
|
|
357
|
+
<div className="flex-1 space-y-1">
|
|
358
|
+
<div className="flex items-center gap-2">
|
|
359
|
+
<span className="text-sm font-medium">{comment.author}</span>
|
|
360
|
+
<span className="text-xs text-muted-foreground">{comment.time}</span>
|
|
361
|
+
</div>
|
|
362
|
+
<p className="text-sm">{comment.content}</p>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
))}
|
|
366
|
+
</div>;
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Avatar con Indicador de Estado
|
|
370
|
+
|
|
371
|
+
Para mostrar estado online/offline/busy:
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
<div className="relative inline-block">
|
|
375
|
+
<Avatar>
|
|
376
|
+
<AvatarImage src={url} alt="User" />
|
|
377
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
378
|
+
</Avatar>
|
|
379
|
+
{/* Indicador de estado */}
|
|
380
|
+
<span className="absolute bottom-0 right-0 block h-3 w-3 rounded-full bg-green-500 ring-2 ring-background" />
|
|
381
|
+
</div>
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Variantes de estado**:
|
|
385
|
+
|
|
386
|
+
- `bg-green-500`: Online
|
|
387
|
+
- `bg-gray-400`: Offline
|
|
388
|
+
- `bg-yellow-500`: Away/Idle
|
|
389
|
+
- `bg-red-500`: Busy/Do Not Disturb
|
|
390
|
+
|
|
391
|
+
### Avatar con Badge
|
|
392
|
+
|
|
393
|
+
Para notificaciones o roles:
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
import { Badge } from "@adamosuiteservices/ui/badge";
|
|
397
|
+
|
|
398
|
+
<div className="relative inline-block">
|
|
399
|
+
<Avatar className="size-12">
|
|
400
|
+
<AvatarImage src={url} alt="User" />
|
|
401
|
+
<AvatarFallback>AD</AvatarFallback>
|
|
402
|
+
</Avatar>
|
|
403
|
+
<Badge
|
|
404
|
+
variant="destructive"
|
|
405
|
+
className="absolute -top-1 -right-1 h-5 w-5 rounded-full p-0 flex items-center justify-center text-xs"
|
|
406
|
+
>
|
|
407
|
+
5
|
|
408
|
+
</Badge>
|
|
409
|
+
</div>;
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Avatar con Icono de Fallback
|
|
413
|
+
|
|
414
|
+
Para usuarios sin nombre o genéricos:
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
import { UserIcon } from "lucide-react";
|
|
418
|
+
|
|
419
|
+
<Avatar>
|
|
420
|
+
<AvatarImage src={url} alt="User" />
|
|
421
|
+
<AvatarFallback>
|
|
422
|
+
<UserIcon className="h-4 w-4" />
|
|
423
|
+
</AvatarFallback>
|
|
424
|
+
</Avatar>;
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Casos de Uso Comunes
|
|
428
|
+
|
|
429
|
+
### Lista de Miembros del Equipo
|
|
430
|
+
|
|
431
|
+
```tsx
|
|
432
|
+
const team = [
|
|
433
|
+
{ name: "John Doe", image: url1, initials: "JD" },
|
|
434
|
+
{ name: "Jane Smith", image: url2, initials: "JS" },
|
|
435
|
+
// ...
|
|
436
|
+
];
|
|
437
|
+
|
|
438
|
+
<div className="grid grid-cols-3 gap-4">
|
|
439
|
+
{team.map((member) => (
|
|
440
|
+
<div key={member.name} className="flex flex-col items-center gap-2">
|
|
441
|
+
<Avatar className="size-16">
|
|
442
|
+
<AvatarImage src={member.image} alt={member.name} />
|
|
443
|
+
<AvatarFallback className="text-lg">{member.initials}</AvatarFallback>
|
|
444
|
+
</Avatar>
|
|
445
|
+
<span className="text-sm font-medium">{member.name}</span>
|
|
446
|
+
</div>
|
|
447
|
+
))}
|
|
448
|
+
</div>;
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### Chat de Mensajería
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
<div className="flex items-start gap-3">
|
|
455
|
+
<Avatar>
|
|
456
|
+
<AvatarImage src={senderAvatar} alt={senderName} />
|
|
457
|
+
<AvatarFallback>{senderInitials}</AvatarFallback>
|
|
458
|
+
</Avatar>
|
|
459
|
+
<div className="flex-1">
|
|
460
|
+
<div className="flex items-center gap-2">
|
|
461
|
+
<span className="font-medium text-sm">{senderName}</span>
|
|
462
|
+
<span className="text-xs text-muted-foreground">{timestamp}</span>
|
|
463
|
+
</div>
|
|
464
|
+
<p className="text-sm mt-1">{messageContent}</p>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Selector de Usuario
|
|
470
|
+
|
|
471
|
+
```tsx
|
|
472
|
+
<div className="flex items-center gap-3 p-2 rounded-lg hover:bg-muted cursor-pointer">
|
|
473
|
+
<Avatar className="size-10">
|
|
474
|
+
<AvatarImage src={userAvatar} alt={userName} />
|
|
475
|
+
<AvatarFallback>{userInitials}</AvatarFallback>
|
|
476
|
+
</Avatar>
|
|
477
|
+
<div className="flex-1">
|
|
478
|
+
<p className="text-sm font-medium">{userName}</p>
|
|
479
|
+
<p className="text-xs text-muted-foreground">{userEmail}</p>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
## Mejores Prácticas
|
|
485
|
+
|
|
486
|
+
### Generación de Iniciales
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
function getInitials(name: string): string {
|
|
490
|
+
return name
|
|
491
|
+
.split(" ")
|
|
492
|
+
.map((part) => part[0])
|
|
493
|
+
.join("")
|
|
494
|
+
.toUpperCase()
|
|
495
|
+
.slice(0, 2);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Uso
|
|
499
|
+
<AvatarFallback>{getInitials("John Doe")}</AvatarFallback>; // "JD"
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
### Prop alt Descriptiva
|
|
503
|
+
|
|
504
|
+
```tsx
|
|
505
|
+
// ✅ Correcto - descriptivo
|
|
506
|
+
<AvatarImage src={url} alt="John Doe" />
|
|
507
|
+
<AvatarImage src={url} alt="@johndoe profile picture" />
|
|
508
|
+
|
|
509
|
+
// ❌ Incorrecto - genérico
|
|
510
|
+
<AvatarImage src={url} alt="avatar" />
|
|
511
|
+
<AvatarImage src={url} alt="user" />
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### Consistencia de Tamaños
|
|
515
|
+
|
|
516
|
+
Mantén tamaños consistentes por contexto:
|
|
517
|
+
|
|
518
|
+
- **Listas pequeñas**: `size-8` (32px)
|
|
519
|
+
- **Perfiles**: `size-16` (64px)
|
|
520
|
+
- **Headers/Nav**: `size-10` (40px)
|
|
521
|
+
- **Comentarios**: `size-8` o `size-10`
|
|
522
|
+
- **Grupos**: `size-8` o más pequeños
|
|
523
|
+
|
|
524
|
+
### Colores de Fallback Personalizados
|
|
525
|
+
|
|
526
|
+
```tsx
|
|
527
|
+
<Avatar>
|
|
528
|
+
<AvatarImage src={url} alt="User" />
|
|
529
|
+
<AvatarFallback className="bg-blue-500 text-white">AB</AvatarFallback>
|
|
530
|
+
</Avatar>
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
**Patrón común**: Asignar colores basados en el nombre del usuario:
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
function getAvatarColor(name: string): string {
|
|
537
|
+
const colors = [
|
|
538
|
+
"bg-red-500",
|
|
539
|
+
"bg-blue-500",
|
|
540
|
+
"bg-green-500",
|
|
541
|
+
"bg-yellow-500",
|
|
542
|
+
"bg-purple-500",
|
|
543
|
+
];
|
|
544
|
+
const index = name.charCodeAt(0) % colors.length;
|
|
545
|
+
return colors[index];
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
## Notas de Implementación
|
|
550
|
+
|
|
551
|
+
- Basado en Radix UI Avatar primitives
|
|
552
|
+
- Lazy loading de imágenes por defecto
|
|
553
|
+
- Fallback se muestra automáticamente en error de carga
|
|
554
|
+
- `aspect-square` mantiene proporción 1:1
|
|
555
|
+
- `overflow-hidden` con `rounded-full` crea forma circular
|
|
556
|
+
- `shrink-0` evita que el avatar se encoja en layouts flex
|
|
557
|
+
- Sistema de slots con `data-slot` para composición
|
|
558
|
+
- Tamaño por defecto: 32x32px (`size-8`)
|
|
559
|
+
|
|
560
|
+
## Accesibilidad
|
|
561
|
+
|
|
562
|
+
- ✅ **SIEMPRE** incluye prop `alt` en `AvatarImage` con texto descriptivo
|
|
563
|
+
- ✅ Radix UI maneja ARIA attributes automáticamente
|
|
564
|
+
- ✅ El fallback es accesible por screen readers
|
|
565
|
+
- ✅ Usa texto real en fallback (no iconos decorativos solos) cuando sea posible
|
|
566
|
+
- ✅ Si el avatar es clickeable, agrégalo dentro de un `<button>` o `<a>` con aria-label
|
|
567
|
+
- ⚠️ No uses solo color para indicar estado (combina con iconos/texto)
|
|
568
|
+
|
|
569
|
+
### Avatar Clickeable Accesible
|
|
570
|
+
|
|
571
|
+
```tsx
|
|
572
|
+
<button
|
|
573
|
+
type="button"
|
|
574
|
+
aria-label="View John Doe's profile"
|
|
575
|
+
className="rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2"
|
|
576
|
+
>
|
|
577
|
+
<Avatar>
|
|
578
|
+
<AvatarImage src={url} alt="John Doe" />
|
|
579
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
580
|
+
</Avatar>
|
|
581
|
+
</button>
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## Referencias
|
|
585
|
+
|
|
586
|
+
- Radix UI Avatar: https://www.radix-ui.com/primitives/docs/components/avatar
|
|
587
|
+
- shadcn/ui Avatar: https://ui.shadcn.com/docs/components/avatar
|
|
588
|
+
- WCAG Image Alternative Text: https://www.w3.org/WAI/tutorials/images/
|