{"version":3,"file":"ClipboardButton.cjs","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 type Props = 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\n/**\n * A control for allowing the user to copy text to their clipboard. Uses native APIs on modern browsers, falling back to the old `document.execCommand('copy')` API on other browsers. The text to be copied should be provided via `getText` prop.\n *\n * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-clipboardbutton--docs\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        {...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":["useStyles2","useState","useEffect","useRef","useCallback","t","jsxs","Fragment","InlineToast","Button","cx","jsx","Icon","css"],"mappings":"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"}