diff --git a/packages/devtools/client/src/App.tsx b/packages/devtools/client/src/App.tsx index 7869b93c3ce..ce9293fe0ea 100644 --- a/packages/devtools/client/src/App.tsx +++ b/packages/devtools/client/src/App.tsx @@ -484,6 +484,7 @@ export default function App() { width: '32px', }} title={isDark ? 'Switch to light mode' : 'Switch to dark mode'} + aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'} > {isDark ? '🌙' : '☀️'} @@ -1072,6 +1073,7 @@ function NetworkView({ padding: '0 8px', }} title="Group by Domain" + aria-label="Group by Domain" > 📂 @@ -1433,6 +1435,15 @@ function BodyView({ t: ThemeColors; }) { const [mode, setMode] = useState<'json' | 'raw'>('json'); + const [copied, setCopied] = useState(false); + const copyTimeoutRef = useRef | null>(null); + + useEffect(() => { + return () => { + if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current); + }; + }, []); + const hasChunks = chunks && chunks.length > 0; const safeContent = hasChunks ? chunks.map((c) => c.data).join('') @@ -1446,9 +1457,16 @@ function BodyView({ }; const copyJson = () => { - navigator.clipboard.writeText(getFormattedJson()).catch(() => { - // Clipboard API unavailable — silently ignore - }); + navigator.clipboard + .writeText(getFormattedJson()) + .then(() => { + setCopied(true); + if (copyTimeoutRef.current) clearTimeout(copyTimeoutRef.current); + copyTimeoutRef.current = setTimeout(() => setCopied(false), 2000); + }) + .catch(() => { + // Clipboard API unavailable — silently ignore + }); }; const downloadJson = () => { @@ -1513,13 +1531,42 @@ function BodyView({ ))}
- -