From 03d3095ad8e9dbbb1c12e3a96e7c8b5ae899603f Mon Sep 17 00:00:00 2001 From: teeverc <72298507+teeverc@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:00:30 -0700 Subject: [PATCH] feat: Add clipboard image paste support (#651) --- components/multimodal-input.tsx | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/components/multimodal-input.tsx b/components/multimodal-input.tsx index 9c0ee87..65064d5 100644 --- a/components/multimodal-input.tsx +++ b/components/multimodal-input.tsx @@ -231,6 +231,60 @@ function PureMultimodalInput({ }, [setAttachments, uploadFile] ); + + const handlePaste = useCallback( + async (event: ClipboardEvent) => { + const items = event.clipboardData?.items; + if (!items) return; + + const imageItems = Array.from(items).filter((item) => + item.type.startsWith('image/'), + ); + + if (imageItems.length === 0) return; + + // Prevent default paste behavior for images + event.preventDefault(); + + setUploadQueue((prev) => [...prev, 'Pasted image']); + + try { + const uploadPromises = imageItems.map(async (item) => { + const file = item.getAsFile(); + if (!file) return; + return uploadFile(file); + }); + + const uploadedAttachments = await Promise.all(uploadPromises); + const successfullyUploadedAttachments = uploadedAttachments.filter( + (attachment) => + attachment !== undefined && + attachment.url !== undefined && + attachment.contentType !== undefined, + ); + + setAttachments((curr) => [ + ...curr, + ...(successfullyUploadedAttachments as Attachment[]), + ]); + } catch (error) { + console.error('Error uploading pasted images:', error); + toast.error('Failed to upload pasted image(s)'); + } finally { + setUploadQueue([]); + } + }, + [setAttachments], + ); + + // Add paste event listener to textarea + useEffect(() => { + const textarea = textareaRef.current; + if (!textarea) return; + + textarea.addEventListener('paste', handlePaste); + return () => textarea.removeEventListener('paste', handlePaste); + }, [handlePaste]); return (