{
  "$schema": "https://ethereal-ui.saefulrohman.dev/schema/registry-item.json",
  "name": "avatar",
  "title": "Avatar",
  "type": "registry:primitives",
  "description": "A photo or initials avatar in four sizes (20 / 24 / 32 / 36px) with neutral and blue initial tints - used across tables, breadcrumbs, menus, and the sidebar.",
  "dependencies": [
    "class-variance-authority"
  ],
  "usage": "import { Avatar } from \"@etherealui/react\"\n\nexport function AvatarDemo() {\n  return (\n    <div className=\"flex items-center gap-3\">\n      <Avatar\n        src=\"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=120&auto=format&fit=crop&q=80\"\n        alt=\"Sarah Jenkins\"\n      />\n      <Avatar fallback=\"B\" tint=\"blue\" />\n      <Avatar fallback=\"M\" tint=\"neutral\" />\n    </div>\n  )\n}",
  "files": [
    {
      "path": "packages/ui/src/primitives/avatar.tsx",
      "target": "components/ui/avatar.tsx",
      "type": "registry:primitives",
      "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../utils/cn\"\n\nconst avatarVariants = cva(\n  \"relative inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full font-medium select-none transition-colors\",\n  {\n    variants: {\n      size: {\n        xs: \"h-5 w-5 text-[10px]\",\n        sm: \"h-6 w-6 text-[11px]\",\n        default: \"h-8 w-8 text-xs\",\n        lg: \"h-9 w-9 text-sm\",\n        xl: \"h-11 w-11 text-sm\",\n      },\n      tint: {\n        neutral:\n          \"bg-zinc-200/80 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200\",\n        blue:\n          \"bg-blue-100 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300\",\n        emerald:\n          \"bg-emerald-100 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300\",\n        amber:\n          \"bg-amber-100 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300\",\n      },\n      ring: {\n        none: \"\",\n        subtle: \"ring-1 ring-zinc-200 dark:ring-zinc-800\",\n        glow: \"ring-2 ring-blue-500/40\",\n        emerald: \"ring-2 ring-emerald-500/40\",\n      },\n    },\n    defaultVariants: {\n      size: \"default\",\n      tint: \"neutral\",\n      ring: \"none\",\n    },\n  }\n)\n\nexport type AvatarStatusType = \"online\" | \"away\" | \"busy\" | \"offline\"\n\nconst statusColorMap: Record<AvatarStatusType, string> = {\n  online: \"bg-emerald-500\",\n  away: \"bg-amber-500\",\n  busy: \"bg-rose-500\",\n  offline: \"bg-zinc-400 dark:bg-zinc-600\",\n}\n\nexport interface AvatarProps\n  extends React.HTMLAttributes<HTMLDivElement>,\n    VariantProps<typeof avatarVariants> {\n  src?: string\n  alt?: string\n  fallback?: string\n  status?: AvatarStatusType\n}\n\nconst Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(\n  ({ className, size, tint, ring, src, alt, fallback, status, children, ...props }, ref) => {\n    const [imgError, setImgError] = React.useState(false)\n\n    const initials = React.useMemo(() => {\n      if (fallback) return fallback.slice(0, 2).toUpperCase()\n      if (alt) {\n        return alt\n          .split(\" \")\n          .map((n) => n[0])\n          .join(\"\")\n          .slice(0, 2)\n          .toUpperCase()\n      }\n      return \"B\"\n    }, [fallback, alt])\n\n    return (\n      <div className=\"relative inline-flex shrink-0\" ref={ref} {...props}>\n        <div className={cn(avatarVariants({ size, tint, ring, className }))}>\n          {src && !imgError ? (\n            <img\n              src={src}\n              alt={alt || \"Avatar\"}\n              onError={() => setImgError(true)}\n              className=\"h-full w-full object-cover\"\n            />\n          ) : (\n            children || <span className=\"leading-none\">{initials}</span>\n          )}\n        </div>\n        {status && (\n          <span\n            aria-label={`Status: ${status}`}\n            className={cn(\n              \"absolute bottom-0 right-0 block rounded-full ring-2 ring-white dark:ring-zinc-950\",\n              size === \"xs\" || size === \"sm\" ? \"h-1.5 w-1.5\" : \"h-2.5 w-2.5\",\n              statusColorMap[status]\n            )}\n          />\n        )}\n      </div>\n    )\n  }\n)\nAvatar.displayName = \"Avatar\"\n\nexport interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n  items: Array<{\n    src?: string\n    alt: string\n    fallback?: string\n    tint?: \"neutral\" | \"blue\" | \"emerald\" | \"amber\"\n    status?: AvatarStatusType\n  }>\n  max?: number\n  size?: \"xs\" | \"sm\" | \"default\" | \"lg\"\n}\n\nconst AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(\n  ({ className, items, max = 4, size = \"default\", ...props }, ref) => {\n    const visible = items.slice(0, max)\n    const remaining = items.length - visible.length\n\n    return (\n      <div\n        ref={ref}\n        className={cn(\"flex items-center -space-x-2\", className)}\n        {...props}\n      >\n        {visible.map((item, idx) => (\n          <Avatar\n            key={`${item.alt}-${idx}`}\n            src={item.src}\n            alt={item.alt}\n            fallback={item.fallback}\n            tint={item.tint || (idx % 2 === 1 ? \"blue\" : \"neutral\")}\n            size={size}\n            className=\"ring-2 ring-white dark:ring-zinc-950\"\n          />\n        ))}\n        {remaining > 0 && (\n          <div\n            className={cn(\n              avatarVariants({ size, tint: \"neutral\" }),\n              \"ring-2 ring-white dark:ring-zinc-950 text-[11px] font-medium z-0\"\n            )}\n          >\n            +{remaining}\n          </div>\n        )}\n      </div>\n    )\n  }\n)\nAvatarGroup.displayName = \"AvatarGroup\"\n\nexport { Avatar, AvatarGroup, avatarVariants }\n"
    }
  ]
}