diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 07b8022abe..7bd72d7a93 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -58,6 +58,27 @@ import { animate } from "motion" import { useLocation } from "@solidjs/router" import { attached, inline, kind } from "./message-file" +async function writeClipboard(text: string): Promise { + const body = typeof document === "undefined" ? undefined : document.body + if (body) { + const textarea = document.createElement("textarea") + textarea.value = text + textarea.setAttribute("readonly", "") + textarea.style.position = "fixed" + textarea.style.opacity = "0" + textarea.style.pointerEvents = "none" + body.appendChild(textarea) + textarea.select() + const copied = document.execCommand("copy") + body.removeChild(textarea) + if (copied) return true + } + + const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard + if (!clipboard?.writeText) return false + return clipboard.writeText(text).then(() => true, () => false) +} + function ShellSubmessage(props: { text: string; animate?: boolean }) { let widthRef: HTMLSpanElement | undefined let valueRef: HTMLSpanElement | undefined @@ -1064,9 +1085,10 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp const handleCopy = async () => { const content = text() if (!content) return - await navigator.clipboard.writeText(content) - setState("copied", true) - setTimeout(() => setState("copied", false), 2000) + if (await writeClipboard(content)) { + setState("copied", true) + setTimeout(() => setState("copied", false), 2000) + } } const revert = () => { @@ -1490,9 +1512,10 @@ PART_MAPPING["text"] = function TextPartDisplay(props) { const handleCopy = async () => { const content = text() if (!content) return - await navigator.clipboard.writeText(content) - setCopied(true) - setTimeout(() => setCopied(false), 2000) + if (await writeClipboard(content)) { + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } } return ( @@ -1834,9 +1857,10 @@ ToolRegistry.register({ const handleCopy = async () => { const content = text() if (!content) return - await navigator.clipboard.writeText(content) - setCopied(true) - setTimeout(() => setCopied(false), 2000) + if (await writeClipboard(content)) { + setCopied(true) + setTimeout(() => setCopied(false), 2000) + } } return (