Files
deer-flow/frontend/src/components/workspace/copy-button.tsx
T
Admire f68bcb771c fix(frontend): guard message copy clipboard access (#3211)
* fix(frontend): guard message copy clipboard access

* fix(frontend): reuse clipboard guard across copy actions
2026-05-26 09:37:51 +08:00

51 lines
1.3 KiB
TypeScript

import { CheckIcon, CopyIcon } from "lucide-react";
import { useCallback, useState, type ComponentProps } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { writeTextToClipboard } from "@/core/clipboard";
import { useI18n } from "@/core/i18n/hooks";
import { Tooltip } from "./tooltip";
export function CopyButton({
clipboardData,
...props
}: ComponentProps<typeof Button> & {
clipboardData: string;
}) {
const { t } = useI18n();
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(() => {
void (async () => {
const didCopy = await writeTextToClipboard(clipboardData);
if (!didCopy) {
toast.error(t.clipboard.failedToCopyToClipboard);
return;
}
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})().catch(() => {
toast.error(t.clipboard.failedToCopyToClipboard);
});
}, [clipboardData, t.clipboard.failedToCopyToClipboard]);
return (
<Tooltip content={t.clipboard.copyToClipboard}>
<Button
size="icon-sm"
type="button"
variant="ghost"
onClick={handleCopy}
{...props}
>
{copied ? (
<CheckIcon className="text-green-500" size={12} />
) : (
<CopyIcon size={12} />
)}
</Button>
</Tooltip>
);
}