torch-glare 2.5.6 → 2.6.0
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/README.md +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -403
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -325
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -395
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -88
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -72
- package/apps/lib/components/DataViews/states.tsx +0 -73
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -451
- package/apps/lib/components/DropdownMenu.tsx +0 -554
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -85
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -168
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -114
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -67
- package/apps/lib/components/FormBuilder/types.ts +0 -316
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -250
- package/apps/lib/components/FormRenderer/detail.tsx +0 -256
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -358
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -17
- package/apps/lib/components/FormRenderer/notch-action.tsx +0 -64
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -393
- package/apps/lib/components/FormRenderer/types.ts +0 -115
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -168
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -255
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -597
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -61
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useHtmlDir.ts +0 -31
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -300
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1217
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/scroller.ts +0 -26
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -738
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1521
- package/docs/components/data-views/migration.md +0 -81
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -284
- package/docs/components/form-renderer.md +0 -396
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -483
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -60
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1523
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -726
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
|
@@ -1,709 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Avatar
|
|
3
|
-
description: User profile image component with automatic fallback to initials, built on Radix UI Avatar primitive.
|
|
4
|
-
component: true
|
|
5
|
-
group: Data Display
|
|
6
|
-
keywords: [avatar, profile, image, user, picture, fallback, initials]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Avatar
|
|
10
|
-
|
|
11
|
-
A flexible avatar component for displaying user profile images with automatic fallback support. Built on Radix UI's Avatar primitive for robust image loading handling.
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
16
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npx torch-glare@latest init
|
|
20
|
-
npx torch-glare@latest add Avatar
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
`add` also copies any components, hooks, and utilities that `Avatar` depends on.
|
|
24
|
-
|
|
25
|
-
## Imports
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
import { Avatar, AvatarImage, AvatarFallback } from '@/components/Avatar'
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Basic Usage
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
import { Avatar, AvatarImage, AvatarFallback } from '@/components/Avatar'
|
|
35
|
-
|
|
36
|
-
export function BasicAvatar() {
|
|
37
|
-
return (
|
|
38
|
-
<Avatar>
|
|
39
|
-
<AvatarImage src="/user-photo.jpg" alt="User Name" />
|
|
40
|
-
<AvatarFallback>UN</AvatarFallback>
|
|
41
|
-
</Avatar>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Examples
|
|
47
|
-
|
|
48
|
-
### With Image
|
|
49
|
-
|
|
50
|
-
Avatar displaying user photo with fallback.
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
export function AvatarWithImage() {
|
|
54
|
-
return (
|
|
55
|
-
<div className="flex items-center gap-4">
|
|
56
|
-
<Avatar>
|
|
57
|
-
<AvatarImage src="https://github.com/shadcn.png" alt="User" />
|
|
58
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
59
|
-
</Avatar>
|
|
60
|
-
|
|
61
|
-
<div>
|
|
62
|
-
<h4 className="font-semibold">John Doe</h4>
|
|
63
|
-
<p className="text-sm text-content-presentation-global-secondary">
|
|
64
|
-
john@example.com
|
|
65
|
-
</p>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Fallback Initials
|
|
73
|
-
|
|
74
|
-
Avatar showing initials when image fails to load.
|
|
75
|
-
|
|
76
|
-
```tsx
|
|
77
|
-
export function AvatarWithInitials() {
|
|
78
|
-
const users = [
|
|
79
|
-
{ name: 'John Doe', initials: 'JD' },
|
|
80
|
-
{ name: 'Jane Smith', initials: 'JS' },
|
|
81
|
-
{ name: 'Bob Johnson', initials: 'BJ' },
|
|
82
|
-
{ name: 'Alice Brown', initials: 'AB' },
|
|
83
|
-
]
|
|
84
|
-
|
|
85
|
-
return (
|
|
86
|
-
<div className="flex gap-3">
|
|
87
|
-
{users.map(user => (
|
|
88
|
-
<Avatar key={user.name}>
|
|
89
|
-
<AvatarImage src="/invalid-url.jpg" alt={user.name} />
|
|
90
|
-
<AvatarFallback>{user.initials}</AvatarFallback>
|
|
91
|
-
</Avatar>
|
|
92
|
-
))}
|
|
93
|
-
</div>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Different Sizes
|
|
99
|
-
|
|
100
|
-
Avatars in various sizes for different contexts.
|
|
101
|
-
|
|
102
|
-
```tsx
|
|
103
|
-
export function AvatarSizes() {
|
|
104
|
-
return (
|
|
105
|
-
<div className="flex items-end gap-4">
|
|
106
|
-
<div className="flex flex-col items-center gap-2">
|
|
107
|
-
<Avatar className="h-8 w-8">
|
|
108
|
-
<AvatarImage src="/user.jpg" />
|
|
109
|
-
<AvatarFallback className="text-xs">XS</AvatarFallback>
|
|
110
|
-
</Avatar>
|
|
111
|
-
<span className="text-xs">32px</span>
|
|
112
|
-
</div>
|
|
113
|
-
|
|
114
|
-
<div className="flex flex-col items-center gap-2">
|
|
115
|
-
<Avatar className="h-10 w-10">
|
|
116
|
-
<AvatarImage src="/user.jpg" />
|
|
117
|
-
<AvatarFallback className="text-sm">S</AvatarFallback>
|
|
118
|
-
</Avatar>
|
|
119
|
-
<span className="text-xs">40px (default)</span>
|
|
120
|
-
</div>
|
|
121
|
-
|
|
122
|
-
<div className="flex flex-col items-center gap-2">
|
|
123
|
-
<Avatar className="h-12 w-12">
|
|
124
|
-
<AvatarImage src="/user.jpg" />
|
|
125
|
-
<AvatarFallback>M</AvatarFallback>
|
|
126
|
-
</Avatar>
|
|
127
|
-
<span className="text-xs">48px</span>
|
|
128
|
-
</div>
|
|
129
|
-
|
|
130
|
-
<div className="flex flex-col items-center gap-2">
|
|
131
|
-
<Avatar className="h-16 w-16">
|
|
132
|
-
<AvatarImage src="/user.jpg" />
|
|
133
|
-
<AvatarFallback className="text-lg">L</AvatarFallback>
|
|
134
|
-
</Avatar>
|
|
135
|
-
<span className="text-xs">64px</span>
|
|
136
|
-
</div>
|
|
137
|
-
|
|
138
|
-
<div className="flex flex-col items-center gap-2">
|
|
139
|
-
<Avatar className="h-24 w-24">
|
|
140
|
-
<AvatarImage src="/user.jpg" />
|
|
141
|
-
<AvatarFallback className="text-2xl">XL</AvatarFallback>
|
|
142
|
-
</Avatar>
|
|
143
|
-
<span className="text-xs">96px</span>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### User List
|
|
151
|
-
|
|
152
|
-
List of users with avatars and info.
|
|
153
|
-
|
|
154
|
-
```tsx
|
|
155
|
-
export function UserList() {
|
|
156
|
-
const users = [
|
|
157
|
-
{ id: 1, name: 'John Doe', email: 'john@example.com', avatar: '/john.jpg', status: 'online' },
|
|
158
|
-
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', avatar: '/jane.jpg', status: 'offline' },
|
|
159
|
-
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', avatar: '/bob.jpg', status: 'away' },
|
|
160
|
-
]
|
|
161
|
-
|
|
162
|
-
const getInitials = (name: string) => {
|
|
163
|
-
return name.split(' ').map(n => n[0]).join('').toUpperCase()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return (
|
|
167
|
-
<div className="space-y-2">
|
|
168
|
-
{users.map(user => (
|
|
169
|
-
<div key={user.id} className="flex items-center gap-3 p-3 rounded-lg hover:bg-background-presentation-global-secondary">
|
|
170
|
-
<div className="relative">
|
|
171
|
-
<Avatar>
|
|
172
|
-
<AvatarImage src={user.avatar} alt={user.name} />
|
|
173
|
-
<AvatarFallback>{getInitials(user.name)}</AvatarFallback>
|
|
174
|
-
</Avatar>
|
|
175
|
-
<span className={cn(
|
|
176
|
-
"absolute bottom-0 right-0 w-3 h-3 rounded-full border-2 border-white",
|
|
177
|
-
user.status === 'online' && "bg-green-500",
|
|
178
|
-
user.status === 'offline' && "bg-gray-400",
|
|
179
|
-
user.status === 'away' && "bg-yellow-500"
|
|
180
|
-
)} />
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
<div className="flex-1">
|
|
184
|
-
<div className="font-medium">{user.name}</div>
|
|
185
|
-
<div className="text-sm text-content-presentation-global-secondary">
|
|
186
|
-
{user.email}
|
|
187
|
-
</div>
|
|
188
|
-
</div>
|
|
189
|
-
|
|
190
|
-
<button className="text-sm text-blue-500 hover:underline">
|
|
191
|
-
Message
|
|
192
|
-
</button>
|
|
193
|
-
</div>
|
|
194
|
-
))}
|
|
195
|
-
</div>
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Avatar Group
|
|
201
|
-
|
|
202
|
-
Stacked avatars showing group members.
|
|
203
|
-
|
|
204
|
-
```tsx
|
|
205
|
-
export function AvatarGroup() {
|
|
206
|
-
const members = [
|
|
207
|
-
{ name: 'Alice', avatar: '/alice.jpg' },
|
|
208
|
-
{ name: 'Bob', avatar: '/bob.jpg' },
|
|
209
|
-
{ name: 'Charlie', avatar: '/charlie.jpg' },
|
|
210
|
-
{ name: 'David', avatar: '/david.jpg' },
|
|
211
|
-
]
|
|
212
|
-
|
|
213
|
-
const remainingCount = 12
|
|
214
|
-
|
|
215
|
-
return (
|
|
216
|
-
<div>
|
|
217
|
-
<h4 className="font-semibold mb-3">Project Team (16 members)</h4>
|
|
218
|
-
|
|
219
|
-
<div className="flex items-center">
|
|
220
|
-
{members.map((member, index) => (
|
|
221
|
-
<Avatar
|
|
222
|
-
key={member.name}
|
|
223
|
-
className="border-2 border-white -ml-2 first:ml-0"
|
|
224
|
-
style={{ zIndex: members.length - index }}
|
|
225
|
-
>
|
|
226
|
-
<AvatarImage src={member.avatar} alt={member.name} />
|
|
227
|
-
<AvatarFallback>{member.name[0]}</AvatarFallback>
|
|
228
|
-
</Avatar>
|
|
229
|
-
))}
|
|
230
|
-
|
|
231
|
-
{remainingCount > 0 && (
|
|
232
|
-
<div className="h-10 w-10 rounded-full bg-background-presentation-global-secondary border-2 border-white -ml-2 flex items-center justify-center text-sm font-semibold"
|
|
233
|
-
style={{ zIndex: 0 }}
|
|
234
|
-
>
|
|
235
|
-
+{remainingCount}
|
|
236
|
-
</div>
|
|
237
|
-
)}
|
|
238
|
-
</div>
|
|
239
|
-
</div>
|
|
240
|
-
)
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Colored Fallbacks
|
|
245
|
-
|
|
246
|
-
Unique colors for each user's initials.
|
|
247
|
-
|
|
248
|
-
```tsx
|
|
249
|
-
export function ColoredAvatars() {
|
|
250
|
-
const users = [
|
|
251
|
-
{ name: 'John Doe', color: 'bg-blue-500' },
|
|
252
|
-
{ name: 'Jane Smith', color: 'bg-green-500' },
|
|
253
|
-
{ name: 'Bob Johnson', color: 'bg-purple-500' },
|
|
254
|
-
{ name: 'Alice Brown', color: 'bg-pink-500' },
|
|
255
|
-
{ name: 'Charlie Davis', color: 'bg-orange-500' },
|
|
256
|
-
]
|
|
257
|
-
|
|
258
|
-
const getInitials = (name: string) => {
|
|
259
|
-
return name.split(' ').map(n => n[0]).join('')
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return (
|
|
263
|
-
<div className="flex gap-3">
|
|
264
|
-
{users.map(user => (
|
|
265
|
-
<Avatar key={user.name}>
|
|
266
|
-
<AvatarImage src="/invalid.jpg" />
|
|
267
|
-
<AvatarFallback className={cn(user.color, "text-white")}>
|
|
268
|
-
{getInitials(user.name)}
|
|
269
|
-
</AvatarFallback>
|
|
270
|
-
</Avatar>
|
|
271
|
-
))}
|
|
272
|
-
</div>
|
|
273
|
-
)
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### With Status Indicator
|
|
278
|
-
|
|
279
|
-
Avatar showing online/offline status.
|
|
280
|
-
|
|
281
|
-
```tsx
|
|
282
|
-
export function AvatarWithStatus() {
|
|
283
|
-
const [isOnline, setIsOnline] = useState(true)
|
|
284
|
-
|
|
285
|
-
return (
|
|
286
|
-
<div className="flex items-center gap-4">
|
|
287
|
-
<div className="relative">
|
|
288
|
-
<Avatar className="h-16 w-16">
|
|
289
|
-
<AvatarImage src="/user.jpg" alt="User" />
|
|
290
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
291
|
-
</Avatar>
|
|
292
|
-
|
|
293
|
-
{/* Status indicator */}
|
|
294
|
-
<span className={cn(
|
|
295
|
-
"absolute bottom-1 right-1 w-4 h-4 rounded-full border-2 border-white",
|
|
296
|
-
isOnline ? "bg-green-500" : "bg-gray-400"
|
|
297
|
-
)} />
|
|
298
|
-
</div>
|
|
299
|
-
|
|
300
|
-
<div>
|
|
301
|
-
<h4 className="font-semibold">John Doe</h4>
|
|
302
|
-
<p className="text-sm text-content-presentation-global-secondary">
|
|
303
|
-
{isOnline ? 'Online' : 'Offline'}
|
|
304
|
-
</p>
|
|
305
|
-
<button
|
|
306
|
-
onClick={() => setIsOnline(!isOnline)}
|
|
307
|
-
className="text-xs text-blue-500 mt-1"
|
|
308
|
-
>
|
|
309
|
-
Toggle Status
|
|
310
|
-
</button>
|
|
311
|
-
</div>
|
|
312
|
-
</div>
|
|
313
|
-
)
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### Comment Thread
|
|
318
|
-
|
|
319
|
-
Avatars in comment/chat interfaces.
|
|
320
|
-
|
|
321
|
-
```tsx
|
|
322
|
-
export function CommentThread() {
|
|
323
|
-
const comments = [
|
|
324
|
-
{ id: 1, author: 'John Doe', avatar: '/john.jpg', text: 'This looks great!', time: '2 hours ago' },
|
|
325
|
-
{ id: 2, author: 'Jane Smith', avatar: '/jane.jpg', text: 'Agreed, nice work!', time: '1 hour ago' },
|
|
326
|
-
{ id: 3, author: 'Bob Johnson', avatar: '/bob.jpg', text: 'Can we add more features?', time: '30 min ago' },
|
|
327
|
-
]
|
|
328
|
-
|
|
329
|
-
const getInitials = (name: string) => name.split(' ').map(n => n[0]).join('')
|
|
330
|
-
|
|
331
|
-
return (
|
|
332
|
-
<div className="space-y-4">
|
|
333
|
-
{comments.map(comment => (
|
|
334
|
-
<div key={comment.id} className="flex gap-3">
|
|
335
|
-
<Avatar>
|
|
336
|
-
<AvatarImage src={comment.avatar} alt={comment.author} />
|
|
337
|
-
<AvatarFallback>{getInitials(comment.author)}</AvatarFallback>
|
|
338
|
-
</Avatar>
|
|
339
|
-
|
|
340
|
-
<div className="flex-1 bg-background-presentation-global-secondary p-3 rounded-lg">
|
|
341
|
-
<div className="flex items-center justify-between mb-1">
|
|
342
|
-
<span className="font-semibold text-sm">{comment.author}</span>
|
|
343
|
-
<span className="text-xs text-content-presentation-global-tertiary">
|
|
344
|
-
{comment.time}
|
|
345
|
-
</span>
|
|
346
|
-
</div>
|
|
347
|
-
<p className="text-sm">{comment.text}</p>
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
))}
|
|
351
|
-
</div>
|
|
352
|
-
)
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Profile Header
|
|
357
|
-
|
|
358
|
-
Large avatar for profile pages.
|
|
359
|
-
|
|
360
|
-
```tsx
|
|
361
|
-
export function ProfileHeader() {
|
|
362
|
-
return (
|
|
363
|
-
<div className="relative">
|
|
364
|
-
{/* Cover photo */}
|
|
365
|
-
<div className="h-48 bg-gradient-to-r from-blue-400 to-purple-500 rounded-t-lg" />
|
|
366
|
-
|
|
367
|
-
{/* Profile info */}
|
|
368
|
-
<div className="px-6 pb-6">
|
|
369
|
-
<div className="flex items-end justify-between -mt-12 mb-4">
|
|
370
|
-
<Avatar className="h-24 w-24 border-4 border-white">
|
|
371
|
-
<AvatarImage src="/profile.jpg" alt="John Doe" />
|
|
372
|
-
<AvatarFallback className="text-2xl">JD</AvatarFallback>
|
|
373
|
-
</Avatar>
|
|
374
|
-
|
|
375
|
-
<button className="px-4 py-2 bg-blue-500 text-white rounded-lg">
|
|
376
|
-
Edit Profile
|
|
377
|
-
</button>
|
|
378
|
-
</div>
|
|
379
|
-
|
|
380
|
-
<h1 className="text-2xl font-bold">John Doe</h1>
|
|
381
|
-
<p className="text-content-presentation-global-secondary">
|
|
382
|
-
Software Engineer @Company
|
|
383
|
-
</p>
|
|
384
|
-
<p className="mt-2">
|
|
385
|
-
Building great products with React and TypeScript. Open source contributor.
|
|
386
|
-
</p>
|
|
387
|
-
|
|
388
|
-
<div className="flex gap-4 mt-4">
|
|
389
|
-
<div>
|
|
390
|
-
<div className="font-bold">1,234</div>
|
|
391
|
-
<div className="text-sm text-content-presentation-global-secondary">Followers</div>
|
|
392
|
-
</div>
|
|
393
|
-
<div>
|
|
394
|
-
<div className="font-bold">567</div>
|
|
395
|
-
<div className="text-sm text-content-presentation-global-secondary">Following</div>
|
|
396
|
-
</div>
|
|
397
|
-
</div>
|
|
398
|
-
</div>
|
|
399
|
-
</div>
|
|
400
|
-
)
|
|
401
|
-
}
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### Team Members Grid
|
|
405
|
-
|
|
406
|
-
Grid layout with team member avatars.
|
|
407
|
-
|
|
408
|
-
```tsx
|
|
409
|
-
export function TeamGrid() {
|
|
410
|
-
const team = [
|
|
411
|
-
{ name: 'John Doe', role: 'CEO', avatar: '/john.jpg' },
|
|
412
|
-
{ name: 'Jane Smith', role: 'CTO', avatar: '/jane.jpg' },
|
|
413
|
-
{ name: 'Bob Johnson', role: 'Designer', avatar: '/bob.jpg' },
|
|
414
|
-
{ name: 'Alice Brown', role: 'Developer', avatar: '/alice.jpg' },
|
|
415
|
-
{ name: 'Charlie Davis', role: 'Marketing', avatar: '/charlie.jpg' },
|
|
416
|
-
{ name: 'Eve Wilson', role: 'Sales', avatar: '/eve.jpg' },
|
|
417
|
-
]
|
|
418
|
-
|
|
419
|
-
const getInitials = (name: string) => name.split(' ').map(n => n[0]).join('')
|
|
420
|
-
|
|
421
|
-
return (
|
|
422
|
-
<div>
|
|
423
|
-
<h2 className="text-2xl font-bold mb-6">Our Team</h2>
|
|
424
|
-
|
|
425
|
-
<div className="grid grid-cols-2 md:grid-cols-3 gap-6">
|
|
426
|
-
{team.map(member => (
|
|
427
|
-
<div key={member.name} className="flex flex-col items-center text-center">
|
|
428
|
-
<Avatar className="h-20 w-20 mb-3">
|
|
429
|
-
<AvatarImage src={member.avatar} alt={member.name} />
|
|
430
|
-
<AvatarFallback className="text-lg">{getInitials(member.name)}</AvatarFallback>
|
|
431
|
-
</Avatar>
|
|
432
|
-
<h3 className="font-semibold">{member.name}</h3>
|
|
433
|
-
<p className="text-sm text-content-presentation-global-secondary">{member.role}</p>
|
|
434
|
-
</div>
|
|
435
|
-
))}
|
|
436
|
-
</div>
|
|
437
|
-
</div>
|
|
438
|
-
)
|
|
439
|
-
}
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
## API Reference
|
|
443
|
-
|
|
444
|
-
### Avatar Props
|
|
445
|
-
|
|
446
|
-
Extends all Radix UI Avatar.Root props.
|
|
447
|
-
|
|
448
|
-
| Prop | Type | Default | Description |
|
|
449
|
-
|------|------|---------|-------------|
|
|
450
|
-
| className | `string` | - | Additional CSS classes |
|
|
451
|
-
| children | `ReactNode` | - | AvatarImage and AvatarFallback |
|
|
452
|
-
| ref | `Ref` | - | Forwarded ref |
|
|
453
|
-
|
|
454
|
-
### AvatarImage Props
|
|
455
|
-
|
|
456
|
-
Extends all Radix UI Avatar.Image props.
|
|
457
|
-
|
|
458
|
-
| Prop | Type | Default | Description |
|
|
459
|
-
|------|------|---------|-------------|
|
|
460
|
-
| src | `string` | - | Image source URL |
|
|
461
|
-
| alt | `string` | - | Alt text for image |
|
|
462
|
-
| className | `string` | - | Additional CSS classes |
|
|
463
|
-
| ref | `Ref` | - | Forwarded ref |
|
|
464
|
-
|
|
465
|
-
### AvatarFallback Props
|
|
466
|
-
|
|
467
|
-
Extends all Radix UI Avatar.Fallback props.
|
|
468
|
-
|
|
469
|
-
| Prop | Type | Default | Description |
|
|
470
|
-
|------|------|---------|-------------|
|
|
471
|
-
| children | `ReactNode` | - | Fallback content (typically initials) |
|
|
472
|
-
| className | `string` | - | Additional CSS classes |
|
|
473
|
-
| ref | `Ref` | - | Forwarded ref |
|
|
474
|
-
|
|
475
|
-
### Size Guide
|
|
476
|
-
|
|
477
|
-
| Class | Size | Use Case |
|
|
478
|
-
|-------|------|----------|
|
|
479
|
-
| `h-6 w-6` | 24px | Tiny inline avatars |
|
|
480
|
-
| `h-8 w-8` | 32px | Small lists, compact UI |
|
|
481
|
-
| `h-10 w-10` | 40px | Default size, most common |
|
|
482
|
-
| `h-12 w-12` | 48px | Prominent lists |
|
|
483
|
-
| `h-16 w-16` | 64px | Profile cards |
|
|
484
|
-
| `h-20 w-20` | 80px | Team pages |
|
|
485
|
-
| `h-24 w-24` | 96px | Large profiles |
|
|
486
|
-
|
|
487
|
-
## Styling
|
|
488
|
-
|
|
489
|
-
### Default Styles
|
|
490
|
-
|
|
491
|
-
- **Shape**: Circular (rounded-full)
|
|
492
|
-
- **Size**: 40px × 40px default
|
|
493
|
-
- **Image**: Object-cover, aspect-square
|
|
494
|
-
- **Fallback**: Centered flex, system background
|
|
495
|
-
|
|
496
|
-
### Custom Styling
|
|
497
|
-
|
|
498
|
-
```tsx
|
|
499
|
-
// Square avatar
|
|
500
|
-
<Avatar className="rounded-lg">
|
|
501
|
-
<AvatarImage src="/user.jpg" />
|
|
502
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
503
|
-
</Avatar>
|
|
504
|
-
|
|
505
|
-
// Custom background
|
|
506
|
-
<Avatar>
|
|
507
|
-
<AvatarImage src="/user.jpg" />
|
|
508
|
-
<AvatarFallback className="bg-gradient-to-br from-purple-400 to-pink-600 text-white">
|
|
509
|
-
JD
|
|
510
|
-
</AvatarFallback>
|
|
511
|
-
</Avatar>
|
|
512
|
-
|
|
513
|
-
// With border
|
|
514
|
-
<Avatar className="border-2 border-blue-500">
|
|
515
|
-
<AvatarImage src="/user.jpg" />
|
|
516
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
517
|
-
</Avatar>
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
## TypeScript Types
|
|
521
|
-
|
|
522
|
-
```typescript
|
|
523
|
-
import type * as AvatarPrimitive from '@radix-ui/react-avatar'
|
|
524
|
-
|
|
525
|
-
type AvatarProps = React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
|
|
526
|
-
|
|
527
|
-
type AvatarImageProps = React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
|
|
528
|
-
|
|
529
|
-
type AvatarFallbackProps = React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
## Common Patterns
|
|
533
|
-
|
|
534
|
-
### Generate Initials
|
|
535
|
-
|
|
536
|
-
```tsx
|
|
537
|
-
function getInitials(name: string): string {
|
|
538
|
-
return name
|
|
539
|
-
.split(' ')
|
|
540
|
-
.map(part => part[0])
|
|
541
|
-
.join('')
|
|
542
|
-
.toUpperCase()
|
|
543
|
-
.slice(0, 2)
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
<Avatar>
|
|
547
|
-
<AvatarImage src={user.avatar} />
|
|
548
|
-
<AvatarFallback>{getInitials(user.name)}</AvatarFallback>
|
|
549
|
-
</Avatar>
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
### Generate Colors
|
|
553
|
-
|
|
554
|
-
```tsx
|
|
555
|
-
function stringToColor(str: string): string {
|
|
556
|
-
let hash = 0
|
|
557
|
-
for (let i = 0; i < str.length; i++) {
|
|
558
|
-
hash = str.charCodeAt(i) + ((hash << 5) - hash)
|
|
559
|
-
}
|
|
560
|
-
const hue = hash % 360
|
|
561
|
-
return `hsl(${hue}, 70%, 50%)`
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
<Avatar>
|
|
565
|
-
<AvatarImage src={user.avatar} />
|
|
566
|
-
<AvatarFallback style={{ backgroundColor: stringToColor(user.name) }}>
|
|
567
|
-
{getInitials(user.name)}
|
|
568
|
-
</AvatarFallback>
|
|
569
|
-
</Avatar>
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### With Loading State
|
|
573
|
-
|
|
574
|
-
```tsx
|
|
575
|
-
function AvatarWithLoading({ src, alt, fallback }) {
|
|
576
|
-
const [isLoading, setIsLoading] = useState(true)
|
|
577
|
-
|
|
578
|
-
return (
|
|
579
|
-
<Avatar>
|
|
580
|
-
{isLoading && (
|
|
581
|
-
<div className="absolute inset-0 flex items-center justify-center bg-gray-200 animate-pulse" />
|
|
582
|
-
)}
|
|
583
|
-
<AvatarImage
|
|
584
|
-
src={src}
|
|
585
|
-
alt={alt}
|
|
586
|
-
onLoadingStatusChange={(status) => setIsLoading(status === 'loading')}
|
|
587
|
-
/>
|
|
588
|
-
<AvatarFallback>{fallback}</AvatarFallback>
|
|
589
|
-
</Avatar>
|
|
590
|
-
)
|
|
591
|
-
}
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
## Testing
|
|
595
|
-
|
|
596
|
-
```typescript
|
|
597
|
-
import { render, screen } from '@testing-library/react'
|
|
598
|
-
import { Avatar, AvatarImage, AvatarFallback } from '@/components/Avatar'
|
|
599
|
-
|
|
600
|
-
describe('Avatar', () => {
|
|
601
|
-
it('renders image when src is valid', () => {
|
|
602
|
-
render(
|
|
603
|
-
<Avatar>
|
|
604
|
-
<AvatarImage src="/valid.jpg" alt="Test User" />
|
|
605
|
-
<AvatarFallback>TU</AvatarFallback>
|
|
606
|
-
</Avatar>
|
|
607
|
-
)
|
|
608
|
-
|
|
609
|
-
expect(screen.getByAltText('Test User')).toBeInTheDocument()
|
|
610
|
-
})
|
|
611
|
-
|
|
612
|
-
it('shows fallback when image fails', async () => {
|
|
613
|
-
render(
|
|
614
|
-
<Avatar>
|
|
615
|
-
<AvatarImage src="/invalid.jpg" alt="Test" />
|
|
616
|
-
<AvatarFallback>TU</AvatarFallback>
|
|
617
|
-
</Avatar>
|
|
618
|
-
)
|
|
619
|
-
|
|
620
|
-
// Wait for image to fail and fallback to show
|
|
621
|
-
await waitFor(() => {
|
|
622
|
-
expect(screen.getByText('TU')).toBeInTheDocument()
|
|
623
|
-
})
|
|
624
|
-
})
|
|
625
|
-
|
|
626
|
-
it('applies custom className', () => {
|
|
627
|
-
const { container } = render(
|
|
628
|
-
<Avatar className="custom-avatar">
|
|
629
|
-
<AvatarFallback>TU</AvatarFallback>
|
|
630
|
-
</Avatar>
|
|
631
|
-
)
|
|
632
|
-
|
|
633
|
-
expect(container.firstChild).toHaveClass('custom-avatar')
|
|
634
|
-
})
|
|
635
|
-
})
|
|
636
|
-
```
|
|
637
|
-
|
|
638
|
-
## Accessibility
|
|
639
|
-
|
|
640
|
-
- **Alt Text**: Always provide meaningful alt text for images
|
|
641
|
-
- **Semantic HTML**: Uses appropriate image elements
|
|
642
|
-
- **Fallback**: Graceful degradation to initials
|
|
643
|
-
- **Screen Reader**: Alt text and fallback are both accessible
|
|
644
|
-
- **Focus**: Can be made focusable with button wrapper
|
|
645
|
-
- **Contrast**: Fallback text meets WCAG standards
|
|
646
|
-
|
|
647
|
-
### Accessible Avatar
|
|
648
|
-
|
|
649
|
-
```tsx
|
|
650
|
-
<button className="focus:ring-2 focus:ring-blue-500 rounded-full">
|
|
651
|
-
<Avatar>
|
|
652
|
-
<AvatarImage src="/user.jpg" alt="John Doe's profile picture" />
|
|
653
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
654
|
-
</Avatar>
|
|
655
|
-
<span className="sr-only">View John Doe's profile</span>
|
|
656
|
-
</button>
|
|
657
|
-
```
|
|
658
|
-
|
|
659
|
-
## Performance
|
|
660
|
-
|
|
661
|
-
- **Lazy Loading**: Images load on demand via Radix
|
|
662
|
-
- **Fallback Priority**: Shows fallback immediately while loading
|
|
663
|
-
- **Image Optimization**: Use Next.js Image for optimized loading
|
|
664
|
-
- **Bundle Size**: ~1.5 KB gzipped (with Radix dependency)
|
|
665
|
-
|
|
666
|
-
### Performance Tips
|
|
667
|
-
|
|
668
|
-
```tsx
|
|
669
|
-
// Use Next.js Image
|
|
670
|
-
import Image from 'next/image'
|
|
671
|
-
|
|
672
|
-
<Avatar>
|
|
673
|
-
<AvatarImage asChild>
|
|
674
|
-
<Image src="/user.jpg" alt="User" width={40} height={40} />
|
|
675
|
-
</AvatarImage>
|
|
676
|
-
<AvatarFallback>JD</AvatarFallback>
|
|
677
|
-
</Avatar>
|
|
678
|
-
|
|
679
|
-
// Memoize avatar lists
|
|
680
|
-
const MemoizedAvatar = React.memo(Avatar)
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
## Migration Guide
|
|
684
|
-
|
|
685
|
-
### From Custom Avatar
|
|
686
|
-
|
|
687
|
-
```tsx
|
|
688
|
-
// Before: Custom avatar
|
|
689
|
-
<div className="w-10 h-10 rounded-full overflow-hidden">
|
|
690
|
-
<img src="/user.jpg" alt="User" className="w-full h-full object-cover" />
|
|
691
|
-
</div>
|
|
692
|
-
|
|
693
|
-
// After: Avatar component
|
|
694
|
-
<Avatar>
|
|
695
|
-
<AvatarImage src="/user.jpg" alt="User" />
|
|
696
|
-
<AvatarFallback>U</AvatarFallback>
|
|
697
|
-
</Avatar>
|
|
698
|
-
```
|
|
699
|
-
|
|
700
|
-
## Best Practices
|
|
701
|
-
|
|
702
|
-
1. **Always Provide Fallback**: Never skip AvatarFallback
|
|
703
|
-
2. **Meaningful Alt Text**: Describe who the avatar represents
|
|
704
|
-
3. **Consistent Sizes**: Use same size for same context
|
|
705
|
-
4. **Initials**: Use 1-2 characters maximum for fallback
|
|
706
|
-
5. **Colors**: Consider unique colors per user
|
|
707
|
-
6. **Loading**: Handle loading states gracefully
|
|
708
|
-
7. **Status Indicators**: Position consistently (bottom-right)
|
|
709
|
-
8. **Accessibility**: Ensure proper labels and focus states
|