import React, { useEffect, useRef, useImperativeHandle } from "react"; import classNames from "classnames"; import { useConfig } from "../util"; import { StyledProps } from "../_type"; import { useDefaultValue } from "../form"; import { forwardRefWithStatics } from "../_util/forward-ref-with-statics"; import { MonacoDiffEditor } from "./MonacoDiffEditor"; import { useIsomorphicLayoutEffect } from "../_util/use-isomorphic-layout-effect"; type Obj = Record; export interface MonacoEditorProps extends StyledProps { /** * [monaco-editor](https://microsoft.github.io/monaco-editor/index.html) * * @docType typeof monaco */ monaco: M; /** * 编辑器高度 * * @default "100%" */ height?: React.CSSProperties["height"]; /** * 编辑器宽度 * * @default "100%" */ width?: React.CSSProperties["width"]; /** * 编辑器初始语言 */ language?: string; /** * 编辑器初始设置,详见 [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html) * * @docType monaco.editor.IStandaloneEditorConstructionOptions */ options?: Parameters[1]; /** * override language service, like editorService, [storageService](https://github.com/microsoft/vscode/blob/ff1e16eebb93af79fd6d7af1356c4003a120c563/src/vs/platform/storage/common/storage.ts#L37) ,详见 [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IEditorOverrideServices.html) * * @docType monaco.editor.IEditorOverrideServices * @since 2.7.4 */ override?: Parameters[2]; /** * 编辑器默认文本 */ defaultValue?: string; /** * 编辑器文本 */ value?: string; /** * 编辑器文本变化回调 */ onChange?: ( value: string, context: { event: any; } ) => void; } export const MonacoEditor = forwardRefWithStatics( function MonacoEditor( { monaco, options = {}, override = {}, language, className, style, width, height, ...props }: MonacoEditorProps, ref: React.Ref<{ editor: ReturnType; }> ) { const { classPrefix } = useConfig(); const { value, onChange } = useDefaultValue(props as any, ""); const containerRef = useRef(null); const editorRef = useRef>(null); const changeEventRef = useRef(null); // https://github.com/react-monaco-editor/react-monaco-editor/blob/master/src/editor.js const preventTriggerChangeEvent = useRef(false); useEffect(() => { if (editorRef.current) { editorRef.current.layout(); } }, [width, height]); useEffect(() => { if (editorRef.current) { const model = editorRef.current.getModel(); monaco.editor.setModelLanguage(model, language); } }, [language, monaco]); useEffect(() => { if (editorRef.current) { const editor = editorRef.current; const model = editor.getModel(); if (value != null && value !== model.getValue()) { preventTriggerChangeEvent.current = true; editor.pushUndoStop(); model.pushEditOperations( [], [ { range: model.getFullModelRange(), text: value, }, ], undefined ); editor.pushUndoStop(); preventTriggerChangeEvent.current = false; } } }, [value, monaco]); useIsomorphicLayoutEffect(() => { const editor = monaco.editor.create( containerRef.current, { ...(options as any), value, language, }, override ); editorRef.current = editor; changeEventRef.current = editor.onDidChangeModelContent(event => { if (!preventTriggerChangeEvent.current) { onChange(editor.getValue(), { event }); } }); return () => { editorRef.current.dispose(); const model = editorRef.current.getModel(); if (model) { model.dispose(); } if (changeEventRef.current) { changeEventRef.current.dispose(); } }; }, []); // eslint-disable-line react-hooks/exhaustive-deps useImperativeHandle(ref, () => ({ editor: editorRef.current, })); return (
); }, { DiffEditor: MonacoDiffEditor, } ) as (( props: MonacoEditorProps & { ref?: React.Ref<{ editor: ReturnType; }>; } ) => React.ReactElement) & { DiffEditor: typeof MonacoDiffEditor; displayName: string; }; MonacoEditor.displayName = "MonacoEditor";