mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Add a fallback for the clipboard API (#45831)
This commit is contained in:
parent
0e7b0f16b8
commit
64ad33f31a
@ -21,24 +21,46 @@ export interface Props extends ButtonProps {
|
|||||||
const dummyClearFunc = () => {};
|
const dummyClearFunc = () => {};
|
||||||
|
|
||||||
export function ClipboardButton({ onClipboardCopy, onClipboardError, children, getText, ...buttonProps }: Props) {
|
export function ClipboardButton({ onClipboardCopy, onClipboardError, children, getText, ...buttonProps }: Props) {
|
||||||
// Can be removed in 9.x
|
|
||||||
const buttonRef = useRef<null | HTMLButtonElement>(null);
|
const buttonRef = useRef<null | HTMLButtonElement>(null);
|
||||||
const copyText = useCallback(() => {
|
const copyTextCallback = useCallback(async () => {
|
||||||
const copiedText = getText();
|
const textToCopy = getText();
|
||||||
|
// Can be removed in 9.x
|
||||||
const dummyEvent: ClipboardEvent = {
|
const dummyEvent: ClipboardEvent = {
|
||||||
action: 'copy',
|
action: 'copy',
|
||||||
clearSelection: dummyClearFunc,
|
clearSelection: dummyClearFunc,
|
||||||
text: copiedText,
|
text: textToCopy,
|
||||||
trigger: buttonRef.current!,
|
trigger: buttonRef.current!,
|
||||||
};
|
};
|
||||||
navigator.clipboard
|
try {
|
||||||
.writeText(copiedText)
|
await copyText(textToCopy, buttonRef);
|
||||||
.then(() => (onClipboardCopy?.(dummyEvent), () => onClipboardError?.(dummyEvent)));
|
onClipboardCopy?.(dummyEvent);
|
||||||
|
} catch {
|
||||||
|
onClipboardError?.(dummyEvent);
|
||||||
|
}
|
||||||
}, [getText, onClipboardCopy, onClipboardError]);
|
}, [getText, onClipboardCopy, onClipboardError]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button onClick={copyText} {...buttonProps} ref={buttonRef}>
|
<Button onClick={copyTextCallback} {...buttonProps} ref={buttonRef}>
|
||||||
{children}
|
{children}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const copyText = async (text: string, buttonRef: React.MutableRefObject<HTMLButtonElement | null>) => {
|
||||||
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
|
return navigator.clipboard.writeText(text);
|
||||||
|
} else {
|
||||||
|
// Use a fallback method for browsers/contexts that don't support the Clipboard API.
|
||||||
|
// See https://web.dev/async-clipboard/#feature-detection.
|
||||||
|
const input = document.createElement('input');
|
||||||
|
// Normally we'd append this to the body. However if we're inside a focus manager
|
||||||
|
// from react-aria, we can't focus anything outside of the managed area.
|
||||||
|
// Instead, let's append it to the button. Then we're guaranteed to be able to focus + copy.
|
||||||
|
buttonRef.current?.appendChild(input);
|
||||||
|
input.value = text;
|
||||||
|
input.focus();
|
||||||
|
input.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
input.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user