diff --git a/app/react/components/CodeEditor.tsx b/app/react/components/CodeEditor.tsx index 7afd5becb..7fb36746c 100644 --- a/app/react/components/CodeEditor.tsx +++ b/app/react/components/CodeEditor.tsx @@ -7,6 +7,8 @@ import { useMemo } from 'react'; import { createTheme } from '@uiw/codemirror-themes'; import { tags as highlightTags } from '@lezer/highlight'; +import { CopyButton } from '@@/buttons/CopyButton'; + import styles from './CodeEditor.module.css'; import { TextTip } from './Tip/TextTip'; @@ -82,7 +84,24 @@ export function CodeEditor({ return ( <> - {!!placeholder && {placeholder}} +
+
+
+ {!!placeholder && {placeholder}} +
+ +
+ + Copy to clipboard + +
+
+
['color']; + indicatorPosition?: 'left' | 'right'; } export function CopyButton({ @@ -23,12 +24,30 @@ export function CopyButton({ displayText = 'copied', className, color, + indicatorPosition = 'right', children, }: PropsWithChildren) { const { handleCopy, copiedSuccessfully } = useCopy(copyText, fadeDelay); + function copiedIndicator() { + return ( + + + {displayText && {displayText}} + + ); + } + return (
+ {indicatorPosition === 'left' && copiedIndicator()} - - - - {displayText && {displayText}} - + {indicatorPosition === 'right' && copiedIndicator()}
); } diff --git a/app/react/components/buttons/CopyButton/useCopy.ts b/app/react/components/buttons/CopyButton/useCopy.ts index edaf8ff7e..88cd17b66 100644 --- a/app/react/components/buttons/CopyButton/useCopy.ts +++ b/app/react/components/buttons/CopyButton/useCopy.ts @@ -1,6 +1,12 @@ import { useEffect, useState } from 'react'; -export function useCopy(copyText: string, fadeDelay = 1000) { +export type CopyTextType = string | (() => string); + +export function useCopy( + copyText: CopyTextType, + fadeDelay = 1000, + context: HTMLElement = document.body +) { const [copiedSuccessfully, setCopiedSuccessfully] = useState(false); useEffect(() => { @@ -15,19 +21,25 @@ export function useCopy(copyText: string, fadeDelay = 1000) { }, [copiedSuccessfully, fadeDelay]); function handleCopy() { + const text = typeof copyText === 'function' ? copyText() : copyText; + + if (!text) { + return; + } + // https://developer.mozilla.org/en-US/docs/Web/API/Clipboard // https://caniuse.com/?search=clipboard if (navigator.clipboard) { - navigator.clipboard.writeText(copyText); + navigator.clipboard.writeText(text); } else { // https://stackoverflow.com/a/57192718 const inputEl = document.createElement('textarea'); - inputEl.value = copyText; - document.body.appendChild(inputEl); + inputEl.value = text; + context.appendChild(inputEl); inputEl.select(); document.execCommand('copy'); inputEl.hidden = true; - document.body.removeChild(inputEl); + context.removeChild(inputEl); } setCopiedSuccessfully(true); }