1 | import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
2 | import PropTypes from "prop-types";
|
3 | import React from "react";
|
4 | import { noop, processSize } from "./utils";
|
5 |
|
6 | class 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 |
|
100 | this.editorWillMount();
|
101 | this.editor = monaco.editor.createDiffEditor(
|
102 | this.containerElement,
|
103 | {
|
104 | ...options,
|
105 | ...(theme ? { theme } : {}),
|
106 | },
|
107 | overrideServices
|
108 | );
|
109 |
|
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 |
|
150 | MonacoDiffEditor.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 |
|
165 | MonacoDiffEditor.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 |
|
180 | export default MonacoDiffEditor;
|