diff --git a/web/app/components/develop/code.tsx b/web/app/components/develop/code.tsx index c1fbaa1cf8..7716cd4c93 100644 --- a/web/app/components/develop/code.tsx +++ b/web/app/components/develop/code.tsx @@ -10,6 +10,7 @@ import { import { Tab } from '@headlessui/react' import { Tag } from './tag' import classNames from '@/utils/classnames' +import { writeTextToClipboard } from '@/utils/clipboard' const languageNames = { js: 'JavaScript', @@ -71,7 +72,7 @@ function CopyButton({ code }: { code: string }) { : 'bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5', )} onClick={() => { - window.navigator.clipboard.writeText(code).then(() => { + writeTextToClipboard(code).then(() => { setCopyCount(count => count + 1) }) }} diff --git a/web/utils/clipboard.ts b/web/utils/clipboard.ts new file mode 100644 index 0000000000..8e7a4495b3 --- /dev/null +++ b/web/utils/clipboard.ts @@ -0,0 +1,35 @@ +export async function writeTextToClipboard(text: string): Promise { + if (navigator.clipboard && navigator.clipboard.writeText) + return navigator.clipboard.writeText(text) + + return fallbackCopyTextToClipboard(text) +} + +async function fallbackCopyTextToClipboard(text: string): Promise { + const textArea = document.createElement('textarea') + textArea.value = text + textArea.style.position = 'fixed' // Avoid scrolling to bottom + document.body.appendChild(textArea) + textArea.focus() + textArea.select() + try { + const successful = document.execCommand('copy') + if (successful) + return Promise.resolve() + + return Promise.reject(new Error('document.execCommand failed')) + } + catch (err) { + return Promise.reject(convertAnyToError(err)) + } + finally { + document.body.removeChild(textArea) + } +} + +function convertAnyToError(err: any): Error { + if (err instanceof Error) + return err + + return new Error(`Caught: ${String(err)}`) +}