UNPKG

@monaco-editor/react

Version:

Monaco Editor for React - use the monaco-editor in any React application without needing to use webpack (or rollup/parcel/etc) configuration files / plugins

180 lines (160 loc) 5.58 kB
import loader from '@monaco-editor/loader'; import React, { useState, useRef, useCallback, useEffect } from 'react'; import PropTypes from 'prop-types'; import MonacoContainer from '../MonacoContainer/index.js'; import useMount from '../hooks/useMount/index.js'; import useUpdate from '../hooks/useUpdate/index.js'; import { getOrCreateModel, noop } from '../utils/index.js'; function DiffEditor({ original, modified, language, originalLanguage, modifiedLanguage, /* === */ originalModelPath, modifiedModelPath, keepCurrentOriginalModel, keepCurrentModifiedModel, theme, loading, options, /* === */ height, width, className, wrapperProps, /* === */ beforeMount, onMount }) { const [isEditorReady, setIsEditorReady] = useState(false); const [isMonacoMounting, setIsMonacoMounting] = useState(true); const editorRef = useRef(null); const monacoRef = useRef(null); const containerRef = useRef(null); const onMountRef = useRef(onMount); const beforeMountRef = useRef(beforeMount); useMount(() => { const cancelable = loader.init(); cancelable.then(monaco => (monacoRef.current = monaco) && setIsMonacoMounting(false)).catch(error => (error === null || error === void 0 ? void 0 : error.type) !== 'cancelation' && console.error('Monaco initialization: error:', error)); return () => editorRef.current ? disposeEditor() : cancelable.cancel(); }); useUpdate(() => { const modifiedEditor = editorRef.current.getModifiedEditor(); if (modifiedEditor.getOption(monacoRef.current.editor.EditorOption.readOnly)) { modifiedEditor.setValue(modified); } else { if (modified !== modifiedEditor.getValue()) { modifiedEditor.executeEdits('', [{ range: modifiedEditor.getModel().getFullModelRange(), text: modified, forceMoveMarkers: true }]); modifiedEditor.pushUndoStop(); } } }, [modified], isEditorReady); useUpdate(() => { editorRef.current.getModel().original.setValue(original); }, [original], isEditorReady); useUpdate(() => { const { original, modified } = editorRef.current.getModel(); monacoRef.current.editor.setModelLanguage(original, originalLanguage || language); monacoRef.current.editor.setModelLanguage(modified, modifiedLanguage || language); }, [language, originalLanguage, modifiedLanguage], isEditorReady); useUpdate(() => { monacoRef.current.editor.setTheme(theme); }, [theme], isEditorReady); useUpdate(() => { editorRef.current.updateOptions(options); }, [options], isEditorReady); const setModels = useCallback(() => { beforeMountRef.current(monacoRef.current); const originalModel = getOrCreateModel(monacoRef.current, original, originalLanguage || language, originalModelPath); const modifiedModel = getOrCreateModel(monacoRef.current, modified, modifiedLanguage || language, modifiedModelPath); editorRef.current.setModel({ original: originalModel, modified: modifiedModel }); }, [language, modified, modifiedLanguage, original, originalLanguage, originalModelPath, modifiedModelPath]); const createEditor = useCallback(() => { editorRef.current = monacoRef.current.editor.createDiffEditor(containerRef.current, { automaticLayout: true, ...options }); setModels(); monacoRef.current.editor.setTheme(theme); setIsEditorReady(true); }, [options, theme, setModels]); useEffect(() => { if (isEditorReady) { onMountRef.current(editorRef.current, monacoRef.current); } }, [isEditorReady]); useEffect(() => { !isMonacoMounting && !isEditorReady && createEditor(); }, [isMonacoMounting, isEditorReady, createEditor]); function disposeEditor() { const models = editorRef.current.getModel(); if (!keepCurrentOriginalModel) { var _models$original; (_models$original = models.original) === null || _models$original === void 0 ? void 0 : _models$original.dispose(); } if (!keepCurrentModifiedModel) { var _models$modified; (_models$modified = models.modified) === null || _models$modified === void 0 ? void 0 : _models$modified.dispose(); } editorRef.current.dispose(); } return /*#__PURE__*/React.createElement(MonacoContainer, { width: width, height: height, isEditorReady: isEditorReady, loading: loading, _ref: containerRef, className: className, wrapperProps: wrapperProps }); } DiffEditor.propTypes = { original: PropTypes.string, modified: PropTypes.string, language: PropTypes.string, originalLanguage: PropTypes.string, modifiedLanguage: PropTypes.string, /* === */ originalModelPath: PropTypes.string, modifiedModelPath: PropTypes.string, keepCurrentOriginalModel: PropTypes.bool, keepCurrentModifiedModel: PropTypes.bool, theme: PropTypes.string, loading: PropTypes.oneOfType([PropTypes.element, PropTypes.string]), options: PropTypes.object, /* === */ width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), className: PropTypes.string, wrapperProps: PropTypes.object, /* === */ beforeMount: PropTypes.func, onMount: PropTypes.func }; DiffEditor.defaultProps = { theme: 'light', loading: 'Loading...', options: {}, keepCurrentOriginalModel: false, keepCurrentModifiedModel: false, /* === */ width: '100%', height: '100%', wrapperProps: {}, /* === */ beforeMount: noop, onMount: noop }; export default DiffEditor;