{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"approval-request","type":"registry:ui","title":"Approval Request","description":"The human-in-the-loop confirmation — what the agent wants to do, the exact details, and allow or deny before it acts.","author":"Scrim UI (https://scrimui.dev)","categories":["agents"],"docs":"https://scrimui.dev/components/approval-request","dependencies":[],"registryDependencies":[],"files":[{"path":"src/showcase/approval-request/approval-request.tsx","content":"\"use client\";\n\nimport * as React from \"react\";\n\n/* ------------------------------------------------------------------ */\n/* Types                                                               */\n/* ------------------------------------------------------------------ */\n\nexport type ApprovalState = \"pending\" | \"approved\" | \"denied\";\n\nexport type ApprovalRequestProps = {\n  title: string;\n  requester?: string;\n  description?: string;\n  detail?: string;\n  status?: ApprovalState;\n  onAllow?: () => void;\n  onDeny?: () => void;\n  className?: string;\n};\n\n/* ------------------------------------------------------------------ */\n/* Icons                                                               */\n/* ------------------------------------------------------------------ */\n\nfunction ShieldIcon(props: React.SVGProps<SVGSVGElement>) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"16\" height=\"16\" {...props}>\n      <path d=\"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\" />\n      <path d=\"m9 12 2 2 4-4\" />\n    </svg>\n  );\n}\n\nfunction CheckIcon(props: React.SVGProps<SVGSVGElement>) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"12\" height=\"12\" {...props}>\n      <path d=\"M20 6 9 17l-5-5\" />\n    </svg>\n  );\n}\n\nfunction XIcon(props: React.SVGProps<SVGSVGElement>) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" width=\"12\" height=\"12\" {...props}>\n      <path d=\"M18 6 6 18M6 6l12 12\" />\n    </svg>\n  );\n}\n\n/* ------------------------------------------------------------------ */\n/* ApprovalRequest                                                     */\n/* ------------------------------------------------------------------ */\n\nexport function ApprovalRequest({\n  title,\n  requester,\n  description,\n  detail,\n  status = \"pending\",\n  onAllow,\n  onDeny,\n  className = \"\",\n}: ApprovalRequestProps) {\n  return (\n    <div className={`rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900 ${className}`}>\n      <div className=\"flex items-start gap-3\">\n        <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-amber-100 text-amber-600 dark:bg-amber-900/40 dark:text-amber-400\">\n          <ShieldIcon />\n        </span>\n\n        <div className=\"min-w-0 flex-1\">\n          <p className=\"text-sm font-medium text-zinc-900 dark:text-zinc-100\">{title}</p>\n          {requester && (\n            <p className=\"mt-0.5 text-xs text-zinc-500 dark:text-zinc-400\">{requester} is requesting approval</p>\n          )}\n          {description && (\n            <p className=\"mt-1.5 text-[13px] leading-5 text-zinc-500 dark:text-zinc-400\">\n              {description}\n            </p>\n          )}\n          {detail && (\n            <pre className=\"mt-2 overflow-x-auto rounded-lg bg-zinc-50 p-2.5 font-mono text-xs leading-5 text-zinc-700 dark:bg-zinc-800/60 dark:text-zinc-300\">\n              {detail}\n            </pre>\n          )}\n\n          {status === \"pending\" ? (\n            <div className=\"mt-3 flex items-center gap-2\">\n              <button\n                type=\"button\"\n                onClick={onAllow}\n                /* emerald-700, not -600: white on emerald-600 is 3.65:1, under\n                   the 4.5 floor for this 12px label. -700 is 5.48:1. */\n                className=\"inline-flex h-8 items-center gap-1.5 rounded-lg bg-emerald-700 px-3.5 text-xs font-medium text-white transition-opacity hover:opacity-90\"\n              >\n                <CheckIcon />\n                Allow\n              </button>\n              <button\n                type=\"button\"\n                onClick={onDeny}\n                className=\"inline-flex h-8 items-center gap-1.5 rounded-lg border border-zinc-200 px-3.5 text-xs font-medium text-zinc-600 transition-colors hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800\"\n              >\n                <XIcon />\n                Deny\n              </button>\n              <span className=\"ml-auto text-[11px] text-zinc-500 dark:text-zinc-400\">Auto-deny in 4:32</span>\n            </div>\n          ) : (\n            <p\n              className={`mt-3 inline-flex items-center gap-1.5 text-xs font-medium ${\n                status === \"approved\"\n                  ? /* -700 in light: emerald-600 on white is 3.65:1 at 12px. */\n                    \"text-emerald-700 dark:text-emerald-400\"\n                  : \"text-red-600 dark:text-red-400\"\n              }`}\n            >\n              {status === \"approved\" ? <CheckIcon /> : <XIcon />}\n              {status === \"approved\" ? \"Approved — action executed\" : \"Denied — action blocked\"}\n            </p>\n          )}\n        </div>\n      </div>\n    </div>\n  );\n}\n","type":"registry:ui","target":"components/ui/approval-request.tsx"}]}