{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "completion-dialog",
  "type": "registry:component",
  "title": "Completion Dialog",
  "description": "Dialog displayed upon completing a task or workflow.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/completion-dialog/completion-dialog.tsx",
      "content": "\"use client\";\n\nimport { memo, useCallback, useEffect, useRef } from \"react\";\n\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\nimport { Button } from \"@vllnt/ui\";\n\nexport type CompletionDialogProps = {\n  cancelLabel?: string;\n  cancelShortcut?: string;\n  className?: string;\n  closeIcon?: ReactNode;\n  confirmLabel?: string;\n  confirmShortcut?: string;\n  description?: ReactNode;\n  isOpen: boolean;\n  onCancel: () => void;\n  onClose: () => void;\n  onConfirm: () => void;\n  title: string;\n};\n\ntype DialogContentProps = Omit<CompletionDialogProps, \"isOpen\">;\n\n// eslint-disable-next-line max-lines-per-function -- Dialog content with keyboard handling\nfunction DialogContent({\n  cancelLabel = \"Skip\",\n  cancelShortcut = \"S\",\n  className,\n  closeIcon,\n  confirmLabel = \"Done\",\n  confirmShortcut = \"D\",\n  description,\n  onCancel,\n  onClose,\n  onConfirm,\n  title,\n}: DialogContentProps): React.ReactNode {\n  const confirmButtonRef = useRef<HTMLButtonElement>(null);\n\n  useEffect(() => {\n    confirmButtonRef.current?.focus();\n  }, []);\n\n  return (\n    <div\n      className={cn(\n        \"relative z-10 w-full max-w-md mx-4 p-6 bg-background border border-border rounded-lg shadow-lg\",\n        \"animate-in fade-in-0 zoom-in-95 duration-200\",\n        className,\n      )}\n    >\n      <button\n        aria-label=\"Close\"\n        className=\"absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100 transition-opacity\"\n        onClick={onClose}\n        type=\"button\"\n      >\n        {closeIcon ?? (\n          <svg\n            className=\"size-4\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            viewBox=\"0 0 24 24\"\n          >\n            <path\n              d=\"M6 18L18 6M6 6l12 12\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth={2}\n            />\n          </svg>\n        )}\n      </button>\n      <div className=\"mb-4\">\n        <h2 className=\"text-lg font-semibold\" id=\"completion-dialog-title\">\n          {title}\n        </h2>\n        {description ? (\n          <div className=\"text-sm text-muted-foreground mt-1.5\">\n            {description}\n          </div>\n        ) : null}\n      </div>\n      <div className=\"flex flex-row gap-2\">\n        <Button className=\"flex-1 gap-2\" onClick={onCancel} variant=\"outline\">\n          <span>{cancelLabel}</span>\n          {cancelShortcut ? (\n            <kbd className=\"hidden md:inline-flex px-1.5 py-0.5 text-[10px] font-mono bg-muted rounded\">\n              {cancelShortcut}\n            </kbd>\n          ) : null}\n        </Button>\n        <Button\n          className=\"flex-1 gap-2\"\n          onClick={onConfirm}\n          ref={confirmButtonRef}\n        >\n          <span>{confirmLabel}</span>\n          {confirmShortcut ? (\n            <kbd className=\"hidden md:inline-flex px-1.5 py-0.5 text-[10px] font-mono bg-primary-foreground/20 rounded\">\n              {confirmShortcut}\n            </kbd>\n          ) : null}\n        </Button>\n      </div>\n    </div>\n  );\n}\n\n// eslint-disable-next-line max-lines-per-function -- Modal with keyboard handling\nfunction CompletionDialogImpl({\n  cancelLabel,\n  cancelShortcut = \"S\",\n  className,\n  closeIcon,\n  confirmLabel,\n  confirmShortcut = \"D\",\n  description,\n  isOpen,\n  onCancel,\n  onClose,\n  onConfirm,\n  title,\n}: CompletionDialogProps): React.ReactNode {\n  const handleKeyDown = useCallback(\n    (event: KeyboardEvent) => {\n      if (!isOpen) return;\n      if (event.key === \"Escape\") {\n        event.preventDefault();\n        event.stopPropagation();\n        onClose();\n        return;\n      }\n      if (\n        event.key === \"Enter\" ||\n        event.key.toLowerCase() === confirmShortcut.toLowerCase()\n      ) {\n        event.preventDefault();\n        event.stopPropagation();\n        onConfirm();\n        return;\n      }\n      if (event.key.toLowerCase() === cancelShortcut.toLowerCase()) {\n        event.preventDefault();\n        event.stopPropagation();\n        onCancel();\n      }\n    },\n    [isOpen, onClose, onConfirm, onCancel, confirmShortcut, cancelShortcut],\n  );\n\n  useEffect(() => {\n    if (!isOpen) return;\n    document.addEventListener(\"keydown\", handleKeyDown, true);\n    return () => {\n      document.removeEventListener(\"keydown\", handleKeyDown, true);\n    };\n  }, [isOpen, handleKeyDown]);\n\n  if (!isOpen) return null;\n\n  return (\n    <div\n      aria-labelledby=\"completion-dialog-title\"\n      aria-modal=\"true\"\n      className=\"absolute inset-0 z-[100] flex items-center justify-center\"\n      role=\"dialog\"\n    >\n      <div\n        aria-hidden=\"true\"\n        className={cn(\n          \"absolute inset-0 bg-background/80 backdrop-blur-sm\",\n          \"animate-in fade-in-0 duration-200\",\n        )}\n        onClick={onClose}\n      />\n      <DialogContent\n        cancelLabel={cancelLabel}\n        cancelShortcut={cancelShortcut}\n        className={className}\n        closeIcon={closeIcon}\n        confirmLabel={confirmLabel}\n        confirmShortcut={confirmShortcut}\n        description={description}\n        onCancel={onCancel}\n        onClose={onClose}\n        onConfirm={onConfirm}\n        title={title}\n      />\n    </div>\n  );\n}\n\nexport const CompletionDialog = memo(CompletionDialogImpl);\nCompletionDialog.displayName = \"CompletionDialog\";\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
