'use client'; import { ClipboardDocumentCheckIcon, ClipboardDocumentIcon, SparklesIcon, } from '@heroicons/react/24/outline'; import { JSX, ReactNode, useEffect, useState } from 'react'; // @ts-ignore import { CopyToClipboard } from 'react-copy-to-clipboard'; // @ts-ignore import SyntaxHighlighter from 'react-syntax-highlighter'; import { CodeOutput } from './fences/code-output'; import { TerminalOutput } from './fences/terminal-output'; import { Selector } from './selector'; function resolveLanguage(lang: string) { switch (lang) { case 'ts': return 'typescript'; case 'js': return 'javascript'; default: return lang; } } function CodeWrapper(options: { fileName: string; command: string; path: string; language: string; children: string; // intentionally typed as such }): ({ children }: { children: ReactNode }) => JSX.Element { return ({ children }: { children: ReactNode }) => options.language === 'shell' ? ( ) : options.command ? ( ) : ( ); } // pre-process the highlightLines to expand ranges like // ["8-10", 19, 22] => [8,9,10,19,22] function processHighlightLines(highlightLines: any): number[] { const expandRange = (range: any) => { const [start, end] = range.split('-').map(Number); return Array.from({ length: end - start + 1 }, (_, i) => start + i); }; // Process each item in the array return ( highlightLines .map((item: any) => { if (typeof item === 'string' && item.includes('-')) { return expandRange(item); } return Number(item); }) .flat() // remove duplicates .filter( (value: any, index: number, self: number[]) => self.indexOf(value) === index ) ); } export interface FenceProps { children: string; command: string; path: string; fileName: string; highlightLines: number[]; lineGroups: Record; language: string; enableCopy: boolean; skipRescope?: boolean; selectedLineGroup?: string; onLineGroupSelectionChange?: (selection: string) => void; } export function Fence({ children, command, path, fileName, lineGroups, highlightLines, language, enableCopy, selectedLineGroup, skipRescope, onLineGroupSelectionChange, }: FenceProps) { if (highlightLines) { highlightLines = processHighlightLines(highlightLines); } function lineNumberStyle(lineNumber: number) { if ( (highlightLines && highlightLines.includes(lineNumber)) || (selectedLineGroup && lineGroups[selectedLineGroup] && lineGroups[selectedLineGroup].includes(lineNumber)) ) { return { fontSize: 0, display: 'inline-block', position: 'absolute', left: 0, right: 0, zIndex: -1, borderLeftStyle: 'solid', borderLeftWidth: 10, lineHeight: '21px', }; } return { fontSize: 0, position: 'absolute', }; } const highlightOptions = Object.keys(lineGroups).map((lineNumberKey) => ({ label: lineNumberKey, value: lineNumberKey, })); if (highlightOptions.length > 0) { highlightOptions.unshift({ label: 'No highlighting', value: '', }); } let selectedOption = highlightOptions.find((option) => option.value === selectedLineGroup) || highlightOptions[0]; const [copied, setCopied] = useState(false); useEffect(() => { let t: NodeJS.Timeout; if (copied) { t = setTimeout(() => { setCopied(false); }, 3000); } return () => { t && clearTimeout(t); }; }, [copied]); function highlightChange(item: { label: string; value: string }) { onLineGroupSelectionChange?.(item.value); } return ( {enableCopy && enableCopy === true && ( { setCopied(true); }} > {copied ? ( ) : ( )} )} {highlightOptions && highlightOptions[0] && ( )} ); }