|
1 | 1 | import { Textarea, UnstyledButton } from "@mantine/core"; |
2 | 2 | import { useCallback, useEffect, useMemo, useRef } from "react"; |
| 3 | +import type { ClipboardEvent } from "react"; |
3 | 4 | import { toast } from "sonner"; |
4 | 5 | import { twJoin } from "tailwind-merge"; |
5 | 6 | import { useImmer } from "use-immer"; |
@@ -176,6 +177,28 @@ const ChatView = ({ |
176 | 177 | setAttachments([]); |
177 | 178 | }; |
178 | 179 |
|
| 180 | + const handlePaste = useCallback( |
| 181 | + (event: ClipboardEvent<HTMLTextAreaElement>) => { |
| 182 | + const clipboardData = event.clipboardData; |
| 183 | + const imageItems = Array.from(clipboardData?.items ?? []).filter( |
| 184 | + (item) => item.kind === "file" && item.type.startsWith("image/"), |
| 185 | + ); |
| 186 | + if (imageItems.length === 0) { |
| 187 | + return; |
| 188 | + } |
| 189 | + if (!clipboardData?.getData("text/plain")) { |
| 190 | + event.preventDefault(); |
| 191 | + } |
| 192 | + for (const item of imageItems) { |
| 193 | + const file = item.getAsFile(); |
| 194 | + if (file) { |
| 195 | + void handleFileInput(file); |
| 196 | + } |
| 197 | + } |
| 198 | + }, |
| 199 | + [handleFileInput], |
| 200 | + ); |
| 201 | + |
179 | 202 | return ( |
180 | 203 | <div className="flex flex-col h-full min-h-0"> |
181 | 204 | <div |
@@ -256,6 +279,7 @@ const ChatView = ({ |
256 | 279 | onChange={(event) => { |
257 | 280 | setPrompt(event.target.value); |
258 | 281 | }} |
| 282 | + onPaste={handlePaste} |
259 | 283 | onCompositionStart={() => { |
260 | 284 | isComposing.current = true; |
261 | 285 | }} |
|
0 commit comments