UNPKG

@grafana/ui

Version:
1 lines 6.82 kB
{"version":3,"file":"ClipboardButton.mjs","sources":["../../../../src/components/ClipboardButton/ClipboardButton.tsx"],"sourcesContent":["import { css, cx } from '@emotion/css';\nimport { useCallback, useRef, useState, useEffect } from 'react';\nimport * as React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data';\nimport { t } from '@grafana/i18n';\n\nimport { useStyles2 } from '../../themes/ThemeContext';\nimport { Button, ButtonProps } from '../Button/Button';\nimport { Icon } from '../Icon/Icon';\nimport { InlineToast } from '../InlineToast/InlineToast';\n\nexport interface Props extends ButtonProps {\n /** A function that returns text to be copied */\n getText(): string;\n /** Callback when the text has been successfully copied */\n onClipboardCopy?(copiedText: string): void;\n /** Callback when there was an error copying the text */\n onClipboardError?(copiedText: string, error: unknown): void;\n}\n\nconst SHOW_SUCCESS_DURATION = 2 * 1000;\n\nexport function ClipboardButton({\n onClipboardCopy,\n onClipboardError,\n children,\n getText,\n icon,\n variant,\n ...buttonProps\n}: Props) {\n const styles = useStyles2(getStyles);\n const [showCopySuccess, setShowCopySuccess] = useState(false);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout>;\n\n if (showCopySuccess) {\n timeoutId = setTimeout(() => {\n setShowCopySuccess(false);\n }, SHOW_SUCCESS_DURATION);\n }\n\n return () => {\n window.clearTimeout(timeoutId);\n };\n }, [showCopySuccess]);\n\n const buttonRef = useRef<null | HTMLButtonElement>(null);\n const copyTextCallback = useCallback(async () => {\n const textToCopy = getText();\n\n try {\n await copyText(textToCopy, buttonRef);\n setShowCopySuccess(true);\n onClipboardCopy?.(textToCopy);\n } catch (e) {\n onClipboardError?.(textToCopy, e);\n }\n }, [getText, onClipboardCopy, onClipboardError]);\n\n const copiedText = t('clipboard-button.inline-toast.success', 'Copied');\n return (\n <>\n {showCopySuccess && (\n <InlineToast placement=\"top\" referenceElement={buttonRef.current}>\n {copiedText}\n </InlineToast>\n )}\n\n <Button\n onClick={copyTextCallback}\n icon={icon}\n variant={showCopySuccess ? 'success' : variant}\n aria-label={showCopySuccess ? copiedText : undefined}\n {...buttonProps}\n className={cx(styles.button, showCopySuccess && styles.successButton, buttonProps.className)}\n ref={buttonRef}\n >\n {children}\n\n {showCopySuccess && (\n <div className={styles.successOverlay}>\n <Icon name=\"check\" />\n </div>\n )}\n </Button>\n </>\n );\n}\n\nconst copyText = async (text: string, buttonRef: React.MutableRefObject<HTMLButtonElement | null>) => {\n if (navigator.clipboard && window.isSecureContext) {\n return navigator.clipboard.writeText(text);\n } else {\n // Use a fallback method for browsers/contexts that don't support the Clipboard API.\n // See https://web.dev/async-clipboard/#feature-detection.\n // Use textarea so the user can copy multi-line content.\n const textarea = document.createElement('textarea');\n // Normally we'd append this to the body. However if we're inside a focus manager\n // from react-aria, we can't focus anything outside of the managed area.\n // Instead, let's append it to the button. Then we're guaranteed to be able to focus + copy.\n buttonRef.current?.appendChild(textarea);\n textarea.value = text;\n textarea.focus();\n textarea.select();\n document.execCommand('copy');\n textarea.remove();\n }\n};\n\nconst getStyles = (theme: GrafanaTheme2) => {\n return {\n button: css({\n position: 'relative',\n }),\n successButton: css({\n '> *': css({\n visibility: 'hidden',\n }),\n }),\n successOverlay: css({\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n left: 0,\n visibility: 'visible', // re-visible the overlay\n }),\n };\n};\n"],"names":[],"mappings":"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"}