{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"status","type":"registry:ui","title":"Status","description":"Presence indicator (online, away, busy, offline): a colored dot with rippling rings, an optional tinted pill and a soft crossfade when the status changes.","dependencies":[],"registryDependencies":["utils"],"files":[{"path":"registry/ui/status.tsx","type":"registry:ui","content":"\"use client\";\n\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n// Two soft rings ripple out of the dot, offset by half a cycle. The label re-enters\n// (keyed on status) so a status change reads as a small crossfade instead of a jump.\nconst css = `\n@keyframes ui-status-ring{0%{scale:1;opacity:.55}100%{scale:3.2;opacity:0}}\n@keyframes ui-status-in{from{opacity:0;translate:0 4px;filter:blur(2px)}}\n.ui-status-ring{animation:ui-status-ring 2s cubic-bezier(.2,.6,.3,1) infinite}\n.ui-status-ring+.ui-status-ring{animation-delay:1s}\n.ui-status-label{animation:ui-status-in .3s ease-out}\n@media (prefers-reduced-motion:reduce){.ui-status-ring{display:none}.ui-status-label{animation:none}}\n`;\n\nexport type StatusKind = \"online\" | \"away\" | \"busy\" | \"offline\";\n\nconst tone: Record<StatusKind, { dot: string; pill: string; label: string }> = {\n  online: { dot: \"bg-emerald-500\", pill: \"border-emerald-500/30 bg-emerald-500/10\", label: \"Online\" },\n  away: { dot: \"bg-amber-500\", pill: \"border-amber-500/30 bg-amber-500/10\", label: \"Away\" },\n  busy: { dot: \"bg-red-500\", pill: \"border-red-500/30 bg-red-500/10\", label: \"Busy\" },\n  offline: { dot: \"bg-zinc-400 dark:bg-zinc-500\", pill: \"border-border bg-muted/50\", label: \"Offline\" },\n};\n\nexport interface StatusProps extends HTMLAttributes<HTMLSpanElement> {\n  status?: StatusKind;\n  /** Visible text. Defaults to the status name (\"Online\", \"Away\", ...). */\n  label?: ReactNode;\n  /** `pill` wraps dot and label in a tinted capsule, `plain` is dot + text only. */\n  variant?: \"pill\" | \"plain\";\n  size?: \"sm\" | \"md\";\n  /** Ripple rings around the dot. Defaults to on for online and busy. */\n  pulse?: boolean;\n  /** Show only the dot; the label stays available to screen readers. */\n  hideLabel?: boolean;\n}\n\nexport function Status({\n  status = \"online\",\n  label,\n  variant = \"pill\",\n  size = \"md\",\n  pulse,\n  hideLabel = false,\n  className,\n  ...props\n}: StatusProps) {\n  const t = tone[status];\n  const text = label ?? t.label;\n  const rings = pulse ?? (status === \"online\" || status === \"busy\");\n  const dot = size === \"sm\" ? \"size-1.5\" : \"size-2\";\n\n  return (\n    <span\n      role=\"status\"\n      {...props}\n      data-status={status}\n      className={cn(\n        \"inline-flex w-fit shrink-0 items-center gap-2 font-medium whitespace-nowrap text-foreground\",\n        size === \"sm\" ? \"text-xs\" : \"text-sm\",\n        variant === \"pill\" && !hideLabel && \"rounded-full border transition-[background-color,border-color] duration-300\",\n        variant === \"pill\" && !hideLabel && (size === \"sm\" ? \"h-6 px-2.5\" : \"h-7 px-3\"),\n        variant === \"pill\" && !hideLabel && t.pill,\n        className,\n      )}\n    >\n      <style href=\"ui-status\" precedence=\"default\">\n        {css}\n      </style>\n      <span aria-hidden className={cn(\"relative grid shrink-0 place-items-center\", dot)}>\n        {rings && (\n          <>\n            <span className={cn(\"ui-status-ring absolute inset-0 rounded-full\", t.dot)} />\n            <span className={cn(\"ui-status-ring absolute inset-0 rounded-full\", t.dot)} />\n          </>\n        )}\n        <span\n          className={cn(\n            \"relative rounded-full transition-[background-color,scale] duration-300\",\n            dot,\n            t.dot,\n            status === \"offline\" && \"scale-90\",\n          )}\n        />\n      </span>\n      <span key={status} className={cn(\"ui-status-label\", hideLabel && \"sr-only\")}>\n        {text}\n      </span>\n    </span>\n  );\n}\n"}]}