import React from 'react'; import {useThemeType} from '@gravity-ui/uikit'; import type {ClipboardButtonProps} from '../ClipboardButton/ClipboardButton'; import {ClipboardButton} from '../ClipboardButton/ClipboardButton'; import {b} from './shared'; import {highlightCode} from './shikiHighlighter'; import type {Language} from './types'; import './YDBSyntaxHighlighter.scss'; export interface WithClipboardButtonProp extends ClipboardButtonProps { alwaysVisible?: boolean; } export type YDBSyntaxHighlighterProps = { text: string; language: Language; className?: string; transparentBackground?: boolean; withClipboardButton?: WithClipboardButtonProp; }; export function YDBSyntaxHighlighter({ text, language, className, transparentBackground = true, withClipboardButton, }: YDBSyntaxHighlighterProps) { const [highlightedHtml, setHighlightedHtml] = React.useState(''); const [isLoading, setIsLoading] = React.useState(true); const themeType = useThemeType(); React.useEffect(() => { let cancelled = false; setIsLoading(true); setHighlightedHtml(''); async function highlight() { try { const html = await highlightCode(text, language, themeType); if (!cancelled) { setHighlightedHtml(html); } } catch (error) { console.error('Failed to highlight code:', error); } finally { if (!cancelled) { setIsLoading(false); } } } // Start highlighting in next render cycle, when content is initially rendered // For big queries highlighting may take some time, so we show not highlighted component first const timeoutId = setTimeout(() => { highlight(); }, 0); return () => { cancelled = true; clearTimeout(timeoutId); }; }, [text, language, themeType]); const renderCopyButton = () => { if (!withClipboardButton) { return null; } const {alwaysVisible, copyText, ...rest} = withClipboardButton; return (
e.stopPropagation()}>
); }; let paddingStyles = {}; if (withClipboardButton?.alwaysVisible) { if (withClipboardButton.withLabel === false) { paddingStyles = {paddingRight: 40}; } else { paddingStyles = {paddingRight: 80}; } } const containerStyle: React.CSSProperties = { ...paddingStyles, }; if (transparentBackground) { containerStyle.background = 'transparent'; } return (
{renderCopyButton()} {isLoading || !highlightedHtml ? (
                        {text}
                    
) : (
)}
); }