@tmagic/editor 1.7.0-beta.4 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +12 -0
- package/dist/tmagic-editor.js +353 -286
- package/dist/tmagic-editor.umd.cjs +382 -314
- package/package.json +7 -7
- package/src/components/CodeBlockEditor.vue +1 -1
- package/src/fields/Code.vue +1 -0
- package/src/fields/DataSourceFields.vue +2 -2
- package/src/fields/DataSourceMocks.vue +1 -1
- package/src/fields/KeyValue.vue +4 -1
- package/src/index.ts +1 -0
- package/src/layouts/CodeEditor.vue +77 -5
- package/src/layouts/sidebar/data-source/DataSourceAddButton.vue +46 -0
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +8 -23
- package/src/layouts/sidebar/layer/LayerNodeTool.vue +8 -3
- package/src/theme/layer-panel.scss +16 -0
- package/src/utils/data-source/index.ts +2 -2
- package/types/index.d.ts +95 -76
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.7.0
|
|
2
|
+
"version": "1.7.0",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
"moveable": "^0.53.0",
|
|
58
58
|
"serialize-javascript": "^7.0.0",
|
|
59
59
|
"sortablejs": "^1.15.6",
|
|
60
|
-
"@tmagic/design": "1.7.0
|
|
61
|
-
"@tmagic/form": "1.7.0
|
|
62
|
-
"@tmagic/table": "1.7.0
|
|
63
|
-
"@tmagic/
|
|
64
|
-
"@tmagic/
|
|
60
|
+
"@tmagic/design": "1.7.0",
|
|
61
|
+
"@tmagic/form": "1.7.0",
|
|
62
|
+
"@tmagic/table": "1.7.0",
|
|
63
|
+
"@tmagic/utils": "1.7.0",
|
|
64
|
+
"@tmagic/stage": "1.7.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/events": "^3.0.3",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"monaco-editor": "^0.48.0",
|
|
76
76
|
"typescript": "^5.9.3",
|
|
77
77
|
"vue": "^3.5.24",
|
|
78
|
-
"@tmagic/core": "1.7.0
|
|
78
|
+
"@tmagic/core": "1.7.0"
|
|
79
79
|
},
|
|
80
80
|
"peerDependenciesMeta": {
|
|
81
81
|
"typescript": {
|
|
@@ -201,7 +201,7 @@ const functionConfig = computed<FormConfig>(() => [
|
|
|
201
201
|
name: 'content',
|
|
202
202
|
type: 'vs-code',
|
|
203
203
|
options: inject('codeOptions', {}),
|
|
204
|
-
|
|
204
|
+
autosize: { minRows: 10, maxRows: 30 },
|
|
205
205
|
onChange: (formState: FormState | undefined, code: string) => {
|
|
206
206
|
try {
|
|
207
207
|
// 检测js代码是否存在语法错误
|
package/src/fields/Code.vue
CHANGED
|
@@ -233,7 +233,6 @@ const dataSourceFieldsConfig: FormConfig = [
|
|
|
233
233
|
{
|
|
234
234
|
name: 'defaultValue',
|
|
235
235
|
text: '默认值',
|
|
236
|
-
height: '200px',
|
|
237
236
|
parse: true,
|
|
238
237
|
type: (mForm: FormState | undefined, { model }: any) => {
|
|
239
238
|
if (model.type === 'number') return 'number';
|
|
@@ -242,6 +241,7 @@ const dataSourceFieldsConfig: FormConfig = [
|
|
|
242
241
|
|
|
243
242
|
return 'vs-code';
|
|
244
243
|
},
|
|
244
|
+
autosize: { minRows: 1, maxRows: 30 },
|
|
245
245
|
options: [
|
|
246
246
|
{ text: 'true', value: true },
|
|
247
247
|
{ text: 'false', value: false },
|
|
@@ -267,7 +267,7 @@ const jsonFromConfig: FormConfig = [
|
|
|
267
267
|
type: 'vs-code',
|
|
268
268
|
labelWidth: '0',
|
|
269
269
|
language: 'json',
|
|
270
|
-
|
|
270
|
+
autosize: { minRows: 30, maxRows: 50 },
|
|
271
271
|
options: inject('codeOptions', {}),
|
|
272
272
|
},
|
|
273
273
|
];
|
|
@@ -96,7 +96,7 @@ const formConfig: FormConfig = [
|
|
|
96
96
|
language: 'json',
|
|
97
97
|
options: inject('codeOptions', {}),
|
|
98
98
|
defaultValue: '{}',
|
|
99
|
-
|
|
99
|
+
autosize: { minRows: 30, maxRows: 50 },
|
|
100
100
|
onChange: (formState: FormState | undefined, v: string | any) => {
|
|
101
101
|
if (typeof v !== 'string') return v;
|
|
102
102
|
return JSON.parse(v);
|
package/src/fields/KeyValue.vue
CHANGED
|
@@ -37,12 +37,15 @@
|
|
|
37
37
|
|
|
38
38
|
<MagicCodeEditor
|
|
39
39
|
v-if="config.advanced && showCode"
|
|
40
|
-
height="200px"
|
|
41
40
|
:init-values="model[name]"
|
|
42
41
|
language="javascript"
|
|
43
42
|
:options="{
|
|
44
43
|
readOnly: disabled,
|
|
45
44
|
}"
|
|
45
|
+
:autosize="{
|
|
46
|
+
minRows: 1,
|
|
47
|
+
maxRows: 20,
|
|
48
|
+
}"
|
|
46
49
|
:parse="true"
|
|
47
50
|
@save="save"
|
|
48
51
|
></MagicCodeEditor>
|
package/src/index.ts
CHANGED
|
@@ -92,6 +92,7 @@ export { default as KeyValue } from './fields/KeyValue.vue';
|
|
|
92
92
|
export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
|
|
93
93
|
export { default as CodeBlockListPanel } from './layouts/sidebar/code-block/CodeBlockListPanel.vue';
|
|
94
94
|
export { default as DataSourceConfigPanel } from './layouts/sidebar/data-source/DataSourceConfigPanel.vue';
|
|
95
|
+
export { default as DataSourceAddButton } from './layouts/sidebar/data-source/DataSourceAddButton.vue';
|
|
95
96
|
export { default as PropsPanel } from './layouts/props-panel/PropsPanel.vue';
|
|
96
97
|
export { default as PropsFormPanel } from './layouts/props-panel/FormPanel.vue';
|
|
97
98
|
export { default as ToolButton } from './components/ToolButton.vue';
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="`magic-code-editor`">
|
|
3
3
|
<Teleport to="body" :disabled="!fullScreen">
|
|
4
|
-
<div
|
|
5
|
-
:class="`magic-code-editor-wrapper${fullScreen ? ' full-screen' : ''}`"
|
|
6
|
-
:style="!fullScreen && height ? `height: ${height}` : '100%'"
|
|
7
|
-
>
|
|
4
|
+
<div :class="{ 'magic-code-editor-wrapper': true, 'full-screen': fullScreen }" :style="{ height: computeHeight }">
|
|
8
5
|
<TMagicButton
|
|
9
6
|
v-if="!disabledFullScreen"
|
|
10
7
|
class="magic-code-editor-full-screen-icon"
|
|
@@ -20,7 +17,7 @@
|
|
|
20
17
|
</template>
|
|
21
18
|
|
|
22
19
|
<script lang="ts" setup>
|
|
23
|
-
import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
|
20
|
+
import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, useTemplateRef, watch } from 'vue';
|
|
24
21
|
import { FullScreen } from '@element-plus/icons-vue';
|
|
25
22
|
import { throttle } from 'lodash-es';
|
|
26
23
|
import serialize from 'serialize-javascript';
|
|
@@ -46,6 +43,10 @@ const props = withDefaults(
|
|
|
46
43
|
autoSave?: boolean;
|
|
47
44
|
parse?: boolean;
|
|
48
45
|
disabledFullScreen?: boolean;
|
|
46
|
+
autosize?: {
|
|
47
|
+
minRows?: number;
|
|
48
|
+
maxRows?: number;
|
|
49
|
+
};
|
|
49
50
|
}>(),
|
|
50
51
|
{
|
|
51
52
|
initValues: '',
|
|
@@ -61,6 +62,58 @@ const props = withDefaults(
|
|
|
61
62
|
|
|
62
63
|
const emit = defineEmits(['initd', 'save']);
|
|
63
64
|
|
|
65
|
+
const autoHeight = ref<string>('');
|
|
66
|
+
|
|
67
|
+
const computeHeight = computed(() => {
|
|
68
|
+
if (fullScreen.value) {
|
|
69
|
+
return '100%';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (props.height) {
|
|
73
|
+
return props.height;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (props.autosize) {
|
|
77
|
+
return autoHeight.value;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return '100%';
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const setAutoHeight = (v = '') => {
|
|
84
|
+
let lines = Math.max(v.split('\n').length, props.autosize?.minRows || 1);
|
|
85
|
+
if (v) {
|
|
86
|
+
if (props.autosize?.maxRows) {
|
|
87
|
+
lines = Math.min(lines, props.autosize.maxRows);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 获取编辑器实际行高,如果编辑器还未初始化则使用默认值
|
|
92
|
+
let lineHeight = 20;
|
|
93
|
+
if (vsEditor) {
|
|
94
|
+
const editorOptions = vsEditor.getOptions();
|
|
95
|
+
lineHeight = editorOptions.get(monaco.editor.EditorOption.lineHeight) || 20;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const newHeight = `${lines * lineHeight + 10}px`;
|
|
99
|
+
|
|
100
|
+
// 只有当高度真正改变时才更新
|
|
101
|
+
if (autoHeight.value !== newHeight) {
|
|
102
|
+
autoHeight.value = newHeight;
|
|
103
|
+
|
|
104
|
+
// 高度变化后需要重新布局编辑器
|
|
105
|
+
nextTick(() => {
|
|
106
|
+
vsEditor?.layout();
|
|
107
|
+
|
|
108
|
+
// 确保内容在可视区域内,滚动到顶部
|
|
109
|
+
if (vsEditor) {
|
|
110
|
+
vsEditor.setScrollTop(0);
|
|
111
|
+
vsEditor.revealLine(1);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
64
117
|
const toString = (v: string | any, language: string): string => {
|
|
65
118
|
let value: string;
|
|
66
119
|
if (typeof v !== 'string') {
|
|
@@ -110,6 +163,8 @@ const resizeObserver = new globalThis.ResizeObserver(
|
|
|
110
163
|
const setEditorValue = (v: string | any, m: string | any) => {
|
|
111
164
|
values.value = toString(v, props.language.toLocaleLowerCase());
|
|
112
165
|
|
|
166
|
+
setAutoHeight(values.value);
|
|
167
|
+
|
|
113
168
|
if (props.type === 'diff') {
|
|
114
169
|
const originalModel = monaco.editor.createModel(values.value, 'text/javascript');
|
|
115
170
|
const modifiedModel = monaco.editor.createModel(toString(m, props.language), 'text/javascript');
|
|
@@ -147,6 +202,7 @@ const handleKeyDown = (e: KeyboardEvent) => {
|
|
|
147
202
|
emit('save', props.parse ? parseCode(newValue, props.language) : newValue);
|
|
148
203
|
}
|
|
149
204
|
};
|
|
205
|
+
|
|
150
206
|
const init = async () => {
|
|
151
207
|
if (!codeEditorEl.value) return;
|
|
152
208
|
|
|
@@ -163,8 +219,24 @@ const init = async () => {
|
|
|
163
219
|
|
|
164
220
|
if (props.type === 'diff') {
|
|
165
221
|
vsDiffEditor = getEditorConfig('customCreateMonacoDiffEditor')(monaco, codeEditorEl.value, options);
|
|
222
|
+
|
|
223
|
+
// 监听diff编辑器内容变化
|
|
224
|
+
vsDiffEditor.getModifiedEditor().onDidChangeModelContent(() => {
|
|
225
|
+
// 如果使用 autosize,内容变化时重新计算高度
|
|
226
|
+
if (props.autosize) {
|
|
227
|
+
setAutoHeight(getEditorValue());
|
|
228
|
+
}
|
|
229
|
+
});
|
|
166
230
|
} else {
|
|
167
231
|
vsEditor = getEditorConfig('customCreateMonacoEditor')(monaco, codeEditorEl.value, options);
|
|
232
|
+
|
|
233
|
+
// 监听编辑器内容变化
|
|
234
|
+
vsEditor.onDidChangeModelContent(() => {
|
|
235
|
+
// 如果使用 autosize,内容变化时重新计算高度
|
|
236
|
+
if (props.autosize) {
|
|
237
|
+
setAutoHeight(getEditorValue());
|
|
238
|
+
}
|
|
239
|
+
});
|
|
168
240
|
}
|
|
169
241
|
|
|
170
242
|
setEditorValue(props.initValues, props.modifiedValues);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TMagicPopover
|
|
3
|
+
placement="right"
|
|
4
|
+
trigger="hover"
|
|
5
|
+
popper-class="data-source-list-panel-add-menu"
|
|
6
|
+
:destroy-on-close="true"
|
|
7
|
+
>
|
|
8
|
+
<template #reference>
|
|
9
|
+
<TMagicButton v-bind="addButtonConfig || {}">{{ addButtonText || '' }}</TMagicButton>
|
|
10
|
+
</template>
|
|
11
|
+
<ToolButton
|
|
12
|
+
v-for="(item, index) in datasourceTypeList"
|
|
13
|
+
:data="{
|
|
14
|
+
type: 'button',
|
|
15
|
+
text: item.text,
|
|
16
|
+
handler: () => {
|
|
17
|
+
$emit('add', item.type);
|
|
18
|
+
},
|
|
19
|
+
}"
|
|
20
|
+
:key="index"
|
|
21
|
+
></ToolButton>
|
|
22
|
+
</TMagicPopover>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { type ButtonProps, TMagicButton, TMagicPopover } from '@tmagic/design';
|
|
27
|
+
|
|
28
|
+
import ToolButton from '@editor/components/ToolButton.vue';
|
|
29
|
+
|
|
30
|
+
defineOptions({
|
|
31
|
+
name: 'MEditorDataSourceAddButton',
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
defineProps<{
|
|
35
|
+
datasourceTypeList: {
|
|
36
|
+
text: string;
|
|
37
|
+
type: string;
|
|
38
|
+
}[];
|
|
39
|
+
addButtonConfig?: ButtonProps;
|
|
40
|
+
addButtonText?: string;
|
|
41
|
+
}>();
|
|
42
|
+
|
|
43
|
+
defineEmits<{
|
|
44
|
+
add: [type: string];
|
|
45
|
+
}>();
|
|
46
|
+
</script>
|
|
@@ -2,28 +2,13 @@
|
|
|
2
2
|
<TMagicScrollbar class="data-source-list-panel m-editor-layer-panel">
|
|
3
3
|
<div class="search-wrapper">
|
|
4
4
|
<SearchInput @search="filterTextChangeHandler"></SearchInput>
|
|
5
|
-
<
|
|
5
|
+
<DataSourceAddButton
|
|
6
6
|
v-if="editable"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
>
|
|
12
|
-
<template #reference>
|
|
13
|
-
<TMagicButton type="primary" size="small">新增</TMagicButton>
|
|
14
|
-
</template>
|
|
15
|
-
<ToolButton
|
|
16
|
-
v-for="(item, index) in datasourceTypeList"
|
|
17
|
-
:data="{
|
|
18
|
-
type: 'button',
|
|
19
|
-
text: item.text,
|
|
20
|
-
handler: () => {
|
|
21
|
-
addHandler(item.type);
|
|
22
|
-
},
|
|
23
|
-
}"
|
|
24
|
-
:key="index"
|
|
25
|
-
></ToolButton>
|
|
26
|
-
</TMagicPopover>
|
|
7
|
+
add-button-text="新增"
|
|
8
|
+
:add-button-config="{ type: 'primary', size: 'small' }"
|
|
9
|
+
:datasource-type-list="datasourceTypeList"
|
|
10
|
+
@add="addHandler"
|
|
11
|
+
></DataSourceAddButton>
|
|
27
12
|
|
|
28
13
|
<slot name="data-source-panel-search"></slot>
|
|
29
14
|
</div>
|
|
@@ -63,15 +48,15 @@
|
|
|
63
48
|
import { computed, inject, useTemplateRef, watch } from 'vue';
|
|
64
49
|
import { mergeWith } from 'lodash-es';
|
|
65
50
|
|
|
66
|
-
import {
|
|
51
|
+
import { tMagicMessageBox, TMagicScrollbar } from '@tmagic/design';
|
|
67
52
|
|
|
68
53
|
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
69
54
|
import SearchInput from '@editor/components/SearchInput.vue';
|
|
70
|
-
import ToolButton from '@editor/components/ToolButton.vue';
|
|
71
55
|
import { useDataSourceEdit } from '@editor/hooks/use-data-source-edit';
|
|
72
56
|
import { useServices } from '@editor/hooks/use-services';
|
|
73
57
|
import type { CustomContentMenuFunction, DataSourceListSlots, EventBus, MenuButton, MenuComponent } from '@editor/type';
|
|
74
58
|
|
|
59
|
+
import DataSourceAddButton from './DataSourceAddButton.vue';
|
|
75
60
|
import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
|
|
76
61
|
import DataSourceList from './DataSourceList.vue';
|
|
77
62
|
import { useContentMenu } from './useContentMenu';
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<template v-if="data.type !== 'page'">
|
|
3
|
-
<
|
|
4
|
-
|
|
3
|
+
<TMagicButton
|
|
4
|
+
link
|
|
5
|
+
:type="data.visible === false ? 'primary' : 'default'"
|
|
6
|
+
:icon="data.visible === false ? Hide : View"
|
|
7
|
+
:title="data.visible === false ? '点击显示' : '点击隐藏'"
|
|
8
|
+
@click.stop="setNodeVisible(data.visible === false)"
|
|
9
|
+
></TMagicButton>
|
|
5
10
|
</template>
|
|
6
11
|
</template>
|
|
7
12
|
|
|
@@ -9,8 +14,8 @@
|
|
|
9
14
|
import { Hide, View } from '@element-plus/icons-vue';
|
|
10
15
|
|
|
11
16
|
import type { MNode } from '@tmagic/core';
|
|
17
|
+
import { TMagicButton } from '@tmagic/design';
|
|
12
18
|
|
|
13
|
-
import MIcon from '@editor/components/Icon.vue';
|
|
14
19
|
import { useServices } from '@editor/hooks/use-services';
|
|
15
20
|
|
|
16
21
|
const props = defineProps<{
|
|
@@ -5,6 +5,22 @@
|
|
|
5
5
|
|
|
6
6
|
.m-editor-tree {
|
|
7
7
|
padding-top: 48px;
|
|
8
|
+
|
|
9
|
+
.tree-node-tool {
|
|
10
|
+
padding-right: 10px;
|
|
11
|
+
|
|
12
|
+
.tmagic-design-button + .tmagic-design-button {
|
|
13
|
+
margin-left: 2px;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tree-node.selected {
|
|
18
|
+
.tree-node-tool {
|
|
19
|
+
.tmagic-design-button {
|
|
20
|
+
color: #fff;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
8
24
|
}
|
|
9
25
|
|
|
10
26
|
.search-wrapper {
|
|
@@ -64,7 +64,7 @@ const fillConfig = (config: FormConfig): FormConfig => [
|
|
|
64
64
|
name: 'beforeRequest',
|
|
65
65
|
type: 'vs-code',
|
|
66
66
|
parse: true,
|
|
67
|
-
|
|
67
|
+
autosize: { minRows: 10, maxRows: 30 },
|
|
68
68
|
},
|
|
69
69
|
],
|
|
70
70
|
},
|
|
@@ -76,7 +76,7 @@ const fillConfig = (config: FormConfig): FormConfig => [
|
|
|
76
76
|
name: 'afterResponse',
|
|
77
77
|
type: 'vs-code',
|
|
78
78
|
parse: true,
|
|
79
|
-
|
|
79
|
+
autosize: { minRows: 10, maxRows: 30 },
|
|
80
80
|
},
|
|
81
81
|
],
|
|
82
82
|
},
|