{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "avatar",
  "type": "registry:ui",
  "title": "Avatar",
  "description": "User avatar primitives with image fallback for Tile UI.",
  "devDependencies": [
    "sass"
  ],
  "registryDependencies": [
    "@tile-ui/core",
    "@tile-ui/styles"
  ],
  "files": [
    {
      "path": "packages/react/src/components/avatar/avatar.tsx",
      "type": "registry:ui",
      "target": "components/ui/avatar/avatar.tsx",
      "content": "import React, { createContext, useContext, useEffect, useRef, useState } from 'react';\nimport { avatarStyleKeys, shouldShowAvatarFallback } from '../lib/core';\nimport type { AvatarImageStatus } from '../lib/core';\nimport type { AvatarBaseProps, AvatarImageBaseProps } from '../lib/core';\nimport styles from './avatar.module.scss';\n\ninterface AvatarContextValue {\n\tstatus: AvatarImageStatus;\n\tsetStatus: (status: AvatarImageStatus) => void;\n\thasImage: boolean;\n\tsetHasImage: (has: boolean) => void;\n}\n\nconst AvatarContext = createContext<AvatarContextValue | null>(null);\n\nfunction useAvatarContext(): AvatarContextValue {\n\tconst context = useContext(AvatarContext);\n\tif (!context) {\n\t\tthrow new Error('Avatar sub-components must be used within <Avatar>.');\n\t}\n\treturn context;\n}\n\nexport interface AvatarProps extends React.HTMLAttributes<HTMLSpanElement>, AvatarBaseProps {}\n\nconst Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>(({ className = '', size = 'default', children, ...props }, ref) => {\n\tconst [status, setStatus] = useState<AvatarImageStatus>('loading');\n\tconst [hasImage, setHasImage] = useState(false);\n\n\treturn (\n\t\t<AvatarContext.Provider value={{ status, setStatus, hasImage, setHasImage }}>\n\t\t\t<span ref={ref} data-size={size} className={`${styles[avatarStyleKeys.root]} ${className}`} {...props}>\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t</AvatarContext.Provider>\n\t);\n});\nAvatar.displayName = 'Avatar';\n\nexport interface AvatarImageProps extends React.ImgHTMLAttributes<HTMLImageElement>, AvatarImageBaseProps {}\n\nconst AvatarImage = React.forwardRef<HTMLImageElement, AvatarImageProps>(({ className = '', onLoad, onError, ...props }, ref) => {\n\tconst context = useAvatarContext();\n\tconst imgRef = useRef<HTMLImageElement | null>(null);\n\n\tuseEffect(() => {\n\t\tcontext.setHasImage(true);\n\n\t\tconst img = imgRef.current;\n\t\tif (img && img.complete) {\n\t\t\tcontext.setStatus(img.naturalWidth > 0 ? 'loaded' : 'error');\n\t\t}\n\t}, [context]);\n\n\tfunction setRef(element: HTMLImageElement | null) {\n\t\timgRef.current = element;\n\n\t\tif (typeof ref === 'function') {\n\t\t\tref(element);\n\t\t} else if (ref) {\n\t\t\tref.current = element;\n\t\t}\n\t}\n\n\tfunction handleLoad(event: React.SyntheticEvent<HTMLImageElement>) {\n\t\tcontext.setStatus('loaded');\n\t\tonLoad?.(event);\n\t}\n\n\tfunction handleError(event: React.SyntheticEvent<HTMLImageElement>) {\n\t\tcontext.setStatus('error');\n\t\tonError?.(event);\n\t}\n\n\treturn <img ref={setRef} className={`${styles[avatarStyleKeys.image]} ${className}`} onLoad={handleLoad} onError={handleError} {...props} />;\n});\nAvatarImage.displayName = 'AvatarImage';\n\nexport interface AvatarFallbackProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst AvatarFallback = React.forwardRef<HTMLSpanElement, AvatarFallbackProps>(({ className = '', children, ...props }, ref) => {\n\tconst context = useAvatarContext();\n\n\tif (!shouldShowAvatarFallback(context.status, context.hasImage)) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<span ref={ref} className={`${styles[avatarStyleKeys.fallback]} ${className}`} {...props}>\n\t\t\t{children}\n\t\t</span>\n\t);\n});\nAvatarFallback.displayName = 'AvatarFallback';\n\nexport interface AvatarBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst AvatarBadge = React.forwardRef<HTMLSpanElement, AvatarBadgeProps>(({ className = '', children, ...props }, ref) => {\n\treturn (\n\t\t<span ref={ref} className={`${styles[avatarStyleKeys.badge]} ${className}`} {...props}>\n\t\t\t{children}\n\t\t</span>\n\t);\n});\nAvatarBadge.displayName = 'AvatarBadge';\n\nexport interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(({ className = '', children, ...props }, ref) => {\n\treturn (\n\t\t<div ref={ref} className={`${styles[avatarStyleKeys.group]} ${className}`} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nAvatarGroup.displayName = 'AvatarGroup';\n\nexport interface AvatarGroupCountProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst AvatarGroupCount = React.forwardRef<HTMLDivElement, AvatarGroupCountProps>(({ className = '', children, ...props }, ref) => {\n\treturn (\n\t\t<div ref={ref} className={`${styles[avatarStyleKeys.groupCount]} ${className}`} {...props}>\n\t\t\t{children}\n\t\t</div>\n\t);\n});\nAvatarGroupCount.displayName = 'AvatarGroupCount';\n\nexport { Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup, AvatarGroupCount };\nexport default Avatar;\n"
    },
    {
      "path": "packages/styles/scss/components/avatar.module.scss",
      "type": "registry:file",
      "target": "components/ui/avatar/avatar.module.scss",
      "content": "@use '../../../styles/variables/colors' as *;\n\n.root {\n\tposition: relative;\n\tdisplay: inline-flex;\n\tflex-shrink: 0;\n\twidth: 2rem;\n\theight: 2rem;\n\toverflow: hidden;\n\tborder-radius: $radius-full;\n\tuser-select: none;\n\n\t&[data-size='sm'] {\n\t\twidth: 1.5rem;\n\t\theight: 1.5rem;\n\t}\n\n\t&[data-size='lg'] {\n\t\twidth: 2.5rem;\n\t\theight: 2.5rem;\n\t}\n}\n\n.image {\n\twidth: 100%;\n\theight: 100%;\n\taspect-ratio: 1 / 1;\n\tobject-fit: cover;\n}\n\n.fallback {\n\tdisplay: flex;\n\twidth: 100%;\n\theight: 100%;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: $radius-full;\n\tbackground-color: var(--tile-avatar-background, $muted);\n\tcolor: var(--tile-avatar-color, $muted-foreground);\n\tfont-size: $text-sm;\n\n\t&[hidden] {\n\t\tdisplay: none;\n\t}\n\n\t[data-size='sm'] & {\n\t\tfont-size: $text-xs;\n\t}\n}\n\n.badge {\n\tposition: absolute;\n\tright: 0;\n\tbottom: 0;\n\tz-index: 10;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: $radius-full;\n\tbackground-color: $primary;\n\tcolor: $primary-foreground;\n\tbox-shadow: 0 0 0 2px $background;\n\tuser-select: none;\n\n\t[data-size='sm'] & {\n\t\twidth: 0.5rem;\n\t\theight: 0.5rem;\n\n\t\tsvg {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n\t[data-size='default'] & {\n\t\twidth: 0.625rem;\n\t\theight: 0.625rem;\n\n\t\tsvg {\n\t\t\twidth: 0.5rem;\n\t\t\theight: 0.5rem;\n\t\t}\n\t}\n\n\t[data-size='lg'] & {\n\t\twidth: 0.75rem;\n\t\theight: 0.75rem;\n\n\t\tsvg {\n\t\t\twidth: 0.5rem;\n\t\t\theight: 0.5rem;\n\t\t}\n\t}\n}\n\n.group {\n\tdisplay: flex;\n\n\t> .root {\n\t\tmargin-left: -0.5rem;\n\t\tbox-shadow: 0 0 0 2px $background;\n\n\t\t&:first-child {\n\t\t\tmargin-left: 0;\n\t\t}\n\t}\n}\n\n.groupCount {\n\tposition: relative;\n\tdisplay: flex;\n\tflex-shrink: 0;\n\twidth: 2rem;\n\theight: 2rem;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: $radius-full;\n\tbackground-color: var(--tile-avatar-background, $muted);\n\tcolor: var(--tile-avatar-color, $muted-foreground);\n\tfont-size: $text-sm;\n\tbox-shadow: 0 0 0 2px $background;\n\n\tsvg {\n\t\twidth: 1rem;\n\t\theight: 1rem;\n\t}\n}\n"
    },
    {
      "path": "packages/react/src/components/avatar/index.ts",
      "type": "registry:ui",
      "target": "components/ui/avatar/index.ts",
      "content": "export {\n\tAvatar,\n\tAvatarImage,\n\tAvatarFallback,\n\tAvatarBadge,\n\tAvatarGroup,\n\tAvatarGroupCount,\n\ttype AvatarProps,\n\ttype AvatarImageProps,\n\ttype AvatarFallbackProps,\n\ttype AvatarBadgeProps,\n\ttype AvatarGroupProps,\n\ttype AvatarGroupCountProps,\n} from './avatar';\n"
    }
  ]
}
