// Prism components need to be imported after Prism // eslint-disable-next-line simple-import-sort/imports import Prism from 'prismjs'; import 'prismjs/components/prism-bash.min'; import {useEffect, useRef, useState} from 'react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import {IconCopy} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; interface CodeSnippetProps { children: string; language: keyof typeof Prism.languages; className?: string; dark?: boolean; filename?: string; hideCopyButton?: boolean; onCopy?: (copiedCode: string) => void; } export function CodeSnippet({ children, language, dark, filename, hideCopyButton, onCopy, className, }: CodeSnippetProps) { const ref = useRef(null); useEffect( () => void (ref.current && Prism.highlightElement(ref.current, false)), [children] ); const [tooltipState, setTooltipState] = useState<'copy' | 'copied' | 'error'>('copy'); const handleCopy = () => { navigator.clipboard .writeText(children) .then(() => { setTooltipState('copied'); }) .catch(() => { setTooltipState('error'); }); onCopy?.(children); }; const tooltipTitle = tooltipState === 'copy' ? t('Copy') : tooltipState === 'copied' ? t('Copied') : t('Unable to copy'); return (
{filename && {filename}} {!hideCopyButton && ( setTooltipState('copy')} > )}
        
          {children}
        
      
); } const Wrapper = styled('div')` position: relative; background: ${p => p.theme.backgroundSecondary}; border-radius: ${p => p.theme.borderRadius}; pre { margin: 0; } `; const Header = styled('div')<{hasFileName: boolean}>` display: flex; justify-content: space-between; align-items: center; font-family: ${p => p.theme.text.familyMono}; font-size: ${p => p.theme.codeFontSize}; color: ${p => p.theme.headingColor}; font-weight: 600; z-index: 2; ${p => p.hasFileName ? ` padding: ${space(0.5)} 0; margin: 0 ${space(0.5)} 0 ${space(2)}; border-bottom: solid 1px ${p.theme.innerBorder}; ` : ` justify-content: flex-end; position: absolute; top: 0; right: 0; width: max-content; height: max-content; max-height: 100%; padding: ${space(1)}; `} `; const FileName = styled('p')` ${p => p.theme.overflowEllipsis} margin: 0; `; const CopyButton = styled(Button)` color: ${p => p.theme.subText}; transition: opacity 0.1s ease-out; opacity: 0; p + &, /* if preceded by FileName */ div:hover > div > &, /* if Wrapper is hovered */ &.focus-visible { opacity: 1; } `;