@tmagic/editor 1.3.13 → 1.3.15
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 +8 -45
- package/dist/tmagic-editor.js +309 -347
- package/dist/tmagic-editor.umd.cjs +311 -349
- package/package.json +11 -11
- package/src/components/ToolButton.vue +6 -1
- package/src/fields/CodeSelect.vue +55 -6
- package/src/fields/CodeSelectCol.vue +8 -4
- package/src/fields/DataSourceMethodSelect.vue +22 -5
- package/src/fields/EventSelect.vue +2 -1
- package/src/hooks/use-float-box.ts +33 -116
- package/src/layouts/page-bar/PageBar.vue +4 -3
- package/src/layouts/sidebar/Sidebar.vue +25 -42
- package/src/layouts/sidebar/layer/LayerPanel.vue +2 -2
- package/src/layouts/sidebar/layer/use-click.ts +1 -1
- package/src/layouts/sidebar/layer/use-node-status.ts +8 -5
- package/src/theme/sidebar.scss +11 -0
- package/src/theme/theme.scss +0 -1
- package/src/type.ts +2 -0
- package/types/fields/CodeSelectCol.vue.d.ts +1 -1
- package/types/fields/DataSourceMethodSelect.vue.d.ts +1 -1
- package/types/hooks/use-float-box.d.ts +9 -9
- package/types/layouts/sidebar/layer/use-click.d.ts +1 -1
- package/types/type.d.ts +2 -0
- package/src/theme/floatbox.scss +0 -48
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.3.
|
|
2
|
+
"version": "1.3.15",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@babel/core": "^7.18.0",
|
|
44
44
|
"@element-plus/icons-vue": "^2.3.1",
|
|
45
|
-
"@tmagic/core": "1.3.
|
|
46
|
-
"@tmagic/dep": "1.3.
|
|
47
|
-
"@tmagic/design": "1.3.
|
|
48
|
-
"@tmagic/form": "1.3.
|
|
49
|
-
"@tmagic/schema": "1.3.
|
|
50
|
-
"@tmagic/stage": "1.3.
|
|
51
|
-
"@tmagic/table": "1.3.
|
|
52
|
-
"@tmagic/utils": "1.3.
|
|
45
|
+
"@tmagic/core": "1.3.15",
|
|
46
|
+
"@tmagic/dep": "1.3.15",
|
|
47
|
+
"@tmagic/design": "1.3.15",
|
|
48
|
+
"@tmagic/form": "1.3.15",
|
|
49
|
+
"@tmagic/schema": "1.3.15",
|
|
50
|
+
"@tmagic/stage": "1.3.15",
|
|
51
|
+
"@tmagic/table": "1.3.15",
|
|
52
|
+
"@tmagic/utils": "1.3.15",
|
|
53
53
|
"buffer": "^6.0.3",
|
|
54
54
|
"color": "^3.1.3",
|
|
55
55
|
"emmet-monaco-es": "^5.3.0",
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"vue": "^3.3.8"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@tmagic/design": "1.3.
|
|
67
|
-
"@tmagic/form": "1.3.
|
|
66
|
+
"@tmagic/design": "1.3.15",
|
|
67
|
+
"@tmagic/form": "1.3.15",
|
|
68
68
|
"monaco-editor": "^0.41.0",
|
|
69
69
|
"vue": "^3.3.8"
|
|
70
70
|
},
|
|
@@ -39,7 +39,12 @@
|
|
|
39
39
|
</template>
|
|
40
40
|
</TMagicDropdown>
|
|
41
41
|
|
|
42
|
-
<component
|
|
42
|
+
<component
|
|
43
|
+
v-else-if="data.type === 'component'"
|
|
44
|
+
v-bind="data.props || {}"
|
|
45
|
+
v-on="(data as MenuComponent).listeners || {}"
|
|
46
|
+
:is="data.component"
|
|
47
|
+
></component>
|
|
43
48
|
</div>
|
|
44
49
|
</template>
|
|
45
50
|
|
|
@@ -12,7 +12,8 @@ import { isEmpty } from 'lodash-es';
|
|
|
12
12
|
|
|
13
13
|
import { TMagicCard } from '@tmagic/design';
|
|
14
14
|
import type { FieldProps } from '@tmagic/form';
|
|
15
|
-
import {
|
|
15
|
+
import { FormState } from '@tmagic/form';
|
|
16
|
+
import { HookCodeType, HookType } from '@tmagic/schema';
|
|
16
17
|
|
|
17
18
|
import type { Services } from '@editor/type';
|
|
18
19
|
|
|
@@ -38,13 +39,61 @@ const codeConfig = computed(() => ({
|
|
|
38
39
|
name: 'hookData',
|
|
39
40
|
enableToggleMode: false,
|
|
40
41
|
expandAll: true,
|
|
41
|
-
|
|
42
|
+
title: (mForm: FormState, { model, index }: any) => {
|
|
43
|
+
if (model.codeType === HookCodeType.DATA_SOURCE_METHOD) {
|
|
44
|
+
if (Array.isArray(model.codeId)) {
|
|
45
|
+
if (model.codeId.length < 2) {
|
|
46
|
+
return index;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const ds = services?.dataSourceService.getDataSourceById(model.codeId[0]);
|
|
50
|
+
return `${ds?.title} / ${model.codeId[1]}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return Array.isArray(model.codeId) ? model.codeId.join('/') : index;
|
|
54
|
+
}
|
|
55
|
+
return model.codeId || index;
|
|
56
|
+
},
|
|
42
57
|
items: [
|
|
43
58
|
{
|
|
44
|
-
type: '
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
type: 'row',
|
|
60
|
+
items: [
|
|
61
|
+
{
|
|
62
|
+
type: 'select',
|
|
63
|
+
name: 'codeType',
|
|
64
|
+
span: 8,
|
|
65
|
+
options: [
|
|
66
|
+
{ value: HookCodeType.CODE, text: '代码块' },
|
|
67
|
+
{ value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
|
|
68
|
+
],
|
|
69
|
+
defaultValue: 'code',
|
|
70
|
+
onChange: (mForm: FormState, v: HookCodeType, { model }: any) => {
|
|
71
|
+
if (v === HookCodeType.DATA_SOURCE_METHOD) {
|
|
72
|
+
model.codeId = [];
|
|
73
|
+
} else {
|
|
74
|
+
model.codeId = '';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return v;
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'code-select-col',
|
|
82
|
+
name: 'codeId',
|
|
83
|
+
span: 16,
|
|
84
|
+
labelWidth: 0,
|
|
85
|
+
display: (mForm: FormState, { model }: any) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
|
|
86
|
+
notEditable: () => !services?.codeBlockService.getEditStatus(),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: 'data-source-method-select',
|
|
90
|
+
name: 'codeId',
|
|
91
|
+
span: 16,
|
|
92
|
+
labelWidth: 0,
|
|
93
|
+
display: (mForm: FormState, { model }: any) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
|
|
94
|
+
notEditable: () => !services?.dataSourceService.get('editable'),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
48
97
|
},
|
|
49
98
|
],
|
|
50
99
|
}));
|
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
@change="onParamsChangeHandler"
|
|
11
11
|
></m-form-container>
|
|
12
12
|
<!-- 查看/编辑按钮 -->
|
|
13
|
-
<Icon v-if="model[name]" class="icon" :icon="!
|
|
13
|
+
<Icon v-if="model[name]" class="icon" :icon="!notEditable ? Edit : View" @click="editCode(model[name])"></Icon>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<!-- 参数填写框 -->
|
|
17
17
|
<CodeParams
|
|
18
18
|
v-if="paramsConfig.length"
|
|
19
19
|
name="params"
|
|
20
|
+
:key="model[name]"
|
|
20
21
|
:model="model"
|
|
21
22
|
:size="size"
|
|
22
23
|
:params-config="paramsConfig"
|
|
@@ -26,19 +27,19 @@
|
|
|
26
27
|
<CodeBlockEditor
|
|
27
28
|
ref="codeBlockEditor"
|
|
28
29
|
v-if="codeConfig"
|
|
29
|
-
:disabled="
|
|
30
|
+
:disabled="notEditable"
|
|
30
31
|
:content="codeConfig"
|
|
31
32
|
@submit="submitCodeBlockHandler"
|
|
32
33
|
></CodeBlockEditor>
|
|
33
34
|
</div>
|
|
34
35
|
</template>
|
|
35
36
|
|
|
36
|
-
<script lang="ts" setup
|
|
37
|
+
<script lang="ts" setup>
|
|
37
38
|
import { computed, inject, ref, watch } from 'vue';
|
|
38
39
|
import { Edit, View } from '@element-plus/icons-vue';
|
|
39
40
|
import { isEmpty, map } from 'lodash-es';
|
|
40
41
|
|
|
41
|
-
import { createValues, FieldProps } from '@tmagic/form';
|
|
42
|
+
import { createValues, type FieldProps, filterFunction, type FormState } from '@tmagic/form';
|
|
42
43
|
import type { Id } from '@tmagic/schema';
|
|
43
44
|
|
|
44
45
|
import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
|
|
@@ -51,9 +52,11 @@ defineOptions({
|
|
|
51
52
|
name: 'MEditorCodeSelectCol',
|
|
52
53
|
});
|
|
53
54
|
|
|
55
|
+
const mForm = inject<FormState | undefined>('mForm');
|
|
54
56
|
const services = inject<Services>('services');
|
|
55
57
|
const emit = defineEmits(['change']);
|
|
56
58
|
|
|
59
|
+
const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
|
|
57
60
|
const props = withDefaults(defineProps<FieldProps<CodeSelectColConfig>>(), {
|
|
58
61
|
disabled: false,
|
|
59
62
|
});
|
|
@@ -91,6 +94,7 @@ watch(
|
|
|
91
94
|
const selectConfig = {
|
|
92
95
|
type: 'select',
|
|
93
96
|
name: props.name,
|
|
97
|
+
disable: props.disabled,
|
|
94
98
|
options: () => {
|
|
95
99
|
if (codeDsl.value) {
|
|
96
100
|
return map(codeDsl.value, (value, key) => ({
|
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
:model="model"
|
|
8
8
|
@change="onChangeHandler"
|
|
9
9
|
></m-form-container>
|
|
10
|
-
<Icon
|
|
10
|
+
<Icon
|
|
11
|
+
v-if="model[name] && isCustomMethod"
|
|
12
|
+
class="icon"
|
|
13
|
+
:icon="!notEditable ? Edit : View"
|
|
14
|
+
@click="editCodeHandler"
|
|
15
|
+
></Icon>
|
|
11
16
|
</div>
|
|
12
17
|
|
|
13
18
|
<CodeParams
|
|
@@ -23,7 +28,7 @@
|
|
|
23
28
|
<CodeBlockEditor
|
|
24
29
|
ref="codeBlockEditor"
|
|
25
30
|
v-if="codeConfig"
|
|
26
|
-
:disabled="
|
|
31
|
+
:disabled="notEditable"
|
|
27
32
|
:content="codeConfig"
|
|
28
33
|
@submit="submitCodeBlockHandler"
|
|
29
34
|
></CodeBlockEditor>
|
|
@@ -34,7 +39,7 @@
|
|
|
34
39
|
import { computed, inject, ref } from 'vue';
|
|
35
40
|
import { Edit, View } from '@element-plus/icons-vue';
|
|
36
41
|
|
|
37
|
-
import { createValues, FieldProps } from '@tmagic/form';
|
|
42
|
+
import { createValues, type FieldProps, filterFunction, type FormState } from '@tmagic/form';
|
|
38
43
|
import type { CodeBlockContent, Id } from '@tmagic/schema';
|
|
39
44
|
|
|
40
45
|
import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
|
|
@@ -47,6 +52,7 @@ defineOptions({
|
|
|
47
52
|
name: 'MEditorDataSourceMethodSelect',
|
|
48
53
|
});
|
|
49
54
|
|
|
55
|
+
const mForm = inject<FormState | undefined>('mForm');
|
|
50
56
|
const services = inject<Services>('services');
|
|
51
57
|
const emit = defineEmits(['change']);
|
|
52
58
|
|
|
@@ -56,14 +62,24 @@ const props = withDefaults(defineProps<FieldProps<DataSourceMethodSelectConfig>>
|
|
|
56
62
|
disabled: false,
|
|
57
63
|
});
|
|
58
64
|
|
|
65
|
+
const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
|
|
66
|
+
|
|
59
67
|
const dataSources = computed(() => dataSourceService?.get('dataSources'));
|
|
60
68
|
|
|
61
|
-
const
|
|
69
|
+
const isCustomMethod = computed(() => {
|
|
70
|
+
const [id, name] = props.model[props.name];
|
|
71
|
+
|
|
72
|
+
const dataSource = dataSourceService?.getDataSourceById(id);
|
|
73
|
+
|
|
74
|
+
return Boolean(dataSource?.methods.find((method) => method.name === name));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const getParamItemsConfig = ([dataSourceId, methodName]: [Id, string] = ['', '']): CodeParamStatement[] => {
|
|
62
78
|
if (!dataSourceId) return [];
|
|
63
79
|
|
|
64
80
|
const paramStatements = dataSources.value
|
|
65
81
|
?.find((item) => item.id === dataSourceId)
|
|
66
|
-
?.methods?.find((item) => item.name ===
|
|
82
|
+
?.methods?.find((item) => item.name === methodName)?.params;
|
|
67
83
|
|
|
68
84
|
if (!paramStatements) return [];
|
|
69
85
|
|
|
@@ -107,6 +123,7 @@ const cascaderConfig = computed(() => ({
|
|
|
107
123
|
type: 'cascader',
|
|
108
124
|
name: props.name,
|
|
109
125
|
options: methodsOptions.value,
|
|
126
|
+
disable: props.disabled,
|
|
110
127
|
onChange: (formState: any, dataSourceMethod: [Id, string]) => {
|
|
111
128
|
setParamsConfig(dataSourceMethod, formState);
|
|
112
129
|
|
|
@@ -171,7 +171,7 @@ const codeActionConfig = computed(() => {
|
|
|
171
171
|
type: 'code-select-col',
|
|
172
172
|
text: '代码块',
|
|
173
173
|
name: 'codeId',
|
|
174
|
-
|
|
174
|
+
notEditable: () => !codeBlockService?.getEditStatus(),
|
|
175
175
|
display: (mForm, { model }) => model.actionType === ActionType.CODE,
|
|
176
176
|
};
|
|
177
177
|
return { ...defaultCodeActionConfig, ...props.config.codeActionConfig };
|
|
@@ -183,6 +183,7 @@ const dataSourceActionConfig = computed(() => {
|
|
|
183
183
|
type: 'data-source-method-select',
|
|
184
184
|
text: '数据源方法',
|
|
185
185
|
name: 'dataSourceMethod',
|
|
186
|
+
notEditable: () => !services?.dataSourceService.get('editable'),
|
|
186
187
|
display: (mForm, { model }) => model.actionType === ActionType.DATA_SOURCE,
|
|
187
188
|
};
|
|
188
189
|
return { ...defaultDataSourceActionConfig, ...props.config.dataSourceActionConfig };
|
|
@@ -1,124 +1,40 @@
|
|
|
1
|
-
import { computed, ComputedRef,
|
|
2
|
-
import Moveable from 'moveable';
|
|
1
|
+
import { computed, ComputedRef, ref, watch } from 'vue';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
interface State {
|
|
4
|
+
status: boolean;
|
|
5
|
+
top: number;
|
|
6
|
+
left: number;
|
|
7
|
+
}
|
|
5
8
|
|
|
6
9
|
export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
const floatBoxStates = ref<{
|
|
11
|
+
[key in (typeof slideKeys.value)[number]]: State;
|
|
12
|
+
}>(
|
|
13
|
+
slideKeys.value.reduce(
|
|
14
|
+
(total, cur) => ({
|
|
15
|
+
...total,
|
|
16
|
+
[cur]: {
|
|
17
|
+
status: false,
|
|
18
|
+
top: 0,
|
|
19
|
+
left: 0,
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
{},
|
|
23
|
+
),
|
|
18
24
|
);
|
|
19
25
|
|
|
20
26
|
const showingBoxKeys = computed(() =>
|
|
21
|
-
|
|
27
|
+
Object.keys(floatBoxStates.value).filter((key) => floatBoxStates.value[key].status),
|
|
22
28
|
);
|
|
23
|
-
|
|
24
29
|
const isDraging = ref(false);
|
|
25
30
|
|
|
26
|
-
const
|
|
27
|
-
const curBoxStatus = floatBoxStates.value?.get(curKey.value)?.status;
|
|
28
|
-
if (curKey.value === key && curBoxStatus) return;
|
|
29
|
-
curKey.value = key;
|
|
30
|
-
setSlideState(key, {
|
|
31
|
-
zIndex: getMaxZIndex() + 1,
|
|
32
|
-
status: true,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
await nextTick();
|
|
36
|
-
if (moveable.value) {
|
|
37
|
-
moveable.value.target = target.value;
|
|
38
|
-
moveable.value.dragTarget = getDragTarget();
|
|
39
|
-
moveable.value.updateRect();
|
|
40
|
-
} else {
|
|
41
|
-
initFloatBoxMoveable();
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const setSlideState = (key: string, data: Record<string, string | number | boolean>) => {
|
|
46
|
-
const slideState = floatBoxStates.value?.get(key);
|
|
47
|
-
if (!slideState) return;
|
|
48
|
-
floatBoxStates.value?.set(key, {
|
|
49
|
-
...slideState,
|
|
50
|
-
...data,
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const getDragTarget = (key?: string) => `.m-editor-float-box-header-${key ?? curKey.value}`;
|
|
55
|
-
|
|
56
|
-
const closeFloatBox = (key: string) => {
|
|
57
|
-
setSlideState(key, {
|
|
58
|
-
status: false,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// 如果只有一个,关掉后需要销毁moveable实例
|
|
62
|
-
if (!floatBoxStates.value?.values) return;
|
|
63
|
-
const keys = [...floatBoxStates.value?.keys()];
|
|
64
|
-
const values = [...floatBoxStates.value?.values()];
|
|
65
|
-
const lastFloatBoxLen = values.filter((state) => state.status).length;
|
|
66
|
-
if (lastFloatBoxLen === 0) {
|
|
67
|
-
moveable.value?.destroy();
|
|
68
|
-
moveable.value = undefined;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 如果关掉的 box 是最大的,需要选中下面的一层
|
|
73
|
-
if (key === curKey.value) {
|
|
74
|
-
// 查找显示的最大 zIndex 对应的 index
|
|
75
|
-
const zIndexList = values.filter((item) => item.status).map((item) => item.zIndex);
|
|
76
|
-
const maxZIndex = Math.max(...zIndexList);
|
|
77
|
-
const key = keys.find((key) => floatBoxStates.value?.get(key)?.zIndex === maxZIndex);
|
|
78
|
-
if (!key) return;
|
|
79
|
-
showFloatBox(key);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const getMaxZIndex = () => {
|
|
84
|
-
if (!floatBoxStates.value?.values()) return 0;
|
|
85
|
-
const list = [...floatBoxStates.value?.values()].map((state) => state.zIndex);
|
|
86
|
-
return Math.max(...list) ?? 0;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const initFloatBoxMoveable = () => {
|
|
90
|
-
const dragTarget = getDragTarget();
|
|
91
|
-
moveable.value = new Moveable(document.body, {
|
|
92
|
-
target: target.value,
|
|
93
|
-
draggable: true,
|
|
94
|
-
resizable: true,
|
|
95
|
-
edge: true,
|
|
96
|
-
keepRatio: false,
|
|
97
|
-
origin: false,
|
|
98
|
-
snappable: true,
|
|
99
|
-
dragTarget,
|
|
100
|
-
dragTargetSelf: false,
|
|
101
|
-
linePadding: 10,
|
|
102
|
-
controlPadding: 10,
|
|
103
|
-
elementGuidelines: [...(floatBoxStates.value?.keys() ?? [])].map((key) => getDragTarget(key)),
|
|
104
|
-
bounds: { left: 0, top: 0, right: 0, bottom: 0, position: 'css' },
|
|
105
|
-
});
|
|
106
|
-
moveable.value.on('drag', (e) => {
|
|
107
|
-
e.target.style.transform = e.transform;
|
|
108
|
-
});
|
|
109
|
-
moveable.value.on('resize', (e) => {
|
|
110
|
-
e.target.style.width = `${e.width}px`;
|
|
111
|
-
e.target.style.height = `${e.height}px`;
|
|
112
|
-
e.target.style.transform = e.drag.transform;
|
|
113
|
-
});
|
|
114
|
-
};
|
|
115
|
-
|
|
31
|
+
const dragstartHandler = () => (isDraging.value = true);
|
|
116
32
|
const dragendHandler = (key: string, e: DragEvent) => {
|
|
117
|
-
|
|
33
|
+
floatBoxStates.value[key] = {
|
|
118
34
|
left: e.clientX,
|
|
119
35
|
top: e.clientY,
|
|
120
|
-
|
|
121
|
-
|
|
36
|
+
status: true,
|
|
37
|
+
};
|
|
122
38
|
isDraging.value = false;
|
|
123
39
|
};
|
|
124
40
|
|
|
@@ -127,13 +43,17 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
|
|
|
127
43
|
e.preventDefault();
|
|
128
44
|
});
|
|
129
45
|
|
|
130
|
-
const dragstartHandler = () => (isDraging.value = true);
|
|
131
|
-
|
|
132
|
-
// 监听 slide 长度变化,更新 ui serice map
|
|
133
46
|
watch(
|
|
134
47
|
() => slideKeys.value,
|
|
135
48
|
() => {
|
|
136
|
-
|
|
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
|
+
}
|
|
137
57
|
},
|
|
138
58
|
{
|
|
139
59
|
deep: true,
|
|
@@ -142,12 +62,9 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
|
|
|
142
62
|
);
|
|
143
63
|
|
|
144
64
|
return {
|
|
145
|
-
showFloatBox,
|
|
146
|
-
closeFloatBox,
|
|
147
65
|
dragstartHandler,
|
|
148
66
|
dragendHandler,
|
|
149
67
|
floatBoxStates,
|
|
150
|
-
floatBox,
|
|
151
68
|
showingBoxKeys,
|
|
152
69
|
};
|
|
153
70
|
};
|
|
@@ -123,7 +123,7 @@ watch(
|
|
|
123
123
|
|
|
124
124
|
watch(active, (active) => {
|
|
125
125
|
if (active === NodeType.PAGE) {
|
|
126
|
-
if (!activePage.value) {
|
|
126
|
+
if (!activePage.value && !pageList.value.length) {
|
|
127
127
|
editorService?.selectRoot();
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
@@ -132,11 +132,12 @@ watch(active, (active) => {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
if (active === NodeType.PAGE_FRAGMENT) {
|
|
135
|
-
|
|
135
|
+
// 之前没有选中过页面片并且当前没有页面片
|
|
136
|
+
if (!activePageFragment.value && !pageFragmentList.value.length) {
|
|
136
137
|
editorService?.selectRoot();
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
|
-
switchPage(activePageFragment.value);
|
|
140
|
+
switchPage(activePageFragment.value || pageFragmentList.value[0].id);
|
|
140
141
|
}
|
|
141
142
|
});
|
|
142
143
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<div
|
|
5
5
|
class="m-editor-sidebar-header-item"
|
|
6
6
|
v-for="(config, index) in sideBarItems"
|
|
7
|
-
v-show="!floatBoxStates
|
|
7
|
+
v-show="!floatBoxStates[config.$key]?.status"
|
|
8
8
|
draggable="true"
|
|
9
9
|
:key="config.$key ?? index"
|
|
10
10
|
:class="{ 'is-active': activeTabName === config.text }"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
v-show="activeTabName === config.text"
|
|
24
24
|
>
|
|
25
25
|
<component
|
|
26
|
-
v-if="config && !floatBoxStates
|
|
26
|
+
v-if="config && !floatBoxStates[config.$key]?.status"
|
|
27
27
|
:is="config.component"
|
|
28
28
|
v-bind="config.props || {}"
|
|
29
29
|
v-on="config?.listeners || {}"
|
|
@@ -96,43 +96,37 @@
|
|
|
96
96
|
</div>
|
|
97
97
|
|
|
98
98
|
<Teleport to="body">
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
v-for="(config, index) in sideBarItems"
|
|
99
|
+
<template v-for="(config, index) in sideBarItems">
|
|
100
|
+
<FloatingBox
|
|
102
101
|
:key="config.$key ?? index"
|
|
103
|
-
|
|
104
|
-
:
|
|
105
|
-
:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
v-if="floatBoxStates[config.$key]?.status"
|
|
103
|
+
v-model:visible="floatBoxStates[config.$key].status"
|
|
104
|
+
:title="config.text"
|
|
105
|
+
:position="{
|
|
106
|
+
left: floatBoxStates[config.$key].left,
|
|
107
|
+
top: floatBoxStates[config.$key].top,
|
|
109
108
|
}"
|
|
110
|
-
v-show="floatBoxStates?.get(config.$key)?.status"
|
|
111
109
|
>
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
v-on="config?.listeners || {}"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
110
|
+
<template #body>
|
|
111
|
+
<div class="m-editor-slide-list-box">
|
|
112
|
+
<component
|
|
113
|
+
v-if="config && floatBoxStates[config.$key].status"
|
|
114
|
+
:is="config.boxComponentConfig?.component || config.component"
|
|
115
|
+
v-bind="config.boxComponentConfig?.props || config.props || {}"
|
|
116
|
+
v-on="config?.listeners || {}"
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
</template>
|
|
120
|
+
</FloatingBox>
|
|
121
|
+
</template>
|
|
129
122
|
</Teleport>
|
|
130
123
|
</template>
|
|
131
124
|
|
|
132
125
|
<script setup lang="ts">
|
|
133
126
|
import { computed, inject, ref, watch } from 'vue';
|
|
134
|
-
import {
|
|
127
|
+
import { Coin, EditPen, Goods, List } from '@element-plus/icons-vue';
|
|
135
128
|
|
|
129
|
+
import FloatingBox from '@editor/components/FloatingBox.vue';
|
|
136
130
|
import MIcon from '@editor/components/Icon.vue';
|
|
137
131
|
import { useFloatBox } from '@editor/hooks/use-float-box';
|
|
138
132
|
import type {
|
|
@@ -200,11 +194,6 @@ const getItemConfig = (data: SideItem): SideComponent => {
|
|
|
200
194
|
text: '代码编辑',
|
|
201
195
|
component: CodeBlockListPanel,
|
|
202
196
|
slots: {},
|
|
203
|
-
boxComponentConfig: {
|
|
204
|
-
props: {
|
|
205
|
-
slideType: 'box',
|
|
206
|
-
},
|
|
207
|
-
},
|
|
208
197
|
},
|
|
209
198
|
'data-source': {
|
|
210
199
|
$key: 'data-source',
|
|
@@ -213,11 +202,6 @@ const getItemConfig = (data: SideItem): SideComponent => {
|
|
|
213
202
|
text: '数据源',
|
|
214
203
|
component: DataSourceListPanel,
|
|
215
204
|
slots: {},
|
|
216
|
-
boxComponentConfig: {
|
|
217
|
-
props: {
|
|
218
|
-
slideType: 'box',
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
205
|
},
|
|
222
206
|
};
|
|
223
207
|
|
|
@@ -235,8 +219,7 @@ watch(
|
|
|
235
219
|
|
|
236
220
|
const slideKeys = computed(() => sideBarItems.value.map((sideBarItem) => sideBarItem.$key));
|
|
237
221
|
|
|
238
|
-
const {
|
|
239
|
-
useFloatBox(slideKeys);
|
|
222
|
+
const { dragstartHandler, dragendHandler, floatBoxStates, showingBoxKeys } = useFloatBox(slideKeys);
|
|
240
223
|
|
|
241
224
|
watch(
|
|
242
225
|
() => showingBoxKeys.value.length,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
@node-dragstart="handleDragStart"
|
|
15
15
|
@node-dragleave="handleDragLeave"
|
|
16
16
|
@node-dragend="handleDragEnd"
|
|
17
|
-
@node-contextmenu="
|
|
17
|
+
@node-contextmenu="nodeContentMenuHandler"
|
|
18
18
|
@node-mouseenter="mouseenterHandler"
|
|
19
19
|
@node-click="nodeClickHandler"
|
|
20
20
|
>
|
|
@@ -113,7 +113,7 @@ const { handleDragStart, handleDragEnd, handleDragLeave, handleDragOver } = useD
|
|
|
113
113
|
const {
|
|
114
114
|
menu,
|
|
115
115
|
nodeClickHandler,
|
|
116
|
-
|
|
116
|
+
nodeContentMenuHandler,
|
|
117
117
|
highlightHandler: mouseenterHandler,
|
|
118
118
|
} = useClick(services, isCtrlKeyDown, nodeStatusMap);
|
|
119
119
|
</script>
|
|
@@ -94,7 +94,7 @@ export const useClick = (
|
|
|
94
94
|
|
|
95
95
|
nodeClickHandler,
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
nodeContentMenuHandler(event: MouseEvent, data: TreeNodeData) {
|
|
98
98
|
event.preventDefault();
|
|
99
99
|
|
|
100
100
|
const nodes = services?.editorService.get('nodes') || [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { computed, ref, watch } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { Id, MNode, MPage, MPageFragment } from '@tmagic/schema';
|
|
4
|
-
import { getNodePath } from '@tmagic/utils';
|
|
4
|
+
import { getNodePath, isPage, isPageFragment } from '@tmagic/utils';
|
|
5
5
|
|
|
6
6
|
import { LayerNodeStatus, Services } from '@editor/type';
|
|
7
7
|
import { traverseNode } from '@editor/utils';
|
|
@@ -48,13 +48,14 @@ export const useNodeStatus = (services: Services | undefined) => {
|
|
|
48
48
|
|
|
49
49
|
// 切换页面或者新增页面,重新生成节点状态
|
|
50
50
|
watch(
|
|
51
|
-
page,
|
|
52
|
-
(
|
|
53
|
-
if (!
|
|
51
|
+
() => page.value?.id,
|
|
52
|
+
(pageId) => {
|
|
53
|
+
if (!pageId) {
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
+
|
|
56
57
|
// 生成节点状态
|
|
57
|
-
nodeStatusMaps.value.set(
|
|
58
|
+
nodeStatusMaps.value.set(pageId, createPageNodeStatus(page.value!, nodeStatusMaps.value.get(pageId)));
|
|
58
59
|
},
|
|
59
60
|
{
|
|
60
61
|
immediate: true,
|
|
@@ -85,6 +86,8 @@ export const useNodeStatus = (services: Services | undefined) => {
|
|
|
85
86
|
|
|
86
87
|
services?.editorService.on('add', (newNodes: MNode[]) => {
|
|
87
88
|
newNodes.forEach((node) => {
|
|
89
|
+
if (isPage(node) || isPageFragment(node)) return;
|
|
90
|
+
|
|
88
91
|
traverseNode(node, (node: MNode) => {
|
|
89
92
|
nodeStatusMap.value?.set(node.id, {
|
|
90
93
|
visible: true,
|