{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "confirmation",
  "title": "AI Confirmation",
  "description": "Human-in-the-loop tool approval workflow with accept/reject states for agentic AI applications.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/blocks/ai/ai-confirmation/components/elements/ai-confirmation.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { Check, ShieldCheck, ShieldQuestion, ShieldX, X } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype ConfirmationState =\n  | \"approval-requested\"\n  | \"approval-responded\"\n  | \"output-available\"\n  | \"output-denied\";\n\ninterface AiConfirmationContextValue {\n  state: ConfirmationState;\n  onApprove?: () => void;\n  onReject?: () => void;\n}\n\nconst AiConfirmationContext =\n  React.createContext<AiConfirmationContextValue | null>(null);\n\nfunction useConfirmationContext() {\n  const context = React.useContext(AiConfirmationContext);\n  if (!context) {\n    throw new Error(\n      \"AiConfirmation components must be used within <AiConfirmation>\",\n    );\n  }\n  return context;\n}\n\ninterface AiConfirmationProps {\n  state: ConfirmationState;\n  onApprove?: () => void;\n  onReject?: () => void;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiConfirmation({\n  state,\n  onApprove,\n  onReject,\n  children,\n  className,\n}: AiConfirmationProps) {\n  const contextValue = React.useMemo(\n    () => ({ state, onApprove, onReject }),\n    [state, onApprove, onReject],\n  );\n\n  const stateStyles = React.useMemo(() => {\n    const styles: Record<ConfirmationState, string> = {\n      \"approval-requested\":\n        \"border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/30\",\n      \"approval-responded\":\n        \"border-blue-200 bg-blue-50 dark:border-blue-900 dark:bg-blue-950/30\",\n      \"output-available\":\n        \"border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-950/30\",\n      \"output-denied\":\n        \"border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/30\",\n    };\n    return styles[state];\n  }, [state]);\n\n  return (\n    <AiConfirmationContext.Provider value={contextValue}>\n      <div\n        data-slot=\"ai-confirmation\"\n        data-state={state}\n        role=\"alert\"\n        className={cn(\"rounded-lg border p-4\", stateStyles, className)}\n      >\n        {children}\n      </div>\n    </AiConfirmationContext.Provider>\n  );\n}\n\ninterface AiConfirmationRequestProps {\n  title?: string;\n  description?: string;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiConfirmationRequest({\n  title = \"Approval Required\",\n  description,\n  children,\n  className,\n}: AiConfirmationRequestProps) {\n  const { state } = useConfirmationContext();\n\n  if (state !== \"approval-requested\") {\n    return null;\n  }\n\n  return (\n    <div\n      data-slot=\"ai-confirmation-request\"\n      className={cn(\"flex items-start gap-3\", className)}\n    >\n      <div className=\"flex size-10 shrink-0 items-center justify-center rounded-full bg-amber-100 dark:bg-amber-900/50\">\n        <ShieldQuestion className=\"size-5 text-amber-600 dark:text-amber-400\" />\n      </div>\n      <div className=\"flex-1 space-y-1\">\n        <h4 className=\"font-semibold text-amber-800 dark:text-amber-200\">\n          {title}\n        </h4>\n        {description && (\n          <p className=\"text-sm text-amber-700 dark:text-amber-300\">\n            {description}\n          </p>\n        )}\n        {children}\n      </div>\n    </div>\n  );\n}\n\ninterface AiConfirmationAcceptedProps {\n  title?: string;\n  description?: string;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiConfirmationAccepted({\n  title = \"Approved\",\n  description,\n  children,\n  className,\n}: AiConfirmationAcceptedProps) {\n  const { state } = useConfirmationContext();\n\n  if (state !== \"output-available\" && state !== \"approval-responded\") {\n    return null;\n  }\n\n  return (\n    <div\n      data-slot=\"ai-confirmation-accepted\"\n      className={cn(\"flex items-start gap-3\", className)}\n    >\n      <div className=\"flex size-10 shrink-0 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/50\">\n        <ShieldCheck className=\"size-5 text-green-600 dark:text-green-400\" />\n      </div>\n      <div className=\"flex-1 space-y-1\">\n        <h4 className=\"font-semibold text-green-800 dark:text-green-200\">\n          {title}\n        </h4>\n        {description && (\n          <p className=\"text-sm text-green-700 dark:text-green-300\">\n            {description}\n          </p>\n        )}\n        {children}\n      </div>\n    </div>\n  );\n}\n\ninterface AiConfirmationRejectedProps {\n  title?: string;\n  description?: string;\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiConfirmationRejected({\n  title = \"Denied\",\n  description,\n  children,\n  className,\n}: AiConfirmationRejectedProps) {\n  const { state } = useConfirmationContext();\n\n  if (state !== \"output-denied\") {\n    return null;\n  }\n\n  return (\n    <div\n      data-slot=\"ai-confirmation-rejected\"\n      className={cn(\"flex items-start gap-3\", className)}\n    >\n      <div className=\"flex size-10 shrink-0 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/50\">\n        <ShieldX className=\"size-5 text-red-600 dark:text-red-400\" />\n      </div>\n      <div className=\"flex-1 space-y-1\">\n        <h4 className=\"font-semibold text-red-800 dark:text-red-200\">\n          {title}\n        </h4>\n        {description && (\n          <p className=\"text-sm text-red-700 dark:text-red-300\">\n            {description}\n          </p>\n        )}\n        {children}\n      </div>\n    </div>\n  );\n}\n\ninterface AiConfirmationActionsProps {\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction AiConfirmationActions({\n  children,\n  className,\n}: AiConfirmationActionsProps) {\n  const { state, onApprove, onReject } = useConfirmationContext();\n\n  if (state !== \"approval-requested\") {\n    return null;\n  }\n\n  return (\n    <div\n      data-slot=\"ai-confirmation-actions\"\n      className={cn(\"mt-3 flex items-center gap-2\", className)}\n    >\n      {children || (\n        <>\n          <button\n            type=\"button\"\n            onClick={onApprove}\n            className=\"inline-flex items-center gap-1.5 rounded-md bg-green-600 px-3 py-1.5 text-sm font-medium text-white transition-colors hover:bg-green-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-green-500 focus-visible:ring-offset-2\"\n          >\n            <Check className=\"size-4\" />\n            Approve\n          </button>\n          <button\n            type=\"button\"\n            onClick={onReject}\n            className=\"inline-flex items-center gap-1.5 rounded-md bg-red-600 px-3 py-1.5 text-sm font-medium text-white transition-colors hover:bg-red-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2\"\n          >\n            <X className=\"size-4\" />\n            Reject\n          </button>\n        </>\n      )}\n    </div>\n  );\n}\n\ninterface AiConfirmationActionProps {\n  variant: \"approve\" | \"reject\";\n  children?: React.ReactNode;\n  className?: string;\n  onClick?: () => void;\n}\n\nfunction AiConfirmationAction({\n  variant,\n  children,\n  className,\n  onClick,\n}: AiConfirmationActionProps) {\n  const { onApprove, onReject } = useConfirmationContext();\n\n  const handleClick = React.useCallback(() => {\n    onClick?.();\n    if (variant === \"approve\") {\n      onApprove?.();\n    } else {\n      onReject?.();\n    }\n  }, [variant, onClick, onApprove, onReject]);\n\n  const variantStyles = React.useMemo(() => {\n    if (variant === \"approve\") {\n      return \"bg-green-600 hover:bg-green-700 focus-visible:ring-green-500\";\n    }\n    return \"bg-red-600 hover:bg-red-700 focus-visible:ring-red-500\";\n  }, [variant]);\n\n  const defaultContent = React.useMemo(() => {\n    if (variant === \"approve\") {\n      return (\n        <>\n          <Check className=\"size-4\" />\n          Approve\n        </>\n      );\n    }\n    return (\n      <>\n        <X className=\"size-4\" />\n        Reject\n      </>\n    );\n  }, [variant]);\n\n  return (\n    <button\n      type=\"button\"\n      data-slot=\"ai-confirmation-action\"\n      data-variant={variant}\n      onClick={handleClick}\n      className={cn(\n        \"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2\",\n        variantStyles,\n        className,\n      )}\n    >\n      {children || defaultContent}\n    </button>\n  );\n}\n\nexport {\n  AiConfirmation,\n  AiConfirmationRequest,\n  AiConfirmationAccepted,\n  AiConfirmationRejected,\n  AiConfirmationActions,\n  AiConfirmationAction,\n};\nexport type { AiConfirmationProps, ConfirmationState };\n",
      "type": "registry:component"
    }
  ],
  "docs": "Compound component for tool approval workflows. States: approval-requested, approval-responded, output-available, output-denied.",
  "categories": [
    "ai"
  ],
  "type": "registry:ui"
}