= ({ block, onHover, onLeave, isHovere
title={copied ? 'Copied!' : 'Copy code'}
>
{copied ? (
-
+
) : (
-
+
)}
diff --git a/packages/ui/components/icons/copyIcons.tsx b/packages/ui/components/icons/copyIcons.tsx
new file mode 100644
index 00000000..fdbe7fd1
--- /dev/null
+++ b/packages/ui/components/icons/copyIcons.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+
+/**
+ * Shared copy/clipboard icons (Copy / Check).
+ *
+ * These SVGs were previously duplicated across 10+ files. Centralizing them
+ * here keeps the iconography consistent and makes future glyph tweaks trivial.
+ *
+ * Each icon takes an optional `className` so callers control sizing:
+ * - inline actions (e.g. inside annotation toolbar): w-3 h-3
+ * - standalone buttons (e.g. file header "Copy Diff"): w-4 h-4
+ */
+
+interface IconProps {
+ className?: string;
+}
+
+export const CopyIcon: React.FC = ({ className = 'w-3 h-3' }) => (
+
+);
+
+export const CheckIcon: React.FC = ({ className = 'w-3 h-3' }) => (
+
+);
diff --git a/packages/ui/hooks/useCopyToClipboard.ts b/packages/ui/hooks/useCopyToClipboard.ts
new file mode 100644
index 00000000..b9bb663e
--- /dev/null
+++ b/packages/ui/hooks/useCopyToClipboard.ts
@@ -0,0 +1,30 @@
+import { useState, useCallback } from 'react';
+
+/**
+ * Centralizes the clipboard + copied state + timeout pattern that was
+ * previously duplicated across 15+ files with inconsistent timeout values
+ * (1500ms vs 2000ms). Default timeout is 1500ms.
+ *
+ * Returns `reset` for callers that need to clear the copied state imperatively
+ * (e.g. when the annotation target element changes).
+ */
+export function useCopyToClipboard(timeoutMs = 1500) {
+ const [copied, setCopied] = useState(false);
+
+ const copy = useCallback(
+ async (text: string) => {
+ try {
+ await navigator.clipboard.writeText(text);
+ setCopied(true);
+ setTimeout(() => setCopied(false), timeoutMs);
+ } catch {
+ // Clipboard API may not be available in some environments
+ }
+ },
+ [timeoutMs],
+ );
+
+ const reset = useCallback(() => setCopied(false), []);
+
+ return { copied, copy, reset };
+}