@tmagic/editor 1.7.0-beta.5 → 1.7.1

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.0-beta.5",
2
+ "version": "1.7.1",
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-beta.5",
61
- "@tmagic/stage": "1.7.0-beta.5",
62
- "@tmagic/form": "1.7.0-beta.5",
63
- "@tmagic/utils": "1.7.0-beta.5",
64
- "@tmagic/table": "1.7.0-beta.5"
60
+ "@tmagic/design": "1.7.1",
61
+ "@tmagic/form": "1.7.1",
62
+ "@tmagic/stage": "1.7.1",
63
+ "@tmagic/table": "1.7.1",
64
+ "@tmagic/utils": "1.7.1"
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-beta.5"
78
+ "@tmagic/core": "1.7.1"
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
- height: '500px',
204
+ autosize: { minRows: 10, maxRows: 30 },
205
205
  onChange: (formState: FormState | undefined, code: string) => {
206
206
  try {
207
207
  // 检测js代码是否存在语法错误
@@ -7,6 +7,7 @@
7
7
  ...config.options,
8
8
  readOnly: disabled,
9
9
  }"
10
+ :autosize="config.autosize"
10
11
  :parse="config.parse"
11
12
  @save="save"
12
13
  ></MagicCodeEditor>
@@ -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
- height: '600px',
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
- height: '400px',
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);
@@ -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
- <TMagicPopover
5
+ <DataSourceAddButton
6
6
  v-if="editable"
7
- placement="right"
8
- trigger="hover"
9
- popper-class="data-source-list-panel-add-menu"
10
- :destroy-on-close="true"
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 { TMagicButton, tMagicMessageBox, TMagicPopover, TMagicScrollbar } from '@tmagic/design';
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
- <MIcon v-if="data.visible === false" :icon="Hide" @click.stop="setNodeVisible(true)" title="点击显示"></MIcon>
4
- <MIcon v-else :icon="View" @click.stop="setNodeVisible(false)" class="node-lock" title="点击隐藏"></MIcon>
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 {
@@ -40,7 +40,7 @@
40
40
  top: 0;
41
41
  width: 100%;
42
42
  background: #fff;
43
- z-index: 2;
43
+ z-index: 3;
44
44
  }
45
45
  }
46
46
  }
@@ -64,7 +64,7 @@ const fillConfig = (config: FormConfig): FormConfig => [
64
64
  name: 'beforeRequest',
65
65
  type: 'vs-code',
66
66
  parse: true,
67
- height: '600px',
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
- height: '600px',
79
+ autosize: { minRows: 10, maxRows: 30 },
80
80
  },
81
81
  ],
82
82
  },