diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx
index 15b2666280..8df6f596c5 100644
--- a/webview-ui/src/components/chat/ChatRow.tsx
+++ b/webview-ui/src/components/chat/ChatRow.tsx
@@ -2,6 +2,7 @@ import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-u
import deepEqual from "fast-deep-equal"
import React, { memo, useEffect, useMemo, useRef, useState } from "react"
import { useSize } from "react-use"
+import { useCopyToClipboard } from "../../utils/clipboard"
import {
ClineApiReqInfo,
ClineAskUseMcpServer,
@@ -985,6 +986,7 @@ export const ProgressIndicator = () => (
const Markdown = memo(({ markdown, partial }: { markdown?: string; partial?: boolean }) => {
const [isHovering, setIsHovering] = useState(false)
+ const { copyWithFeedback } = useCopyToClipboard(200) // shorter feedback duration for copy button flash
return (
{
- navigator.clipboard.writeText(markdown)
- // Flash the button background briefly to indicate success
- const button = document.activeElement as HTMLElement
- if (button) {
- button.style.background = "var(--vscode-button-background)"
- setTimeout(() => {
- button.style.background = ""
- }, 200)
+ onClick={async () => {
+ const success = await copyWithFeedback(markdown)
+ if (success) {
+ const button = document.activeElement as HTMLElement
+ if (button) {
+ button.style.background = "var(--vscode-button-background)"
+ setTimeout(() => {
+ button.style.background = ""
+ }, 200)
+ }
}
}}
title="Copy as markdown">
diff --git a/webview-ui/src/components/history/HistoryPreview.tsx b/webview-ui/src/components/history/HistoryPreview.tsx
index 562c110097..7825844e70 100644
--- a/webview-ui/src/components/history/HistoryPreview.tsx
+++ b/webview-ui/src/components/history/HistoryPreview.tsx
@@ -1,8 +1,9 @@
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { vscode } from "../../utils/vscode"
-import { memo, useState } from "react"
+import { memo } from "react"
import { formatLargeNumber } from "../../utils/format"
+import { useCopyToClipboard } from "../../utils/clipboard"
type HistoryPreviewProps = {
showHistoryView: () => void
@@ -10,18 +11,7 @@ type HistoryPreviewProps = {
const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
const { taskHistory } = useExtensionState()
- const [showCopyModal, setShowCopyModal] = useState(false)
-
- const handleCopyTask = async (e: React.MouseEvent, task: string) => {
- e.stopPropagation()
- try {
- await navigator.clipboard.writeText(task)
- setShowCopyModal(true)
- setTimeout(() => setShowCopyModal(false), 2000)
- } catch (error) {
- console.error("Failed to copy to clipboard:", error)
- }
- }
+ const { showCopyFeedback, copyWithFeedback } = useCopyToClipboard()
const handleHistorySelect = (id: string) => {
vscode.postMessage({ type: "showTaskWithId", text: id })
}
@@ -43,7 +33,7 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
return (
- {showCopyModal &&
Prompt Copied to Clipboard
}
+ {showCopyFeedback &&
Prompt Copied to Clipboard
}
- {showCopyModal &&
Prompt Copied to Clipboard
}
+ {showCopyFeedback &&
Prompt Copied to Clipboard
}
{
title="Copy Prompt"
className="copy-button"
data-appearance="icon"
- onClick={(e) => handleCopyTask(e, item.task)}>
+ onClick={(e) => copyWithFeedback(item.task, e)}>