{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"avatar","title":"Avatar","description":"Image and fallback avatar compound component.","dependencies":["@base-ui/react@1.7.0"],"registryDependencies":["@siteplane/base"],"files":[{"path":"packages/ui/src/components/avatar/avatar.tsx","content":"\"use client\";\n\nimport { Avatar as AvatarPrimitive } from \"@base-ui/react/avatar\";\nimport type React from \"react\";\n\nimport { cn, type WithStringClassName } from \"../../system/utils/cn\";\nimport { slotClass } from \"../../system/utils/slot-class\";\n\nexport type AvatarStatus = \"online\" | \"away\" | \"busy\" | \"offline\";\n\nexport type AvatarProps = WithStringClassName<AvatarPrimitive.Root.Props> & {\n  /** Presence dot at the bottom-end corner of the avatar. */\n  status?: AvatarStatus | undefined;\n  /** Accessible name of the dot; defaults to the English status name. */\n  statusLabel?: string | undefined;\n};\n\nconst avatarStatusLabels: Record<AvatarStatus, string> = {\n  away: \"Away\",\n  busy: \"Busy\",\n  offline: \"Offline\",\n  online: \"Online\",\n};\n\nconst avatarStatusClassNames: Record<AvatarStatus, string> = {\n  away: \"bg-warning\",\n  busy: \"bg-destructive\",\n  offline: \"bg-muted-foreground\",\n  online: \"bg-success\",\n};\n\nexport function Avatar({\n  className,\n  status,\n  statusLabel,\n  ...props\n}: AvatarProps): React.ReactElement {\n  const root = (\n    <AvatarPrimitive.Root\n      className={cn(\n        slotClass(\"avatar\", props),\n        \"inline-flex shrink-0 select-none items-center justify-center overflow-hidden align-middle\",\n        className,\n      )}\n      data-slot=\"avatar\"\n      {...props}\n    />\n  );\n  if (!status) return root;\n  // The avatar clips its image to the circle, so the dot sits beside it in a\n  // wrapper that takes the avatar's size. The dot is a quarter of the avatar,\n  // so it scales with every avatar size: 8 px at 32 px, 9 px at 36 px, 10 px at\n  // 40 px. A 1.5 px ring in the colour of the surface separates it from the\n  // photo: it reads --sp-rw-surface-color, which Card, Dialog, Popover and the\n  // other surfaces publish, and falls back to the page background. Set\n  // --avatar-status-ring on a surface that does not publish its colour.\n  return (\n    <span\n      className=\"sp-avatar-status-root relative inline-flex shrink-0 align-middle\"\n      data-slot=\"avatar-status-root\"\n    >\n      {root}\n      <span\n        aria-label={statusLabel ?? avatarStatusLabels[status]}\n        className={cn(\n          \"sp-avatar-status\",\n          \"absolute end-0 bottom-0 size-1/4 rounded-full ring-[1.5px] ring-(--avatar-status-ring,var(--sp-rw-surface-color,var(--sp-rw-bg-base)))\",\n          avatarStatusClassNames[status],\n        )}\n        data-slot=\"avatar-status\"\n        data-status={status}\n        role=\"img\"\n      />\n    </span>\n  );\n}\n\nexport function AvatarImage({\n  className,\n  ...props\n}: WithStringClassName<AvatarPrimitive.Image.Props>): React.ReactElement {\n  return (\n    <AvatarPrimitive.Image\n      className={cn(slotClass(\"avatar-image\", props), \"size-full\", className)}\n      data-slot=\"avatar-image\"\n      {...props}\n    />\n  );\n}\n\nexport function AvatarFallback({\n  className,\n  ...props\n}: WithStringClassName<AvatarPrimitive.Fallback.Props>): React.ReactElement {\n  return (\n    <AvatarPrimitive.Fallback\n      className={cn(\n        slotClass(\"avatar-fallback\", props),\n        \"flex size-full items-center justify-center\",\n        className,\n      )}\n      data-slot=\"avatar-fallback\"\n      {...props}\n    />\n  );\n}\n\nexport { AvatarPrimitive };\n","type":"registry:ui","target":"~/src/siteplane/components/avatar/avatar.tsx"},{"path":"packages/ui/src/components/avatar/index.ts","content":"export * from \"./avatar\";\n","type":"registry:ui","target":"~/src/siteplane/components/avatar/index.ts"}],"type":"registry:ui","docs":"https://ui.siteplane.io/docs-markdown/components/avatar.md","categories":["Data display"],"meta":{"avoidWhen":["Avoid for a decorative picture or a logo that is not an account; use an image.","Avoid overlapping several avatars by hand; Avatar Group draws the overlap, the ring and the overflow count."],"description":"Image and fallback avatar compound component.","knownLimitations":["An image needs a meaningful alt. An avatar that shows only initials or an icon can take role=\"img\" and an aria-label.","Navigation and upload are not managed, and the application supplies the status that the status dot shows."],"providerNotes":[],"releaseStatus":"stable","searchTerms":["avatar"],"useWhen":["Use to represent a person, team or account with an image that falls back to initials or an icon."]}}