{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "reasoning-steps",
  "title": "Reasoning Steps",
  "description": "Collapsed timeline of the model's steps; the header names the current one, the body shows them all.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/reasoning-steps.tsx",
      "content": "import type * as React from \"react\"\nimport { Check, TriangleAlert } from \"lucide-react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\ntype ReasoningStepStatus = \"pending\" | \"active\" | \"done\" | \"error\"\n\ninterface ReasoningStep {\n  id: string\n  label: string\n  status: ReasoningStepStatus\n  /** One line under the label: what the step found or why it failed. */\n  detail?: string\n}\n\n/** Same breath as the thinking indicator, so both read as \"the model is working\". */\nconst BREATH_SECONDS = 0.9\nconst BREATH_SCALE = 1.4\nconst SEPARATOR = \" · \"\n\ninterface ReasoningStepsProps extends React.ComponentProps<\"details\"> {\n  steps: ReadonlyArray<ReasoningStep>\n  /** Start expanded. The user can still collapse it. */\n  defaultOpen?: boolean\n  /** Replaces the generated header (\"3 steps · Searching docs\"). */\n  summary?: string\n}\n\nfunction describeSteps(steps: ReadonlyArray<ReasoningStep>) {\n  const count = `${steps.length} ${steps.length === 1 ? \"step\" : \"steps\"}`\n  const active = steps.find((step) => step.status === \"active\")\n  if (active) return `${count}${SEPARATOR}${active.label}`\n  if (steps.some((step) => step.status === \"error\")) return `${count}${SEPARATOR}error`\n  if (steps.length > 0 && steps.every((step) => step.status === \"done\")) return `${count}${SEPARATOR}done`\n  return count\n}\n\nfunction ReasoningSteps({ steps, defaultOpen = false, summary, className, ...props }: ReasoningStepsProps) {\n  return (\n    <details\n      data-slot=\"reasoning-steps\"\n      open={defaultOpen}\n      className={cn(\"rounded-lg border text-sm\", className)}\n      {...props}\n    >\n      <summary\n        className={cn(\n          \"flex cursor-pointer list-none items-center gap-2 px-3 py-2 text-muted-foreground select-none\",\n          \"[&::-webkit-details-marker]:hidden\",\n        )}\n      >\n        {summary ?? describeSteps(steps)}\n      </summary>\n      <ol data-slot=\"reasoning-steps-list\" className=\"relative ml-5 flex flex-col gap-3 border-l py-3 pr-3 pl-5\">\n        {steps.map((step) => (\n          <li key={step.id} data-status={step.status} className=\"relative flex flex-col gap-0.5\">\n            <span className=\"absolute top-1 -left-[1.6rem] flex size-3.5 items-center justify-center\">\n              <StepMark status={step.status} />\n            </span>\n            <span className={cn(step.status === \"pending\" && \"text-muted-foreground\", step.status === \"error\" && \"text-destructive\")}>\n              {step.label}\n            </span>\n            {step.detail ? <span className=\"text-xs text-muted-foreground\">{step.detail}</span> : null}\n          </li>\n        ))}\n      </ol>\n    </details>\n  )\n}\n\nfunction StepMark({ status }: { status: ReasoningStepStatus }) {\n  const reduceMotion = useReducedMotion()\n\n  if (status === \"done\") return <Check className=\"size-3.5 text-foreground\" aria-hidden=\"true\" />\n  if (status === \"error\") return <TriangleAlert className=\"size-3.5 text-destructive\" aria-hidden=\"true\" />\n  if (status === \"pending\") {\n    return <span className=\"size-2.5 rounded-full border-2 border-muted-foreground\" aria-hidden=\"true\" />\n  }\n  return (\n    <motion.span\n      className=\"size-2.5 rounded-full bg-mise\"\n      aria-hidden=\"true\"\n      initial={false}\n      animate={reduceMotion ? { scale: 1 } : { scale: [1, BREATH_SCALE, 1] }}\n      transition={reduceMotion ? { duration: 0 } : { duration: BREATH_SECONDS, repeat: Infinity, ease: \"easeInOut\" }}\n    />\n  )\n}\n\nexport { ReasoningSteps, describeSteps, type ReasoningStep, type ReasoningStepStatus, type ReasoningStepsProps }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "ai"
  ],
  "type": "registry:ui"
}