/** * Avatar ported from chakra-ui (license MIT) * Accessed 2021-12-26, component September 9th, 2021, theme August 23rd, 2021 * - https://github.com/chakra-ui/chakra-ui/blob/5b3373d/packages/theme/src/components/avatar.ts * - https://github.com/chakra-ui/chakra-ui/blob/93c99bd/packages/avatar/src/avatar.tsx * Changes: * - Use .css instead of chakra styling props */ import React from "react"; import { useImage } from "../hooks/useImage"; import type { ImageProps } from "./Image"; import "../styles/ChakraAvatar.css"; interface AvatarOptions { /** * The name of the person in the avatar. * * - if `src` has loaded, the name will be used as the `alt` attribute of the `img` * - If `src` is not loaded, the name will be used to create the initials */ name?: string; /** * If `true`, the `Avatar` will show a border around it. * * Best for a group of avatars */ showBorder?: boolean; /** * The badge at the bottom right corner of the avatar. */ children?: React.ReactNode; /** * The image url of the `Avatar` */ src?: string; /** * List of sources to use for different screen resolutions */ srcSet?: string; /** * Defines loading strategy */ loading?: "eager" | "lazy"; /** * The border color of the avatar * @type SystemProps["borderColor"] */ borderColor?: React.CSSProperties["borderColor"]; /** * Function called when image failed to load */ onError?: () => void; /** * The default avatar used as fallback when `name`, and `src` * is not specified. * @type React.ReactElement */ icon?: React.ReactElement; /** * Function to get the initials to display */ getInitials?: (name: string) => string; } type AvatarBadgeProps = React.HTMLProps; /** * AvatarBadge used to show extra badge to the top-right * or bottom-right corner of an avatar. */ export const AvatarBadge = React.forwardRef( (props, ref) => { return (
); }, ); AvatarBadge.displayName = "AvatarBadge"; function initials(name: string) { const [firstName, lastName] = name.split(" "); return firstName && lastName ? `${firstName.charAt(0)}${lastName.charAt(0)}` : firstName.charAt(0); } interface AvatarNameProps extends React.HTMLProps, Pick {} /** * The avatar name container */ const AvatarName: React.FC = (props) => { const { name, getInitials, ...rest } = props; return (
{name ? getInitials?.(name) : null}
); }; /** * Fallback avatar react component. * This should be a generic svg used to represent an avatar */ const DefaultIcon = (props: React.HTMLProps) => ( // @ts-ignore ); export interface AvatarProps extends Omit, "onError">, AvatarOptions { iconLabel?: string; /** * If `true`, opt out of the avatar's `fallback` logic and * renders the `img` at all times. */ ignoreFallback?: boolean; borderRadius?: React.CSSProperties["borderRadius"]; } /** * Avatar component that renders an user avatar with * support for fallback avatar and name-only avatars */ export const Avatar = React.forwardRef( (props, ref) => { const { src, name, showBorder, borderRadius = "9999px", onError, getInitials = initials, icon = , iconLabel = " avatar", loading, children, borderColor, ignoreFallback, style, ...rest } = props; const avatarStyles: React.CSSProperties = { borderRadius, borderWidth: showBorder ? "2px" : undefined, ...style, }; if (borderColor) { avatarStyles.borderColor = borderColor as unknown as string; } return ( {children} ); }, ); Avatar.displayName = "Avatar"; interface AvatarImageProps extends ImageProps, Pick { iconLabel?: string; } const AvatarImage: React.FC = (props) => { const { src, onError, getInitials, name, borderRadius, loading, iconLabel, icon = , ignoreFallback, } = props; /** * use the image hook to only show the image when it has loaded */ const status = useImage({ src, onError, ignoreFallback }); const hasLoaded = status === "loaded"; /** * Fallback avatar applies under 2 conditions: * - If `src` was passed and the image has not loaded or failed to load * - If `src` wasn't passed * * In this case, we'll show either the name avatar or default avatar */ const showFallback = !src || !hasLoaded; if (showFallback) { return name ? ( ) : ( React.cloneElement(icon, { role: "img", "aria-label": iconLabel, }) ); } /** * If `src` was passed and the image has loaded, we'll show it */ return ( {name} ); }; AvatarImage.displayName = "AvatarImage";