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);
}