@cadraos/sdk 0.1.9 → 0.1.11-test

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/chat/utils/compress-image.ts","../../src/chat/components/FileDropZone.tsx","../../src/chat/hooks/useFileAttachments.ts"],"names":["FileDropZone","useState","useRef","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Client-side image compression using Canvas API.\n *\n * Resizes images to max 1920px on longest side and iteratively\n * reduces JPEG/WebP quality to hit a ~150KB target size.\n * Skips SVGs, non-image files, and files already under the target.\n */\n\nconst DEFAULT_TARGET_SIZE_KB = 150;\nconst MAX_DIMENSION = 1920;\nconst QUALITY_START = 0.85;\nconst QUALITY_STEP = 0.05;\nconst QUALITY_MIN = 0.1;\n\n/**\n * Load a File as an HTMLImageElement via object URL.\n */\nfunction loadImage(file: File): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n const url = URL.createObjectURL(file);\n img.onload = () => {\n URL.revokeObjectURL(url);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error(`Failed to load image: ${file.name}`));\n };\n img.src = url;\n });\n}\n\n/**\n * Calculate scaled dimensions keeping aspect ratio, capped at MAX_DIMENSION.\n */\nfunction getScaledDimensions(\n width: number,\n height: number,\n maxDim: number\n): { width: number; height: number } {\n if (width <= maxDim && height <= maxDim) {\n return { width, height };\n }\n const ratio = Math.min(maxDim / width, maxDim / height);\n return {\n width: Math.round(width * ratio),\n height: Math.round(height * ratio),\n };\n}\n\n/**\n * Draw image to canvas at target dimensions and export as blob.\n */\nfunction canvasToBlob(\n img: HTMLImageElement,\n width: number,\n height: number,\n format: string,\n quality: number\n): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Failed to get canvas 2d context\"));\n return;\n }\n\n ctx.drawImage(img, 0, 0, width, height);\n\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n reject(new Error(\"Canvas toBlob returned null\"));\n return;\n }\n resolve(blob);\n },\n format,\n quality\n );\n });\n}\n\n/**\n * Check if browser supports WebP encoding via canvas.\n */\nlet webpSupported: boolean | null = null;\nfunction supportsWebP(): boolean {\n if (webpSupported !== null) return webpSupported;\n try {\n const canvas = document.createElement(\"canvas\");\n canvas.width = 1;\n canvas.height = 1;\n webpSupported = canvas.toDataURL(\"image/webp\").startsWith(\"data:image/webp\");\n } catch {\n webpSupported = false;\n }\n return webpSupported;\n}\n\n/**\n * Determine output format and file extension for compressed image.\n */\nfunction getOutputFormat(_originalType: string): { mime: string; ext: string } {\n // Prefer WebP if supported, fall back to JPEG\n if (supportsWebP()) {\n return { mime: \"image/webp\", ext: \".webp\" };\n }\n return { mime: \"image/jpeg\", ext: \".jpg\" };\n}\n\n/**\n * Replace file extension in a filename.\n */\nfunction replaceExtension(filename: string, newExt: string): string {\n const dotIndex = filename.lastIndexOf(\".\");\n if (dotIndex === -1) return filename + newExt;\n return filename.substring(0, dotIndex) + newExt;\n}\n\n/**\n * Compress an image file to approximately targetSizeKB using Canvas API.\n *\n * - Returns the original file if it's already under targetSizeKB\n * - Skips SVGs and non-image files (returns as-is)\n * - Resizes to max 1920px on longest side\n * - Iteratively reduces quality to approach target size\n *\n * @param file - The File to compress\n * @param targetSizeKB - Target output size in KB (default: 150)\n * @returns Compressed File, or the original if no compression needed\n */\nexport async function compressImage(\n file: File,\n targetSizeKB: number = DEFAULT_TARGET_SIZE_KB\n): Promise<File> {\n // Skip non-image files\n if (!file.type.startsWith(\"image/\")) {\n return file;\n }\n\n // Skip SVGs - they're vector and already small\n if (file.type === \"image/svg+xml\") {\n return file;\n }\n\n // Skip GIFs - canvas loses animation frames\n if (file.type === \"image/gif\") {\n return file;\n }\n\n const targetBytes = targetSizeKB * 1024;\n\n // Already under target, no compression needed\n if (file.size <= targetBytes) {\n return file;\n }\n\n const img = await loadImage(file);\n\n const { width, height } = getScaledDimensions(\n img.naturalWidth,\n img.naturalHeight,\n MAX_DIMENSION\n );\n\n const { mime, ext } = getOutputFormat(file.type);\n\n // Iteratively reduce quality to hit target size\n let quality = QUALITY_START;\n let blob: Blob | null = null;\n\n while (quality >= QUALITY_MIN) {\n blob = await canvasToBlob(img, width, height, mime, quality);\n\n if (blob.size <= targetBytes) {\n break;\n }\n\n quality -= QUALITY_STEP;\n }\n\n // If we exhausted quality iterations, use whatever we got (lowest quality)\n if (!blob) {\n blob = await canvasToBlob(img, width, height, mime, QUALITY_MIN);\n }\n\n // If compressed is actually larger than original, return original\n if (blob.size >= file.size) {\n return file;\n }\n\n const newFilename = replaceExtension(file.name, ext);\n\n return new File([blob], newFilename, {\n type: mime,\n lastModified: Date.now(),\n });\n}\n","\"use client\";\n\n/**\n * FileDropZone - Reusable file upload component with drag-and-drop\n *\n * Supports drag-and-drop file upload with visual feedback, file validation,\n * image compression, upload progress tracking, and thumbnail previews.\n *\n * Two modes:\n * - Standalone: renders a drop zone UI (default)\n * - Wrapper: wraps children with a drag-drop overlay (when children provided)\n *\n * @packageDocumentation\n */\n\nimport React, {\n useState,\n useCallback,\n useRef,\n useEffect,\n useImperativeHandle,\n forwardRef,\n} from \"react\";\nimport { compressImage } from \"../utils/compress-image.js\";\nimport type { AttachmentFile } from \"../types.js\";\n\n// =============================================================================\n// INLINE SVG ICONS (no lucide-react dependency)\n// =============================================================================\n\ninterface IconProps {\n className?: string;\n}\n\nfunction Upload({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" /><polyline points=\"17 8 12 3 7 8\" /><line x1=\"12\" x2=\"12\" y1=\"3\" y2=\"15\" />\n </svg>\n );\n}\n\nfunction X({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nfunction FileText({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" /><path d=\"M14 2v4a2 2 0 0 0 2 2h4\" /><line x1=\"16\" x2=\"8\" y1=\"13\" y2=\"13\" /><line x1=\"16\" x2=\"8\" y1=\"17\" y2=\"17\" /><line x1=\"10\" x2=\"8\" y1=\"9\" y2=\"9\" />\n </svg>\n );\n}\n\nfunction ImageIcon({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" /><circle cx=\"9\" cy=\"9\" r=\"2\" /><path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\" />\n </svg>\n );\n}\n\nfunction Music({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M9 18V5l12-2v13\" /><circle cx=\"6\" cy=\"18\" r=\"3\" /><circle cx=\"18\" cy=\"16\" r=\"3\" />\n </svg>\n );\n}\n\nfunction Loader2({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\nfunction FileIcon({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" /><path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n </svg>\n );\n}\n\nfunction RotateCw({ className }: IconProps) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className}>\n <path d=\"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\" /><path d=\"M21 3v5h-5\" />\n </svg>\n );\n}\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\nfunction cn(...classes: (string | undefined | false)[]): string {\n return classes.filter(Boolean).join(\" \");\n}\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface FileDropZoneProps {\n files: AttachmentFile[];\n onFilesChange: (files: AttachmentFile[]) => void;\n /** Upload a file. Return the UUID and presigned URL. If uploadUrl is empty, the S3 PUT step is skipped. */\n onUpload: (\n file: File,\n metadata: { filename: string; mimeType: string; size: number },\n ) => Promise<{ uuid: string; uploadUrl: string }>;\n /** Confirm the upload after S3 PUT succeeds */\n onConfirmUpload?: (uuid: string) => Promise<void>;\n /** Error callback instead of toast */\n onError?: (message: string) => void;\n maxFiles?: number;\n maxTotalSizeMB?: number;\n disabled?: boolean;\n className?: string;\n /** Restrict accepted file types, e.g. \"image/*\" */\n accept?: string;\n /** Compact mode for embedding in small panels */\n compact?: boolean;\n children?: React.ReactNode;\n}\n\n/** Ref interface for programmatic access to FileDropZone */\nexport interface FileDropZoneRef {\n /** Trigger the file selection dialog */\n openFileDialog: () => void;\n}\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\nconst SUPPORTED_TYPES = {\n document: {\n mimeTypes: [\n \"application/pdf\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n \"application/msword\",\n \"text/plain\",\n \"text/markdown\",\n \"text/csv\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n \"application/vnd.ms-excel\",\n ],\n extensions: [\n \".pdf\",\n \".docx\",\n \".doc\",\n \".txt\",\n \".md\",\n \".csv\",\n \".xlsx\",\n \".xls\",\n ],\n maxSizeMB: 25,\n label: \"Documents\",\n },\n image: {\n mimeTypes: [\n \"image/png\",\n \"image/jpeg\",\n \"image/gif\",\n \"image/webp\",\n \"image/svg+xml\",\n ],\n extensions: [\".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\", \".svg\"],\n maxSizeMB: 10,\n label: \"Images\",\n },\n audio: {\n mimeTypes: [\n \"audio/mpeg\",\n \"audio/wav\",\n \"audio/mp4\",\n \"audio/ogg\",\n \"audio/webm\",\n ],\n extensions: [\".mp3\", \".wav\", \".m4a\", \".ogg\", \".webm\"],\n maxSizeMB: 50,\n label: \"Audio\",\n },\n};\n\nconst MAX_FILES_PER_DROP = 10;\nconst MAX_TOTAL_SIZE_MB = 100;\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\nfunction categorizeFile(\n mimeType: string,\n): \"document\" | \"image\" | \"audio\" | null {\n for (const [category, config] of Object.entries(SUPPORTED_TYPES)) {\n if (config.mimeTypes.includes(mimeType)) {\n return category as \"document\" | \"image\" | \"audio\";\n }\n }\n return null;\n}\n\nfunction validateFile(file: File): {\n valid: boolean;\n error?: string;\n category?: \"document\" | \"image\" | \"audio\";\n} {\n const category = categorizeFile(file.type);\n\n if (!category) {\n return {\n valid: false,\n error: `Unsupported file type: ${file.type || file.name.split(\".\").pop()}`,\n };\n }\n\n const config = SUPPORTED_TYPES[category];\n const maxSizeBytes = config.maxSizeMB * 1024 * 1024;\n\n if (file.size > maxSizeBytes) {\n return {\n valid: false,\n error: `${file.name} exceeds ${config.maxSizeMB}MB limit for ${config.label.toLowerCase()}`,\n };\n }\n\n return { valid: true, category };\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction getCategoryIcon(category: \"document\" | \"image\" | \"audio\") {\n switch (category) {\n case \"document\":\n return FileText;\n case \"image\":\n return ImageIcon;\n case \"audio\":\n return Music;\n default:\n return FileIcon;\n }\n}\n\n// =============================================================================\n// COMPONENT\n// =============================================================================\n\nexport const FileDropZone = forwardRef<FileDropZoneRef, FileDropZoneProps>(\n function FileDropZone(\n {\n onFilesChange,\n files,\n onUpload,\n onConfirmUpload,\n onError,\n maxFiles = MAX_FILES_PER_DROP,\n maxTotalSizeMB = MAX_TOTAL_SIZE_MB,\n disabled = false,\n className,\n accept,\n compact = false,\n children,\n },\n ref,\n ) {\n const [isDragging, setIsDragging] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const dropZoneRef = useRef<HTMLDivElement>(null);\n const dragCounter = useRef(0);\n\n // Expose openFileDialog method via ref\n useImperativeHandle(\n ref,\n () => ({\n openFileDialog: () => {\n if (!disabled) {\n fileInputRef.current?.click();\n }\n },\n }),\n [disabled],\n );\n\n // Calculate current total size\n const currentTotalSize = files.reduce((sum, f) => sum + f.file.size, 0);\n\n // Upload a single file\n const uploadFile = useCallback(\n async (file: File, _tempId: string) => {\n const result = await onUpload(file, {\n filename: file.name,\n mimeType: file.type,\n size: file.size,\n });\n\n // If uploadUrl is provided, do the S3 PUT\n if (result.uploadUrl) {\n const uploadResponse = await fetch(result.uploadUrl, {\n method: \"PUT\",\n body: file,\n headers: { \"Content-Type\": file.type },\n });\n if (!uploadResponse.ok) {\n throw new Error(`Upload failed: ${uploadResponse.statusText}`);\n }\n }\n\n // Confirm if callback provided\n if (onConfirmUpload) {\n await onConfirmUpload(result.uuid);\n }\n\n return result.uuid;\n },\n [onUpload, onConfirmUpload],\n );\n\n // Handle file validation and upload\n const handleFiles = useCallback(\n async (selectedFiles: File[]) => {\n if (disabled) return;\n\n // Validate total file count\n if (files.length + selectedFiles.length > maxFiles) {\n onError?.(`Maximum ${maxFiles} files allowed`);\n return;\n }\n\n // Validate and categorize files\n const validFiles: {\n file: File;\n category: \"document\" | \"image\" | \"audio\";\n }[] = [];\n let newTotalSize = currentTotalSize;\n\n for (const file of selectedFiles) {\n const validation = validateFile(file);\n\n if (!validation.valid) {\n onError?.(validation.error!);\n continue;\n }\n\n newTotalSize += file.size;\n if (newTotalSize > maxTotalSizeMB * 1024 * 1024) {\n onError?.(`Total upload size exceeds ${maxTotalSizeMB}MB`);\n break;\n }\n\n validFiles.push({ file, category: validation.category! });\n }\n\n if (validFiles.length === 0) return;\n\n // Compress images before upload\n const processedFiles: {\n file: File;\n category: \"document\" | \"image\" | \"audio\";\n }[] = [];\n for (const entry of validFiles) {\n if (entry.category === \"image\") {\n try {\n const compressed = await compressImage(entry.file);\n processedFiles.push({ file: compressed, category: entry.category });\n } catch (err) {\n console.warn(\"Image compression failed, using original:\", err);\n processedFiles.push(entry);\n }\n } else {\n processedFiles.push(entry);\n }\n }\n\n // Create attachment records\n const newAttachments: AttachmentFile[] = processedFiles.map(\n ({ file, category }) => {\n const tempId = `temp-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n return {\n uuid: tempId,\n file,\n status: \"pending\" as const,\n progress: 0,\n category,\n previewUrl:\n category === \"image\" ? URL.createObjectURL(file) : undefined,\n };\n },\n );\n\n // Add to state immediately\n let currentFiles = [...files, ...newAttachments];\n onFilesChange(currentFiles);\n\n // Upload each file\n for (const attachment of newAttachments) {\n try {\n // Update status to uploading\n currentFiles = currentFiles.map((f: AttachmentFile) =>\n f.uuid === attachment.uuid\n ? { ...f, status: \"uploading\" as const, progress: 10 }\n : f,\n );\n onFilesChange(currentFiles);\n\n const realUuid = await uploadFile(attachment.file, attachment.uuid);\n\n // Update with real UUID and ready status\n currentFiles = currentFiles.map((f: AttachmentFile) =>\n f.uuid === attachment.uuid\n ? {\n ...f,\n uuid: realUuid,\n status: \"ready\" as const,\n progress: 100,\n hasThumbnail: f.category === \"image\",\n }\n : f,\n );\n onFilesChange(currentFiles);\n } catch (error) {\n console.error(\"Upload error:\", error);\n currentFiles = currentFiles.map((f: AttachmentFile) =>\n f.uuid === attachment.uuid\n ? {\n ...f,\n status: \"error\" as const,\n error:\n error instanceof Error ? error.message : \"Upload failed\",\n }\n : f,\n );\n onFilesChange(currentFiles);\n onError?.(`Failed to upload ${attachment.file.name}`);\n }\n }\n },\n [\n disabled,\n files,\n maxFiles,\n currentTotalSize,\n maxTotalSizeMB,\n onFilesChange,\n uploadFile,\n onError,\n ],\n );\n\n // Remove a file\n const handleRemove = useCallback(\n (uuid: string) => {\n const file = files.find((f) => f.uuid === uuid);\n if (file?.previewUrl) {\n URL.revokeObjectURL(file.previewUrl);\n }\n onFilesChange(files.filter((f) => f.uuid !== uuid));\n },\n [files, onFilesChange],\n );\n\n // Retry a failed upload\n const handleRetry = useCallback(\n async (uuid: string) => {\n const attachment = files.find((f) => f.uuid === uuid);\n if (!attachment || attachment.status !== \"error\") return;\n\n // Reset to pending\n let currentFiles = files.map((f: AttachmentFile) =>\n f.uuid === uuid\n ? { ...f, status: \"pending\" as const, progress: 0, error: undefined }\n : f,\n );\n onFilesChange(currentFiles);\n\n try {\n currentFiles = currentFiles.map((f: AttachmentFile) =>\n f.uuid === uuid\n ? { ...f, status: \"uploading\" as const, progress: 10 }\n : f,\n );\n onFilesChange(currentFiles);\n\n const realUuid = await uploadFile(attachment.file, uuid);\n\n currentFiles = currentFiles.map((f: AttachmentFile) =>\n f.uuid === uuid\n ? {\n ...f,\n uuid: realUuid,\n status: \"ready\" as const,\n progress: 100,\n hasThumbnail: f.category === \"image\",\n }\n : f,\n );\n onFilesChange(currentFiles);\n } catch (error) {\n console.error(\"Retry upload error:\", error);\n currentFiles = currentFiles.map((f: AttachmentFile) =>\n f.uuid === uuid\n ? {\n ...f,\n status: \"error\" as const,\n error:\n error instanceof Error ? error.message : \"Upload failed\",\n }\n : f,\n );\n onFilesChange(currentFiles);\n onError?.(`Failed to upload ${attachment.file.name}`);\n }\n },\n [files, onFilesChange, uploadFile, onError],\n );\n\n // Helper to check if the drag event contains files\n const hasDraggedFiles = useCallback((e: React.DragEvent): boolean => {\n if (e.dataTransfer.types) {\n for (const type of e.dataTransfer.types) {\n if (type === \"Files\") return true;\n }\n }\n return false;\n }, []);\n\n // Drag and drop handlers (standalone mode)\n const handleDragEnter = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!hasDraggedFiles(e)) return;\n dragCounter.current++;\n if (!disabled && dragCounter.current === 1) {\n setIsDragging(true);\n }\n },\n [disabled, hasDraggedFiles],\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (hasDraggedFiles(e)) {\n e.dataTransfer.dropEffect = disabled ? \"none\" : \"copy\";\n }\n },\n [disabled, hasDraggedFiles],\n );\n\n const handleDragLeave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (dragCounter.current > 0) {\n dragCounter.current--;\n if (dragCounter.current === 0) {\n setIsDragging(false);\n }\n }\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n dragCounter.current = 0;\n setIsDragging(false);\n if (disabled) return;\n const droppedFiles = Array.from(e.dataTransfer.files);\n if (droppedFiles.length > 0) {\n handleFiles(droppedFiles);\n }\n },\n [handleFiles, disabled],\n );\n\n const handleFileSelect = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const selectedFiles = e.target.files;\n if (selectedFiles) {\n handleFiles(Array.from(selectedFiles));\n }\n if (fileInputRef.current) {\n fileInputRef.current.value = \"\";\n }\n },\n [handleFiles],\n );\n\n const handleClick = useCallback(() => {\n if (!disabled) {\n fileInputRef.current?.click();\n }\n }, [disabled]);\n\n // Helper to check if dataTransfer contains files (cross-browser)\n const checkDataTransferHasFiles = useCallback(\n (dataTransfer: DataTransfer | null): boolean => {\n if (!dataTransfer?.types) return false;\n for (let i = 0; i < dataTransfer.types.length; i++) {\n if (dataTransfer.types[i] === \"Files\") return true;\n }\n return false;\n },\n [],\n );\n\n // Native event listeners for wrapper mode drag-drop\n useEffect(() => {\n if (!children || !dropZoneRef.current) return;\n\n const element = dropZoneRef.current;\n let enterCounter = 0;\n\n const handleDragEnterNative = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!checkDataTransferHasFiles(e.dataTransfer)) return;\n enterCounter++;\n if (enterCounter === 1 && !disabled) {\n setIsDragging(true);\n }\n };\n\n const handleDragLeaveNative = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (!checkDataTransferHasFiles(e.dataTransfer)) return;\n enterCounter--;\n if (enterCounter <= 0) {\n enterCounter = 0;\n setIsDragging(false);\n }\n };\n\n const handleDragOverNative = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n if (\n checkDataTransferHasFiles(e.dataTransfer) &&\n !disabled &&\n e.dataTransfer\n ) {\n e.dataTransfer.dropEffect = \"copy\";\n }\n };\n\n const handleDropNative = (e: DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n enterCounter = 0;\n setIsDragging(false);\n if (disabled) return;\n const droppedFiles = e.dataTransfer?.files;\n if (droppedFiles && droppedFiles.length > 0) {\n handleFiles(Array.from(droppedFiles));\n }\n };\n\n element.addEventListener(\"dragenter\", handleDragEnterNative, true);\n element.addEventListener(\"dragleave\", handleDragLeaveNative, true);\n element.addEventListener(\"dragover\", handleDragOverNative, true);\n element.addEventListener(\"drop\", handleDropNative, true);\n\n return () => {\n element.removeEventListener(\"dragenter\", handleDragEnterNative, true);\n element.removeEventListener(\"dragleave\", handleDragLeaveNative, true);\n element.removeEventListener(\"dragover\", handleDragOverNative, true);\n element.removeEventListener(\"drop\", handleDropNative, true);\n };\n }, [children, disabled, handleFiles, checkDataTransferHasFiles]);\n\n // Reset drag state when disabled changes\n useEffect(() => {\n if (disabled) {\n dragCounter.current = 0;\n setIsDragging(false);\n }\n }, [disabled]);\n\n // Build accept string for file input\n const acceptTypes =\n accept ||\n Object.values(SUPPORTED_TYPES)\n .flatMap((t) => [...t.mimeTypes, ...t.extensions])\n .join(\",\");\n\n const hasFiles = files.length > 0;\n const isUploading = files.some((f) => f.status === \"uploading\");\n\n // --- Wrapper mode ---\n if (children) {\n return (\n <div\n ref={dropZoneRef}\n data-dropzone=\"wrapper\"\n className={cn(\"relative w-full h-full\", className)}\n style={{ minHeight: \"inherit\" }}\n >\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept={acceptTypes}\n onChange={handleFileSelect}\n className=\"hidden\"\n disabled={disabled}\n />\n {children}\n {isDragging && !disabled && (\n <div\n className=\"absolute inset-0 z-50 bg-primary/10 border-2 border-dashed border-primary rounded-xl flex flex-col items-center justify-center backdrop-blur-sm transition-opacity duration-200\"\n style={{ pointerEvents: \"none\" }}\n >\n <div className=\"bg-background/80 rounded-xl p-8 flex flex-col items-center shadow-lg\">\n <Upload className=\"h-12 w-12 text-primary mb-4 animate-bounce\" />\n <p className=\"text-lg font-medium text-primary\">\n Drop files here\n </p>\n <p className=\"text-sm text-muted-foreground mt-2\">\n Documents, images, or audio files\n </p>\n </div>\n </div>\n )}\n </div>\n );\n }\n\n // --- Standalone mode ---\n return (\n <div className={cn(\"w-full\", className)}>\n <input\n ref={fileInputRef}\n type=\"file\"\n multiple\n accept={acceptTypes}\n onChange={handleFileSelect}\n className=\"hidden\"\n disabled={disabled}\n />\n\n {/* Drop zone */}\n <div\n onDragEnter={handleDragEnter}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n onClick={handleClick}\n className={cn(\n \"relative rounded-lg border-2 border-dashed transition-all cursor-pointer\",\n \"flex flex-col items-center justify-center\",\n compact ? \"p-2 min-h-[60px]\" : \"p-4 min-h-[100px]\",\n isDragging && !disabled\n ? \"border-primary bg-primary/5\"\n : \"border-muted-foreground/25\",\n disabled\n ? \"opacity-50 cursor-not-allowed\"\n : \"hover:border-primary/50 hover:bg-muted/25\",\n )}\n >\n {isUploading ? (\n <Loader2\n className={cn(\n \"animate-spin text-muted-foreground\",\n compact ? \"h-5 w-5 mb-1\" : \"h-8 w-8 mb-2\",\n )}\n />\n ) : (\n <Upload\n className={cn(\n \"text-muted-foreground\",\n compact ? \"h-5 w-5 mb-1\" : \"h-8 w-8 mb-2\",\n )}\n />\n )}\n\n <p\n className={cn(\n \"font-medium text-center text-muted-foreground\",\n compact ? \"text-xs\" : \"text-sm\",\n )}\n >\n {isDragging\n ? \"Drop files here\"\n : isUploading\n ? \"Uploading...\"\n : \"Click to upload or drag and drop\"}\n </p>\n\n {!compact && (\n <p className=\"text-xs text-muted-foreground/70 text-center mt-1\">\n Documents, images, or audio files\n </p>\n )}\n </div>\n\n {/* File list */}\n {hasFiles && (\n <div className={cn(\"space-y-2\", compact ? \"mt-2\" : \"mt-3\")}>\n {files.map((attachment) => {\n const Icon = getCategoryIcon(attachment.category);\n const isError = attachment.status === \"error\";\n const isLoading =\n attachment.status === \"uploading\" ||\n attachment.status === \"processing\";\n\n return (\n <div\n key={attachment.uuid}\n className={cn(\n \"flex items-center gap-3 p-2 rounded-lg border\",\n isError\n ? \"border-destructive/50 bg-destructive/5\"\n : \"border-border bg-muted/25\",\n )}\n >\n {/* Preview or icon */}\n <div className=\"relative flex-shrink-0 w-10 h-10 rounded overflow-hidden bg-muted flex items-center justify-center\">\n {attachment.previewUrl ? (\n <img\n src={attachment.previewUrl}\n alt={attachment.file.name}\n className=\"w-full h-full object-cover\"\n />\n ) : (\n <Icon className=\"h-5 w-5 text-muted-foreground\" />\n )}\n {isLoading && (\n <div className=\"absolute inset-0 bg-background/80 flex items-center justify-center\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n </div>\n )}\n </div>\n\n {/* File info */}\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">\n {attachment.file.name}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {formatFileSize(attachment.file.size)}\n {isError && attachment.error && (\n <span className=\"text-destructive ml-2\">\n {attachment.error}\n </span>\n )}\n </p>\n </div>\n\n {/* Status indicator */}\n <div className=\"flex-shrink-0\">\n {isLoading ? (\n <span className=\"text-xs text-muted-foreground\">\n {attachment.progress}%\n </span>\n ) : attachment.status === \"ready\" ? (\n <span className=\"text-xs text-green-600\">Ready</span>\n ) : null}\n </div>\n\n {/* Retry button for failed uploads */}\n {isError && (\n <button\n type=\"button\"\n className=\"flex-shrink-0 h-8 w-8 inline-flex items-center justify-center rounded-md text-primary hover:bg-muted transition-colors\"\n onClick={(e) => {\n e.stopPropagation();\n handleRetry(attachment.uuid);\n }}\n title=\"Retry upload\"\n >\n <RotateCw className=\"h-4 w-4\" />\n </button>\n )}\n\n {/* Remove button */}\n <button\n type=\"button\"\n className=\"flex-shrink-0 h-8 w-8 inline-flex items-center justify-center rounded-md hover:bg-muted transition-colors disabled:opacity-50\"\n onClick={(e) => {\n e.stopPropagation();\n handleRemove(attachment.uuid);\n }}\n disabled={isLoading}\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n },\n);\n","\"use client\";\n\n/**\n * useFileAttachments - Standalone hook for managing file attachment lifecycle\n *\n * Manages AttachmentFile[] state and provides callback props that can be\n * spread directly onto FileDropZone. Works standalone (e.g., in slides RemixPanel)\n * or composed into AgentChat.\n *\n * @example\n * ```tsx\n * // Standalone usage with direct upload\n * const attachments = useFileAttachments({\n * onUpload: async (file, meta) => {\n * const res = await fetch('/api/upload', { method: 'POST', body: file });\n * const data = await res.json();\n * return { uuid: data.url, uploadUrl: '' };\n * },\n * });\n *\n * <FileDropZone {...attachments.dropZoneProps} compact accept=\"image/*\" />\n * const urls = attachments.getReadyUrls();\n * ```\n *\n * @example\n * ```tsx\n * // With Cadra adapter\n * const attachments = useFileAttachments({\n * onUpload: async (file, meta) => {\n * const result = await adapter.getUploadUrl({ sessionId, ...meta });\n * return { uuid: result.attachmentUuid, uploadUrl: result.uploadUrl };\n * },\n * onConfirmUpload: (uuid) => adapter.confirmUpload(uuid),\n * });\n *\n * sendMessage(content, { attachmentUuids: attachments.getReadyUuids() });\n * attachments.clear();\n * ```\n *\n * @module @cadraos/sdk/chat\n */\n\nimport { useCallback, useRef, useState } from \"react\";\nimport type { AttachmentFile } from \"../types.js\";\nimport type { FileDropZoneProps } from \"../components/FileDropZone.js\";\nimport { compressImage } from \"../utils/compress-image.js\";\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface UseFileAttachmentsOptions {\n /**\n * Upload handler called immediately when files are dropped/selected.\n * Return the UUID and a presigned upload URL.\n * If uploadUrl is empty, the S3 PUT step in FileDropZone is skipped\n * (useful for direct-upload patterns where the upload happens here).\n */\n onUpload: (\n file: File,\n metadata: { filename: string; mimeType: string; size: number },\n ) => Promise<{ uuid: string; uploadUrl: string }>;\n\n /** Optional confirm callback after S3 PUT succeeds */\n onConfirmUpload?: (uuid: string) => Promise<void>;\n\n /**\n * Deferred upload handler called during prepareForSubmit().\n * Use this for two-phase upload patterns where files are uploaded to local\n * storage on drop, but a second upload to an AI service happens on submit.\n *\n * Receives the file and localUuid (from onUpload) and should return\n * the AI service's attachment UUID.\n *\n * If not provided, prepareForSubmit() returns the UUIDs from onUpload as-is.\n */\n onSubmitUpload?: (\n file: File,\n localUuid: string,\n metadata: { filename: string; mimeType: string; size: number },\n ) => Promise<string>;\n\n /** Error handler */\n onError?: (message: string) => void;\n\n /** Maximum number of files (default: 10) */\n maxFiles?: number;\n\n /** Maximum total upload size in MB (default: 100) */\n maxTotalSizeMB?: number;\n}\n\nexport interface UseFileAttachmentsResult {\n /** Current attachment files */\n files: AttachmentFile[];\n\n /**\n * Props to spread onto FileDropZone.\n * Includes: files, onFilesChange, onUpload, onConfirmUpload, onError, maxFiles, maxTotalSizeMB\n */\n dropZoneProps: Pick<\n FileDropZoneProps,\n \"files\" | \"onFilesChange\" | \"onUpload\" | \"onConfirmUpload\" | \"onError\" | \"maxFiles\" | \"maxTotalSizeMB\"\n >;\n\n /** Remove a file by UUID */\n removeFile: (uuid: string) => void;\n\n /** Get UUIDs of ready (uploaded) attachments — for Cadra adapter pattern */\n getReadyUuids: () => string[];\n\n /** Get UUIDs of ready attachments as URLs — for direct-upload pattern where uuid IS the url */\n getReadyUrls: () => string[];\n\n /**\n * Two-phase submit: uploads ready files to the AI service via onSubmitUpload,\n * returns the AI service attachment UUIDs. Call this on Generate/Remix.\n * If onSubmitUpload is not configured, returns getReadyUuids().\n */\n prepareForSubmit: () => Promise<string[]>;\n\n /** Clear all attachments (revokes preview URLs) */\n clear: () => void;\n\n /** Whether any files are currently uploading */\n isUploading: boolean;\n\n /** Whether there are files ready to send */\n hasReadyFiles: boolean;\n\n /** Total number of files */\n fileCount: number;\n}\n\n// =============================================================================\n// HOOK IMPLEMENTATION\n// =============================================================================\n\nexport function useFileAttachments(\n options: UseFileAttachmentsOptions,\n): UseFileAttachmentsResult {\n const { onUpload, onConfirmUpload, onSubmitUpload, onError, maxFiles = 10, maxTotalSizeMB = 100 } = options;\n\n const [files, setFiles] = useState<AttachmentFile[]>([]);\n // Keep a ref in sync for synchronous reads (getReadyUuids, etc.)\n const filesRef = useRef<AttachmentFile[]>(files);\n filesRef.current = files;\n\n const onFilesChange = useCallback((newFiles: AttachmentFile[]) => {\n // Sync ref immediately so getReadyUrls/getReadyUuids always read\n // the latest state, even before React re-renders.\n filesRef.current = newFiles;\n setFiles(newFiles);\n }, []);\n\n const removeFile = useCallback((uuid: string) => {\n setFiles((prev) => {\n const file = prev.find((f) => f.uuid === uuid);\n if (file?.previewUrl) {\n URL.revokeObjectURL(file.previewUrl);\n }\n return prev.filter((f) => f.uuid !== uuid);\n });\n }, []);\n\n const getReadyUuids = useCallback((): string[] => {\n return filesRef.current\n .filter((f) => f.status === \"ready\")\n .map((f) => f.uuid);\n }, []);\n\n const getReadyUrls = useCallback((): string[] => {\n // In direct-upload patterns, uuid is the URL\n return filesRef.current\n .filter((f) => f.status === \"ready\")\n .map((f) => f.uuid);\n }, []);\n\n const prepareForSubmit = useCallback(async (): Promise<string[]> => {\n const readyFiles = filesRef.current.filter((f) => f.status === \"ready\");\n console.log(\"[useFileAttachments] prepareForSubmit - readyFiles:\", readyFiles.length, \"hasSubmitUpload:\", !!onSubmitUpload);\n if (readyFiles.length === 0) return [];\n\n // If no deferred upload handler, just return existing UUIDs\n if (!onSubmitUpload) {\n return readyFiles.map((f) => f.uuid);\n }\n\n // Compress images and upload each ready file to the AI service\n const aiUuids: string[] = [];\n for (const attachment of readyFiles) {\n try {\n // Compress images before sending to AI service (same as playground)\n let fileToSend = attachment.file;\n if (attachment.category === \"image\") {\n try {\n fileToSend = await compressImage(attachment.file);\n } catch {\n // Compression failed, use original\n }\n }\n console.log(\"[useFileAttachments] Uploading to AI service:\", attachment.file.name, \"localUuid:\", attachment.uuid.substring(0, 40));\n const aiUuid = await onSubmitUpload(\n fileToSend,\n attachment.uuid,\n { filename: fileToSend.name, mimeType: fileToSend.type, size: fileToSend.size },\n );\n console.log(\"[useFileAttachments] AI service returned UUID:\", aiUuid);\n aiUuids.push(aiUuid);\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"Submit upload failed\";\n console.error(\"[useFileAttachments] Submit upload failed for:\", attachment.file.name, msg);\n onError?.(msg);\n }\n }\n console.log(\"[useFileAttachments] prepareForSubmit result:\", aiUuids);\n return aiUuids;\n }, [onSubmitUpload, onError]);\n\n const clear = useCallback(() => {\n // Revoke all preview URLs before clearing\n for (const file of filesRef.current) {\n if (file.previewUrl) {\n URL.revokeObjectURL(file.previewUrl);\n }\n }\n setFiles([]);\n }, []);\n\n const isUploading = files.some(\n (f) => f.status === \"uploading\" || f.status === \"pending\" || f.status === \"processing\",\n );\n\n const hasReadyFiles = files.some((f) => f.status === \"ready\");\n\n const dropZoneProps: UseFileAttachmentsResult[\"dropZoneProps\"] = {\n files,\n onFilesChange,\n onUpload,\n onConfirmUpload,\n onError,\n maxFiles,\n maxTotalSizeMB,\n };\n\n return {\n files,\n dropZoneProps,\n removeFile,\n getReadyUuids,\n getReadyUrls,\n prepareForSubmit,\n clear,\n isUploading,\n hasReadyFiles,\n fileCount: files.length,\n };\n}\n"]}