UNPKG

4.6 kBJavaScriptView Raw
1import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
2import PropTypes from "prop-types";
3import React from "react";
4import { noop, processSize } from "./utils";
5
6class MonacoDiffEditor extends React.Component {
7 constructor(props) {
8 super(props);
9 this.containerElement = undefined;
10 }
11
12 componentDidMount() {
13 this.initMonaco();
14 }
15
16 componentDidUpdate(prevProps) {
17 const { language, theme, height, options, width } = this.props;
18
19 const { original, modified } = this.editor.getModel();
20
21 if (this.props.original !== original.getValue()) {
22 original.setValue(this.props.original);
23 }
24
25 if (this.props.value != null && this.props.value !== modified.getValue()) {
26 this.__prevent_trigger_change_event = true;
27 this.editor.modifiedEditor.pushUndoStop();
28 modified.pushEditOperations(
29 [],
30 [
31 {
32 range: modified.getFullModelRange(),
33 text: this.props.value,
34 },
35 ]
36 );
37 this.editor.modifiedEditor.pushUndoStop();
38 this.__prevent_trigger_change_event = false;
39 }
40
41 if (prevProps.language !== language) {
42 monaco.editor.setModelLanguage(original, language);
43 monaco.editor.setModelLanguage(modified, language);
44 }
45 if (prevProps.theme !== theme) {
46 monaco.editor.setTheme(theme);
47 }
48 if (
49 this.editor &&
50 (width !== prevProps.width || height !== prevProps.height)
51 ) {
52 this.editor.layout();
53 }
54 if (prevProps.options !== options) {
55 this.editor.updateOptions(options);
56 }
57 }
58
59 componentWillUnmount() {
60 this.destroyMonaco();
61 }
62
63 assignRef = (component) => {
64 this.containerElement = component;
65 };
66
67 editorWillMount() {
68 const { editorWillMount } = this.props;
69 const options = editorWillMount(monaco);
70 return options || {};
71 }
72
73 editorDidMount(editor) {
74 this.props.editorDidMount(editor, monaco);
75
76 const { modified } = editor.getModel();
77 this._subscription = modified.onDidChangeContent((event) => {
78 if (!this.__prevent_trigger_change_event) {
79 this.props.onChange(modified.getValue(), event);
80 }
81 });
82 }
83
84 initModels(value, original) {
85 const { language } = this.props;
86 const originalModel = monaco.editor.createModel(original, language);
87 const modifiedModel = monaco.editor.createModel(value, language);
88 this.editor.setModel({
89 original: originalModel,
90 modified: modifiedModel,
91 });
92 }
93
94 initMonaco() {
95 const value =
96 this.props.value != null ? this.props.value : this.props.defaultValue;
97 const { original, theme, options, overrideServices } = this.props;
98 if (this.containerElement) {
99 // Before initializing monaco editor
100 this.editorWillMount();
101 this.editor = monaco.editor.createDiffEditor(
102 this.containerElement,
103 {
104 ...options,
105 ...(theme ? { theme } : {}),
106 },
107 overrideServices
108 );
109 // After initializing monaco editor
110 this.initModels(value, original);
111 this.editorDidMount(this.editor);
112 }
113 }
114
115 destroyMonaco() {
116 if (this.editor) {
117 this.editor.dispose();
118 const { original, modified } = this.editor.getModel();
119 if (original) {
120 original.dispose();
121 }
122 if (modified) {
123 modified.dispose();
124 }
125 }
126 if (this._subscription) {
127 this._subscription.dispose();
128 }
129 }
130
131 render() {
132 const { width, height } = this.props;
133 const fixedWidth = processSize(width);
134 const fixedHeight = processSize(height);
135 const style = {
136 width: fixedWidth,
137 height: fixedHeight,
138 };
139
140 return (
141 <div
142 ref={this.assignRef}
143 style={style}
144 className="react-monaco-editor-container"
145 />
146 );
147 }
148}
149
150MonacoDiffEditor.propTypes = {
151 width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
152 height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
153 original: PropTypes.string,
154 value: PropTypes.string,
155 defaultValue: PropTypes.string,
156 language: PropTypes.string,
157 theme: PropTypes.string,
158 options: PropTypes.object,
159 overrideServices: PropTypes.object,
160 editorDidMount: PropTypes.func,
161 editorWillMount: PropTypes.func,
162 onChange: PropTypes.func,
163};
164
165MonacoDiffEditor.defaultProps = {
166 width: "100%",
167 height: "100%",
168 original: null,
169 value: null,
170 defaultValue: "",
171 language: "javascript",
172 theme: null,
173 options: {},
174 overrideServices: {},
175 editorDidMount: noop,
176 editorWillMount: noop,
177 onChange: noop,
178};
179
180export default MonacoDiffEditor;