import React, { useEffect, useRef, useState } from 'react'; import type * as Monaco from 'monaco-editor'; import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; const configureMonacoWorkers = () => { // @ts-ignore self.MonacoEnvironment = { getWorker(_: string, label: string) { if (label === 'typescript' || label === 'javascript') { return new tsWorker(); } if (label === 'json') { return new jsonWorker(); } return new editorWorker(); } }; }; interface TaskCodeEditorProps { source: string; className?: string; onCodeChange: (value: string) => void; schema?: any; } const configureTypeScript = async (monacoInstance: typeof Monaco) => { // 1. Configure TypeScript compiler options monacoInstance.languages.typescript.typescriptDefaults.setCompilerOptions({ target: monacoInstance.languages.typescript.ScriptTarget.ESNext, moduleResolution: monacoInstance.languages.typescript.ModuleResolutionKind.NodeJs, module: monacoInstance.languages.typescript.ModuleKind.ESNext, allowNonTsExtensions: true, allowJs: true, strict: false, noImplicitAny: false, jsx: monacoInstance.languages.typescript.JsxEmit.React, esModuleInterop: true }); // 2. Load and add type definitions let moduleDefinitions: string; try { const response = await fetch('/index.d.ts'); moduleDefinitions = await response.text(); // Register the module monacoInstance.languages.typescript.typescriptDefaults.addExtraLib( moduleDefinitions, 'file:///node_modules/l33t-lib/index.d.ts' ); } catch (error) { console.error('Failed to load type definitions:', error); alert('Failed to load type definitions: '+ error) } }; const TaskCodeEditor: React.FC = ({ source, className, onCodeChange, schema }) => { const editorRef = useRef(null); const containerRef = useRef(null); const disposablesRef = useRef([]); const [monacoInstance, setMonacoInstance] = useState(null); useEffect(() => { if (typeof window === 'undefined') return; let mounted = true; const loadMonaco = async () => { configureMonacoWorkers(); try { const monaco = await import('monaco-editor'); if (mounted) { setMonacoInstance(monaco); } } catch (error) { console.error('Failed to load Monaco Editor:', error); } }; loadMonaco(); return () => { mounted = false; }; }, []); useEffect(() => { if (!containerRef.current || !monacoInstance) return; const initializeEditor = async () => { if (!containerRef.current) return; // Configure TypeScript await configureTypeScript(monacoInstance); // Create the model for user script const scriptUri = monacoInstance.Uri.parse('file:///src/script.ts'); let model = monacoInstance.editor.getModel(scriptUri); if (!model) { model = monacoInstance.editor.createModel( source, 'typescript', scriptUri ); } else { model.setValue(source); } // Create editor if (!containerRef.current) return; editorRef.current = monacoInstance.editor.create(containerRef.current, { model: model, language: 'typescript', theme: 'vs-dark', automaticLayout: true, minimap: { enabled: false }, scrollBeyondLastLine: false, fontSize: 14, lineNumbers: 'on', folding: true, glyphMargin: true, lineDecorationsWidth: 0, lineNumbersMinChars: 3, }); // Handle changes const changeDisposable = editorRef.current.onDidChangeModelContent(() => { if (editorRef.current) { onCodeChange(editorRef.current.getValue()); } }); disposablesRef.current.push(changeDisposable); }; initializeEditor(); return () => { disposablesRef.current.forEach(d => d.dispose()); if (editorRef.current) { editorRef.current.dispose(); } }; }, [monacoInstance, source]); if (!monacoInstance) { return (
Loading editor...
); } return (
); }; export default TaskCodeEditor;