{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"error-message","type":"registry:ui","title":"Error & Retry","description":"What to show when a generation fails — a plain-English reason, a retry button, and a countdown for rate limits.","author":"Scrim UI (https://scrimui.dev)","categories":["messages"],"docs":"https://scrimui.dev/components/error-message","dependencies":[],"registryDependencies":[],"files":[{"path":"src/showcase/error-message/error-message.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\n\n/* ------------------------------------------------------------------ */\n/* Types                                                               */\n/* ------------------------------------------------------------------ */\n\nexport type ErrorMessageProps = {\n  title?: string;\n  message: string;\n  /** Show an inline retry action. */\n  onRetry?: () => void;\n  /** True while a retry is in flight — shows a spinner instead of the button. */\n  retrying?: boolean;\n  /** Seconds until retry is allowed — shows a countdown when > 0. */\n  retryCountdown?: number;\n  /** One of \"error\" | \"rate-limit\" | \"warning\" — changes the icon and tint. */\n  severity?: \"error\" | \"rate-limit\" | \"warning\";\n  className?: string;\n};\n\n/* ------------------------------------------------------------------ */\n/* Icons                                                               */\n/* ------------------------------------------------------------------ */\n\nfunction TriangleIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\">\n      <path d=\"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z\" />\n      <path d=\"M12 9v4\" />\n      <path d=\"M12 17h.01\" />\n    </svg>\n  );\n}\n\nfunction GaugeIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\">\n      <path d=\"M12 14l4-4\" />\n      <path d=\"M3.34 19a10 10 0 1 1 17.32 0\" />\n    </svg>\n  );\n}\n\nfunction RetryIcon() {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"13\" height=\"13\">\n      <path d=\"M21 12a9 9 0 1 1-2.64-6.36L21 8\" />\n      <path d=\"M21 3v5h-5\" />\n    </svg>\n  );\n}\n\n/* ------------------------------------------------------------------ */\n/* ErrorMessage                                                        */\n/* ------------------------------------------------------------------ */\n\nexport function ErrorMessage({\n  title,\n  message,\n  onRetry,\n  retrying = false,\n  retryCountdown = 0,\n  severity = \"error\",\n  className = \"\",\n}: ErrorMessageProps) {\n  const isRateLimit = severity === \"rate-limit\";\n  const Icon = isRateLimit ? GaugeIcon : TriangleIcon;\n  const tint = isRateLimit\n    ? \"text-amber-600 dark:text-amber-400\"\n    : \"text-red-600 dark:text-red-400\";\n\n  return (\n    <div className={`flex items-start gap-3 rounded-2xl rounded-tl-md border border-red-200 bg-red-50/60 px-4 py-3 dark:border-red-900/50 dark:bg-red-950/30 ${className}`}>\n      <span className={`mt-0.5 shrink-0 ${tint}`}>\n        <Icon />\n      </span>\n      <div className=\"min-w-0 flex-1\">\n        <div className=\"text-sm font-medium text-zinc-900 dark:text-zinc-100\">\n          {title ?? (isRateLimit ? \"Slow down a bit\" : \"Something went wrong\")}\n        </div>\n        <p className=\"mt-0.5 text-[13px] leading-5 text-zinc-600 dark:text-zinc-400\">{message}</p>\n\n        {onRetry && !retrying && retryCountdown === 0 && (\n          <button\n            type=\"button\"\n            onClick={onRetry}\n            className=\"mt-2 inline-flex h-7 items-center gap-1.5 rounded-lg border border-zinc-200 bg-white px-2.5 text-xs font-medium text-zinc-700 transition-colors hover:bg-zinc-100 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-200 dark:hover:bg-zinc-800\"\n          >\n            <RetryIcon />\n            Retry\n          </button>\n        )}\n\n        {/* zinc-600 on both captions below: they sit on the tinted error\n            surface, where zinc-500 measures 4.49:1 — a hair under AA at 12px. */}\n        {retrying && (\n          <div className=\"mt-2 inline-flex h-7 items-center gap-1.5 text-xs text-zinc-600 dark:text-zinc-400\">\n            <span className=\"h-3.5 w-3.5 animate-spin rounded-full border-2 border-zinc-300 border-t-zinc-600 dark:border-zinc-700 dark:border-t-zinc-300\" />\n            Retrying…\n          </div>\n        )}\n\n        {!retrying && retryCountdown > 0 && (\n          <div className=\"mt-2 text-xs text-zinc-600 dark:text-zinc-400\">\n            Try again in {retryCountdown}s\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n","type":"registry:ui","target":"components/ui/error-message.tsx"}]}