import { useEffect, useState } from 'react' import CodeMirror from '@uiw/react-codemirror' import { css } from '@codemirror/lang-css' import { json, jsonParseLinter } from '@codemirror/lang-json' import { python } from '@codemirror/lang-python' import { oneDark } from '@codemirror/theme-one-dark' import { EditorView } from '@codemirror/view' import { StreamLanguage } from '@codemirror/language' import { toml as tomlMode } from '@codemirror/legacy-modes/mode/toml' import { useTheme } from '@/components/use-theme' export type Language = 'python' | 'json' | 'toml' | 'css' | 'text' interface CodeEditorProps { value: string onChange?: (value: string) => void language?: Language readOnly?: boolean height?: string minHeight?: string maxHeight?: string placeholder?: string theme?: 'light' | 'dark' className?: string } // eslint-disable-next-line @typescript-eslint/no-explicit-any const languageExtensions: Record = { python: [python()], json: [json(), jsonParseLinter()], toml: [StreamLanguage.define(tomlMode)], css: [css()], text: [], } export function CodeEditor({ value, onChange, language = 'text', readOnly = false, height = '400px', minHeight, maxHeight, placeholder, theme, className = '', }: CodeEditorProps) { const [mounted, setMounted] = useState(false) const { resolvedTheme } = useTheme() useEffect(() => { setMounted(true) }, []) if (!mounted) { return (
) } const extensions = [ ...(languageExtensions[language] || []), EditorView.lineWrapping, // 应用 JetBrains Mono 字体 EditorView.theme({ '&': { fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace', }, '.cm-content': { fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace', }, '.cm-gutters': { fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace', }, '.cm-scroller': { fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace', }, }), ] if (readOnly) { extensions.push(EditorView.editable.of(false)) } // 如果外部传了 theme prop 则使用,否则从 context 自动获取 const effectiveTheme = theme ?? resolvedTheme return (
) } export default CodeEditor