@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
JavaScript
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;