import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import { DiffEditor, type DiffEditorProps, type MonacoDiffEditor } from '@monaco-editor/react'; import { useThemeSystem } from '@/contexts/useThemeSystem'; import { ensureMonacoThemeRegistered, getMonacoThemeIdForTheme } from '@/lib/theme/monacoThemeGenerator'; interface MonacoDiffViewerProps { original: string; modified: string; language: string; renderSideBySide: boolean; allowResponsive?: boolean; readOnly?: boolean; showLineNumbers?: boolean; } export const MonacoDiffViewer: React.FC = ({ original, modified, language, renderSideBySide, allowResponsive = false, readOnly = true, showLineNumbers = true, }) => { const { currentTheme } = useThemeSystem(); const diffEditorRef = useRef(null); const themeId = useMemo( () => getMonacoThemeIdForTheme(currentTheme), [currentTheme], ); const handleBeforeMount = useCallback>( (monacoInstance) => { ensureMonacoThemeRegistered( currentTheme, monacoInstance as Parameters[1], ); }, [currentTheme], ); const options = useMemo( (): DiffEditorProps['options'] => ({ readOnly, renderSideBySide, automaticLayout: true, minimap: { enabled: false }, wordWrap: 'off', lineNumbers: showLineNumbers ? 'on' : 'off', renderIndicators: false, scrollBeyondLastLine: false, renderLineHighlight: 'none', selectionHighlight: false, occurrencesHighlight: 'off', roundedSelection: false, contextmenu: false, folding: false, glyphMargin: false, renderMarginRevertIcon: false, scrollbar: { vertical: 'visible', horizontal: 'visible', verticalScrollbarSize: 6, horizontalScrollbarSize: 6, useShadows: false, }, hover: { enabled: false, }, overviewRulerLanes: 1, useInlineViewWhenSpaceIsLimited: allowResponsive, }), [allowResponsive, readOnly, renderSideBySide, showLineNumbers], ); useEffect(() => { if (typeof window === 'undefined') return; const monaco = (window as typeof window & { monaco?: { editor: { setTheme: (id: string) => void } } }).monaco; if (!monaco?.editor?.setTheme) return; ensureMonacoThemeRegistered(currentTheme); monaco.editor.setTheme(themeId); }, [currentTheme, themeId]); useEffect(() => { const diffEditor = diffEditorRef.current; if (!diffEditor) return; const originalEditor = diffEditor.getOriginalEditor(); const modifiedEditor = diffEditor.getModifiedEditor(); const disablePopups = { hover: { enabled: false }, quickSuggestions: false, parameterHints: { enabled: false }, suggestOnTriggerCharacters: false, } as const; originalEditor.updateOptions(disablePopups); modifiedEditor.updateOptions(disablePopups); }, [themeId, readOnly, renderSideBySide]); useEffect(() => { return () => { const diffEditor = diffEditorRef.current; if (diffEditor) { try { diffEditor.dispose?.(); } catch (error) { console.warn('Error disposing DiffEditor:', error); } } diffEditorRef.current = null; }; }, []); if (typeof window === 'undefined') { return null; } return ( { diffEditorRef.current = diffEditor; const original = diffEditor.getOriginalEditor(); const modified = diffEditor.getModifiedEditor(); const disablePopups = { hover: { enabled: false }, quickSuggestions: false, parameterHints: { enabled: false }, suggestOnTriggerCharacters: false, } as const; original.updateOptions(disablePopups); modified.updateOptions(disablePopups); }} loading={null} className="monaco-diff-wrapper" /> ); };