Skip to content

Commit 6158f88

Browse files
authored
feat: add pro component MonacoEditor (#112)
* feat: add pro component `MonacoEditor` * fix: types * docs: add docs & examples for MonacoEditor * fix: update of correction value * chore: add changeset * fix: inject the monaco loader from `ms.Application` * fix: typo
1 parent 294e662 commit 6158f88

33 files changed

+1280
-8
lines changed

.changeset/silly-bats-own.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@modelscope-studio/pro': minor
3+
'@modelscope-studio/frontend': minor
4+
'modelscope_studio': minor
5+
---
6+
7+
feat: add pro component `MonacoEditor`

backend/modelscope_studio/components/base/text/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ def __init__(
2727
elem_style: dict | None = None,
2828
render: bool = True,
2929
**kwargs):
30-
super().__init__(visible=visible,
30+
super().__init__(value=value,
31+
visible=visible,
3132
elem_id=elem_id,
3233
elem_classes=elem_classes,
3334
render=render,
3435
as_item=as_item,
3536
elem_style=elem_style,
3637
**kwargs)
37-
self.value = value
3838

3939
FRONTEND_DIR = resolve_frontend_dir("text", type="base")
4040

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
from .chatbot import ModelScopeProChatbot as Chatbot
2+
from .monaco_editor import ModelScopeProMonacoEditor as MonacoEditor
3+
from .monaco_editor.diff_editor import \
4+
ModelScopeProMonacoEditorDiffEditor as MonacoEditorDiffEditor
25
from .multimodal_input import ModelScopeProMultimodalInput as MultimodalInput
36
from .web_sandbox import ModelScopeProWebSandbox as WebSandbox
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
from .chatbot import ModelScopeProChatbot as ProChatbot
2+
from .monaco_editor import ModelScopeProMonacoEditor as ProMonacoEditor
3+
from .monaco_editor.diff_editor import \
4+
ModelScopeProMonacoEditorDiffEditor as ProMonacoEditorDiffEditor
25
from .multimodal_input import \
36
ModelScopeProMultimodalInput as ProMultimodalInput
47
from .web_sandbox import ModelScopeProWebSandbox as ProWebSandbox
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Literal, TypedDict, Union
4+
5+
from gradio.events import EventListener
6+
7+
from ....utils.dev import ModelScopeDataLayoutComponent, resolve_frontend_dir
8+
from .diff_editor import ModelScopeProMonacoEditorDiffEditor
9+
10+
11+
class LoaderConfig(TypedDict):
12+
mode: Literal['cdn', 'local'] | None = None
13+
cdn_url: str | None = None
14+
15+
16+
class ModelScopeProMonacoEditor(ModelScopeDataLayoutComponent):
17+
"""
18+
"""
19+
DiffEditor = ModelScopeProMonacoEditorDiffEditor
20+
21+
EVENTS = [
22+
EventListener("mount",
23+
callback=lambda block: block._internal.update(
24+
bind_mount_event=True),
25+
doc="An event is emitted when the editor is mounted."),
26+
EventListener(
27+
"change",
28+
callback=lambda block: block._internal.update(bind_change_event=
29+
True),
30+
doc="An event is emitted when the editor value is changed."),
31+
EventListener(
32+
"validate",
33+
callback=lambda block: block._internal.update(bind_validate_event=
34+
True),
35+
doc=
36+
"An event is emitted when the editor value is changed and the validation markers are ready."
37+
),
38+
]
39+
40+
# supported slots
41+
SLOTS = ["loading"]
42+
43+
# or { "mode": "cdn" }, default cdn: https://cdn.jsdelivr.net/npm/monaco-editor@xxx/min/vs
44+
LOADER: Union[LoaderConfig, dict, None] = {"mode": "local"}
45+
46+
def __init__(
47+
self,
48+
value: str | None = None,
49+
*,
50+
# python, javascript etc.
51+
language: str | None = None,
52+
before_mount: str | None = None,
53+
after_mount: str | None = None,
54+
override_services: dict | None = None,
55+
loading: str | None = "Editor is loading...",
56+
options: dict | None = None,
57+
line: int | None = None,
58+
read_only: bool | None = None,
59+
height: str | int | float | None = 400,
60+
_loader: None = None,
61+
_internal: None = None,
62+
# gradio properties
63+
visible: bool = True,
64+
elem_id: str | None = None,
65+
elem_classes: list[str] | str | None = None,
66+
elem_style: dict | None = None,
67+
render: bool = True,
68+
**kwargs):
69+
super().__init__(visible=visible,
70+
value=value,
71+
elem_id=elem_id,
72+
elem_classes=elem_classes,
73+
render=render,
74+
elem_style=elem_style,
75+
**kwargs)
76+
self.line = line
77+
self.loading = loading
78+
self._loader = ModelScopeProMonacoEditor.LOADER
79+
self.override_services = override_services
80+
self.options = options
81+
self.read_only = read_only
82+
self.before_mount = before_mount
83+
self.after_mount = after_mount
84+
self.language = language
85+
self.height = height
86+
87+
FRONTEND_DIR = resolve_frontend_dir("monaco-editor", type='pro')
88+
89+
@property
90+
def skip_api(self):
91+
return False
92+
93+
def api_info(self) -> dict[str, Any]:
94+
return {"type": "string"}
95+
96+
def preprocess(self, payload: None | str) -> None | str:
97+
return payload
98+
99+
def postprocess(self, value: None | str) -> None | str:
100+
return value
101+
102+
def example_payload(self) -> Any:
103+
return None
104+
105+
def example_value(self) -> Any:
106+
return None
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
5+
from gradio.events import EventListener
6+
7+
from .....utils.dev import ModelScopeDataLayoutComponent, resolve_frontend_dir
8+
9+
10+
class ModelScopeProMonacoEditorDiffEditor(ModelScopeDataLayoutComponent):
11+
"""
12+
"""
13+
14+
EVENTS = [
15+
EventListener("mount",
16+
callback=lambda block: block._internal.update(
17+
bind_mount_event=True),
18+
doc="An event is emitted when the editor is mounted."),
19+
EventListener(
20+
"change",
21+
callback=lambda block: block._internal.update(bind_change_event=
22+
True),
23+
doc="An event is emitted when the editor value is changed."),
24+
EventListener(
25+
"validate",
26+
callback=lambda block: block._internal.update(bind_validate_event=
27+
True),
28+
doc=
29+
"An event is emitted when the editor value is changed and the validation markers are ready."
30+
),
31+
]
32+
33+
# supported slots
34+
SLOTS = ["loading"]
35+
36+
def __init__(
37+
self,
38+
value: str | None = None,
39+
*,
40+
original: str | None = None,
41+
# python, javascript etc.
42+
language: str | None = None,
43+
original_language: str | None = None,
44+
modified_language: str | None = None,
45+
before_mount: str | None = None,
46+
after_mount: str | None = None,
47+
override_services: dict | None = None,
48+
loading: str | None = "Editor is loading...",
49+
read_only: bool | None = None,
50+
options: dict | None = None,
51+
line: int | None = None,
52+
height: str | int | float | None = 400,
53+
_loader: None = None,
54+
_internal: None = None,
55+
# gradio properties
56+
visible: bool = True,
57+
elem_id: str | None = None,
58+
elem_classes: list[str] | str | None = None,
59+
elem_style: dict | None = None,
60+
render: bool = True,
61+
**kwargs):
62+
super().__init__(value=value,
63+
visible=visible,
64+
elem_id=elem_id,
65+
elem_classes=elem_classes,
66+
render=render,
67+
elem_style=elem_style,
68+
**kwargs)
69+
from .. import ModelScopeProMonacoEditor
70+
self._loader = ModelScopeProMonacoEditor.LOADER
71+
self.original = original
72+
self.line = line
73+
self.loading = loading
74+
self.override_services = override_services
75+
self.options = options
76+
self.read_only = read_only
77+
self.before_mount = before_mount
78+
self.after_mount = after_mount
79+
self.language = language
80+
self.original_language = original_language
81+
self.modified_language = modified_language
82+
self.height = height
83+
84+
FRONTEND_DIR = resolve_frontend_dir("monaco-editor",
85+
'diff-editor',
86+
type='pro')
87+
88+
@property
89+
def skip_api(self):
90+
return False
91+
92+
def api_info(self) -> dict[str, Any]:
93+
return {"type": "string"}
94+
95+
def preprocess(self, payload: None | str) -> None | str:
96+
return payload
97+
98+
def postprocess(self, value: None | str) -> None | str:
99+
return value
100+
101+
def example_payload(self) -> Any:
102+
return None
103+
104+
def example_value(self) -> Any:
105+
return None

docs/app.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ def render(self):
181181
"children": [{
182182
"label": get_text("WebSandbox", "WebSandbox 网页沙盒"),
183183
"key": "web_sandbox"
184+
}, {
185+
"label": get_text("MonacoEditor", "MonacoEditor 代码编辑器"),
186+
"key": "monaco_editor"
184187
}]
185188
}]
186189

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# MonacoEditor
2+
3+
代码编辑器,[Monaco Editor](https://microsoft.github.io/monaco-editor/) 的 Gradio 实现,基于 [@monaco-editor/react](https://github.com/suren-atoyan/monaco-react) 集成。
4+
5+
## 示例
6+
7+
### 基本使用
8+
9+
<demo name="basic"></demo>
10+
11+
### Diff 编辑器
12+
13+
<demo name="diff_editor"></demo>
14+
15+
### Monaco Editor 配置项
16+
17+
可以直接传入 Monaco Editor 的配置项 [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html)
18+
19+
在这个示例中,我们关闭了编辑器的`minimap``lineNumbers`
20+
21+
<demo name="monaco_editor_options"></demo>
22+
23+
### 通过 JavaScript 定制化配置
24+
25+
如果你还需要更进一步地操作 Monaco Editor,你可以通过传入 JavaScript 函数字符串来进一步定制化配置。
26+
27+
<demo name="javascript_customize"></demo>
28+
29+
## API 
30+
31+
### 属性
32+
33+
#### MonacoEditor
34+
35+
| 属性 | 类型 | 默认值 | 描述 |
36+
| ---------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
37+
| value | `str\| None` | None | 编辑器的值。 |
38+
| language | `str\| None` | None | 编辑器的语言(monaco-editor [支持](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages)的所有语言)。 |
39+
| line | `number\| None` | None | 垂直滚动编辑器到指定行。 |
40+
| read_only | `bool\| None` | None | 编辑器是否只读。 |
41+
| loading | `str\| None` | 'Editor is loading...' | 编辑器初始化加载时的加载文案。 |
42+
| options | `dict \| None` | None | [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html) |
43+
| overrideServices | `dict \| None` | None | [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOverrideServices.html) |
44+
| height | `str \| float \| int` | 400 | 组件的高度,如果值为数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
45+
| before_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载前执行,可以获取到 `monaco` 对象。 |
46+
| after_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载后执行,可以获取到`editor`对象与`monaco` 对象。 |
47+
48+
#### MonacoEditor.DiffEditor
49+
50+
| 属性 | 类型 | 默认值 | 描述 |
51+
| ----------------- | --------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
52+
| value | `str\| None` | None | 修改后的源的值(右侧)。 |
53+
| original | `str\| None` | None | 原始源的值(左侧)。 |
54+
| language | `str\| None` | None | 编辑器的语言(monaco-editor [支持](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages)的所有语言)。 |
55+
| original_language | `str\| None` | None | 单独指定原始源的语言。否则,它将获取 language 属性的值。 |
56+
| modified_language | `str\| None` | None | 单独指定修改后的源的语言。否则,它将获取 language 属性的值。 |
57+
| line | `number\| None` | None | 垂直滚动编辑器到指定行。 |
58+
| read_only | `bool\| None` | None | 编辑器是否只读。 |
59+
| loading | `str\| None` | 'Editor is loading...' | 编辑器初始化加载时的加载文案。 |
60+
| options | `dict \| None` | None | [IStandaloneEditorConstructionOptions](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IStandaloneEditorConstructionOptions.html) |
61+
| overrideServices | `dict \| None` | None | [IEditorOverrideServices](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IEditorOverrideServices.html) |
62+
| height | `str \| float \| int` | 400 | 组件的高度,如果值为数字,则以像素为单位指定,如果传递的是字符串,则以 CSS 单位指定。 |
63+
| before_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载前执行,可以获取到 `monaco` 对象。 |
64+
| after_mount | `str \| None` | None | 传入 JavaScript 函数字符串,在编辑器加载后执行,可以获取到`editor`对象与`monaco` 对象。 |
65+
66+
### 事件
67+
68+
| 事件 | 描述 |
69+
| ----------------------------------------------------------------- | ---------------------------------------- |
70+
| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).mount(fn, ···)` | 当编辑器加载完成时触发。 |
71+
| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).change(fn, ···)` | 当编辑器值改变时触发。 |
72+
| `pro.(MonacoEditor \| MonacoEditor.DiffEditor).validate(fn, ···)` | 当编辑器触发校验并且校错误记存在时触发。 |
73+
74+
**注:** 根据 [monaco-editor](https://microsoft.github.io/monaco-editor/),只有具备丰富智能感知的语言才会触发 validate 事件。
75+
76+
- TypeScript
77+
- JavaScript
78+
- CSS
79+
- LESS
80+
- SCSS
81+
- JSON
82+
- HTML
83+
84+
### 插槽
85+
86+
```python
87+
SLOTS=['loading']
88+
```

0 commit comments

Comments
 (0)