import makeBlockie from "ethereum-blockies-base64" import React, { forwardRef, ComponentPropsWithoutRef, ForwardedRef, useMemo, } from "react" import { Image } from "../../icons" import type { IconComponent, IconProps } from "../../icons/types" import { ObjectFitVariantProps, objectFitVariants, } from "../../styles/utils/objectFit" import { classNames } from "../../utils" import { CenterAligned, CenterAlignedProps } from "../CenterAligned" import { generateAvatarBadgeClipPath } from "./avatar-badge" import { AvatarBadge } from "./AvatarBadge" export type AvatarBaseProps = CenterAlignedProps & { /** * Whether the avatar should be a circle. */ rounded?: boolean /** * Add an inset border */ border?: boolean borderClassName?: string /** * Width and height of the avatar. */ size?: number /** * This is useful for usage in NextJS projects that want to use NextImage. **/ renderImage?: React.ComponentType> /** * Renders a badge in the bottom right corner of the avatar. */ badge?: React.JSX.Element } export type AvatarImageProps = AvatarBaseProps & { /** * Optional url src for the image. */ src: string | null | undefined icon?: undefined seed?: string } & Omit, "width" | "height"> & ObjectFitVariantProps export type AvatarVideoProps = AvatarBaseProps & { src: string icon?: undefined } & ComponentPropsWithoutRef<"video"> export type AvatarIconProps = AvatarBaseProps & { /** * Optional svg icon component. */ icon: IconComponent overrides?: { Icon?: IconProps } src?: undefined } export type AvatarProps = AvatarImageProps | AvatarIconProps | AvatarBaseProps const isIcon = (props: AvatarProps): props is AvatarIconProps => { return (props as Partial).icon !== undefined } // Filters a className string based on prefix // E.g. filterClassName("mx-3 rounded-xl", "rounded") -> "rounded-xl" const filterClassName = (className: string, prefix: string) => { return classNames(className.split(" ").filter(c => c.startsWith(prefix))) } export const isVideo = (props: AvatarProps): props is AvatarVideoProps => { return [".webm", ".mp4", ".m4v", ".ogg", ".ogv", ".mov"].some(ext => (props as Partial).src?.toLowerCase().endsWith(ext), ) } const ImgAvatar = forwardRef( function ImgAvatar({ renderImage, seed, src, ...rest }, ref) { const Comp = renderImage ?? "img" const dataUrl = useMemo(() => { if (seed) { return makeBlockie(seed) } }, [seed]) return }, ) const VideoAvatar = forwardRef( function VideoAvatar(props, ref) { return