{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "avatar", "title": "Avatar", "description": "A hand-drawn circle border around a profile image or initials fallback.", "dependencies": [ "roughjs" ], "registryDependencies": [ "https://www.bydefaulthuman.fun/r/use-rough.json", "utils", "https://www.bydefaulthuman.fun/r/crumble-theme.json", "https://www.bydefaulthuman.fun/r/rough-lib.json" ], "files": [ { "path": "registry/new-york/ui/avatar.tsx", "content": "\"use client\";\n\nimport { useCallback, useContext, useEffect } from \"react\";\nimport { useRough } from \"@/hooks/use-rough\";\nimport { cn } from \"@/lib/utils\";\nimport {\n CrumbleContext,\n randomSeed,\n resolveRoughVars,\n type CrumbleColorProps,\n type CrumbleTheme,\n} from \"@/lib/rough\";\n\nexport interface AvatarProps extends CrumbleColorProps {\n animateOnHover?: boolean;\n className?: string;\n fallback?: string;\n id?: string;\n size?: number;\n src?: string;\n theme?: CrumbleTheme;\n}\n\nexport interface AvatarGroupProps {\n avatars: AvatarProps[];\n className?: string;\n fill?: string;\n max?: number;\n size?: number;\n stroke?: string;\n strokeMuted?: string;\n theme?: CrumbleTheme;\n}\n\nfunction AvatarCircle({\n animateOnHover = true,\n className,\n fallback,\n fill,\n id,\n size = 40,\n src,\n stroke,\n strokeMuted,\n theme: themeProp,\n}: AvatarProps) {\n const stableId = id ?? `avatar-${fallback ?? \"user\"}`;\n const roughStyle = resolveRoughVars({ stroke, strokeMuted, fill });\n const {\n animateOnHover: animateFromContext,\n drawCircle,\n svgRef,\n } = useRough({\n stableId,\n theme: themeProp,\n variant: \"border\",\n });\n\n const draw = useCallback(\n (reseed = false) => {\n const svg = svgRef.current;\n if (!svg) return;\n\n svg.replaceChildren();\n svg.setAttribute(\"width\", String(size));\n svg.setAttribute(\"height\", String(size));\n svg.setAttribute(\"viewBox\", `0 0 ${size} ${size}`);\n\n const circle = drawCircle(size / 2, size / 2, size - 3, {\n fill: \"none\",\n seed: reseed ? randomSeed() : undefined,\n stroke: \"var(--cr-stroke)\",\n });\n if (circle) svg.appendChild(circle);\n },\n [drawCircle, size, svgRef],\n );\n\n useEffect(() => {\n const id = requestAnimationFrame(() => draw());\n return () => cancelAnimationFrame(id);\n }, [draw]);\n\n return (\n