),
};
// register custom elements
customElements.define('react-portal-target', class extends HTMLElement {});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 418b75f6..203961a6 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -220,6 +220,9 @@ importers:
'@gradio/utils':
specifier: 0.9.0
version: 0.9.0(svelte@4.2.20)
+ '@monaco-editor/react':
+ specifier: ^4.7.0
+ version: 4.7.0(monaco-editor@0.54.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
amuchina:
specifier: ^1.0.12
version: 1.0.12
@@ -259,6 +262,9 @@ importers:
mermaid:
specifier: ^11.12.1
version: 11.12.1
+ monaco-editor:
+ specifier: ^0.54.0
+ version: 0.54.0
path-browserify-esm:
specifier: ^1.0.6
version: 1.0.6
@@ -1736,6 +1742,16 @@ packages:
'@microsoft/tsdoc@0.15.1':
resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==}
+ '@monaco-editor/loader@1.6.1':
+ resolution: {integrity: sha512-w3tEnj9HYEC73wtjdpR089AqkUPskFRcdkxsiSFt3SoUc3OHpmu+leP94CXBm4mHfefmhsdfI0ZQu6qJ0wgtPg==}
+
+ '@monaco-editor/react@4.7.0':
+ resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==}
+ peerDependencies:
+ monaco-editor: '>= 0.25.0 < 1'
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
'@mrmlnc/readdir-enhanced@2.2.1':
resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==}
engines: {node: '>=4'}
@@ -3785,6 +3801,9 @@ packages:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
+ dompurify@3.1.7:
+ resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==}
+
dompurify@3.2.5:
resolution: {integrity: sha512-mLPd29uoRe9HpvwP2TxClGQBzGXeEC/we/q+bFlmPPmj2p2Ugl3r6ATu/UU1v77DXNcehiBg9zsr1dREyA/dJQ==}
@@ -5534,6 +5553,11 @@ packages:
peerDependencies:
marked: '>=4 <17'
+ marked@14.0.0:
+ resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==}
+ engines: {node: '>= 18'}
+ hasBin: true
+
marked@16.4.1:
resolution: {integrity: sha512-ntROs7RaN3EvWfy3EZi14H4YxmT6A5YvywfhO+0pm+cH/dnSQRmdAmoFIc3B9aiwTehyk7pESH4ofyBY+V5hZg==}
engines: {node: '>= 20'}
@@ -5804,6 +5828,9 @@ packages:
mlly@1.8.0:
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
+ monaco-editor@0.54.0:
+ resolution: {integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==}
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -7133,6 +7160,7 @@ packages:
source-map@0.8.0-beta.0:
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
engines: {node: '>= 8'}
+ deprecated: The work that was done in this beta branch won't be included in future versions
space-separated-tokens@1.1.5:
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
@@ -7174,6 +7202,9 @@ packages:
resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==}
engines: {node: '>=12.0.0'}
+ state-local@1.0.7:
+ resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==}
+
state-toggle@1.0.3:
resolution: {integrity: sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==}
@@ -9538,6 +9569,17 @@ snapshots:
'@microsoft/tsdoc@0.15.1':
optional: true
+ '@monaco-editor/loader@1.6.1':
+ dependencies:
+ state-local: 1.0.7
+
+ '@monaco-editor/react@4.7.0(monaco-editor@0.54.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@monaco-editor/loader': 1.6.1
+ monaco-editor: 0.54.0
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
'@mrmlnc/readdir-enhanced@2.2.1':
dependencies:
call-me-maybe: 1.0.2
@@ -10250,7 +10292,7 @@ snapshots:
'@types/dompurify@3.2.0':
dependencies:
- dompurify: 3.2.5
+ dompurify: 3.3.0
'@types/eslint@9.6.1':
dependencies:
@@ -11642,6 +11684,8 @@ snapshots:
dependencies:
domelementtype: 2.3.0
+ dompurify@3.1.7: {}
+
dompurify@3.2.5:
optionalDependencies:
'@types/trusted-types': 2.0.7
@@ -13692,6 +13736,8 @@ snapshots:
dependencies:
marked: 16.4.1
+ marked@14.0.0: {}
+
marked@16.4.1: {}
math-intrinsics@1.1.0: {}
@@ -14254,6 +14300,11 @@ snapshots:
pkg-types: 1.3.1
ufo: 1.6.1
+ monaco-editor@0.54.0:
+ dependencies:
+ dompurify: 3.1.7
+ marked: 14.0.0
+
mri@1.2.0: {}
ms@2.0.0: {}
@@ -15889,6 +15940,8 @@ snapshots:
stable-hash-x@0.2.0: {}
+ state-local@1.0.7: {}
+
state-toggle@1.0.3: {}
static-extend@0.1.2:
diff --git a/pyproject.toml b/pyproject.toml
index 3911d9bc..5516bc54 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -230,6 +230,7 @@ artifacts = [
"/backend/modelscope_studio/components/pro/multimodal_input/templates",
"/backend/modelscope_studio/components/pro/web_sandbox/templates",
"/backend/modelscope_studio/components/antd/statistic/timer/templates",
+ "/backend/modelscope_studio/components/pro/monaco_editor/templates",
]
[tool.yapfignore]
From b908822c26df7f77c665836db392ac11783a3ebe Mon Sep 17 00:00:00 2001
From: Col0ring <1561999073@qq.com>
Date: Mon, 10 Nov 2025 14:41:15 +0800
Subject: [PATCH 2/7] fix: types
---
.../components/pro/monaco_editor/__init__.py | 1 -
frontend/fixtures.d.ts | 7 +++++++
frontend/svelte-preprocess-react/sveltify.ts | 7 +++++++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/backend/modelscope_studio/components/pro/monaco_editor/__init__.py b/backend/modelscope_studio/components/pro/monaco_editor/__init__.py
index bcfa71a8..c662b098 100644
--- a/backend/modelscope_studio/components/pro/monaco_editor/__init__.py
+++ b/backend/modelscope_studio/components/pro/monaco_editor/__init__.py
@@ -67,7 +67,6 @@ def __init__(
**kwargs)
self.line = line
self.loading = loading
- print('loader', ModelScopeProMonacoEditor.LOADER)
self._loader = ModelScopeProMonacoEditor.LOADER
self.override_services = override_services
self.options = options
diff --git a/frontend/fixtures.d.ts b/frontend/fixtures.d.ts
index ee80763b..32078f08 100644
--- a/frontend/fixtures.d.ts
+++ b/frontend/fixtures.d.ts
@@ -1,6 +1,13 @@
declare module 'virtual:component-loader' {
export const load_component;
}
+
+declare module '*?worker' {
+ const workerConstructor: {
+ new (options?: { name?: string }): Worker;
+ };
+ export default workerConstructor;
+}
declare module '*?inline' {
const string: string;
export default string;
diff --git a/frontend/svelte-preprocess-react/sveltify.ts b/frontend/svelte-preprocess-react/sveltify.ts
index 1fe3ec21..27175e69 100644
--- a/frontend/svelte-preprocess-react/sveltify.ts
+++ b/frontend/svelte-preprocess-react/sveltify.ts
@@ -87,6 +87,13 @@ export function sveltify(
}
return new Promise((resolve) => {
+ if (!window.ms_globals.initializePromise) {
+ window.ms_globals.initializePromise = new Promise((r) => {
+ window.ms_globals.initialize = () => {
+ r();
+ };
+ });
+ }
window.ms_globals.initializePromise.then(() => {
resolve(Sveltified as any);
});
From 7ac243ad2adbc35d715728ca745db5d634ca0180 Mon Sep 17 00:00:00 2001
From: Col0ring <1561999073@qq.com>
Date: Tue, 11 Nov 2025 13:57:27 +0800
Subject: [PATCH 3/7] docs: add docs & examples for MonacoEditor
---
.../components/pro/monaco_editor/__init__.py | 25 ++++--
.../pro/monaco_editor/diff_editor/__init__.py | 23 +++--
docs/app.py | 3 +
.../pro/monaco_editor/README-zh_CN.md | 88 +++++++++++++++++++
docs/components/pro/monaco_editor/README.md | 88 +++++++++++++++++++
docs/components/pro/monaco_editor/app.py | 6 ++
.../pro/monaco_editor/demos/basic.py | 33 +++++++
.../pro/monaco_editor/demos/diff_editor.py | 43 +++++++++
.../demos/javascript_customize.py | 35 ++++++++
.../demos/monaco_editor_options.py | 33 +++++++
10 files changed, 362 insertions(+), 15 deletions(-)
create mode 100644 docs/components/pro/monaco_editor/README-zh_CN.md
create mode 100644 docs/components/pro/monaco_editor/README.md
create mode 100644 docs/components/pro/monaco_editor/app.py
create mode 100644 docs/components/pro/monaco_editor/demos/basic.py
create mode 100644 docs/components/pro/monaco_editor/demos/diff_editor.py
create mode 100644 docs/components/pro/monaco_editor/demos/javascript_customize.py
create mode 100644 docs/components/pro/monaco_editor/demos/monaco_editor_options.py
diff --git a/backend/modelscope_studio/components/pro/monaco_editor/__init__.py b/backend/modelscope_studio/components/pro/monaco_editor/__init__.py
index c662b098..837d6db2 100644
--- a/backend/modelscope_studio/components/pro/monaco_editor/__init__.py
+++ b/backend/modelscope_studio/components/pro/monaco_editor/__init__.py
@@ -21,13 +21,20 @@ class ModelScopeProMonacoEditor(ModelScopeDataLayoutComponent):
EVENTS = [
EventListener("mount",
callback=lambda block: block._internal.update(
- bind_mount_event=True)),
- EventListener("change",
- callback=lambda block: block._internal.update(
- bind_change_event=True)),
- EventListener("validate",
- callback=lambda block: block._internal.update(
- bind_validate_event=True)),
+ bind_mount_event=True),
+ doc="An event is emitted when the editor is mounted."),
+ EventListener(
+ "change",
+ callback=lambda block: block._internal.update(bind_change_event=
+ True),
+ doc="An event is emitted when the editor value is changed."),
+ EventListener(
+ "validate",
+ callback=lambda block: block._internal.update(bind_validate_event=
+ True),
+ doc=
+ "An event is emitted when the editor value is changed and the validation markers are ready."
+ ),
]
# supported slots
@@ -45,9 +52,10 @@ def __init__(
before_mount: str | None = None,
after_mount: str | None = None,
override_services: dict | None = None,
- loading: str | None = None,
+ loading: str | None = "Editor is loading...",
options: dict | None = None,
line: int | None = None,
+ read_only: bool | None = None,
height: str | int | float | None = 400,
_loader: None = None,
_internal: None = None,
@@ -70,6 +78,7 @@ def __init__(
self._loader = ModelScopeProMonacoEditor.LOADER
self.override_services = override_services
self.options = options
+ self.read_only = read_only
self.before_mount = before_mount
self.after_mount = after_mount
self.language = language
diff --git a/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py b/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py
index a86000bb..99482ea1 100644
--- a/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py
+++ b/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py
@@ -14,13 +14,20 @@ class ModelScopeProMonacoEditorDiffEditor(ModelScopeDataLayoutComponent):
EVENTS = [
EventListener("mount",
callback=lambda block: block._internal.update(
- bind_mount_event=True)),
- EventListener("change",
- callback=lambda block: block._internal.update(
- bind_change_event=True)),
- EventListener("validate",
- callback=lambda block: block._internal.update(
- bind_validate_event=True)),
+ bind_mount_event=True),
+ doc="An event is emitted when the editor is mounted."),
+ EventListener(
+ "change",
+ callback=lambda block: block._internal.update(bind_change_event=
+ True),
+ doc="An event is emitted when the editor value is changed."),
+ EventListener(
+ "validate",
+ callback=lambda block: block._internal.update(bind_validate_event=
+ True),
+ doc=
+ "An event is emitted when the editor value is changed and the validation markers are ready."
+ ),
]
# supported slots
@@ -39,6 +46,7 @@ def __init__(
after_mount: str | None = None,
override_services: dict | None = None,
loading: str | None = None,
+ read_only: bool | None = None,
options: dict | None = None,
line: int | None = None,
height: str | int | float | None = 400,
@@ -65,6 +73,7 @@ def __init__(
self.loading = loading
self.override_services = override_services
self.options = options
+ self.read_only = read_only
self.before_mount = before_mount
self.after_mount = after_mount
self.language = language
diff --git a/docs/app.py b/docs/app.py
index 3338b0d9..a185c0d3 100644
--- a/docs/app.py
+++ b/docs/app.py
@@ -181,6 +181,9 @@ def render(self):
"children": [{
"label": get_text("WebSandbox", "WebSandbox 网页沙盒"),
"key": "web_sandbox"
+ }, {
+ "label": get_text("MonacoEditor", "MonacoEditor 代码编辑器"),
+ "key": "monaco_editor"
}]
}]
diff --git a/docs/components/pro/monaco_editor/README-zh_CN.md b/docs/components/pro/monaco_editor/README-zh_CN.md
new file mode 100644
index 00000000..7e7891e3
--- /dev/null
+++ b/docs/components/pro/monaco_editor/README-zh_CN.md
@@ -0,0 +1,88 @@
+# MonacoEditor
+
+代码编辑器,[Monaco Editor](https://microsoft.github.io/monaco-editor/) 的 Gradio 实现,基于 [@monaco-editor/react](https://github.com/suren-atoyan/monaco-react) 集成。
+
+## 示例
+
+### 基本使用
+
+
+
+### Diff 编辑器
+
+
+
+### Monaco Editor 配置项
+
+可以直接传入 Monaco Editor 的配置项 [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html)。
+
+在这个示例中,我们关闭了编辑器的`minimap`与 `lineNumbers`。
+
+
+
+### 通过 JavaScript 定制化配置
+
+如果你还需要更进一步地操作 Monaco Editor,你可以通过传入 JavaScript 函数字符串来进一步定制化配置。
+
+
+
+## API
+
+### 属性
+
+#### MonacoEditor
+
+| 属性 | 类型 | 默认值 | 描述 |
+| ---------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
+| value | `str\| None` | None | 编辑器的值。 |
+| language | `str\| None` | None | 编辑器的语言(monaco-editor [支持](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages)的所有语言)。 |
+| line | `number\| None` | None | 垂直滚动编辑器到指定行。 |
+| read_only | `bool\| None` | None | 编辑器是否只读。 |
+| loading | `str\| None` | 'Editor is loading...' | 编辑器初始化加载时的加载文案。 |
+| options | `dict \| None` | None | [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html) |
+| overrideServices | `dict \| None` | None | [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOverrideServices.html) |
+| height | `str \| float \| int` | 400 | 组件的高度,如果值为数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
+| before_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载前执行,可以获取到 `monaco` 对象。 |
+| after_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载后执行,可以获取到`editor`对象与`monaco` 对象。 |
+
+#### MonacoEditor.DiffEditor
+
+| 属性 | 类型 | 默认值 | 描述 |
+| ----------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
+| value | `str\| None` | None | 修改后的源的值(右侧)。 |
+| original | `str\| None` | None | 原始源的值(左侧)。 |
+| language | `str\| None` | None | 编辑器的语言(monaco-editor [支持](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages)的所有语言)。 |
+| original_language | `str\| None` | None | 单独指定原始源的语言。否则,它将获取 language 属性的值。 |
+| modified_Language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 |
+| line | `number\| None` | None | 垂直滚动编辑器到指定行。 |
+| read_only | `bool\| None` | None | 编辑器是否只读。 |
+| loading | `str\| None` | 'Editor is loading...' | 编辑器初始化加载时的加载文案。 |
+| options | `dict \| None` | None | [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html) |
+| overrideServices | `dict \| None` | None | [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOverrideServices.html) |
+| height | `str \| float \| int` | 400 | 组件的高度,如果值为数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
+| before_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载前执行,可以获取到 `monaco` 对象。 |
+| after_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载后执行,可以获取到`editor`对象与`monaco` 对象。 |
+
+### 事件
+
+| 事件 | 描述 |
+| ----------------------------------------------------------------- | ---------------------------------------- |
+| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).mount(fn, ···)` | 当编辑器加载完成时触发。 |
+| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).change(fn, ···)` | 当编辑器值改变时触发。 |
+| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).validate(fn, ···)` | 当编辑器触发校验并且校错误记存在时触发。 |
+
+**注:** 根据 [monaco-editor](https://microsoft.github.io/monaco-editor/),只有具备丰富智能感知的语言才会触发 validate 事件。
+
+- TypeScript
+- JavaScript
+- CSS
+- LESS
+- SCSS
+- JSON
+- HTML
+
+### 插槽
+
+```python
+SLOTS=['loading']
+```
diff --git a/docs/components/pro/monaco_editor/README.md b/docs/components/pro/monaco_editor/README.md
new file mode 100644
index 00000000..314f286f
--- /dev/null
+++ b/docs/components/pro/monaco_editor/README.md
@@ -0,0 +1,88 @@
+# MonacoEditor
+
+Code editor, Gradio implementation of [Monaco Editor](https://microsoft.github.io/monaco-editor/), integrated based on [@monaco-editor/react](https://github.com/suren-atoyan/monaco-react).
+
+## Examples
+
+### Basic Usage
+
+
+
+### Diff Editor
+
+
+
+### Monaco Editor Options
+
+You can directly pass in Monaco Editor configuration options [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html).
+
+In this example, we disable the `minimap` and `lineNumbers` of the editor.
+
+
+
+### Customization via JavaScript
+
+If you need further customization of Monaco Editor, you can pass in JavaScript function strings for more advanced configuration.
+
+
+
+## API
+
+### Props
+
+#### MonacoEditor
+
+| Attribute | Type | Default | Description |
+| ---------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
+| value | `str\| None` | None | The value of the editor. |
+| language | `str\| None` | None | The language of the editor (all languages [supported](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages) by monaco-editor). |
+| line | `number\| None` | None | Vertically scroll the editor to the specified line. |
+| read_only | `bool\| None` | None | Whether the editor is read-only. |
+| loading | `str\| None` | 'Editor is loading...' | The loading text when the editor is initializing. |
+| options | `dict \| None` | None | [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html) |
+| overrideServices | `dict \| None` | None | [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOverrideServices.html) |
+| height | `str \| float \| int` | 400 | The height of the component. If the value is a number, it is specified in pixels. If a string is passed, it is specified in CSS units. |
+| before_mount | `str \| None` | None | Pass in a JavaScript function string to execute before the editor loads, which can access the `monaco` object. |
+| after_mount | `str \| None` | None | Pass in a JavaScript function string to execute after the editor loads, which can access the `editor` object and `monaco` object. |
+
+#### MonacoEditor.DiffEditor
+
+| Property | Type | Default | Description |
+| ----------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
+| value | `str\| None` | None | The modified source (right one) value. |
+| original | `str\| None` | None | The original source (left one) value. |
+| language | `str\| None` | None | The language of the editor (all languages [supported](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages) by monaco-editor). |
+| original_language | `str\| None` | None | Specifies the language of the original source separately. Otherwise, it will take the value of the language property. |
+| modified_Language | `str\| None` | None | Specifies the language of the modified source separately. Otherwise, it will take the value of the language property. |
+| line | `number\| None` | None | Vertically scroll the editor to the specified line. |
+| read_only | `bool\| None` | None | Whether the editor is read-only. |
+| loading | `str\| None` | 'Editor is loading...' | The loading text when the editor is initializing. |
+| options | `dict \| None` | None | [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html) |
+| overrideServices | `dict \| None` | None | [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOverrideServices.html) |
+| height | `str \| float \| int` | 400 | The height of the component. If the value is a number, it is specified in pixels. If a string is passed, it is specified in CSS units. |
+| before_mount | `str \| None` | None | Pass in a JavaScript function string to execute before the editor loads, which can access the `monaco` object. |
+| after_mount | `str \| None` | None | Pass in a JavaScript function string to execute after the editor loads, which can access the `editor` object and `monaco` object. |
+
+### Events
+
+| Event | Description |
+| ----------------------------------------------------------------- | ---------------------------------------------------------------------- |
+| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).mount(fn, ···)` | Triggered when the editor is mounted. |
+| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).change(fn, ···)` | Triggered when the editor value changes. |
+| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).validate(fn, ···)` | Triggered when the editor triggers validation and error markers exist. |
+
+**Note:** According to [monaco-editor](https://microsoft.github.io/monaco-editor/), only languages with rich IntelliSense will trigger the validate event.
+
+- TypeScript
+- JavaScript
+- CSS
+- LESS
+- SCSS
+- JSON
+- HTML
+
+### Slots
+
+```python
+SLOTS=['loading']
+```
diff --git a/docs/components/pro/monaco_editor/app.py b/docs/components/pro/monaco_editor/app.py
new file mode 100644
index 00000000..0018b7c1
--- /dev/null
+++ b/docs/components/pro/monaco_editor/app.py
@@ -0,0 +1,6 @@
+from helper.Docs import Docs
+
+docs = Docs(__file__)
+
+if __name__ == "__main__":
+ docs.render().queue().launch()
diff --git a/docs/components/pro/monaco_editor/demos/basic.py b/docs/components/pro/monaco_editor/demos/basic.py
new file mode 100644
index 00000000..1a75f32b
--- /dev/null
+++ b/docs/components/pro/monaco_editor/demos/basic.py
@@ -0,0 +1,33 @@
+import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+
+def change(editor_value):
+ print(editor_value)
+
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ editor = pro.MonacoEditor(
+ value="""import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ pro.MonacoEditor(
+ value="Hello World",
+ height=400,
+ )
+
+if __name__ == "__main__":
+ demo.queue().launch()
+""",
+ language="python",
+ height=400,
+ )
+ editor.change(fn=change, inputs=[editor])
+
+if __name__ == "__main__":
+ demo.queue().launch()
diff --git a/docs/components/pro/monaco_editor/demos/diff_editor.py b/docs/components/pro/monaco_editor/demos/diff_editor.py
new file mode 100644
index 00000000..4a3f6693
--- /dev/null
+++ b/docs/components/pro/monaco_editor/demos/diff_editor.py
@@ -0,0 +1,43 @@
+import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+
+def change(editor_value):
+ print(editor_value)
+
+
+def readonly_change(switch_value):
+ return gr.update(read_only=switch_value)
+
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider(
+), ms.AutoLoading():
+ with antd.Flex(gap="small", elem_style=dict(marginBottom=10)):
+ ms.Text("Readonly")
+ switch = antd.Switch(value=False)
+ editor = pro.MonacoEditor.DiffEditor(
+ original="import gradio as gr",
+ value="""import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ pro.MonacoEditor(
+ value="Hello World",
+ height=400,
+ )
+
+if __name__ == "__main__":
+ demo.queue().launch()
+""",
+ language="python",
+ height=400,
+ )
+ editor.change(fn=change, inputs=[editor])
+ switch.change(fn=readonly_change, inputs=[switch], outputs=[editor])
+
+if __name__ == "__main__":
+ demo.queue().launch()
diff --git a/docs/components/pro/monaco_editor/demos/javascript_customize.py b/docs/components/pro/monaco_editor/demos/javascript_customize.py
new file mode 100644
index 00000000..429711d4
--- /dev/null
+++ b/docs/components/pro/monaco_editor/demos/javascript_customize.py
@@ -0,0 +1,35 @@
+import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ pro.MonacoEditor(
+ value="""import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ pro.MonacoEditor(
+ value="Hello World",
+ height=400,
+ )
+
+if __name__ == "__main__":
+ demo.queue().launch()
+""",
+ language="python",
+ height=400,
+ # pass a javascript function string to the after_mount prop
+ after_mount="""(editor) => {
+ editor.updateOptions({
+ readOnly: true,
+ minimap: {
+ enabled: false,
+ },
+ })
+}""")
+
+if __name__ == "__main__":
+ demo.queue().launch()
diff --git a/docs/components/pro/monaco_editor/demos/monaco_editor_options.py b/docs/components/pro/monaco_editor/demos/monaco_editor_options.py
new file mode 100644
index 00000000..2c3fe88b
--- /dev/null
+++ b/docs/components/pro/monaco_editor/demos/monaco_editor_options.py
@@ -0,0 +1,33 @@
+import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ pro.MonacoEditor(
+ value="""import gradio as gr
+import modelscope_studio.components.antd as antd
+import modelscope_studio.components.base as ms
+import modelscope_studio.components.pro as pro
+
+with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
+ pro.MonacoEditor(
+ value="Hello World",
+ height=400,
+ )
+
+if __name__ == "__main__":
+ demo.queue().launch()
+""",
+ language="python",
+ height=400,
+ options={
+ "minimap": {
+ "enabled": False
+ },
+ "lineNumbers": False
+ },
+ )
+
+if __name__ == "__main__":
+ demo.queue().launch()
From 540ecc98aa933a6b2e6febd7ca1af17123999b41 Mon Sep 17 00:00:00 2001
From: Col0ring <1561999073@qq.com>
Date: Tue, 11 Nov 2025 13:59:21 +0800
Subject: [PATCH 4/7] fix: update of correction value
---
.../diff-editor/monaco-editor.diff-editor.tsx | 56 ++++++++++++++-----
frontend/pro/monaco-editor/monaco-editor.tsx | 36 ++++++++----
frontend/pro/monaco-editor/useValueChange.ts | 43 ++++++++++++++
3 files changed, 111 insertions(+), 24 deletions(-)
create mode 100644 frontend/pro/monaco-editor/useValueChange.ts
diff --git a/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx b/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx
index 08c5678d..7bb67d14 100644
--- a/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx
+++ b/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx
@@ -5,17 +5,21 @@ import {
} from '@monaco-editor/react';
import { ReactSlot } from '@svelte-preprocess-react/react-slot';
import { sveltify } from '@svelte-preprocess-react/sveltify';
-import React, { useEffect } from 'react';
+import React, { useEffect, useMemo, useRef } from 'react';
import { useFunction } from '@utils/hooks/useFunction';
import { Spin } from 'antd';
+import { isNumber } from 'lodash-es';
import type { editor, IDisposable } from 'monaco-editor';
+import { useValueChange } from '../useValueChange';
+
import '../monaco-editor.less';
export interface MonacoDiffEditorProps extends DiffEditorProps {
themeMode?: string;
height?: string | number;
children?: React.ReactNode;
+ readOnly?: boolean;
value?: string;
onValueChange: (value: string | undefined) => void;
onChange?: (
@@ -24,6 +28,7 @@ export interface MonacoDiffEditorProps extends DiffEditorProps {
) => void;
onValidate?: OnValidate;
afterMount?: DiffEditorProps['onMount'];
+ line?: number;
}
export const MonacoDiffEditor = sveltify(
@@ -40,22 +45,35 @@ export const MonacoDiffEditor = sveltify(
onChange,
onValueChange,
onValidate,
- value,
+ value: valueProp,
modified,
+ options,
+ readOnly,
+ line,
...props
}) => {
const beforeMountFunction = useFunction(beforeMount);
const afterMountFunction = useFunction(afterMount);
- const disposablesRef = React.useRef([]);
-
+ const disposablesRef = useRef([]);
+ const editorRef = useRef(null);
+ const [isEditorReady, setIsEditorReady] = React.useState(false);
+ const [value, setValue] = useValueChange({
+ onValueChange,
+ value: valueProp,
+ });
const handleEditorMount: MonacoDiffEditorProps['onMount'] = (
editor,
monaco
) => {
+ editorRef.current = editor;
+ if (isNumber(line)) {
+ editor.revealLine(line);
+ }
+ setIsEditorReady(true);
const modifiedEditor = editor.getModifiedEditor();
const mountDisposable = modifiedEditor.onDidChangeModelContent((e) => {
const newValue = modifiedEditor.getValue();
- onValueChange(newValue);
+ setValue(newValue);
onChange?.(newValue, e);
});
@@ -84,6 +102,13 @@ export const MonacoDiffEditor = sveltify(
});
};
}, []);
+
+ useEffect(() => {
+ if (isEditorReady && isNumber(line)) {
+ editorRef.current?.revealLine(line);
+ }
+ }, [line, isEditorReady]);
+
return (
<>
{children}
@@ -96,6 +121,13 @@ export const MonacoDiffEditor = sveltify(
>
({
+ readOnly,
+ ...(options || {}),
+ }),
+ [options, readOnly]
+ )}
modified={value || modified}
beforeMount={beforeMountFunction}
onMount={(editor, monaco) => {
@@ -107,14 +139,12 @@ export const MonacoDiffEditor = sveltify(
slots.loading ? (
) : (
- props.loading || (
-
-
-
- )
+
+
+
)
}
theme={themeMode === 'dark' ? 'vs-dark' : 'light'}
diff --git a/frontend/pro/monaco-editor/monaco-editor.tsx b/frontend/pro/monaco-editor/monaco-editor.tsx
index bd67b2d8..6b0886ee 100644
--- a/frontend/pro/monaco-editor/monaco-editor.tsx
+++ b/frontend/pro/monaco-editor/monaco-editor.tsx
@@ -1,15 +1,18 @@
import { Editor, type EditorProps } from '@monaco-editor/react';
import { ReactSlot } from '@svelte-preprocess-react/react-slot';
import { sveltify } from '@svelte-preprocess-react/sveltify';
-import React from 'react';
+import React, { useMemo } from 'react';
import { useFunction } from '@utils/hooks/useFunction';
import { Spin } from 'antd';
+import { useValueChange } from './useValueChange';
+
import './monaco-editor.less';
export interface MonacoEditorProps extends EditorProps {
themeMode?: string;
height?: string | number;
+ readOnly?: boolean;
onValueChange: (value: string | undefined) => void;
children?: React.ReactNode;
afterMount?: EditorProps['onMount'];
@@ -18,7 +21,7 @@ export interface MonacoEditorProps extends EditorProps {
export const MonacoEditor = sveltify(
({
height,
- value,
+ value: valueProp,
className,
style,
themeMode,
@@ -29,10 +32,16 @@ export const MonacoEditor = sveltify(
afterMount,
children,
onMount,
+ options,
+ readOnly,
...props
}) => {
const beforeMountFunction = useFunction(beforeMount);
const afterMountFunction = useFunction(afterMount);
+ const [value, setValue] = useValueChange({
+ onValueChange,
+ value: valueProp,
+ });
return (
<>
@@ -52,22 +61,27 @@ export const MonacoEditor = sveltify(
onMount?.(...args);
afterMountFunction?.(...args);
}}
+ options={useMemo(
+ () => ({
+ readOnly,
+ ...(options || {}),
+ }),
+ [options, readOnly]
+ )}
loading={
slots.loading ? (
) : (
- props.loading || (
-
-
-
- )
+
+
+
)
}
onChange={(v, ev) => {
- onValueChange(v);
+ setValue(v);
onChange?.(v, ev);
}}
theme={themeMode === 'dark' ? 'vs-dark' : 'light'}
diff --git a/frontend/pro/monaco-editor/useValueChange.ts b/frontend/pro/monaco-editor/useValueChange.ts
new file mode 100644
index 00000000..18996800
--- /dev/null
+++ b/frontend/pro/monaco-editor/useValueChange.ts
@@ -0,0 +1,43 @@
+import { useCallback, useEffect, useRef, useState } from 'react';
+import { useMemoizedFn } from '@utils/hooks/useMemoizedFn';
+
+export function useValueChange(options: {
+ value: string | undefined;
+ onValueChange: (value: string | undefined) => void;
+}) {
+ const { value: valueProp, onValueChange } = options;
+ const [typing, setTyping] = useState(false);
+ const [displayValue, setDisplayValue] = useState(valueProp);
+ const typingTimerRef = useRef | null>(null);
+ const onValueChangeMemoized = useMemoizedFn(onValueChange);
+
+ const setValue = useCallback(
+ (value: string | undefined) => {
+ typingTimerRef.current && clearTimeout(typingTimerRef.current);
+ setTyping(true);
+ typingTimerRef.current = setTimeout(() => {
+ setTyping(false);
+ }, 100);
+ onValueChangeMemoized(value);
+ },
+ [onValueChangeMemoized]
+ );
+
+ useEffect(() => {
+ // if not typing, use the cache value
+ if (!typing) {
+ // eslint-disable-next-line react-hooks/set-state-in-effect
+ setDisplayValue(valueProp);
+ }
+ }, [typing, valueProp]);
+
+ useEffect(() => {
+ return () => {
+ if (typingTimerRef.current) {
+ clearTimeout(typingTimerRef.current);
+ typingTimerRef.current = null;
+ }
+ };
+ }, []);
+ return [displayValue, setValue] as const;
+}
From f70defaf9c84bdfdfee6fdfd3475d718c465cab8 Mon Sep 17 00:00:00 2001
From: Col0ring <1561999073@qq.com>
Date: Tue, 11 Nov 2025 14:00:27 +0800
Subject: [PATCH 5/7] chore: add changeset
---
.changeset/silly-bats-own.md | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 .changeset/silly-bats-own.md
diff --git a/.changeset/silly-bats-own.md b/.changeset/silly-bats-own.md
new file mode 100644
index 00000000..a1c138d2
--- /dev/null
+++ b/.changeset/silly-bats-own.md
@@ -0,0 +1,7 @@
+---
+'@modelscope-studio/pro': minor
+'@modelscope-studio/frontend': minor
+'modelscope_studio': minor
+---
+
+feat: add pro component `MonacoEditor`
From fe4b3a164e9cbdc7463ae80936d835cd050b577e Mon Sep 17 00:00:00 2001
From: Col0ring <1561999073@qq.com>
Date: Tue, 11 Nov 2025 16:06:52 +0800
Subject: [PATCH 6/7] fix: inject the monaco loader from `ms.Application`
---
.../pro/monaco_editor/diff_editor/__init__.py | 2 +-
frontend/pro/monaco-editor/Index.svelte | 29 +++++----------
.../monaco-editor/diff-editor/Index.svelte | 29 +++++----------
.../diff-editor/gradio.config.js | 6 +--
frontend/pro/monaco-editor/gradio.config.js | 6 +--
frontend/pro/monaco-editor/loader.ts | 37 ++++++++-----------
frontend/svelte-preprocess-react/inject.ts | 5 ++-
pyproject.toml | 1 +
8 files changed, 41 insertions(+), 74 deletions(-)
diff --git a/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py b/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py
index 99482ea1..8d3d98c1 100644
--- a/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py
+++ b/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/__init__.py
@@ -45,7 +45,7 @@ def __init__(
before_mount: str | None = None,
after_mount: str | None = None,
override_services: dict | None = None,
- loading: str | None = None,
+ loading: str | None = "Editor is loading...",
read_only: bool | None = None,
options: dict | None = None,
line: int | None = None,
diff --git a/frontend/pro/monaco-editor/Index.svelte b/frontend/pro/monaco-editor/Index.svelte
index 46d1b233..6ac1300a 100644
--- a/frontend/pro/monaco-editor/Index.svelte
+++ b/frontend/pro/monaco-editor/Index.svelte
@@ -77,32 +77,21 @@
slots: $slots,
themeMode: gradio.theme,
};
+
+ $: awaitedLoader =
+ _loader?.mode === 'local'
+ ? initLocalLoader()
+ : _loader?.cdn_url
+ ? initCDNLoader(_loader.cdn_url)
+ : undefined;
{#if $mergedProps.visible}
- {#if _loader?.mode === 'local'}
- {#await initLocalLoader()}
-
- {:then}
- {#await AwaitedMonacoEditor then MonacoEditor}
-
-
-
- {/await}
- {/await}
- {:else if _loader?.cdn_url}
- {#await initCDNLoader(_loader.cdn_url)}
- {#await AwaitedMonacoEditor then MonacoEditor}
-
-
-
- {/await}
- {/await}
- {:else}
+ {#await awaitedLoader then}
{#await AwaitedMonacoEditor then MonacoEditor}
{/await}
- {/if}
+ {/await}
{/if}
diff --git a/frontend/pro/monaco-editor/diff-editor/Index.svelte b/frontend/pro/monaco-editor/diff-editor/Index.svelte
index 07c498f6..f75e249d 100644
--- a/frontend/pro/monaco-editor/diff-editor/Index.svelte
+++ b/frontend/pro/monaco-editor/diff-editor/Index.svelte
@@ -79,32 +79,21 @@
slots: $slots,
themeMode: gradio.theme,
};
+
+ $: awaitedLoader =
+ _loader?.mode === 'local'
+ ? initLocalLoader()
+ : _loader?.cdn_url
+ ? initCDNLoader(_loader.cdn_url)
+ : undefined;
{#if $mergedProps.visible}
- {#if _loader?.mode === 'local'}
- {#await initLocalLoader()}
-
- {:then}
- {#await AwaitedMonacoDiffEditor then MonacoDiffEditor}
-
-
-
- {/await}
- {/await}
- {:else if _loader?.cdn_url}
- {#await initCDNLoader(_loader.cdn_url)}
- {#await AwaitedMonacoDiffEditor then MonacoDiffEditor}
-
-
-
- {/await}
- {/await}
- {:else}
+ {#await awaitedLoader then}
{#await AwaitedMonacoDiffEditor then MonacoDiffEditor}
{/await}
- {/if}
+ {/await}
{/if}
diff --git a/frontend/pro/monaco-editor/diff-editor/gradio.config.js b/frontend/pro/monaco-editor/diff-editor/gradio.config.js
index 80740416..1992403d 100644
--- a/frontend/pro/monaco-editor/diff-editor/gradio.config.js
+++ b/frontend/pro/monaco-editor/diff-editor/gradio.config.js
@@ -1,7 +1,3 @@
import config from '../../../defineConfig.js';
-export default config({
- external: {
- excludes: ['@monaco-editor/loader'],
- },
-});
+export default config();
diff --git a/frontend/pro/monaco-editor/gradio.config.js b/frontend/pro/monaco-editor/gradio.config.js
index 6641fe8e..916857c0 100644
--- a/frontend/pro/monaco-editor/gradio.config.js
+++ b/frontend/pro/monaco-editor/gradio.config.js
@@ -1,7 +1,3 @@
import config from '../../defineConfig.js';
-export default config({
- external: {
- excludes: ['@monaco-editor/loader'],
- },
-});
+export default config();
diff --git a/frontend/pro/monaco-editor/loader.ts b/frontend/pro/monaco-editor/loader.ts
index e4524279..13a9cb61 100644
--- a/frontend/pro/monaco-editor/loader.ts
+++ b/frontend/pro/monaco-editor/loader.ts
@@ -1,30 +1,25 @@
-function getMonacoLoader() {
+import { initialize } from '@svelte-preprocess-react/component';
+
+async function getMonacoLoader() {
+ await initialize();
return new Promise<{
loader: typeof window.ms_globals.monacoLoader;
done?: () => void;
}>((resolve) => {
- if (!window.ms_globals?.monacoLoader) {
- if (window.ms_globals?.monacoLoaderPromise) {
- window.ms_globals.monacoLoaderPromise.then((loader) => {
- resolve({
- loader,
- });
- });
- } else {
- window.ms_globals ??= {} as typeof window.ms_globals;
- window.ms_globals.monacoLoaderPromise = new Promise((resolve2) => {
- import('@monaco-editor/react').then((m) => {
- window.ms_globals.monacoLoader = m.loader;
- resolve({
- loader: m.loader,
- done: () => resolve2(m.loader),
- });
- });
+ if (window.ms_globals?.monacoLoaderPromise) {
+ window.ms_globals.monacoLoaderPromise.then(() => {
+ resolve({
+ loader: window.ms_globals.monacoLoader,
});
- }
+ });
} else {
- resolve({
- loader: window.ms_globals.monacoLoader,
+ window.ms_globals.monacoLoaderPromise = new Promise((resolve2) => {
+ resolve({
+ loader: window.ms_globals.monacoLoader,
+ done: () => {
+ resolve2();
+ },
+ });
});
}
});
diff --git a/frontend/svelte-preprocess-react/inject.ts b/frontend/svelte-preprocess-react/inject.ts
index 5233e777..831c157b 100644
--- a/frontend/svelte-preprocess-react/inject.ts
+++ b/frontend/svelte-preprocess-react/inject.ts
@@ -1,4 +1,5 @@
import type { loader as monacoLoader } from '@monaco-editor/react';
+import { loader } from '@monaco-editor/react';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMClient from 'react-dom/client';
@@ -42,7 +43,7 @@ declare global {
autokey: number;
loadingKey: number;
monacoLoader: typeof monacoLoader | null;
- monacoLoaderPromise: Promise | null;
+ monacoLoaderPromise: Promise | null;
rerender: (props: BridgeProps) => void;
// render items
createItemsContext: typeof createItemsContext;
@@ -103,7 +104,7 @@ window.ms_globals = {
nodes: [],
},
rerender,
- monacoLoader: null,
+ monacoLoader: loader,
monacoLoaderPromise: null,
// render items
createItemsContext,
diff --git a/pyproject.toml b/pyproject.toml
index 5516bc54..0bca7918 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -231,6 +231,7 @@ artifacts = [
"/backend/modelscope_studio/components/pro/web_sandbox/templates",
"/backend/modelscope_studio/components/antd/statistic/timer/templates",
"/backend/modelscope_studio/components/pro/monaco_editor/templates",
+ "/backend/modelscope_studio/components/pro/monaco_editor/diff_editor/templates",
]
[tool.yapfignore]
From dc9c77beaf1d1223adc47646987866dcd2996c9b Mon Sep 17 00:00:00 2001
From: Col0ring <1561999073@qq.com>
Date: Tue, 11 Nov 2025 16:11:56 +0800
Subject: [PATCH 7/7] fix: typo
---
docs/components/pro/monaco_editor/README-zh_CN.md | 2 +-
docs/components/pro/monaco_editor/README.md | 2 +-
.../diff-editor/monaco-editor.diff-editor.tsx | 7 +++++--
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/docs/components/pro/monaco_editor/README-zh_CN.md b/docs/components/pro/monaco_editor/README-zh_CN.md
index 7e7891e3..c0ff766a 100644
--- a/docs/components/pro/monaco_editor/README-zh_CN.md
+++ b/docs/components/pro/monaco_editor/README-zh_CN.md
@@ -53,7 +53,7 @@
| original | `str\| None` | None | 原始源的值(左侧)。 |
| language | `str\| None` | None | 编辑器的语言(monaco-editor [支持](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages)的所有语言)。 |
| original_language | `str\| None` | None | 单独指定原始源的语言。否则,它将获取 language 属性的值。 |
-| modified_Language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 |
+| modified_language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 |
| line | `number\| None` | None | 垂直滚动编辑器到指定行。 |
| read_only | `bool\| None` | None | 编辑器是否只读。 |
| loading | `str\| None` | 'Editor is loading...' | 编辑器初始化加载时的加载文案。 |
diff --git a/docs/components/pro/monaco_editor/README.md b/docs/components/pro/monaco_editor/README.md
index 314f286f..05af360b 100644
--- a/docs/components/pro/monaco_editor/README.md
+++ b/docs/components/pro/monaco_editor/README.md
@@ -53,7 +53,7 @@ If you need further customization of Monaco Editor, you can pass in JavaScript f
| original | `str\| None` | None | The original source (left one) value. |
| language | `str\| None` | None | The language of the editor (all languages [supported](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages) by monaco-editor). |
| original_language | `str\| None` | None | Specifies the language of the original source separately. Otherwise, it will take the value of the language property. |
-| modified_Language | `str\| None` | None | Specifies the language of the modified source separately. Otherwise, it will take the value of the language property. |
+| modified_language | `str\| None` | None | Specifies the language of the modified source separately. Otherwise, it will take the value of the language property. |
| line | `number\| None` | None | Vertically scroll the editor to the specified line. |
| read_only | `bool\| None` | None | Whether the editor is read-only. |
| loading | `str\| None` | 'Editor is loading...' | The loading text when the editor is initializing. |
diff --git a/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx b/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx
index 7bb67d14..4cd7e3ea 100644
--- a/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx
+++ b/frontend/pro/monaco-editor/diff-editor/monaco-editor.diff-editor.tsx
@@ -7,6 +7,7 @@ import { ReactSlot } from '@svelte-preprocess-react/react-slot';
import { sveltify } from '@svelte-preprocess-react/sveltify';
import React, { useEffect, useMemo, useRef } from 'react';
import { useFunction } from '@utils/hooks/useFunction';
+import { useMemoizedFn } from '@utils/hooks/useMemoizedFn';
import { Spin } from 'antd';
import { isNumber } from 'lodash-es';
import type { editor, IDisposable } from 'monaco-editor';
@@ -61,6 +62,8 @@ export const MonacoDiffEditor = sveltify(
onValueChange,
value: valueProp,
});
+ const onChangeMemoized = useMemoizedFn(onChange);
+ const onValidateMemoized = useMemoizedFn(onValidate);
const handleEditorMount: MonacoDiffEditorProps['onMount'] = (
editor,
monaco
@@ -74,7 +77,7 @@ export const MonacoDiffEditor = sveltify(
const mountDisposable = modifiedEditor.onDidChangeModelContent((e) => {
const newValue = modifiedEditor.getValue();
setValue(newValue);
- onChange?.(newValue, e);
+ onChangeMemoized(newValue, e);
});
const validateDisposable = monaco.editor.onDidChangeMarkers((uris) => {
@@ -87,7 +90,7 @@ export const MonacoDiffEditor = sveltify(
const markers = monaco.editor.getModelMarkers({
resource: editorUri,
});
- onValidate?.(markers);
+ onValidateMemoized(markers);
}
}
});