{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checks-panel",
  "type": "registry:ui",
  "title": "Checks Panel",
  "description": "CI checks list with expandable failure logs and a merge button that names its method.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://seamui.dev/r/utils.json",
    "https://seamui.dev/r/motion.json",
    "https://seamui.dev/r/collapsible.json",
    "https://seamui.dev/r/button.json",
    "https://seamui.dev/r/spinner.json"
  ],
  "files": [
    {
      "path": "registry/seam/ui/checks-panel.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { motion } from \"motion/react\"\nimport {\n  ChevronDown,\n  CircleCheck,\n  CircleDashed,\n  CircleMinus,\n  CircleX,\n  GitMerge,\n} from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { springs, fades, depth, reduced, useReducedMotion } from \"@/lib/motion\"\nimport { Button, buttonVariants } from \"./button\"\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"./collapsible\"\nimport { Spinner } from \"./spinner\"\n\n// Conductor's Checks tab / Paseo's PR panel as a component: CI, deploys, and\n// reviews in a flat list on a raised card; failed logs one disclosure away;\n// the merge action names what it will do.\n\ntype CheckStatus = \"pass\" | \"fail\" | \"running\" | \"pending\" | \"skipped\"\n\n// Monochrome rule: fail is the one hue; everything else reads by icon shape.\nconst STATUS: Record<\n  CheckStatus,\n  { icon: React.ReactNode; label: string; className?: string }\n> = {\n  pass: { icon: <CircleCheck className=\"size-4\" />, label: \"passed\" },\n  fail: {\n    icon: <CircleX className=\"size-4\" />,\n    label: \"failed\",\n    className: \"text-destructive\",\n  },\n  running: { icon: <Spinner className=\"size-4\" />, label: \"running\" },\n  pending: {\n    icon: <CircleDashed className=\"size-4\" />,\n    label: \"pending\",\n    className: \"text-muted-foreground\",\n  },\n  skipped: {\n    icon: <CircleMinus className=\"size-4\" />,\n    label: \"skipped\",\n    className: \"text-muted-foreground\",\n  },\n}\n\nfunction ChecksPanel({\n  title = \"Checks\",\n  summary,\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  title?: React.ReactNode\n  /** e.g. \"3 passed, 1 failed\" — announced with the panel. */\n  summary?: string\n}) {\n  return (\n    <div\n      data-slot=\"checks-panel\"\n      role=\"group\"\n      aria-label={summary ? `Checks: ${summary}` : \"Checks\"}\n      className={cn(\n        \"bg-card text-card-foreground w-full max-w-md rounded-xl squircle border border-border/60 shadow-resting\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"flex items-baseline justify-between gap-2 border-b border-border/60 px-4 py-2.5\">\n        <div className=\"text-sm font-medium\">{title}</div>\n        {summary ? (\n          <div className=\"text-muted-foreground text-xs\">{summary}</div>\n        ) : null}\n      </div>\n      <div className=\"p-1.5\">{children}</div>\n    </div>\n  )\n}\n\n// One check row. With children it becomes a disclosure exposing the log in a\n// debossed well (the tool.tsx pattern — buttonVariants + a motion.button\n// render, the composite-safe press).\nfunction ChecksPanelItem({\n  name,\n  status,\n  duration,\n  className,\n  children,\n  ...props\n}: Omit<React.ComponentProps<typeof Collapsible>, \"children\"> & {\n  name: React.ReactNode\n  status: CheckStatus\n  duration?: React.ReactNode\n  children?: React.ReactNode\n}) {\n  const reduceMotion = useReducedMotion()\n  const s = STATUS[status]\n\n  const row = (\n    <>\n      <span\n        aria-hidden\n        className={cn(\n          \"flex size-4 shrink-0 items-center justify-center\",\n          s.className\n        )}\n      >\n        {s.icon}\n      </span>\n      <span className=\"min-w-0 flex-1 truncate text-left text-sm\">\n        {name}\n        <span className=\"sr-only\"> {s.label}</span>\n      </span>\n      {duration ? (\n        <span className=\"text-muted-foreground shrink-0 text-xs tabular-nums\">\n          {duration}\n        </span>\n      ) : null}\n    </>\n  )\n\n  if (!children) {\n    return (\n      <div\n        data-slot=\"checks-panel-item\"\n        data-status={status}\n        className={cn(\"flex items-center gap-2.5 px-2.5 py-2\", className)}\n        {...(props as React.ComponentProps<\"div\">)}\n      >\n        {row}\n      </div>\n    )\n  }\n\n  return (\n    <Collapsible\n      data-slot=\"checks-panel-item\"\n      data-status={status}\n      className={className}\n      {...props}\n    >\n      <CollapsibleTrigger\n        className={cn(\n          buttonVariants({ variant: \"ghost\" }),\n          \"group/check h-auto w-full justify-start gap-2.5 px-2.5 py-2 font-normal\"\n        )}\n        render={\n          <motion.button\n            whileTap={reduceMotion ? reduced.pressed : depth.pressed}\n            transition={reduceMotion ? fades.fast : springs.press}\n          />\n        }\n      >\n        {row}\n        <ChevronDown\n          aria-hidden\n          className=\"text-muted-foreground size-4 shrink-0 transition-transform duration-200 group-data-[panel-open]/check:rotate-180 motion-reduce:transition-none\"\n        />\n      </CollapsibleTrigger>\n      <CollapsibleContent>\n        <div\n          data-slot=\"checks-panel-log\"\n          // Log output is read into — a carved well inside the card.\n          tabIndex={0}\n          className=\"bg-muted mx-2.5 mb-2 max-h-56 overflow-auto rounded-md squircle border border-border/60 p-2.5 shadow-well outline-none\"\n        >\n          <pre className=\"font-mono text-xs leading-relaxed whitespace-pre-wrap\">\n            {children}\n          </pre>\n        </div>\n      </CollapsibleContent>\n    </Collapsible>\n  )\n}\n\nconst MERGE_LABEL = {\n  merge: \"Merge\",\n  squash: \"Squash and merge\",\n  rebase: \"Rebase and merge\",\n} as const\n\n// The merge action that says what it will do (Paseo names the method on the\n// button). A plain seamui Button — primary embossed key.\nfunction MergeButton({\n  method = \"merge\",\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof Button> & {\n  method?: keyof typeof MERGE_LABEL\n}) {\n  return (\n    <Button\n      data-slot=\"merge-button\"\n      size=\"sm\"\n      className={cn(\"gap-1.5\", className)}\n      {...props}\n    >\n      <GitMerge className=\"size-3.5\" />\n      {children ?? MERGE_LABEL[method]}\n    </Button>\n  )\n}\n\n// Footer strip for the merge action (and anything beside it).\nfunction ChecksPanelFooter({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"checks-panel-footer\"\n      className={cn(\n        \"flex items-center justify-end gap-2 border-t border-border/60 px-4 py-2.5\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  ChecksPanel,\n  ChecksPanelItem,\n  ChecksPanelFooter,\n  MergeButton,\n  type CheckStatus,\n}\n",
      "type": "registry:ui",
      "target": "components/ui/checks-panel.tsx"
    }
  ]
}