"use client" import * as React from "react"; import Image from "../../embed-shims/next-image"; import { useAuthedImageSrc } from "../../hooks/use-authed-image-src"; import { cn } from "../../utils/cn"; import { getFirstLastInitials } from "../../utils/format"; interface SquareAvatarProps extends React.HTMLAttributes { src?: string; alt?: string; size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** Exact pixel size (width & height). Overrides the `size` bucket dimensions — * for callers with a numeric-px API (e.g. UserDisplay/MSPDisplay). */ sizePx?: number; fallback?: string; variant?: 'square' | 'round'; /** Override the initials-fallback styling (font size/color). Merged over the * defaults (`text-xs font-medium text-ods-text-primary`) via tailwind-merge, * so callers can shrink/recolor the initials for compact avatars. */ initialsClassName?: string; } const SquareAvatar = React.memo(React.forwardRef( ({ className, src, alt, size = 'md', sizePx, fallback, variant = 'square', initialsClassName, style, ...props }, ref) => { const resolvedSrc = useAuthedImageSrc(src) const sizeClasses = { // xs (24px): dense card meta rows — avatar stacks on delivery/ // roadmap cards. Part of the shared scale so no caller ever // bypasses the buckets with raw sizePx for a standard size. xs: 'h-6 w-6', sm: 'h-8 w-8', md: 'h-10 w-10', lg: 'h-12 w-12', xl: 'h-16 w-16' }; const sizePxBySize = { xs: 24, sm: 32, md: 40, lg: 48, xl: 64 }; const variantClasses = { square: 'rounded-md', round: 'rounded-full' }; return (
{getFirstLastInitials(fallback || alt) || '?'}
{resolvedSrc && ( {alt { e.currentTarget.style.display = 'none'; const el = e.currentTarget.previousElementSibling as HTMLElement; if (el) el.classList.remove('hidden'); }} /> )}
) } )) SquareAvatar.displayName = "SquareAvatar" export { SquareAvatar };