From 8fae712a4fcbd331045b994e84c509dcc852e54d Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 9 Jul 2026 00:13:59 +0000 Subject: [PATCH] Fix copy button in Assistant embed (RND-11876) Harden the code-block copy button so it works in the Assistant embed. The async Clipboard API can be unavailable or reject in cross-origin iframe / non-secure contexts, which threw an unhandled rejection and left the button showing a false success. Fall back to execCommand('copy') and only show the copied state when the write actually succeeds. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01FxDckjBnKCnQDGnuWufeKp --- .../DocumentView/CodeBlock/CopyCodeButton.tsx | 12 ++-- .../DocumentView/CodeBlock/utils.ts | 55 +++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/packages/gitbook/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx b/packages/gitbook/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx index 1ac0f94d4..1253fb16e 100644 --- a/packages/gitbook/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx +++ b/packages/gitbook/src/components/DocumentView/CodeBlock/CopyCodeButton.tsx @@ -6,7 +6,7 @@ import { Button } from '@/components/primitives'; import { t, useLanguage } from '@/intl/client'; import { type ClassValue, tcls } from '@/lib/tailwind'; -import { getCodeTextFromId } from './utils'; +import { copyToClipboard, getCodeTextFromId } from './utils'; /** * Client component to copy the code of a code block. @@ -32,15 +32,17 @@ export function CopyCodeButton(props: { codeId: string; style: ClassValue }) { }; }, [copied]); - const onClick = () => { + const onClick = async () => { const codeText = getCodeTextFromId(codeId); if (codeText === null) { return; } - navigator.clipboard.writeText(codeText); - - setCopied(true); + // Only surface the "copied" state when the write actually succeeded, so a blocked + // clipboard in the embed no longer looks like a successful copy. + if (await copyToClipboard(codeText)) { + setCopied(true); + } }; return ( diff --git a/packages/gitbook/src/components/DocumentView/CodeBlock/utils.ts b/packages/gitbook/src/components/DocumentView/CodeBlock/utils.ts index 0ce29ecc5..c20f7e37d 100644 --- a/packages/gitbook/src/components/DocumentView/CodeBlock/utils.ts +++ b/packages/gitbook/src/components/DocumentView/CodeBlock/utils.ts @@ -75,6 +75,61 @@ export function getCodeTextFromId(codeId: string): string | null { return element ? getCodeText(element) : null; } +/** + * Copy text to the clipboard in a way that survives embed contexts. + * + * The async Clipboard API (`navigator.clipboard`) is unavailable or rejects in some embed + * setups — cross-origin iframes where the `clipboard-write` permission wasn't delegated, or + * non-secure contexts — which is why copying silently failed (and logged an error) in the + * Assistant embed. We fall back to a hidden `