diff --git a/src/components/UserAvatar/README.md b/src/components/UserAvatar/README.md index 240f6e074a..8b79b403bc 100644 --- a/src/components/UserAvatar/README.md +++ b/src/components/UserAvatar/README.md @@ -4,11 +4,12 @@ Component for displaying user avatar. ### PropTypes -| Name | Type | Required | Default | Description | -| :-------- | :--------------- | :------- | :------ | :--------------------------------------------------------- | -| imgUrl | `string` | | | Link to image | -| size | `UserAvatarSize` | | 'm' | Component size. Possible values: `xs`, `s`, `m`, `l`, `xl` | -| srcSet | `string` | | | `srcSet` attribute of the image | -| sizes | `string` | | | `sizes` attribute of the image | -| title | `string` | | | Tooltip text on hover | -| className | `string` | | | Class name | +| Name | Type | Required | Default | Description | +| :------------- | :--------------- | :------- | :------ | :--------------------------------------------------------- | +| imgUrl | `string` | | | Link to image | +| fallbackImgUrl | `string` | | | Link to fallback image | +| size | `UserAvatarSize` | | 'm' | Component size. Possible values: `xs`, `s`, `m`, `l`, `xl` | +| srcSet | `string` | | | `srcSet` attribute of the image | +| sizes | `string` | | | `sizes` attribute of the image | +| title | `string` | | | Tooltip text on hover | +| className | `string` | | | Class name | diff --git a/src/components/UserAvatar/UserAvatar.tsx b/src/components/UserAvatar/UserAvatar.tsx index f55d62b39a..2e88d45e4d 100644 --- a/src/components/UserAvatar/UserAvatar.tsx +++ b/src/components/UserAvatar/UserAvatar.tsx @@ -9,6 +9,7 @@ import './UserAvatar.scss'; export interface UserAvatarProps { imgUrl?: string; + fallbackImgUrl?: string; size?: UserAvatarSize; srcSet?: string; sizes?: string; @@ -21,20 +22,34 @@ export interface UserAvatarProps { const b = block('user-avatar'); export const UserAvatar = React.forwardRef( - ({imgUrl, size = 'm', srcSet, sizes, title, className, onClick}, ref) => ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions -
- {''} -
- ), + ({imgUrl, fallbackImgUrl, size = 'm', srcSet, sizes, title, className, onClick}, ref) => { + const [isErrored, setIsErrored] = React.useState(false); + + const handleError = React.useCallback(() => { + setIsErrored(true); + }, []); + + // Reset error if `imgUrl` was changed to check it again + React.useEffect(() => { + setIsErrored(false); + }, [imgUrl]); + + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions +
+ +
+ ); + }, ); UserAvatar.displayName = 'UserAvatar'; diff --git a/src/components/UserAvatar/__stories__/UserAvatar.stories.tsx b/src/components/UserAvatar/__stories__/UserAvatar.stories.tsx index 8b36bad837..ca6a8840e9 100644 --- a/src/components/UserAvatar/__stories__/UserAvatar.stories.tsx +++ b/src/components/UserAvatar/__stories__/UserAvatar.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {faker} from '@faker-js/faker/locale/en'; import {useArgs} from '@storybook/client-api'; -import type {ComponentStory, Meta, StoryFn} from '@storybook/react'; +import type {Meta, StoryFn} from '@storybook/react'; import {UserAvatar} from '../UserAvatar'; import type {UserAvatarProps} from '../UserAvatar'; @@ -42,7 +42,7 @@ const randomAvatars = faker.helpers }), {}, ); -export const WithSrcSet: ComponentStory = (args) => { +export const WithSrcSet: StoryFn = (args) => { const [, setArgs] = useArgs(); React.useEffect(() => { @@ -54,6 +54,16 @@ export const WithSrcSet: ComponentStory = (args) => { return ; }; WithSrcSet.args = { - imgUrl: faker.image.cats(), + imgUrl: faker.image.urlLoremFlickr({category: 'cats'}), + size: 'xl', +}; + +export const WithFallback: StoryFn = (args) => { + return ; +}; +WithFallback.args = { + // Invalid image link + imgUrl: imgUrl + '1', + fallbackImgUrl: imgUrl, size: 'xl', };