Aller au contenu principal

Editor Component

The Editor component is responsible for rendering the Monaco Editor, which provides a rich text editing experience for Markdown.

Props

  • value: string: The current Markdown content to be displayed in the editor.
  • onChange: (value: string) => void: A callback function that is called whenever the content of the editor changes.
  • minimapEnabled: boolean: A boolean to control the visibility of the minimap.
  • wordWrapEnabled?: boolean: An optional boolean to control word wrapping. It defaults to true.

State

  • theme: Manages the theme of the Monaco Editor, switching between 'vs-dark' and 'vs-light' based on the application's theme.

Key Features

Theme Synchronization

The editor's theme is automatically synchronized with the application's theme (light/dark mode). This is achieved using a MutationObserver that watches for changes to the class attribute of the <html> element. When the dark class is added or removed, the editor's theme is updated accordingly.

Editor Options

The component exposes props to control editor features like the minimap and word wrapping. These options are dynamically updated using a useEffect hook that listens for changes to the minimapEnabled and wordWrapEnabled props.

Code Breakdown

import { useRef, useEffect, useState } from 'react';
import MonacoEditor, { type OnMount } from '@monaco-editor/react';
import type { editor } from 'monaco-editor';

interface EditorProps {
value: string;
onChange: (value: string) => void;
minimapEnabled: boolean;
wordWrapEnabled?: boolean;
}

const Editor: React.FC<EditorProps> = ({
value,
onChange,
minimapEnabled,
wordWrapEnabled = true
}) => {
const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);
const [theme, setTheme] = useState<'vs-dark' | 'vs-light'>('vs-dark');

const handleEditorDidMount: OnMount = (editor) => {
editorRef.current = editor;
};

useEffect(() => {
if (editorRef.current) {
editorRef.current.updateOptions({
minimap: {
enabled: minimapEnabled,
},
wordWrap: wordWrapEnabled ? 'on' : 'off',
});
}
}, [minimapEnabled, wordWrapEnabled]);

useEffect(() => {
const updateTheme = () => {
const isDark = document.documentElement.classList.contains('dark');
setTheme(isDark ? 'vs-dark' : 'vs-light');
};
updateTheme();
const observer = new MutationObserver(() => updateTheme());
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
return () => observer.disconnect();
}, []);

return (
<div className="h-full w-full">
<MonacoEditor
height="100%"
defaultLanguage="markdown"
value={value}
onChange={(value) => onChange(value || '')}
onMount={handleEditorDidMount}
theme={theme}
options={{
wordWrap: wordWrapEnabled ? 'on' : 'off',
minimap: {
enabled: minimapEnabled,
},
// ... other options
}}
/>
</div>
);
};

export default Editor;
  • editorRef: A useRef hook to hold a reference to the Monaco Editor instance. This allows direct interaction with the editor's API.
  • handleEditorDidMount: A callback function that runs when the editor is first mounted. It saves the editor instance to editorRef.
  • useEffect for Options: This effect runs whenever minimapEnabled or wordWrapEnabled props change. It calls the editor's updateOptions method to apply the new settings.
  • useEffect for Theme: This effect sets up the MutationObserver to listen for theme changes on the main document and updates the editor's theme state accordingly. It also cleans up the observer when the component unmounts.