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 = () => {};
|
||||
|
||||
export function ClipboardButton({ onClipboardCopy, onClipboardError, children, getText, ...buttonProps }: Props) {
|
||||
// Can be removed in 9.x
|
||||
const buttonRef = useRef<null | HTMLButtonElement>(null);
|
||||
const copyText = useCallback(() => {
|
||||
const copiedText = getText();
|
||||
const copyTextCallback = useCallback(async () => {
|
||||
const textToCopy = getText();
|
||||
// Can be removed in 9.x
|
||||
const dummyEvent: ClipboardEvent = {
|
||||
action: 'copy',
|
||||
clearSelection: dummyClearFunc,
|
||||
text: copiedText,
|
||||
text: textToCopy,
|
||||
trigger: buttonRef.current!,
|
||||
};
|
||||
navigator.clipboard
|
||||
.writeText(copiedText)
|
||||
.then(() => (onClipboardCopy?.(dummyEvent), () => onClipboardError?.(dummyEvent)));
|
||||
try {
|
||||
await copyText(textToCopy, buttonRef);
|
||||
onClipboardCopy?.(dummyEvent);
|
||||
} catch {
|
||||
onClipboardError?.(dummyEvent);
|
||||
}
|
||||
}, [getText, onClipboardCopy, onClipboardError]);
|
||||
|
||||
return (
|
||||
<Button onClick={copyText} {...buttonProps} ref={buttonRef}>
|
||||
<Button onClick={copyTextCallback} {...buttonProps} ref={buttonRef}>
|
||||
{children}
|
||||
</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