@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.
- package/dist/style.css +22 -26
- package/dist/tmagic-editor.js +977 -798
- package/dist/tmagic-editor.umd.cjs +981 -800
- package/package.json +11 -11
- package/src/components/CodeBlockEditor.vue +75 -101
- package/src/components/FloatingBox.vue +58 -38
- package/src/components/SplitView.vue +46 -35
- package/src/fields/DataSourceFieldSelect.vue +2 -1
- package/src/fields/DataSourceFields.vue +55 -30
- package/src/fields/DataSourceInput.vue +6 -2
- package/src/fields/DataSourceMocks.vue +35 -17
- package/src/hooks/index.ts +2 -0
- package/src/hooks/use-code-block-edit.ts +1 -1
- package/src/hooks/use-editor-content-height.ts +20 -0
- package/src/hooks/use-float-box.ts +21 -15
- package/src/hooks/use-next-float-box-position.ts +29 -0
- package/src/hooks/use-window-rect.ts +20 -0
- package/src/layouts/CodeEditor.vue +3 -6
- package/src/layouts/Framework.vue +33 -34
- package/src/layouts/PropsPanel.vue +37 -0
- package/src/layouts/sidebar/Sidebar.vue +17 -15
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +1 -3
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +36 -22
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +1 -6
- package/src/layouts/workspace/viewer/NodeListMenu.vue +1 -0
- package/src/layouts/workspace/viewer/StageOverlay.vue +3 -1
- package/src/services/stageOverlay.ts +2 -2
- package/src/services/ui.ts +6 -0
- package/src/theme/code-block.scss +0 -19
- package/src/theme/component-list-panel.scss +0 -1
- package/src/theme/floating-box.scss +2 -2
- package/src/theme/icon.scss +7 -1
- package/src/theme/layer-panel.scss +0 -1
- package/src/theme/props-panel.scss +14 -0
- package/src/theme/sidebar.scss +0 -7
- package/src/type.ts +6 -6
- package/types/components/CodeBlockEditor.vue.d.ts +39 -25
- package/types/components/FloatingBox.vue.d.ts +42 -57
- package/types/components/SplitView.vue.d.ts +2 -0
- package/types/fields/DataSourceFields.vue.d.ts +84 -28
- package/types/fields/DataSourceMocks.vue.d.ts +80 -28
- package/types/hooks/index.d.ts +2 -0
- package/types/hooks/use-code-block-edit.d.ts +16 -11
- package/types/hooks/use-data-source-method.d.ts +16 -11
- package/types/hooks/use-editor-content-height.d.ts +3 -0
- package/types/hooks/use-next-float-box-position.d.ts +9 -0
- package/types/hooks/use-window-rect.d.ts +6 -0
- package/types/layouts/sidebar/Sidebar.vue.d.ts +1 -1
- package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +1 -3
- package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +34 -22
- package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +2 -15
- package/types/services/stageOverlay.d.ts +1 -1
- package/types/services/ui.d.ts +6 -0
- 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
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
<FloatingBox
|
|
11
|
+
v-model:visible="addDialogVisible"
|
|
12
|
+
v-model:width="width"
|
|
13
|
+
v-model:height="editorHeight"
|
|
13
14
|
:title="fieldTitle"
|
|
14
|
-
:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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 {
|
|
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,
|
|
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 =
|
|
85
|
+
const width = defineModel<number>('width', { default: 670 });
|
|
70
86
|
|
|
71
87
|
const newHandler = () => {
|
|
72
88
|
fieldValues.value = {};
|
|
73
89
|
fieldTitle.value = '新增属性';
|
|
74
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
<FloatingBox
|
|
10
|
+
v-model:visible="addDialogVisible"
|
|
11
|
+
v-model:width="width"
|
|
12
|
+
v-model:height="editorHeight"
|
|
12
13
|
:title="drawerTitle"
|
|
13
|
-
:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 {
|
|
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,
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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>
|
package/src/hooks/index.ts
CHANGED
|
@@ -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
|
|
33
|
+
const isDragging = ref(false);
|
|
30
34
|
|
|
31
|
-
const dragstartHandler = () => (
|
|
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:
|
|
40
|
+
top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
|
|
36
41
|
status: true,
|
|
37
42
|
};
|
|
38
|
-
|
|
43
|
+
isDragging.value = false;
|
|
39
44
|
};
|
|
40
45
|
|
|
41
46
|
document.body.addEventListener('dragover', (e: DragEvent) => {
|
|
42
|
-
if (!
|
|
47
|
+
if (!isDragging.value) return;
|
|
43
48
|
e.preventDefault();
|
|
44
49
|
});
|
|
45
50
|
|
|
46
51
|
watch(
|
|
47
52
|
() => slideKeys.value,
|
|
48
|
-
() => {
|
|
49
|
-
|
|
50
|
-
if (floatBoxStates.value[key])
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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:
|
|
106
|
+
left: getLeftColumnWidthCacheData(),
|
|
110
107
|
center: 0,
|
|
111
|
-
right:
|
|
108
|
+
right: Number(globalThis.localStorage.getItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_RIGHT_COLUMN_WIDTH,
|
|
112
109
|
});
|
|
113
110
|
|
|
114
|
-
watch(
|
|
115
|
-
|
|
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
|
|
148
|
-
|
|
149
|
-
|
|
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>
|