{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "avatar",
  "registryDependencies": [
    "https://taki-ui.com/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/new-york/ui/avatar.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype AvatarContextValue = {\n  imageLoadingStatus: \"idle\" | \"loading\" | \"loaded\" | \"error\"\n  onImageLoadingStatusChange: (status: \"loading\" | \"loaded\" | \"error\") => void\n}\n\nconst AvatarContext = React.createContext<AvatarContextValue | undefined>(\n  undefined\n)\n\nfunction useAvatarContext() {\n  const context = React.useContext(AvatarContext)\n  if (!context) {\n    throw new Error(\"Avatar components must be used within Avatar\")\n  }\n  return context\n}\n\ninterface AvatarProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nfunction Avatar({ className, ...props }: AvatarProps) {\n  const [imageLoadingStatus, setImageLoadingStatus] = React.useState<\n    \"idle\" | \"loading\" | \"loaded\" | \"error\"\n  >(\"idle\")\n\n  return (\n    <AvatarContext.Provider\n      value={{\n        imageLoadingStatus,\n        onImageLoadingStatusChange: setImageLoadingStatus,\n      }}\n    >\n      <span\n        data-slot=\"avatar\"\n        className={cn(\n          \"relative flex size-8 shrink-0 overflow-hidden rounded-full\",\n          className\n        )}\n        {...props}\n      />\n    </AvatarContext.Provider>\n  )\n}\n\ninterface AvatarImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {}\n\nfunction AvatarImage({ className, src, alt, ...props }: AvatarImageProps) {\n  const { onImageLoadingStatusChange } = useAvatarContext()\n  const [loadingStatus, setLoadingStatus] = React.useState<\n    \"idle\" | \"loading\" | \"loaded\" | \"error\"\n  >(\"idle\")\n\n  React.useEffect(() => {\n    if (!src) {\n      onImageLoadingStatusChange(\"error\")\n      return\n    }\n\n    let isMounted = true\n    const image = new window.Image()\n\n    const updateStatus = (status: \"loading\" | \"loaded\" | \"error\") => {\n      if (!isMounted) return\n      setLoadingStatus(status)\n      onImageLoadingStatusChange(status)\n    }\n\n    updateStatus(\"loading\")\n\n    image.onload = () => updateStatus(\"loaded\")\n    image.onerror = () => updateStatus(\"error\")\n    image.src = src\n\n    return () => {\n      isMounted = false\n    }\n  }, [src, onImageLoadingStatusChange])\n\n  if (loadingStatus !== \"loaded\") {\n    return null\n  }\n\n  return (\n    <img\n      data-slot=\"avatar-image\"\n      className={cn(\"aspect-square size-full\", className)}\n      src={src}\n      alt={alt}\n      {...props}\n    />\n  )\n}\n\ninterface AvatarFallbackProps extends React.HTMLAttributes<HTMLSpanElement> {\n  delayMs?: number\n}\n\nfunction AvatarFallback({ className, delayMs, ...props }: AvatarFallbackProps) {\n  const { imageLoadingStatus } = useAvatarContext()\n  const [canRender, setCanRender] = React.useState(delayMs === undefined)\n\n  React.useEffect(() => {\n    if (delayMs === undefined) return\n\n    const timerId = window.setTimeout(() => setCanRender(true), delayMs)\n    return () => window.clearTimeout(timerId)\n  }, [delayMs])\n\n  if (!canRender || imageLoadingStatus === \"loaded\") {\n    return null\n  }\n\n  return (\n    <span\n      data-slot=\"avatar-fallback\"\n      className={cn(\n        \"bg-muted flex size-full items-center justify-center rounded-full\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Avatar, AvatarImage, AvatarFallback }\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}