{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "entity-avatar",
  "title": "Entity Avatar",
  "author": "AniBT <https://anibt.net>",
  "description": "One picture of a thing — a subtitle group's logo or a user's portrait — with the one fallback rule: the real image, else script-aware initials in the same die-cut sticker.",
  "registryDependencies": [
    "@anibt/theme",
    "@anibt/avatar"
  ],
  "files": [
    {
      "path": "registry/anibt/ui/entity-avatar.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { Avatar, AvatarFallback, AvatarImage, type AvatarProps } from \"@/registry/anibt/ui/avatar\"\n\n/**\n * EntityAvatar — the one picture of a thing (a subtitle group's logo, a\n * user's portrait) with the one fallback rule.\n *\n * Show the real image when there is one; otherwise the initials, in the round\n * face on the pink wash, inside the same die-cut sticker. Never a hashed\n * gradient, never initials painted over a logo that exists.\n *\n * Initials follow the script: two Latin letters fit any size, but a Han, kana\n * or hangul glyph is as wide as it is tall, so the small sizes (`xs`, `sm`,\n * `default`) take one and the large ones take two —「喵萌」reads better than\n * 「喵」on a profile head, and「喵萌」clipped on both sides in a 24px circle\n * reads as nothing.\n */\ntype EntityAvatarSize = NonNullable<AvatarProps[\"size\"]>\n\ntype EntityAvatarProps = Omit<AvatarProps, \"children\"> & {\n  /** Display name: the alt text and the source of the initials. */\n  name: string\n  /** Image URL. Empty means \"no image\" and the initials take over. */\n  src?: string | null\n  /** `srcSet` for the image; give a 3× source for sharp edges on phones. */\n  srcSet?: string\n  /** Overrides the derived initials (a single letter, an emoji). */\n  initials?: string\n  /** Loads the image eagerly: a header above the fold. */\n  priority?: boolean\n  fallbackClassName?: string\n}\n\nconst SIZE_PX: Record<EntityAvatarSize, number> = { xs: 20, sm: 24, default: 32, lg: 40, xl: 64 }\n\n/** How many wide (CJK) glyphs each size has room for. */\nconst WIDE_GLYPHS: Record<EntityAvatarSize, number> = { xs: 1, sm: 1, default: 1, lg: 2, xl: 2 }\n\nconst WIDE_SCRIPT = /[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}]/u\n\n/** Initials for a name, by the rule above. `?` for an empty name. */\nfunction getEntityInitials(name: string, wideGlyphs = 1): string {\n  const glyphs = [...name.trim()]\n  if (glyphs.length === 0) return \"?\"\n  const limit = WIDE_SCRIPT.test(glyphs[0] ?? \"\") ? wideGlyphs : 2\n  return glyphs.slice(0, limit).join(\"\").toUpperCase()\n}\n\nfunction EntityAvatar({\n  name,\n  src,\n  srcSet,\n  initials,\n  priority = false,\n  size,\n  shape = \"circle\",\n  className,\n  fallbackClassName,\n  ...props\n}: EntityAvatarProps) {\n  const resolved = size ?? \"default\"\n  const text = initials ?? getEntityInitials(name, WIDE_GLYPHS[resolved])\n\n  return (\n    <Avatar\n      data-entity=\"true\"\n      size={resolved}\n      shape={shape}\n      title={name}\n      className={className}\n      {...props}\n    >\n      {src ? (\n        <AvatarImage\n          src={src}\n          srcSet={srcSet}\n          // Width descriptors need the rendered width, or the browser assumes\n          // 100vw and fetches the largest file for a 32px circle.\n          sizes={srcSet ? `${SIZE_PX[resolved]}px` : undefined}\n          alt={name}\n          width={SIZE_PX[resolved]}\n          height={SIZE_PX[resolved]}\n          loading={priority ? \"eager\" : \"lazy\"}\n          fetchPriority={priority ? \"high\" : undefined}\n          decoding=\"async\"\n        />\n      ) : null}\n      {/* Shown with no image, before it loads and when it fails: the name\n          goes to assistive technology, the letters only to the eye. */}\n      <AvatarFallback role=\"img\" aria-label={name} className={fallbackClassName}>\n        <span aria-hidden=\"true\">{text}</span>\n      </AvatarFallback>\n    </Avatar>\n  )\n}\n\nexport { EntityAvatar, getEntityInitials }\nexport type { EntityAvatarProps }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "display"
  ],
  "type": "registry:ui"
}