{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "status",
  "title": "Status",
  "description": "A state word with a mark that means something: online, away, busy, offline, error or your own, each with its own shape as well as its own hue.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/status.tsx",
      "content": "import type * as React from \"react\"\nimport { useReducedMotion } from \"motion/react\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype StatusState = \"online\" | \"away\" | \"busy\" | \"offline\" | \"error\" | \"custom\"\ntype StatusTone = \"success\" | \"warning\" | \"danger\" | \"neutral\"\ntype StatusVariant = \"dot\" | \"badge\" | \"pill\" | \"plain\"\ntype StatusEffect = \"pulse\"\n\nconst DEFAULT_WORD: Record<Exclude<StatusState, \"custom\">, string> = {\n  online: \"Online\",\n  away: \"Away\",\n  busy: \"Busy\",\n  offline: \"Offline\",\n  error: \"Error\",\n}\n\nconst STATE_TONE: Record<Exclude<StatusState, \"custom\">, StatusTone> = {\n  online: \"success\",\n  away: \"warning\",\n  busy: \"danger\",\n  offline: \"neutral\",\n  error: \"danger\",\n}\n\n/** Fixed hues, never the accent: on a red or amber theme the accent would say the wrong state. */\nconst MARK_TONE_CLASS: Record<StatusTone, string> = {\n  success: \"text-emerald-500\",\n  warning: \"text-amber-500\",\n  danger: \"text-red-500 dark:text-red-400\",\n  neutral: \"text-muted-foreground\",\n}\n\nconst WORD_TONE_CLASS: Record<StatusTone, string> = {\n  success: \"text-emerald-800 dark:text-emerald-300\",\n  warning: \"text-amber-800 dark:text-amber-300\",\n  danger: \"text-red-800 dark:text-red-300\",\n  neutral: \"text-muted-foreground\",\n}\n\nconst BADGE_TONE_CLASS: Record<StatusTone, string> = {\n  success: \"bg-emerald-500/15\",\n  warning: \"bg-amber-400/20\",\n  danger: \"bg-red-500/10 dark:bg-red-500/15\",\n  neutral: \"bg-muted\",\n}\n\nconst ROOT_CLASS: Record<StatusVariant, string> = {\n  dot: \"inline-flex size-4 shrink-0 items-center justify-center\",\n  badge: \"inline-flex h-6 max-w-full min-w-0 items-center gap-2 rounded-md px-2 text-[13px] font-medium\",\n  pill: \"inline-flex h-6 max-w-full min-w-0 items-center gap-2 rounded-full border bg-background px-2 text-[13px] text-foreground\",\n  plain: \"inline-flex max-w-full min-w-0 items-center gap-2 text-sm text-foreground\",\n}\n\ninterface MarkProps {\n  state: StatusState\n  tone: StatusTone\n  pulsing: boolean\n}\n\n/** Each state has its own silhouette, so the mark still reads in greyscale and for people who cannot tell red from green. */\nfunction MarkShape({ state }: { state: StatusState }) {\n  switch (state) {\n    case \"away\":\n      return (\n        <>\n          <circle cx=\"5\" cy=\"5\" r=\"4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n          <path d=\"M5 1a4 4 0 0 0 0 8z\" fill=\"currentColor\" />\n        </>\n      )\n    case \"busy\":\n      return (\n        <>\n          <circle cx=\"5\" cy=\"5\" r=\"4.5\" fill=\"currentColor\" />\n          <rect x=\"2.5\" y=\"4.25\" width=\"5\" height=\"1.5\" rx=\"0.5\" className=\"fill-background\" />\n        </>\n      )\n    case \"offline\":\n      return <circle cx=\"5\" cy=\"5\" r=\"3.75\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n    case \"error\":\n      return <path d=\"M5 .75 9.5 9H.5z\" fill=\"currentColor\" stroke=\"currentColor\" strokeLinejoin=\"round\" />\n    default:\n      return <circle cx=\"5\" cy=\"5\" r=\"4.5\" fill=\"currentColor\" />\n  }\n}\n\nfunction StatusMark({ state, tone, pulsing }: MarkProps) {\n  return (\n    <span aria-hidden=\"true\" data-slot=\"status-mark\" data-state={state} className={cn(\"relative inline-flex size-2.5 shrink-0\", MARK_TONE_CLASS[tone])}>\n      {pulsing ? <span data-slot=\"status-pulse\" className=\"absolute inset-0 animate-ping rounded-full bg-current opacity-50 [animation-duration:1800ms]\" /> : null}\n      <svg viewBox=\"0 0 10 10\" className=\"relative size-full\">\n        <MarkShape state={state} />\n      </svg>\n    </span>\n  )\n}\n\ntype StatusProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n  /** What is true now. `custom` takes its word from children and its hue from `tone`. */\n  state: StatusState\n  /** The word. Defaults to the name of the state; `custom` must pass one. */\n  children?: React.ReactNode\n  /** The hue of a `custom` state. Ignored otherwise. */\n  tone?: StatusTone\n  /** `dot` the mark alone, `badge` a tinted tag, `pill` a neutral capsule with the mark in colour, `plain` mark and word with no surface. */\n  variant?: StatusVariant\n  /** `pulse` rings the mark, only while the state is live. Stops under reduced motion. */\n  effect?: StatusEffect\n  /** Is this state happening right now? Defaults to true for `online` alone. Pulsing an outage would only be noise. */\n  live?: boolean\n  /** Extra context after the word, such as \"2 hours ago\". Not shown by `dot`. */\n  detail?: React.ReactNode\n  /** Turns the root into a polite live region, for a status that changes while someone is reading. */\n  announce?: boolean\n}\n\nfunction Status({ state, children, tone, variant = \"plain\", effect, live, detail, announce = false, className, ...props }: StatusProps) {\n  const reduceMotion = useReducedMotion() ?? false\n  const resolvedTone = state === \"custom\" ? (tone ?? \"neutral\") : STATE_TONE[state]\n  const word = children ?? (state === \"custom\" ? null : DEFAULT_WORD[state])\n  const isLive = live ?? state === \"online\"\n  const onlyMark = variant === \"dot\"\n  return (\n    <span\n      data-slot=\"status\"\n      data-variant={variant}\n      data-effect={effect}\n      data-state={state}\n      data-live={isLive ? \"true\" : \"false\"}\n      role={announce ? \"status\" : undefined}\n      className={cn(ROOT_CLASS[variant], variant === \"badge\" && [BADGE_TONE_CLASS[resolvedTone], WORD_TONE_CLASS[resolvedTone]], className)}\n      {...props}\n    >\n      <StatusMark state={state} tone={resolvedTone} pulsing={effect === \"pulse\" && isLive && !reduceMotion} />\n      <span data-slot=\"status-word\" className={onlyMark ? \"sr-only\" : \"min-w-0 truncate\"}>\n        {word}\n      </span>\n      {detail && !onlyMark ? (\n        <span data-slot=\"status-detail\" className=\"min-w-0 truncate font-normal text-muted-foreground\">\n          {detail}\n        </span>\n      ) : null}\n    </span>\n  )\n}\n\nexport { Status, type StatusProps, type StatusState, type StatusTone, type StatusVariant, type StatusEffect }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "feedback"
  ],
  "type": "registry:ui"
}