import { Children, FC } from 'react' import CopyToClipboard from 'react-copy-to-clipboard' import { Light as SyntaxHighlighter } from 'react-syntax-highlighter' import monokaiCustomTheme from './CodeBlock.utils' import { Button, IconCheck, IconCopy } from 'ui' import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript' import ts from 'react-syntax-highlighter/dist/cjs/languages/hljs/typescript' import csharp from 'react-syntax-highlighter/dist/cjs/languages/hljs/csharp' import py from 'react-syntax-highlighter/dist/cjs/languages/hljs/python' import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql' import bash from 'react-syntax-highlighter/dist/cjs/languages/hljs/bash' import dart from 'react-syntax-highlighter/dist/cjs/languages/hljs/dart' import json from 'react-syntax-highlighter/dist/cjs/languages/hljs/json' import { useState } from 'react' import { useTheme } from 'common/Providers' interface Props { title?: string language: 'js' | 'jsx' | 'sql' | 'py' | 'bash' | 'ts' | 'dart' | 'json' | 'csharp' linesToHighlight?: number[] hideCopy?: boolean hideLineNumbers?: boolean className?: string value?: string children?: string } const CodeBlock: FC = ({ title, language, linesToHighlight = [], className, value, children, hideCopy = false, hideLineNumbers = false, }) => { const { isDarkMode } = useTheme() const monokaiTheme = monokaiCustomTheme(isDarkMode) const [copied, setCopied] = useState(false) const handleCopy = () => { setCopied(true) setTimeout(() => { setCopied(false) }, 1000) } // Extract string when `children` has a single string node const childrenArray = Children.toArray(children) const [singleChild] = childrenArray.length === 1 ? childrenArray : [] const singleString = typeof singleChild === 'string' ? singleChild : undefined let codeValue = value ?? singleString ?? children codeValue = codeValue?.trimEnd?.() ?? codeValue // check the length of the string inside the tag // if it's fewer than 70 characters, add a white-space: pre so it doesn't wrap const shortCodeBlockClasses = typeof codeValue === 'string' && codeValue.length < 70 ? 'short-inline-codeblock' : '' let lang = language ? language : className ? className.replace('language-', '') : 'js' // force jsx to be js highlighted if (lang === 'jsx') lang = 'js' SyntaxHighlighter.registerLanguage('js', js) SyntaxHighlighter.registerLanguage('ts', ts) SyntaxHighlighter.registerLanguage('py', py) SyntaxHighlighter.registerLanguage('sql', sql) SyntaxHighlighter.registerLanguage('bash', bash) SyntaxHighlighter.registerLanguage('dart', dart) SyntaxHighlighter.registerLanguage('csharp', csharp) SyntaxHighlighter.registerLanguage('json', json) const large = false // don't show line numbers if bash == lang if (lang !== 'bash') hideLineNumbers = true const showLineNumbers = !hideLineNumbers return ( <> {title && (
{title.replace(/%20/g, ' ')}
)} {className ? (
{ if (linesToHighlight.includes(lineNumber)) { return { style: { display: 'block', backgroundColor: 'var(--colors-scale6)' }, } } return {} }} lineNumberContainerStyle={{ paddingTop: '128px', }} lineNumberStyle={{ minWidth: '44px', paddingLeft: '4px', paddingRight: '4px', marginRight: '12px', color: '#828282', textAlign: 'center', fontSize: large ? 14 : 12, paddingTop: '4px', paddingBottom: '4px', }} > {codeValue} {!hideCopy && (value || children) && className ? (
{/* // @ts-ignore */}
) : null}
) : ( {value || children} )} ) } export default CodeBlock