{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "avatar",
  "title": "Avatar",
  "description": "The shadcn Avatar on Base UI, not Radix, without the badge and group parts. Adds what the stock avatar leaves to the caller: a deterministic two-letter monogram on a brand-role fill picked by the name, the kit's six illustrated characters (SVG files that ship with the item, referenced by key), token-based sizes sm/md/lg/xl, and one accessibility contract: `decorative` when a visible name sits beside it so a screen reader hears the name once, otherwise role=img with the name.",
  "dependencies": [
    "@base-ui/react@1.9.0",
    "class-variance-authority@0.7.1"
  ],
  "registryDependencies": [
    "@waimakers/utils",
    "@waimakers/theme"
  ],
  "files": [
    {
      "path": "src/components/ui/avatar.tsx",
      "content": "import { Avatar as AvatarPrimitive } from \"@base-ui/react/avatar\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport amberOwl from \"../../assets/characters/amber-owl.svg?no-inline\";\nimport blueFox from \"../../assets/characters/blue-fox.svg?no-inline\";\nimport greenTurtle from \"../../assets/characters/green-turtle.svg?no-inline\";\nimport orangeTiger from \"../../assets/characters/orange-tiger.svg?no-inline\";\nimport purpleOctopus from \"../../assets/characters/purple-octopus.svg?no-inline\";\nimport redPanda from \"../../assets/characters/red-panda.svg?no-inline\";\nimport { cn } from \"../../lib/utils\";\n\nconst AVATAR_CHARACTER_KEYS = [\n  \"amber-owl\",\n  \"blue-fox\",\n  \"green-turtle\",\n  \"orange-tiger\",\n  \"purple-octopus\",\n  \"red-panda\",\n] as const;\n\ntype AvatarCharacterKey = (typeof AVATAR_CHARACTER_KEYS)[number];\n\nconst AVATAR_CHARACTER_SOURCES: Readonly<Record<AvatarCharacterKey, string>> = {\n  \"amber-owl\": amberOwl,\n  \"blue-fox\": blueFox,\n  \"green-turtle\": greenTurtle,\n  \"orange-tiger\": orangeTiger,\n  \"purple-octopus\": purpleOctopus,\n  \"red-panda\": redPanda,\n};\n\nconst AVATAR_CHARACTER_LABELS: Readonly<Record<AvatarCharacterKey, string>> = {\n  \"amber-owl\": \"Amber owl\",\n  \"blue-fox\": \"Blue fox\",\n  \"green-turtle\": \"Green turtle\",\n  \"orange-tiger\": \"Orange tiger\",\n  \"purple-octopus\": \"Purple octopus\",\n  \"red-panda\": \"Red panda\",\n};\n\nfunction isAvatarCharacterKey(value: string): value is AvatarCharacterKey {\n  return (AVATAR_CHARACTER_KEYS as readonly string[]).includes(value);\n}\n\nfunction avatarCharacterSource(key: AvatarCharacterKey): string {\n  return AVATAR_CHARACTER_SOURCES[key];\n}\n\nconst MONOGRAM_CHARACTERS = 2;\n\nfunction monogram(name: string): string {\n  const words = name\n    .split(/\\s+/u)\n    .map((word) => word.replace(/[^A-Za-z0-9]/gu, \"\"))\n    .filter((word) => word !== \"\");\n\n  if (words.length === 0) {\n    return \"?\";\n  }\n  if (words.length === 1) {\n    return (words[0] ?? \"\").slice(0, MONOGRAM_CHARACTERS).toUpperCase();\n  }\n  return words\n    .slice(0, MONOGRAM_CHARACTERS)\n    .map((word) => word.charAt(0))\n    .join(\"\")\n    .toUpperCase();\n}\n\nconst MONOGRAM_FILLS = [\n  \"bg-accent text-accent-foreground\",\n  \"bg-secondary text-secondary-foreground\",\n  \"bg-primary text-primary-foreground\",\n  \"bg-brand-accent-strong text-primary-foreground\",\n  \"bg-foreground text-background\",\n  \"bg-brand-muted text-background\",\n] as const;\n\nfunction monogramFill(name: string): string {\n  let hash = 0;\n  for (const character of name.trim().toLowerCase()) {\n    hash = (hash * 31 + (character.codePointAt(0) ?? 0)) % 2_147_483_647;\n  }\n  return MONOGRAM_FILLS[hash % MONOGRAM_FILLS.length] ?? MONOGRAM_FILLS[0];\n}\n\nconst avatarVariants = cva(\n  \"relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full bg-muted align-middle\",\n  {\n    variants: {\n      size: {\n        sm: \"size-6 text-[0.625rem]\",\n        md: \"size-8 text-xs\",\n        lg: \"size-12 text-base\",\n        xl: \"size-24 text-3xl\",\n      },\n    },\n    defaultVariants: { size: \"md\" },\n  },\n);\n\ntype AvatarSize = NonNullable<VariantProps<typeof avatarVariants>[\"size\"]>;\n\ninterface AvatarProps\n  extends\n    Omit<ComponentProps<typeof AvatarPrimitive.Root>, \"children\">,\n    VariantProps<typeof avatarVariants> {\n  name: string;\n\n  src?: string | null | undefined;\n\n  character?: AvatarCharacterKey | null | undefined;\n\n  alt?: string | undefined;\n\n  decorative?: boolean | undefined;\n}\n\nfunction Avatar({\n  className,\n  size,\n  name,\n  src,\n  character,\n  alt,\n  decorative = false,\n  ...props\n}: AvatarProps) {\n  const source = src ?? (character ? AVATAR_CHARACTER_SOURCES[character] : null);\n  const label =\n    alt ?? (src ? name : character ? `${name}, ${AVATAR_CHARACTER_LABELS[character]}` : name);\n  const accessibility = decorative\n    ? { \"aria-hidden\": true as const }\n    : { role: \"img\" as const, \"aria-label\": label };\n\n  return (\n    <AvatarPrimitive.Root\n      data-slot=\"avatar\"\n      data-size={size ?? \"md\"}\n      className={cn(avatarVariants({ size }), className)}\n      {...accessibility}\n      {...props}\n    >\n      {source !== null && (\n        <AvatarPrimitive.Image\n          data-slot=\"avatar-image\"\n\n          alt=\"\"\n          aria-hidden\n          className=\"aspect-square size-full object-cover\"\n          src={source}\n        />\n      )}\n      <AvatarPrimitive.Fallback\n        data-slot=\"avatar-fallback\"\n        aria-hidden\n        className={cn(\n          \"flex size-full items-center justify-center rounded-full font-display font-bold tracking-brand-tight\",\n          monogramFill(name),\n        )}\n      >\n        {monogram(name)}\n      </AvatarPrimitive.Fallback>\n    </AvatarPrimitive.Root>\n  );\n}\n\nexport {\n  AVATAR_CHARACTER_KEYS,\n  AVATAR_CHARACTER_LABELS,\n  Avatar,\n  avatarCharacterSource,\n  avatarVariants,\n  isAvatarCharacterKey,\n  monogram,\n  monogramFill,\n};\nexport type { AvatarCharacterKey, AvatarProps, AvatarSize };\n",
      "type": "registry:ui",
      "target": "components/ui/avatar.tsx"
    },
    {
      "path": "src/assets/characters/amber-owl.svg",
      "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" role=\"img\" aria-label=\"Amber owl\">\n  <!-- Waimakers character: amber owl. Palette from packages/ui/src/styles/tokens.css:\n       orange-tint #FFE9DF, amber #CC6B3D, cream #F8F5F0, ink #1A1A1A, orange #FF6635, paper #FFFFFF. -->\n  <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"#FFE9DF\"/>\n  <path d=\"M14 22 L20 12 L26 20 Z\" fill=\"#CC6B3D\"/>\n  <path d=\"M50 22 L44 12 L38 20 Z\" fill=\"#CC6B3D\"/>\n  <ellipse cx=\"32\" cy=\"36\" rx=\"20\" ry=\"21\" fill=\"#CC6B3D\"/>\n  <ellipse cx=\"32\" cy=\"43\" rx=\"11\" ry=\"12\" fill=\"#F8F5F0\"/>\n  <circle cx=\"23\" cy=\"30\" r=\"8\" fill=\"#F8F5F0\"/>\n  <circle cx=\"41\" cy=\"30\" r=\"8\" fill=\"#F8F5F0\"/>\n  <circle cx=\"23.5\" cy=\"30.5\" r=\"4\" fill=\"#1A1A1A\"/>\n  <circle cx=\"40.5\" cy=\"30.5\" r=\"4\" fill=\"#1A1A1A\"/>\n  <circle cx=\"25\" cy=\"29\" r=\"1.3\" fill=\"#FFFFFF\"/>\n  <circle cx=\"42\" cy=\"29\" r=\"1.3\" fill=\"#FFFFFF\"/>\n  <path d=\"M29 37 L32 43 L35 37 Z\" fill=\"#FF6635\"/>\n</svg>\n",
      "type": "registry:file",
      "target": "assets/characters/amber-owl.svg"
    },
    {
      "path": "src/assets/characters/blue-fox.svg",
      "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" role=\"img\" aria-label=\"Blue fox\">\n  <!-- Waimakers character: blue fox. The brand has no blue; the fox is teal on navy.\n       Palette from packages/ui/src/styles/tokens.css: fog #E8E6E0, teal #1A3A52, navy #0A1628, cream #F8F5F0, ink #1A1A1A, paper #FFFFFF. -->\n  <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"#E8E6E0\"/>\n  <path d=\"M12 16 L24 24 L16 34 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M52 16 L40 24 L48 34 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M15 19 L23 25 L18 31 Z\" fill=\"#0A1628\"/>\n  <path d=\"M49 19 L41 25 L46 31 Z\" fill=\"#0A1628\"/>\n  <path d=\"M14 30 C14 20 50 20 50 30 C50 40 40 52 32 54 C24 52 14 40 14 30 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M32 54 C27 50 22 44 24 38 C28 36 36 36 40 38 C42 44 37 50 32 54 Z\" fill=\"#F8F5F0\"/>\n  <circle cx=\"24\" cy=\"33\" r=\"3\" fill=\"#1A1A1A\"/>\n  <circle cx=\"40\" cy=\"33\" r=\"3\" fill=\"#1A1A1A\"/>\n  <circle cx=\"25\" cy=\"32\" r=\"1\" fill=\"#FFFFFF\"/>\n  <circle cx=\"41\" cy=\"32\" r=\"1\" fill=\"#FFFFFF\"/>\n  <ellipse cx=\"32\" cy=\"44\" rx=\"3\" ry=\"2.2\" fill=\"#1A1A1A\"/>\n</svg>\n",
      "type": "registry:file",
      "target": "assets/characters/blue-fox.svg"
    },
    {
      "path": "src/assets/characters/green-turtle.svg",
      "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" role=\"img\" aria-label=\"Green turtle\">\n  <!-- Waimakers character: green turtle. The brand has no green; the turtle is slate with a graphite shell.\n       Palette from packages/ui/src/styles/tokens.css: cream-2 #F2EEE6, slate #3D4148, graphite #595959, mist #B8B5AF, ink #1A1A1A, paper #FFFFFF. -->\n  <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"#F2EEE6\"/>\n  <circle cx=\"46\" cy=\"30\" r=\"8\" fill=\"#B8B5AF\"/>\n  <circle cx=\"18\" cy=\"46\" r=\"4\" fill=\"#B8B5AF\"/>\n  <circle cx=\"36\" cy=\"48\" r=\"4\" fill=\"#B8B5AF\"/>\n  <path d=\"M8 42 C8 26 48 24 48 42 Z\" fill=\"#3D4148\"/>\n  <path d=\"M14 42 C14 32 42 30 42 42 Z\" fill=\"#595959\"/>\n  <path d=\"M22 42 L26 34 L34 34 L38 42 Z\" fill=\"#3D4148\"/>\n  <path d=\"M26 34 L30 29 L34 34 Z\" fill=\"#3D4148\"/>\n  <rect x=\"6\" y=\"41\" width=\"44\" height=\"6\" rx=\"3\" fill=\"#3D4148\"/>\n  <circle cx=\"48\" cy=\"28\" r=\"2\" fill=\"#1A1A1A\"/>\n  <circle cx=\"48.7\" cy=\"27.4\" r=\"0.7\" fill=\"#FFFFFF\"/>\n  <path d=\"M48 33 Q51 34 53 32\" stroke=\"#1A1A1A\" stroke-width=\"1.3\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>\n",
      "type": "registry:file",
      "target": "assets/characters/green-turtle.svg"
    },
    {
      "path": "src/assets/characters/orange-tiger.svg",
      "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" role=\"img\" aria-label=\"Orange tiger\">\n  <!-- Waimakers character: orange tiger. Palette from packages/ui/src/styles/tokens.css:\n       cream #F8F5F0, orange #FF6635, orange-deep #E55020, peach #FFA67E, ink #1A1A1A, paper #FFFFFF. -->\n  <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"#F8F5F0\"/>\n  <circle cx=\"16\" cy=\"20\" r=\"7\" fill=\"#FF6635\"/>\n  <circle cx=\"48\" cy=\"20\" r=\"7\" fill=\"#FF6635\"/>\n  <circle cx=\"16\" cy=\"20\" r=\"3.5\" fill=\"#FFA67E\"/>\n  <circle cx=\"48\" cy=\"20\" r=\"3.5\" fill=\"#FFA67E\"/>\n  <circle cx=\"32\" cy=\"34\" r=\"20\" fill=\"#FF6635\"/>\n  <path d=\"M26 15 L30 22 L22 22 Z\" fill=\"#E55020\"/>\n  <path d=\"M38 15 L42 22 L34 22 Z\" fill=\"#E55020\"/>\n  <path d=\"M13 32 L20 34 L13 37 Z\" fill=\"#E55020\"/>\n  <path d=\"M51 32 L44 34 L51 37 Z\" fill=\"#E55020\"/>\n  <ellipse cx=\"32\" cy=\"42\" rx=\"9\" ry=\"7\" fill=\"#FFA67E\"/>\n  <circle cx=\"24\" cy=\"31\" r=\"3\" fill=\"#1A1A1A\"/>\n  <circle cx=\"40\" cy=\"31\" r=\"3\" fill=\"#1A1A1A\"/>\n  <circle cx=\"25\" cy=\"30\" r=\"1\" fill=\"#FFFFFF\"/>\n  <circle cx=\"41\" cy=\"30\" r=\"1\" fill=\"#FFFFFF\"/>\n  <path d=\"M29 39 L32 42 L35 39 Z\" fill=\"#1A1A1A\"/>\n  <path d=\"M32 42 L32 45 M28 45 Q32 48 36 45\" stroke=\"#1A1A1A\" stroke-width=\"1.3\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>\n",
      "type": "registry:file",
      "target": "assets/characters/orange-tiger.svg"
    },
    {
      "path": "src/assets/characters/purple-octopus.svg",
      "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" role=\"img\" aria-label=\"Purple octopus\">\n  <!-- Waimakers character: purple octopus. The brand has no purple; the octopus is navy with teal arms.\n       Palette from packages/ui/src/styles/tokens.css: fog #E8E6E0, navy #0A1628, teal #1A3A52, cream #F8F5F0, paper #FFFFFF, peach #FFA67E. -->\n  <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"#E8E6E0\"/>\n  <path d=\"M12 46 C10 54 16 58 20 52 C20 46 18 42 18 40 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M52 46 C54 54 48 58 44 52 C44 46 46 42 46 40 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M22 44 C18 54 22 60 28 56 C28 50 26 46 26 42 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M42 44 C46 54 42 60 36 56 C36 50 38 46 38 42 Z\" fill=\"#1A3A52\"/>\n  <path d=\"M28 46 C26 54 30 58 32 54 C34 58 38 54 36 46 Z\" fill=\"#1A3A52\"/>\n  <ellipse cx=\"32\" cy=\"30\" rx=\"19\" ry=\"18\" fill=\"#0A1628\"/>\n  <circle cx=\"25\" cy=\"30\" r=\"6\" fill=\"#F8F5F0\"/>\n  <circle cx=\"39\" cy=\"30\" r=\"6\" fill=\"#F8F5F0\"/>\n  <circle cx=\"26\" cy=\"31\" r=\"3\" fill=\"#0A1628\"/>\n  <circle cx=\"38\" cy=\"31\" r=\"3\" fill=\"#0A1628\"/>\n  <circle cx=\"27\" cy=\"30\" r=\"1\" fill=\"#FFFFFF\"/>\n  <circle cx=\"39\" cy=\"30\" r=\"1\" fill=\"#FFFFFF\"/>\n  <path d=\"M28 40 Q32 44 36 40\" stroke=\"#FFA67E\" stroke-width=\"1.6\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>\n",
      "type": "registry:file",
      "target": "assets/characters/purple-octopus.svg"
    },
    {
      "path": "src/assets/characters/red-panda.svg",
      "content": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\" role=\"img\" aria-label=\"Red panda\">\n  <!-- Waimakers character: red panda. Palette from packages/ui/src/styles/tokens.css:\n       orange-tint #FFE9DF, orange-deep #E55020, cream #F8F5F0, ink #1A1A1A, paper #FFFFFF, amber #CC6B3D. -->\n  <circle cx=\"32\" cy=\"32\" r=\"32\" fill=\"#FFE9DF\"/>\n  <circle cx=\"16\" cy=\"18\" r=\"7\" fill=\"#1A1A1A\"/>\n  <circle cx=\"48\" cy=\"18\" r=\"7\" fill=\"#1A1A1A\"/>\n  <circle cx=\"16\" cy=\"18\" r=\"3.5\" fill=\"#F8F5F0\"/>\n  <circle cx=\"48\" cy=\"18\" r=\"3.5\" fill=\"#F8F5F0\"/>\n  <ellipse cx=\"32\" cy=\"34\" rx=\"21\" ry=\"19\" fill=\"#E55020\"/>\n  <path d=\"M14 30 C18 20 26 24 26 34 C26 40 20 42 16 38 Z\" fill=\"#F8F5F0\"/>\n  <path d=\"M50 30 C46 20 38 24 38 34 C38 40 44 42 48 38 Z\" fill=\"#F8F5F0\"/>\n  <ellipse cx=\"32\" cy=\"43\" rx=\"9\" ry=\"7\" fill=\"#F8F5F0\"/>\n  <path d=\"M27 20 L32 14 L37 20 Z\" fill=\"#CC6B3D\"/>\n  <circle cx=\"23\" cy=\"32\" r=\"3\" fill=\"#1A1A1A\"/>\n  <circle cx=\"41\" cy=\"32\" r=\"3\" fill=\"#1A1A1A\"/>\n  <circle cx=\"24\" cy=\"31\" r=\"1\" fill=\"#FFFFFF\"/>\n  <circle cx=\"42\" cy=\"31\" r=\"1\" fill=\"#FFFFFF\"/>\n  <ellipse cx=\"32\" cy=\"40\" rx=\"3\" ry=\"2.2\" fill=\"#1A1A1A\"/>\n  <path d=\"M28 46 Q32 49 36 46\" stroke=\"#1A1A1A\" stroke-width=\"1.3\" fill=\"none\" stroke-linecap=\"round\"/>\n</svg>\n",
      "type": "registry:file",
      "target": "assets/characters/red-panda.svg"
    }
  ],
  "type": "registry:ui"
}