@tmagic/editor 1.4.0-beta.1 → 1.4.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.
Files changed (54) hide show
  1. package/dist/style.css +22 -26
  2. package/dist/tmagic-editor.js +977 -798
  3. package/dist/tmagic-editor.umd.cjs +981 -800
  4. package/package.json +11 -11
  5. package/src/components/CodeBlockEditor.vue +75 -101
  6. package/src/components/FloatingBox.vue +58 -38
  7. package/src/components/SplitView.vue +46 -35
  8. package/src/fields/DataSourceFieldSelect.vue +2 -1
  9. package/src/fields/DataSourceFields.vue +55 -30
  10. package/src/fields/DataSourceInput.vue +6 -2
  11. package/src/fields/DataSourceMocks.vue +35 -17
  12. package/src/hooks/index.ts +2 -0
  13. package/src/hooks/use-code-block-edit.ts +1 -1
  14. package/src/hooks/use-editor-content-height.ts +20 -0
  15. package/src/hooks/use-float-box.ts +21 -15
  16. package/src/hooks/use-next-float-box-position.ts +29 -0
  17. package/src/hooks/use-window-rect.ts +20 -0
  18. package/src/layouts/CodeEditor.vue +3 -6
  19. package/src/layouts/Framework.vue +33 -34
  20. package/src/layouts/PropsPanel.vue +37 -0
  21. package/src/layouts/sidebar/Sidebar.vue +17 -15
  22. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +1 -3
  23. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +36 -22
  24. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +1 -6
  25. package/src/layouts/workspace/viewer/NodeListMenu.vue +1 -0
  26. package/src/layouts/workspace/viewer/StageOverlay.vue +3 -1
  27. package/src/services/stageOverlay.ts +2 -2
  28. package/src/services/ui.ts +6 -0
  29. package/src/theme/code-block.scss +0 -19
  30. package/src/theme/component-list-panel.scss +0 -1
  31. package/src/theme/floating-box.scss +2 -2
  32. package/src/theme/icon.scss +7 -1
  33. package/src/theme/layer-panel.scss +0 -1
  34. package/src/theme/props-panel.scss +14 -0
  35. package/src/theme/sidebar.scss +0 -7
  36. package/src/type.ts +6 -6
  37. package/types/components/CodeBlockEditor.vue.d.ts +39 -25
  38. package/types/components/FloatingBox.vue.d.ts +42 -57
  39. package/types/components/SplitView.vue.d.ts +2 -0
  40. package/types/fields/DataSourceFields.vue.d.ts +84 -28
  41. package/types/fields/DataSourceMocks.vue.d.ts +80 -28
  42. package/types/hooks/index.d.ts +2 -0
  43. package/types/hooks/use-code-block-edit.d.ts +16 -11
  44. package/types/hooks/use-data-source-method.d.ts +16 -11
  45. package/types/hooks/use-editor-content-height.d.ts +3 -0
  46. package/types/hooks/use-next-float-box-position.d.ts +9 -0
  47. package/types/hooks/use-window-rect.d.ts +6 -0
  48. package/types/layouts/sidebar/Sidebar.vue.d.ts +1 -1
  49. package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +1 -3
  50. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +34 -22
  51. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +2 -15
  52. package/types/services/stageOverlay.d.ts +1 -1
  53. package/types/services/ui.d.ts +6 -0
  54. package/types/type.d.ts +6 -5
@@ -7,39 +7,57 @@
7
7
  <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
8
8
  </div>
9
9
 
10
- <MFormDrawer
11
- ref="addDialog"
12
- label-width="80px"
10
+ <FloatingBox
11
+ v-model:visible="addDialogVisible"
12
+ v-model:width="width"
13
+ v-model:height="editorHeight"
13
14
  :title="fieldTitle"
14
- :config="dataSourceFieldsConfig"
15
- :values="fieldValues"
16
- :parentValues="model[name]"
17
- :disabled="disabled"
18
- :width="width"
19
- @submit="fieldChange"
20
- ></MFormDrawer>
21
-
22
- <MFormDrawer
23
- ref="addFromJsonDialog"
15
+ :position="boxPosition"
16
+ >
17
+ <template #body>
18
+ <MFormBox
19
+ label-width="80px"
20
+ :title="fieldTitle"
21
+ :config="dataSourceFieldsConfig"
22
+ :values="fieldValues"
23
+ :parentValues="model[name]"
24
+ :disabled="disabled"
25
+ @submit="fieldChange"
26
+ ></MFormBox>
27
+ </template>
28
+ </FloatingBox>
29
+
30
+ <FloatingBox
31
+ v-model:visible="addFromJsonDialogVisible"
32
+ v-model:width="width"
33
+ v-model:height="editorHeight"
24
34
  title="快速添加数据定义"
25
- :config="jsonFromConfig"
26
- :values="jsonFromValues"
27
- :disabled="disabled"
28
- :width="width"
29
- @submit="addFromJsonFromChange"
30
- ></MFormDrawer>
35
+ :position="boxPosition"
36
+ >
37
+ <template #body>
38
+ <MFormBox
39
+ :config="jsonFromConfig"
40
+ :values="jsonFromValues"
41
+ :disabled="disabled"
42
+ @submit="addFromJsonFromChange"
43
+ ></MFormBox>
44
+ </template>
45
+ </FloatingBox>
31
46
  </div>
32
47
  </template>
33
48
 
34
49
  <script setup lang="ts">
35
- import { computed, inject, ref } from 'vue';
50
+ import { inject, Ref, ref } from 'vue';
36
51
 
37
52
  import { TMagicButton, tMagicMessage, tMagicMessageBox } from '@tmagic/design';
38
- import { type FieldProps, type FormConfig, type FormState, MFormDrawer } from '@tmagic/form';
53
+ import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
39
54
  import type { DataSchema } from '@tmagic/schema';
40
55
  import { type ColumnConfig, MagicTable } from '@tmagic/table';
41
56
  import { getDefaultValueFromFields } from '@tmagic/utils';
42
57
 
58
+ import FloatingBox from '@editor/components/FloatingBox.vue';
59
+ import { useEditorContentHeight } from '@editor/hooks';
60
+ import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
43
61
  import type { Services } from '@editor/type';
44
62
 
45
63
  defineOptions({
@@ -61,17 +79,16 @@ const emit = defineEmits(['change']);
61
79
 
62
80
  const services = inject<Services>('services');
63
81
 
64
- const addDialog = ref<InstanceType<typeof MFormDrawer>>();
65
-
66
82
  const fieldValues = ref<Record<string, any>>({});
67
83
  const fieldTitle = ref('');
68
84
 
69
- const width = computed(() => globalThis.document.body.clientWidth - (services?.uiService.get('columnWidth').left || 0));
85
+ const width = defineModel<number>('width', { default: 670 });
70
86
 
71
87
  const newHandler = () => {
72
88
  fieldValues.value = {};
73
89
  fieldTitle.value = '新增属性';
74
- addDialog.value?.show();
90
+ calcBoxPosition();
91
+ addDialogVisible.value = true;
75
92
  };
76
93
 
77
94
  const fieldChange = ({ index, ...value }: Record<string, any>) => {
@@ -81,7 +98,7 @@ const fieldChange = ({ index, ...value }: Record<string, any>) => {
81
98
  props.model[props.name].push(value);
82
99
  }
83
100
 
84
- addDialog.value?.hide();
101
+ addDialogVisible.value = false;
85
102
 
86
103
  emit('change', props.model[props.name]);
87
104
  };
@@ -122,7 +139,8 @@ const fieldColumns: ColumnConfig[] = [
122
139
  index,
123
140
  };
124
141
  fieldTitle.value = `编辑${row.title}`;
125
- addDialog.value?.show();
142
+ calcBoxPosition();
143
+ addDialogVisible.value = true;
126
144
  },
127
145
  },
128
146
  {
@@ -220,7 +238,6 @@ const dataSourceFieldsConfig: FormConfig = [
220
238
  },
221
239
  ];
222
240
 
223
- const addFromJsonDialog = ref<InstanceType<typeof MFormDrawer>>();
224
241
  const jsonFromConfig: FormConfig = [
225
242
  {
226
243
  name: 'data',
@@ -238,7 +255,8 @@ const jsonFromValues = ref({
238
255
 
239
256
  const newFromJsonHandler = () => {
240
257
  jsonFromValues.value.data = getDefaultValueFromFields(props.model[props.name]);
241
- addFromJsonDialog.value?.show();
258
+ calcBoxPosition();
259
+ addFromJsonDialogVisible.value = true;
242
260
  };
243
261
 
244
262
  const getValueType = (value: any) => {
@@ -288,11 +306,18 @@ const addFromJsonFromChange = ({ data }: { data: string }) => {
288
306
 
289
307
  props.model[props.name] = getFieldsConfig(value, props.model[props.name]);
290
308
 
291
- addFromJsonDialog.value?.hide();
309
+ addFromJsonDialogVisible.value = false;
292
310
 
293
311
  emit('change', props.model[props.name]);
294
312
  } catch (e: any) {
295
313
  tMagicMessage.error(e.message);
296
314
  }
297
315
  };
316
+
317
+ const addDialogVisible = defineModel<boolean>('visible', { default: false });
318
+ const addFromJsonDialogVisible = defineModel<boolean>('visible1', { default: false });
319
+ const { height: editorHeight } = useEditorContentHeight();
320
+
321
+ const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
322
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
298
323
  </script>
@@ -29,9 +29,13 @@
29
29
  </div>
30
30
  </template>
31
31
  </component>
32
- <div :class="`tmagic-data-source-input-text el-input el-input--${size}`" @mouseup="mouseupHandler" v-else>
32
+ <div
33
+ :class="`tmagic-data-source-input-text el-input t-input t-size-${size?.[0]} el-input--${size}`"
34
+ @mouseup="mouseupHandler"
35
+ v-else
36
+ >
33
37
  <div :class="`tmagic-data-source-input-text-wrapper el-input__wrapper ${isFocused ? ' is-focus' : ''}`">
34
- <div class="el-input__inner">
38
+ <div class="el-input__inner t-input__inner">
35
39
  <template v-for="(item, index) in displayState">
36
40
  <span :key="index" v-if="item.type === 'text'" style="margin-right: 2px">{{ item.value }}</span>
37
41
  <TMagicTag :key="index" :size="size" v-if="item.type === 'var'">{{ item.value }}</TMagicTag>
@@ -6,32 +6,44 @@
6
6
  <TMagicButton size="small" type="primary" :disabled="disabled" plain @click="newHandler()">添加</TMagicButton>
7
7
  </div>
8
8
 
9
- <MFormDrawer
10
- ref="addDialog"
11
- label-width="120px"
9
+ <FloatingBox
10
+ v-model:visible="addDialogVisible"
11
+ v-model:width="width"
12
+ v-model:height="editorHeight"
12
13
  :title="drawerTitle"
13
- :config="formConfig"
14
- :values="formValues"
15
- :parentValues="model[name]"
16
- :disabled="disabled"
17
- :width="width"
18
- @submit="formChangeHandler"
19
- ></MFormDrawer>
14
+ :position="boxPosition"
15
+ >
16
+ <template #body>
17
+ <MFormBox
18
+ ref="addDialog"
19
+ label-width="120px"
20
+ :config="formConfig"
21
+ :values="formValues"
22
+ :parentValues="model[name]"
23
+ :disabled="disabled"
24
+ @submit="formChangeHandler"
25
+ ></MFormBox>
26
+ </template>
27
+ </FloatingBox>
20
28
  </div>
21
29
  </template>
22
30
 
23
31
  <script setup lang="ts">
24
- import { computed, inject, ref } from 'vue';
32
+ import { inject, Ref, ref } from 'vue';
25
33
 
26
34
  import { TMagicButton, tMagicMessageBox, TMagicSwitch } from '@tmagic/design';
27
- import { type FieldProps, type FormConfig, type FormState, MFormDrawer } from '@tmagic/form';
35
+ import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
28
36
  import type { MockSchema } from '@tmagic/schema';
29
37
  import { type ColumnConfig, MagicTable } from '@tmagic/table';
30
38
  import { getDefaultValueFromFields } from '@tmagic/utils';
31
39
 
40
+ import FloatingBox from '@editor/components/FloatingBox.vue';
41
+ import { useNextFloatBoxPosition } from '@editor/hooks/use-next-float-box-position';
32
42
  import CodeEditor from '@editor/layouts/CodeEditor.vue';
33
43
  import { Services } from '@editor/type';
34
44
 
45
+ import { useEditorContentHeight } from '..';
46
+
35
47
  defineOptions({
36
48
  name: 'MFieldsDataSourceMocks',
37
49
  });
@@ -50,9 +62,8 @@ const props = withDefaults(
50
62
  const emit = defineEmits(['change']);
51
63
 
52
64
  const services = inject<Services>('services');
53
- const width = computed(() => globalThis.document.body.clientWidth - (services?.uiService.get('columnWidth').left || 0));
65
+ const width = defineModel<number>('width', { default: 670 });
54
66
 
55
- const addDialog = ref<InstanceType<typeof MFormDrawer>>();
56
67
  const drawerTitle = ref('');
57
68
  const formValues = ref<Record<string, any>>({});
58
69
 
@@ -182,7 +193,8 @@ const columns: ColumnConfig[] = [
182
193
  index,
183
194
  };
184
195
  drawerTitle.value = `编辑${row.title}`;
185
- addDialog.value?.show();
196
+ calcBoxPosition();
197
+ addDialogVisible.value = true;
186
198
  },
187
199
  },
188
200
  {
@@ -206,7 +218,8 @@ const newHandler = () => {
206
218
  enable: isFirstRow,
207
219
  };
208
220
  drawerTitle.value = '新增Mock';
209
- addDialog.value?.show();
221
+ calcBoxPosition();
222
+ addDialogVisible.value = true;
210
223
  };
211
224
 
212
225
  const formChangeHandler = ({ index, ...value }: Record<string, any>) => {
@@ -216,7 +229,7 @@ const formChangeHandler = ({ index, ...value }: Record<string, any>) => {
216
229
  props.model[props.name].push(value);
217
230
  }
218
231
 
219
- addDialog.value?.hide();
232
+ addDialogVisible.value = false;
220
233
 
221
234
  emit('change', props.model[props.name]);
222
235
  };
@@ -234,4 +247,9 @@ const toggleValue = (row: MockSchema, key: 'enable' | 'useInEditor', value: bool
234
247
  index,
235
248
  });
236
249
  };
250
+
251
+ const addDialogVisible = defineModel<boolean>('visible', { default: false });
252
+ const { height: editorHeight } = useEditorContentHeight();
253
+ const parentFloating = inject<Ref<HTMLDivElement | null>>('parentFloating', ref(null));
254
+ const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(services?.uiService, parentFloating);
237
255
  </script>
@@ -20,3 +20,5 @@ export * from './use-code-block-edit';
20
20
  export * from './use-data-source-method';
21
21
  export * from './use-stage';
22
22
  export * from './use-float-box';
23
+ export * from './use-window-rect';
24
+ export * from './use-editor-content-height';
@@ -20,7 +20,7 @@ export const useCodeBlockEdit = (codeBlockService?: CodeBlockService) => {
20
20
  }
21
21
 
22
22
  codeConfig.value = {
23
- name: '代码块',
23
+ name: '',
24
24
  content: `({app, params}) => {\n // place your code here\n}`,
25
25
  params: [],
26
26
  };
@@ -0,0 +1,20 @@
1
+ import { computed, inject, ref, watchEffect } from 'vue';
2
+
3
+ import type { Services } from '@editor/type';
4
+
5
+ export const useEditorContentHeight = () => {
6
+ const services = inject<Services>('services');
7
+ const frameworkHeight = computed(() => services?.uiService.get('frameworkRect').height || 0);
8
+ const navMenuHeight = computed(() => services?.uiService.get('navMenuRect').height || 0);
9
+ const editorContentHeight = computed(() => frameworkHeight.value - navMenuHeight.value);
10
+
11
+ const height = ref(0);
12
+ watchEffect(() => {
13
+ if (height.value > 0 && height.value === editorContentHeight.value) return;
14
+ height.value = editorContentHeight.value;
15
+ });
16
+
17
+ return {
18
+ height,
19
+ };
20
+ };
@@ -1,4 +1,6 @@
1
- import { computed, ComputedRef, ref, watch } from 'vue';
1
+ import { computed, ComputedRef, inject, ref, watch } from 'vue';
2
+
3
+ import type { Services } from '@editor/type';
2
4
 
3
5
  interface State {
4
6
  status: boolean;
@@ -7,6 +9,8 @@ interface State {
7
9
  }
8
10
 
9
11
  export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
12
+ const services = inject<Services>('services');
13
+
10
14
  const floatBoxStates = ref<{
11
15
  [key in (typeof slideKeys.value)[number]]: State;
12
16
  }>(
@@ -26,34 +30,36 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
26
30
  const showingBoxKeys = computed(() =>
27
31
  Object.keys(floatBoxStates.value).filter((key) => floatBoxStates.value[key].status),
28
32
  );
29
- const isDraging = ref(false);
33
+ const isDragging = ref(false);
30
34
 
31
- const dragstartHandler = () => (isDraging.value = true);
35
+ const dragstartHandler = () => (isDragging.value = true);
32
36
  const dragendHandler = (key: string, e: DragEvent) => {
37
+ const navMenuRect = services?.uiService?.get('navMenuRect');
33
38
  floatBoxStates.value[key] = {
34
39
  left: e.clientX,
35
- top: e.clientY,
40
+ top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
36
41
  status: true,
37
42
  };
38
- isDraging.value = false;
43
+ isDragging.value = false;
39
44
  };
40
45
 
41
46
  document.body.addEventListener('dragover', (e: DragEvent) => {
42
- if (!isDraging.value) return;
47
+ if (!isDragging.value) return;
43
48
  e.preventDefault();
44
49
  });
45
50
 
46
51
  watch(
47
52
  () => slideKeys.value,
48
- () => {
49
- for (const key in slideKeys.value) {
50
- if (floatBoxStates.value[key]) continue;
51
- floatBoxStates.value[key] = {
52
- status: false,
53
- top: 0,
54
- left: 0,
55
- };
56
- }
53
+ (slideKeys) => {
54
+ slideKeys.forEach((key) => {
55
+ if (!floatBoxStates.value[key]) {
56
+ floatBoxStates.value[key] = {
57
+ status: false,
58
+ top: 0,
59
+ left: 0,
60
+ };
61
+ }
62
+ });
57
63
  },
58
64
  {
59
65
  deep: true,
@@ -0,0 +1,29 @@
1
+ import { Ref, ref } from 'vue';
2
+
3
+ import { UiService } from '@editor/services/ui';
4
+
5
+ export const useNextFloatBoxPosition = (uiService?: UiService, parent?: Ref<HTMLDivElement | null>) => {
6
+ const boxPosition = ref({
7
+ left: 0,
8
+ top: 0,
9
+ });
10
+
11
+ const calcBoxPosition = () => {
12
+ const columnWidth = uiService?.get('columnWidth');
13
+ const navMenuRect = uiService?.get('navMenuRect');
14
+ let left = columnWidth?.left ?? 0;
15
+ if (parent?.value) {
16
+ const rect = parent?.value?.getBoundingClientRect();
17
+ left = (rect?.left ?? 0) + (rect?.width ?? 0);
18
+ }
19
+ boxPosition.value = {
20
+ left,
21
+ top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
22
+ };
23
+ };
24
+
25
+ return {
26
+ boxPosition,
27
+ calcBoxPosition,
28
+ };
29
+ };
@@ -0,0 +1,20 @@
1
+ import { onBeforeUnmount, reactive } from 'vue';
2
+
3
+ export const useWindowRect = () => {
4
+ const rect = reactive({ width: globalThis.innerWidth, height: globalThis.innerHeight });
5
+
6
+ const windowResizeHandler = () => {
7
+ rect.width = globalThis.innerWidth;
8
+ rect.height = globalThis.innerHeight;
9
+ };
10
+
11
+ globalThis.addEventListener('resize', windowResizeHandler);
12
+
13
+ onBeforeUnmount(() => {
14
+ globalThis.removeEventListener('resize', windowResizeHandler);
15
+ });
16
+
17
+ return {
18
+ rect,
19
+ };
20
+ };
@@ -5,12 +5,8 @@
5
5
  :class="`magic-code-editor-wrapper${fullScreen ? ' full-screen' : ''}`"
6
6
  :style="!fullScreen && height ? `height: ${height}` : '100%'"
7
7
  >
8
- <TMagicButton
9
- class="magic-code-editor-full-screen-icon"
10
- circle
11
- size="small"
12
- :icon="FullScreen"
13
- @click="fullScreenHandler"
8
+ <TMagicButton class="magic-code-editor-full-screen-icon" circle size="small" @click="fullScreenHandler"
9
+ ><MIcon :icon="FullScreen"></MIcon
14
10
  ></TMagicButton>
15
11
  <div ref="codeEditor" class="magic-code-editor-content"></div>
16
12
  </div>
@@ -26,6 +22,7 @@ import serialize from 'serialize-javascript';
26
22
 
27
23
  import { TMagicButton } from '@tmagic/design';
28
24
 
25
+ import MIcon from '@editor/components/Icon.vue';
29
26
  import { getConfig } from '@editor/utils/config';
30
27
  import monaco from '@editor/utils/monaco-editor';
31
28
 
@@ -24,6 +24,7 @@
24
24
  :min-left="65"
25
25
  :min-right="20"
26
26
  :min-center="100"
27
+ :width="frameworkRect?.width || 0"
27
28
  @change="columnWidthChange"
28
29
  >
29
30
  <template #left>
@@ -57,7 +58,7 @@
57
58
  </template>
58
59
 
59
60
  <script lang="ts" setup>
60
- import { computed, inject, ref, watch } from 'vue';
61
+ import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
61
62
 
62
63
  import { TMagicScrollbar } from '@tmagic/design';
63
64
 
@@ -101,40 +102,15 @@ const RIGHT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorRightColumnWidthData';
101
102
  const getLeftColumnWidthCacheData = () =>
102
103
  Number(globalThis.localStorage.getItem(LEFT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_LEFT_COLUMN_WIDTH;
103
104
 
104
- const leftColumnWidthCacheData = getLeftColumnWidthCacheData();
105
- const RightColumnWidthCacheData =
106
- Number(globalThis.localStorage.getItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_RIGHT_COLUMN_WIDTH;
107
-
108
105
  const columnWidth = ref<Partial<GetColumnWidth>>({
109
- left: leftColumnWidthCacheData,
106
+ left: getLeftColumnWidthCacheData(),
110
107
  center: 0,
111
- right: RightColumnWidthCacheData,
108
+ right: Number(globalThis.localStorage.getItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_RIGHT_COLUMN_WIDTH,
112
109
  });
113
110
 
114
- watch(
115
- [pageLength, splitView],
116
- () => {
117
- splitView.value?.updateWidth();
118
- },
119
- {
120
- immediate: true,
121
- },
122
- );
123
-
124
- watch(
125
- () => columnWidth.value.right,
126
- (right) => {
127
- if (typeof right === 'undefined') return;
128
- globalThis.localStorage.setItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY, `${right}`);
129
- },
130
- );
131
-
132
- watch(
133
- () => columnWidth.value.left,
134
- (left) => {
135
- globalThis.localStorage.setItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, `${left}`);
136
- },
137
- );
111
+ watch(pageLength, () => {
112
+ splitView.value?.updateWidth();
113
+ });
138
114
 
139
115
  watch(
140
116
  () => uiService?.get('hideSlideBar'),
@@ -144,12 +120,35 @@ watch(
144
120
  );
145
121
 
146
122
  const columnWidthChange = (columnW: GetColumnWidth) => {
147
- columnWidth.value.left = columnW.left;
148
- columnWidth.value.center = columnW.center;
149
- columnWidth.value.right = columnW.right;
123
+ columnWidth.value = columnW;
124
+
125
+ globalThis.localStorage.setItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, `${columnW.left}`);
126
+ globalThis.localStorage.setItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY, `${columnW.right}`);
150
127
  uiService?.set('columnWidth', columnW);
151
128
  };
152
129
 
130
+ const frameworkRect = computed(() => uiService?.get('frameworkRect'));
131
+
132
+ const resizerObserver = new ResizeObserver((entries) => {
133
+ const { contentRect } = entries[0];
134
+ uiService?.set('frameworkRect', {
135
+ width: contentRect.width,
136
+ height: contentRect.height,
137
+ left: contentRect.left,
138
+ top: contentRect.top,
139
+ });
140
+ });
141
+
142
+ onMounted(() => {
143
+ if (content.value) {
144
+ resizerObserver.observe(content.value);
145
+ }
146
+ });
147
+
148
+ onBeforeUnmount(() => {
149
+ resizerObserver.disconnect();
150
+ });
151
+
153
152
  const saveCode = (value: string) => {
154
153
  try {
155
154
  const parseDSL = getConfig('parseDSL');
@@ -12,17 +12,44 @@
12
12
  @change="submit"
13
13
  @error="errorHandler"
14
14
  ></MForm>
15
+
16
+ <TMagicButton
17
+ class="m-editor-props-panel-src-icon"
18
+ circle
19
+ size="large"
20
+ title="源码"
21
+ :type="showSrc ? 'primary' : ''"
22
+ @click="showSrc = !showSrc"
23
+ >
24
+ <MIcon :icon="DocumentIcon"></MIcon>
25
+ </TMagicButton>
26
+
27
+ <CodeEditor
28
+ v-if="showSrc"
29
+ :height="`${editorContentHeight}px`"
30
+ :init-values="values"
31
+ :options="codeOptions"
32
+ :parse="true"
33
+ @save="saveCode"
34
+ ></CodeEditor>
15
35
  </div>
16
36
  </template>
17
37
 
18
38
  <script lang="ts" setup>
19
39
  import { computed, getCurrentInstance, inject, onBeforeUnmount, onMounted, ref, watchEffect } from 'vue';
40
+ import { Document as DocumentIcon } from '@element-plus/icons-vue';
20
41
 
42
+ import { TMagicButton } from '@tmagic/design';
21
43
  import type { FormState, FormValue } from '@tmagic/form';
22
44
  import { MForm } from '@tmagic/form';
45
+ import type { MNode } from '@tmagic/schema';
23
46
 
47
+ import MIcon from '@editor/components/Icon.vue';
48
+ import { useEditorContentHeight } from '@editor/hooks/use-editor-content-height';
24
49
  import type { PropsPanelSlots, Services } from '@editor/type';
25
50
 
51
+ import CodeEditor from './CodeEditor.vue';
52
+
26
53
  defineSlots<PropsPanelSlots>();
27
54
 
28
55
  defineOptions({
@@ -33,8 +60,12 @@ defineProps<{
33
60
  extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
34
61
  }>();
35
62
 
63
+ const codeOptions = inject('codeOptions', {});
64
+
36
65
  const emit = defineEmits(['mounted', 'submit-error', 'form-error']);
37
66
 
67
+ const showSrc = ref(false);
68
+
38
69
  const internalInstance = getCurrentInstance();
39
70
  const values = ref<FormValue>({});
40
71
  const configForm = ref<InstanceType<typeof MForm>>();
@@ -46,6 +77,8 @@ const nodes = computed(() => services?.editorService.get('nodes') || []);
46
77
  const propsPanelSize = computed(() => services?.uiService.get('propsPanelSize') || 'small');
47
78
  const stage = computed(() => services?.editorService.get('stage'));
48
79
 
80
+ const { height: editorContentHeight } = useEditorContentHeight();
81
+
49
82
  const init = async () => {
50
83
  if (!node.value) {
51
84
  curFormConfig.value = [];
@@ -87,5 +120,9 @@ const errorHandler = (e: any) => {
87
120
  emit('form-error', e);
88
121
  };
89
122
 
123
+ const saveCode = (values: MNode) => {
124
+ services?.editorService.update(values);
125
+ };
126
+
90
127
  defineExpose({ configForm, submit });
91
128
  </script>