Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 598a43e

Browse filesBrowse files
committed
feat: support singleton mode / upgrade linkage
1 parent 073c1ff commit 598a43e
Copy full SHA for 598a43e

File tree

Expand file treeCollapse file tree

6 files changed

+187
-126
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+187
-126
lines changed
Open diff view settings
Collapse file

‎.github/CODEOWNERS‎

Copy file name to clipboardExpand all lines: .github/CODEOWNERS
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* @leoyuan @alvarto
66

77
/packages/plugin-manual/ @alvarto
8-
/packages/base-monaco-editor/ @alvarto
8+
/packages/base-monaco-editor/ @alvarto @wangshihao111
99
/packages/plugin-code-editor/ @alvarto
1010
/packages/plugin-schema/ @alvarto
1111
/packages/plugin-components-pane/ @mark-ck
Collapse file

‎packages/base-monaco-editor/CHANGELOG.md‎

Copy file name to clipboardExpand all lines: packages/base-monaco-editor/CHANGELOG.md
+7Lines changed: 7 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.1.0-beta.0
2+
3+
- 重构 type / path / value 联动,彻底修复 monaco 在多文件模式下覆盖多个 path 值的 bug
4+
- 修复 ts 类型问题 @wangshihao111
5+
- 添加 configure 方法,支持配置是否开启 monaco 单例模式 @wangshihao111
6+
- 新增插件参数:`enhancers`,用于强化编辑器功能 @wangshihao111
7+
18
## 1.0.0
29

310
- Publish following changes
Collapse file

‎packages/base-monaco-editor/package.json‎

Copy file name to clipboardExpand all lines: packages/base-monaco-editor/package.json
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@alilc/lowcode-plugin-base-monaco-editor",
3-
"version": "1.0.0",
3+
"version": "1.1.0-beta.0",
44
"description": "代码编辑组件,monaco-editor 的低代码适配封装",
55
"publishConfig": {
66
"access": "public"
@@ -31,7 +31,7 @@
3131
"component"
3232
],
3333
"dependencies": {
34-
"@monaco-editor/loader": "^1.2.0",
34+
"@monaco-editor/loader": "1.3.0",
3535
"classnames": "^2.3.1"
3636
},
3737
"devDependencies": {
Collapse file

‎packages/base-monaco-editor/src/helper.ts‎

Copy file name to clipboardExpand all lines: packages/base-monaco-editor/src/helper.ts
+96-110Lines changed: 96 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,25 @@
11
/* eslint-disable no-empty */
2-
import { useEffect, useState, useRef, CSSProperties } from 'react';
3-
import loader from '@monaco-editor/loader';
4-
5-
loader.config({
6-
paths: {
7-
vs: 'https://g.alicdn.com/code/lib/monaco-editor/0.31.1/min/vs',
8-
},
9-
});
10-
11-
type IAmbigousFn = (...args: any[]) => any;
2+
import React, { useEffect, useState, useRef, CSSProperties } from 'react';
3+
import { Monaco } from '@monaco-editor/loader';
4+
import type { editor as oEditor } from 'monaco-editor';
5+
import { getMonaco } from './monaco';
126

137
// @todo fill type def for monaco editor without refering monaco editor
148
/**
159
* @see https://microsoft.github.io/monaco-editor/api/index.html
1610
*/
17-
export interface IEditorInstance {
18-
getModel: IAmbigousFn;
19-
dispose: IAmbigousFn;
20-
getValue: () => string;
21-
onDidChangeModelContent: (input: any) => void;
22-
setTheme: (input: string) => void;
23-
setModelLanguage: (model: any, language: string) => void;
24-
layout: () => void;
25-
setValue: (value: string) => void;
26-
executeEdits: IAmbigousFn;
27-
pushUndoStop: IAmbigousFn;
28-
EditorOption?: Record<string, any>;
29-
getOption?: (input: string) => any;
30-
onDidFocusEditorText: (...args: any[]) => void;
31-
onDidBlurEditorText: (...args: any[]) => void;
32-
getModifiedEditor?: () => IEditorInstance;
33-
setModel: IAmbigousFn;
34-
revealLineInCenter: IAmbigousFn;
35-
focus: IAmbigousFn;
36-
Range: new(...args: any[]) => any;
37-
getPosition: IAmbigousFn;
38-
setPosition: IAmbigousFn;
39-
deltaDecorations: IAmbigousFn;
40-
addAction: IAmbigousFn;
41-
saveViewState: () => ICodeEditorViewState;
42-
createModel: IAmbigousFn;
43-
[key: string]: any;
44-
}
45-
export interface IMonacoInstance {
46-
editor?: {
47-
create: IAmbigousFn;
48-
[key: string]: any;
49-
};
50-
KeyCode?: Record<string, any>;
51-
KeyMod?: Record<string, any>;
52-
[otherKeys: string]: any;
53-
}
11+
export type IEditorInstance = oEditor.IStandaloneCodeEditor | oEditor.IStandaloneDiffEditor;
5412

55-
type ICodeEditorViewState = {
56-
contributionsState: any;
57-
cursorState: any;
58-
viewState: any;
59-
}
13+
export type EditorEnhancer =
14+
(monaco: Monaco, editorIns: IEditorInstance) => any;
6015

6116
export interface IGeneralManacoEditorProps {
6217
/** [Monaco editor options](https://microsoft.github.io/monaco-editor/) */
6318
options?: Record<string, any>;
6419
/** callback after monaco's loaded and after editor's loaded */
65-
editorDidMount?: (monaco: IMonacoInstance, editor: IEditorInstance) => void;
20+
editorDidMount?: (monaco: Monaco, editor: IEditorInstance) => void;
6621
/** callback after monaco's loaded and before editor's loaded */
67-
editorWillMount?: (monaco: IMonacoInstance) => void;
22+
editorWillMount?: (monaco: Monaco) => void;
6823
/** path of the current model, useful when creating a multi-model editor */
6924
path?: string;
7025
/** whether to save the models' view states between model changes or not */
@@ -89,6 +44,7 @@ export interface IGeneralManacoEditorProps {
8944
enableOutline?: boolean;
9045
/** style of wrapper */
9146
style?: CSSProperties;
47+
enhancers?: EditorEnhancer[];
9248
}
9349

9450
export interface ISingleMonacoEditorProps extends IGeneralManacoEditorProps {
@@ -103,16 +59,15 @@ export interface IDiffMonacoEditorProps extends IGeneralManacoEditorProps {
10359
const CURRENT_LANGUAGE = ((window as any).locale || window.localStorage.getItem('vdev-locale') || '').replace(/_/, '-') || 'zh-CN';
10460
export const WORD_EDITOR_INITIALIZING = CURRENT_LANGUAGE === 'en-US' ? 'Initializing Editor' : '编辑器初始化中';
10561

106-
export const INITIAL_OPTIONS = {
62+
export const INITIAL_OPTIONS: oEditor.IStandaloneEditorConstructionOptions = {
10763
fontSize: 12,
10864
tabSize: 2,
10965
fontFamily: 'Menlo, Monaco, Courier New, monospace',
110-
renderIndentGuides: true,
11166
folding: true,
11267
minimap: {
11368
enabled: false,
11469
},
115-
autoIndent: true,
70+
autoIndent: 'advanced',
11671
contextmenu: true,
11772
useTabStops: true,
11873
wordBasedSuggestions: true,
@@ -131,9 +86,34 @@ export const INITIAL_OPTIONS = {
13186
},
13287
};
13388

134-
export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorProps) => {
89+
const DIFF_EDITOR_INITIAL_OPTIONS: oEditor.IStandaloneDiffEditorConstructionOptions = {
90+
fontSize: 12,
91+
fontFamily: 'Menlo, Monaco, Courier New, monospace',
92+
folding: true,
93+
minimap: {
94+
enabled: false,
95+
},
96+
autoIndent: 'advanced',
97+
contextmenu: true,
98+
useTabStops: true,
99+
formatOnPaste: true,
100+
automaticLayout: true,
101+
lineNumbers: 'on',
102+
wordWrap: 'off',
103+
scrollBeyondLastLine: false,
104+
fixedOverflowWidgets: false,
105+
snippetSuggestions: 'top',
106+
scrollbar: {
107+
vertical: 'auto',
108+
horizontal: 'auto',
109+
verticalScrollbarSize: 10,
110+
horizontalScrollbarSize: 10,
111+
},
112+
};
113+
114+
export const useEditor = <T = IEditorInstance>(type: 'single' | 'diff', props: IGeneralManacoEditorProps) => {
135115
const {
136-
editorDidMount, editorWillMount, theme, value, path, language, saveViewState, defaultValue,
116+
editorDidMount, editorWillMount, theme, value, path, language, saveViewState, defaultValue, enhancers,
137117
} = props;
138118

139119
const [isEditorReady, setIsEditorReady] = useState(false);
@@ -146,15 +126,21 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
146126
const previousPath = usePrevious(path);
147127
const requireConfigRef = useRef(props.requireConfig);
148128
const optionRef = useRef(props.options);
149-
const monacoRef = useRef<IMonacoInstance>();
129+
const monacoRef = useRef<Monaco>();
150130
const editorRef = useRef<IEditorInstance>();
151131
const containerRef = useRef<HTMLDivElement>();
152132
const typeRef = useRef(type);
153133
const editorDidMountRef = useRef<ISingleMonacoEditorProps['editorDidMount']>();
154134
const editorWillMountRef = useRef<ISingleMonacoEditorProps['editorWillMount']>();
155135

156136
const decomposeRef = useRef(false);
157-
const viewStatusRef = useRef<Map<any, ICodeEditorViewState>>(new Map())
137+
const viewStatusRef = useRef<Map<any, oEditor.ICodeEditorViewState>>(new Map());
138+
139+
const enhancersRef = useRef<any>({});
140+
141+
useEffect(() => {
142+
enhancersRef.current.enhancers = enhancers;
143+
}, [enhancers]);
158144

159145
useEffect(() => {
160146
editorDidMountRef.current = editorDidMount;
@@ -180,13 +166,8 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
180166
// make sure loader / editor only init once
181167
useEffect(() => {
182168
setLoading(true);
183-
184-
if (requireConfigRef.current) {
185-
loader.config(requireConfigRef.current);
186-
}
187-
188-
loader.init()
189-
.then((monaco: any) => {
169+
getMonaco(requireConfigRef.current)
170+
.then((monaco: Monaco) => {
190171
// 兼容旧版本 monaco-editor 写死 MonacoEnvironment 的问题
191172
(window as any).MonacoEnvironment = undefined;
192173
if (typeof (window as any).define === 'function' && (window as any).define.amd) {
@@ -203,13 +184,13 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
203184
if (!containerRef.current) {
204185
return;
205186
}
206-
let editor: IEditorInstance;
187+
let editor: oEditor.IStandaloneCodeEditor | oEditor.IStandaloneDiffEditor;
207188
if (typeRef.current === 'single') {
208189
const model = getOrCreateModel(
209190
monaco,
210191
valueRef.current ?? defaultValueRef.current ?? '',
211192
languageRef.current,
212-
pathRef.current
193+
pathRef.current,
213194
);
214195
editor = monaco.editor.create(containerRef.current, {
215196
automaticLayout: true,
@@ -228,14 +209,14 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
228209

229210
editor = monaco.editor.createDiffEditor(containerRef.current, {
230211
automaticLayout: true,
231-
...INITIAL_OPTIONS,
212+
...DIFF_EDITOR_INITIAL_OPTIONS,
232213
...optionRef.current,
233214
});
234215

235216
editor.setModel({ original: originalModel, modified: modifiedModel });
236217
}
237-
238218
editorRef.current = editor;
219+
enhancersRef.current.enhancers?.forEach((en: any) => en(monaco, editor as any));
239220
try {
240221
editorDidMountRef.current?.(monaco, editor);
241222
} catch (err) { }
@@ -258,39 +239,15 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
258239
monacoRef.current.editor.setTheme(theme);
259240
}, [isEditorReady, theme]);
260241

261-
// controlled value
262-
useEffect(() => {
263-
if (!isEditorReady) {
264-
return;
265-
}
266-
267-
const editor = type === 'diff'
268-
? editorRef.current.getModifiedEditor()
269-
: editorRef.current;
270-
271-
const nextValue = value ?? defaultValueRef.current ?? ''
272-
if (editor?.getOption?.(monacoRef.current?.editor.EditorOption.readOnly)) {
273-
editor?.setValue(nextValue);
274-
} else if (value !== editor?.getValue()) {
275-
editor?.executeEdits('', [{
276-
range: editor?.getModel().getFullModelRange(),
277-
text: nextValue,
278-
forceMoveMarkers: true,
279-
}]);
280-
281-
editor?.pushUndoStop();
282-
}
283-
}, [isEditorReady, type, value]);
284-
285242
// focus status
286243
useEffect(() => {
287244
if (!isEditorReady) {
288245
return;
289246
}
290247

291248
const editor = type === 'diff'
292-
? editorRef.current.getModifiedEditor()
293-
: editorRef.current;
249+
? (editorRef.current as oEditor.IStandaloneDiffEditor).getModifiedEditor()
250+
: editorRef.current as oEditor.IStandaloneCodeEditor;
294251
editor?.onDidFocusEditorText(() => {
295252
!decomposeRef.current && setFocused(true);
296253
});
@@ -306,7 +263,35 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
306263
};
307264
}, []);
308265

309-
// multi-model implementation
266+
// controlled value -- diff mode / without path only
267+
useEffect(() => {
268+
if (!isEditorReady) {
269+
return;
270+
}
271+
272+
if (type !== 'diff' && !!path) {
273+
return;
274+
}
275+
276+
const editor = type === 'diff'
277+
? (editorRef.current as oEditor.IStandaloneDiffEditor).getModifiedEditor()
278+
: editorRef.current as oEditor.IStandaloneCodeEditor;
279+
280+
const nextValue = value ?? defaultValueRef.current ?? '';
281+
if (editor?.getOption?.(monacoRef.current?.editor.EditorOption.readOnly)) {
282+
editor?.setValue(nextValue);
283+
} else if (value !== editor?.getValue()) {
284+
editor?.executeEdits('', [{
285+
range: editor?.getModel().getFullModelRange(),
286+
text: nextValue,
287+
forceMoveMarkers: true,
288+
}]);
289+
290+
editor?.pushUndoStop();
291+
}
292+
}, [isEditorReady, path, type, value]);
293+
294+
// multi-model && controlled value (shouldn't be diff mode)
310295
useEffect(() => {
311296
if (!isEditorReady) {
312297
return;
@@ -327,29 +312,30 @@ export const useEditor = (type: 'single' | 'diff', props: IGeneralManacoEditorPr
327312
path,
328313
);
329314

315+
const editor = editorRef.current as oEditor.IStandaloneCodeEditor;
330316
if (valueRef.current !== null && valueRef.current !== undefined && model.getValue() !== valueRef.current) {
331317
model.setValue(valueRef.current);
332318
}
333-
334319
if (model !== editorRef.current.getModel()) {
335-
saveViewState && viewStatusRef.current.set(previousPath, editorRef.current.saveViewState());
336-
editorRef.current.setModel(model);
337-
saveViewState && editorRef.current.restoreViewState(viewStatusRef.current.get(path));
320+
saveViewState && viewStatusRef.current.set(previousPath, editor.saveViewState());
321+
editor.setModel(model);
322+
saveViewState && editor.restoreViewState(viewStatusRef.current.get(path));
338323
}
339-
}, [isEditorReady, path, previousPath, type]);
324+
}, [isEditorReady, value, path, previousPath, type]);
340325

326+
let retEditorRef: React.MutableRefObject<T> = editorRef as any;
341327
return {
342328
isEditorReady,
343329
focused,
344330
loading,
345331
containerRef,
346332
monacoRef,
347-
editorRef,
333+
editorRef: retEditorRef,
348334
valueRef,
349335
} as const;
350336
};
351337

352-
function getOrCreateModel(monaco: IMonacoInstance, value?: string, language?: string, path?: string) {
338+
function getOrCreateModel(monaco: Monaco, value?: string, language?: string, path?: string) {
353339
if (path) {
354340
const prevModel = monaco
355341
.editor
@@ -365,9 +351,9 @@ function getOrCreateModel(monaco: IMonacoInstance, value?: string, language?: st
365351
}
366352

367353
function usePrevious<T>(value: T) {
368-
const ref = useRef<T>()
354+
const ref = useRef<T>();
369355
useEffect(() => {
370-
ref.current = value
371-
}, [value])
372-
return ref.current
356+
ref.current = value;
357+
}, [value]);
358+
return ref.current;
373359
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.