Skip to content

Commit 7d0b77f

Browse files
committed
fix(showcase/shell-docs): copy-button surfaces clipboard failure
- Replace the silent empty `catch {}` with a proper error state: clipboard write failures now set state to "error", surface a "Copy blocked" label for 2s, and log the original error so devs can debug (permissions, insecure context, etc.) instead of the button failing invisibly. - Collapse the two booleans into a single `CopyState` so idle/copied/ error styling and aria-label stay in sync.
1 parent f119bbe commit 7d0b77f

1 file changed

Lines changed: 32 additions & 9 deletions

File tree

showcase/shell-docs/src/components/copy-button.tsx

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@
55

66
import React, { useState } from "react";
77

8+
type CopyState = "idle" | "copied" | "error";
9+
810
export function CopyButton({ text }: { text: string }) {
9-
const [copied, setCopied] = useState(false);
11+
const [state, setState] = useState<CopyState>("idle");
12+
13+
const copied = state === "copied";
14+
const error = state === "error";
15+
16+
let label: string;
17+
if (copied) label = "Copied";
18+
else if (error) label = "Copy blocked";
19+
else label = "Copy";
1020

1121
return (
1222
<button
@@ -15,27 +25,40 @@ export function CopyButton({ text }: { text: string }) {
1525
e.preventDefault();
1626
try {
1727
await navigator.clipboard.writeText(text);
18-
setCopied(true);
19-
setTimeout(() => setCopied(false), 1500);
20-
} catch {
21-
// noop — clipboard blocked by browser
28+
setState("copied");
29+
setTimeout(() => setState("idle"), 1500);
30+
} catch (err) {
31+
// Clipboard blocked (permissions, insecure context, etc.) — surface
32+
// the failure to the user so they know the button didn't work, and
33+
// log enough for devs to debug rather than silently swallowing.
34+
console.warn("[copy-button] clipboard write failed", err);
35+
setState("error");
36+
setTimeout(() => setState("idle"), 2000);
2237
}
2338
}}
24-
aria-label={copied ? "Copied" : "Copy code"}
39+
aria-label={label}
2540
style={{
2641
padding: "2px 8px",
2742
fontSize: "10px",
2843
lineHeight: 1.2,
2944
border: "1px solid var(--border)",
3045
borderRadius: "4px",
31-
background: copied ? "var(--accent-light)" : "var(--bg-surface)",
32-
color: copied ? "var(--accent)" : "var(--text-muted)",
46+
background: copied
47+
? "var(--accent-light)"
48+
: error
49+
? "var(--bg-elevated)"
50+
: "var(--bg-surface)",
51+
color: copied
52+
? "var(--accent)"
53+
: error
54+
? "var(--text)"
55+
: "var(--text-muted)",
3356
cursor: "pointer",
3457
fontFamily: "inherit",
3558
transition: "background 120ms, color 120ms",
3659
}}
3760
>
38-
{copied ? "Copied" : "Copy"}
61+
{label}
3962
</button>
4063
);
4164
}

0 commit comments

Comments
 (0)