@tmagic/editor 1.4.14 → 1.4.16
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/tmagic-editor.js +246 -127
- package/dist/tmagic-editor.umd.cjs +244 -125
- package/package.json +12 -12
- package/src/Editor.vue +4 -0
- package/src/components/ContentMenu.vue +8 -1
- package/src/components/TreeNode.vue +7 -0
- package/src/fields/CodeSelect.vue +3 -3
- package/src/fields/DataSourceFieldSelect/FieldSelect.vue +12 -8
- package/src/fields/DataSourceFieldSelect/Index.vue +10 -9
- package/src/fields/DataSourceMethodSelect.vue +8 -8
- package/src/fields/DataSourceSelect.vue +6 -8
- package/src/hooks/use-float-box.ts +52 -12
- package/src/layouts/sidebar/ComponentListPanel.vue +30 -27
- package/src/layouts/sidebar/Sidebar.vue +24 -3
- package/src/layouts/sidebar/layer/LayerPanel.vue +1 -1
- package/src/layouts/sidebar/layer/use-click.ts +9 -0
- package/src/layouts/sidebar/layer/use-drag.ts +28 -4
- package/src/services/editor.ts +13 -2
- package/src/type.ts +5 -0
- package/types/Editor.vue.d.ts +2313 -0
- package/types/components/CodeParams.vue.d.ts +4 -4
- package/types/components/ContentMenu.vue.d.ts +23 -15
- package/types/components/FloatingBox.vue.d.ts +9 -7
- package/types/components/Resizer.vue.d.ts +6 -4
- package/types/components/ScrollBar.vue.d.ts +2 -2
- package/types/components/ScrollViewer.vue.d.ts +22 -20
- package/types/components/SplitView.vue.d.ts +26 -24
- package/types/components/ToolButton.vue.d.ts +5 -5
- package/types/components/Tree.vue.d.ts +28 -26
- package/types/components/TreeNode.vue.d.ts +33 -24
- package/types/fields/Code.vue.d.ts +8 -8
- package/types/fields/CodeLink.vue.d.ts +4 -4
- package/types/fields/CodeSelect.vue.d.ts +2 -2
- package/types/fields/DisplayConds.vue.d.ts +4 -4
- package/types/fields/KeyValue.vue.d.ts +2 -2
- package/types/hooks/use-code-block-edit.d.ts +91 -2
- package/types/hooks/use-data-source-edit.d.ts +85 -2
- package/types/hooks/use-data-source-method.d.ts +90 -1
- package/types/hooks/use-editor-content-height.d.ts +1 -1
- package/types/hooks/use-filter.d.ts +1 -1
- package/types/hooks/use-float-box.d.ts +3 -1
- package/types/hooks/use-getso.d.ts +2 -2
- package/types/hooks/use-next-float-box-position.d.ts +6 -0
- package/types/hooks/use-node-status.d.ts +6 -1
- package/types/initService.d.ts +1 -1
- package/types/layouts/CodeEditor.vue.d.ts +14 -14
- package/types/layouts/Framework.vue.d.ts +6 -4
- package/types/layouts/NavMenu.vue.d.ts +4 -4
- package/types/layouts/PropsPanel.vue.d.ts +265 -14
- package/types/layouts/page-bar/PageBar.vue.d.ts +10 -8
- package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +9 -7
- package/types/layouts/page-bar/PageList.vue.d.ts +8 -6
- package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +3 -1
- package/types/layouts/sidebar/Sidebar.vue.d.ts +9 -7
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +6 -4
- package/types/layouts/sidebar/code-block/CodeBlockListPanel.vue.d.ts +6 -4
- package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +4 -2
- package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +3 -1
- package/types/layouts/sidebar/layer/LayerMenu.vue.d.ts +8 -8
- package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +9 -7
- package/types/layouts/sidebar/layer/use-click.d.ts +65 -10
- package/types/layouts/sidebar/layer/use-keybinding.d.ts +1 -1
- package/types/layouts/sidebar/layer/use-node-status.d.ts +6 -1
- package/types/layouts/workspace/Workspace.vue.d.ts +10 -8
- package/types/layouts/workspace/viewer/Stage.vue.d.ts +6 -6
- package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +10 -10
- package/types/services/BaseService.d.ts +0 -1
- package/types/services/dataSource.d.ts +4 -4
- package/types/services/ui.d.ts +7 -5
- package/types/type.d.ts +7 -1
- package/types/utils/data-source/index.d.ts +1 -1
- package/types/utils/idle-task.d.ts +0 -1
- package/types/utils/scroll-viewer.d.ts +0 -1
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.4.
|
|
2
|
+
"version": "1.4.16",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"moveable": "^0.53.0",
|
|
56
56
|
"serialize-javascript": "^6.0.0",
|
|
57
57
|
"sortablejs": "^1.15.2",
|
|
58
|
-
"@tmagic/dep": "1.4.
|
|
59
|
-
"@tmagic/table": "1.4.
|
|
58
|
+
"@tmagic/dep": "1.4.16",
|
|
59
|
+
"@tmagic/table": "1.4.16"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/events": "^3.0.0",
|
|
@@ -64,26 +64,26 @@
|
|
|
64
64
|
"@types/node": "^18.19.0",
|
|
65
65
|
"@types/serialize-javascript": "^5.0.1",
|
|
66
66
|
"@types/sortablejs": "^1.15.8",
|
|
67
|
-
"@vitejs/plugin-vue": "^5.
|
|
67
|
+
"@vitejs/plugin-vue": "^5.1.1",
|
|
68
68
|
"@vue/compiler-sfc": "^3.4.27",
|
|
69
69
|
"@vue/test-utils": "^2.4.6",
|
|
70
70
|
"rimraf": "^3.0.2",
|
|
71
71
|
"sass": "^1.77.0",
|
|
72
72
|
"tsc-alias": "^1.8.5",
|
|
73
73
|
"type-fest": "^4.10.3",
|
|
74
|
-
"vite": "^5.3.
|
|
74
|
+
"vite": "^5.3.5",
|
|
75
75
|
"vue-tsc": "^2.0.19"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
78
|
"monaco-editor": "^0.48.0",
|
|
79
79
|
"typescript": "*",
|
|
80
|
-
"vue": "^3.4.
|
|
81
|
-
"@tmagic/core": "1.4.
|
|
82
|
-
"@tmagic/design": "1.4.
|
|
83
|
-
"@tmagic/schema": "1.4.
|
|
84
|
-
"@tmagic/
|
|
85
|
-
"@tmagic/
|
|
86
|
-
"@tmagic/
|
|
80
|
+
"vue": "^3.4.35",
|
|
81
|
+
"@tmagic/core": "1.4.16",
|
|
82
|
+
"@tmagic/design": "1.4.16",
|
|
83
|
+
"@tmagic/schema": "1.4.16",
|
|
84
|
+
"@tmagic/stage": "1.4.16",
|
|
85
|
+
"@tmagic/utils": "1.4.16",
|
|
86
|
+
"@tmagic/form": "1.4.16"
|
|
87
87
|
},
|
|
88
88
|
"peerDependenciesMeta": {
|
|
89
89
|
"typescript": {
|
package/src/Editor.vue
CHANGED
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
<slot name="layer-node-tool" :data="data"></slot>
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
|
+
<template #component-list="{ componentGroupList }">
|
|
37
|
+
<slot name="component-list" :component-group-list="componentGroupList"></slot>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
36
40
|
<template #component-list-panel-header>
|
|
37
41
|
<slot name="component-list-panel-header"></slot>
|
|
38
42
|
</template>
|
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
<script lang="ts" setup>
|
|
39
39
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
|
|
40
40
|
|
|
41
|
+
import { useZIndex } from '@tmagic/design';
|
|
42
|
+
|
|
41
43
|
import { MenuButton, MenuComponent } from '@editor/type';
|
|
42
44
|
|
|
43
45
|
import ToolButton from './ToolButton.vue';
|
|
@@ -71,6 +73,8 @@ const buttons = ref<InstanceType<typeof ToolButton>[]>();
|
|
|
71
73
|
const subMenu = ref<any>();
|
|
72
74
|
const visible = ref(false);
|
|
73
75
|
const subMenuData = ref<(MenuButton | MenuComponent)[]>([]);
|
|
76
|
+
const zIndex = useZIndex();
|
|
77
|
+
const curZIndex = ref<number>(0);
|
|
74
78
|
|
|
75
79
|
const menuPosition = ref({
|
|
76
80
|
left: 0,
|
|
@@ -80,6 +84,7 @@ const menuPosition = ref({
|
|
|
80
84
|
const menuStyle = computed(() => ({
|
|
81
85
|
top: `${menuPosition.value.top}px`,
|
|
82
86
|
left: `${menuPosition.value.left}px`,
|
|
87
|
+
zIndex: curZIndex.value,
|
|
83
88
|
}));
|
|
84
89
|
|
|
85
90
|
const contains = (el: HTMLElement) => menu.value?.contains(el) || subMenu.value?.contains(el);
|
|
@@ -127,13 +132,15 @@ const setPosition = (e: { clientY: number; clientX: number }) => {
|
|
|
127
132
|
};
|
|
128
133
|
|
|
129
134
|
const show = (e?: { clientY: number; clientX: number }) => {
|
|
130
|
-
// 加
|
|
135
|
+
// 加setTimeout是以为,如果菜单中的按钮监听的是mouseup,那么菜单显示出来时鼠标如果正好在菜单上就会马上触发按钮的mouseup
|
|
131
136
|
setTimeout(() => {
|
|
132
137
|
visible.value = true;
|
|
133
138
|
|
|
134
139
|
nextTick(() => {
|
|
135
140
|
e && setPosition(e);
|
|
136
141
|
|
|
142
|
+
curZIndex.value = zIndex.nextZIndex();
|
|
143
|
+
|
|
137
144
|
emit('show');
|
|
138
145
|
});
|
|
139
146
|
}, 300);
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
class="m-editor-tree-node"
|
|
5
5
|
:draggable="draggable"
|
|
6
6
|
:data-node-id="data.id"
|
|
7
|
+
:data-parent-id="parent?.id"
|
|
8
|
+
:data-parents-id="parentsId"
|
|
7
9
|
:data-is-container="Array.isArray(data.items)"
|
|
8
10
|
@dragstart="handleDragStart"
|
|
9
11
|
@dragleave="handleDragLeave"
|
|
@@ -40,6 +42,8 @@
|
|
|
40
42
|
v-for="item in data.items"
|
|
41
43
|
:key="item.id"
|
|
42
44
|
:data="item"
|
|
45
|
+
:parent="data"
|
|
46
|
+
:parentsId="[...parentsId, data.id]"
|
|
43
47
|
:node-status-map="nodeStatusMap"
|
|
44
48
|
:indent="indent + 11"
|
|
45
49
|
>
|
|
@@ -91,11 +95,14 @@ const treeEmit = inject<typeof emit>('treeEmit');
|
|
|
91
95
|
const props = withDefaults(
|
|
92
96
|
defineProps<{
|
|
93
97
|
data: TreeNodeData;
|
|
98
|
+
parent?: TreeNodeData;
|
|
99
|
+
parentsId?: Id[];
|
|
94
100
|
nodeStatusMap: Map<Id, LayerNodeStatus>;
|
|
95
101
|
indent?: number;
|
|
96
102
|
}>(),
|
|
97
103
|
{
|
|
98
104
|
indent: 0,
|
|
105
|
+
parentsId: () => [],
|
|
99
106
|
},
|
|
100
107
|
);
|
|
101
108
|
|
|
@@ -72,7 +72,7 @@ const codeConfig = computed(() => ({
|
|
|
72
72
|
{
|
|
73
73
|
type: 'select',
|
|
74
74
|
name: 'codeType',
|
|
75
|
-
span:
|
|
75
|
+
span: 6,
|
|
76
76
|
options: [
|
|
77
77
|
{ value: HookCodeType.CODE, text: '代码块' },
|
|
78
78
|
{ value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
|
|
@@ -91,7 +91,7 @@ const codeConfig = computed(() => ({
|
|
|
91
91
|
{
|
|
92
92
|
type: 'code-select-col',
|
|
93
93
|
name: 'codeId',
|
|
94
|
-
span:
|
|
94
|
+
span: 18,
|
|
95
95
|
labelWidth: 0,
|
|
96
96
|
display: (mForm: FormState, { model }: any) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
|
|
97
97
|
notEditable: () => !services?.codeBlockService.getEditStatus(),
|
|
@@ -99,7 +99,7 @@ const codeConfig = computed(() => ({
|
|
|
99
99
|
{
|
|
100
100
|
type: 'data-source-method-select',
|
|
101
101
|
name: 'codeId',
|
|
102
|
-
span:
|
|
102
|
+
span: 18,
|
|
103
103
|
labelWidth: 0,
|
|
104
104
|
display: (mForm: FormState, { model }: any) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
|
|
105
105
|
notEditable: () => !services?.dataSourceService.get('editable'),
|
|
@@ -57,13 +57,11 @@
|
|
|
57
57
|
@change="onChangeHandler"
|
|
58
58
|
></TMagicCascader>
|
|
59
59
|
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
><MIcon :icon="!notEditable ? Edit : View"></MIcon
|
|
66
|
-
></TMagicButton>
|
|
60
|
+
<TMagicTooltip v-if="selectDataSourceId && hasDataSourceSidePanel" :content="notEditable ? '查看' : '编辑'">
|
|
61
|
+
<TMagicButton class="m-fields-select-action-button" :size="size" @click="editHandler(selectDataSourceId)"
|
|
62
|
+
><MIcon :icon="!notEditable ? Edit : View"></MIcon
|
|
63
|
+
></TMagicButton>
|
|
64
|
+
</TMagicTooltip>
|
|
67
65
|
</div>
|
|
68
66
|
</template>
|
|
69
67
|
|
|
@@ -71,7 +69,13 @@
|
|
|
71
69
|
import { computed, inject, ref, watch } from 'vue';
|
|
72
70
|
import { Edit, View } from '@element-plus/icons-vue';
|
|
73
71
|
|
|
74
|
-
import {
|
|
72
|
+
import {
|
|
73
|
+
getConfig as getDesignConfig,
|
|
74
|
+
TMagicButton,
|
|
75
|
+
TMagicCascader,
|
|
76
|
+
TMagicSelect,
|
|
77
|
+
TMagicTooltip,
|
|
78
|
+
} from '@tmagic/design';
|
|
75
79
|
import { type FilterFunction, filterFunction, type FormState, type SelectOption } from '@tmagic/form';
|
|
76
80
|
import { DataSourceFieldType } from '@tmagic/schema';
|
|
77
81
|
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
|
|
@@ -26,14 +26,15 @@
|
|
|
26
26
|
@change="onChangeHandler"
|
|
27
27
|
></component>
|
|
28
28
|
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
<TMagicTooltip v-if="config.fieldConfig" :disabled="showDataSourceFieldSelect" content="选择数据源">
|
|
30
|
+
<TMagicButton
|
|
31
|
+
style="margin-left: 5px"
|
|
32
|
+
:type="showDataSourceFieldSelect ? 'primary' : 'default'"
|
|
33
|
+
:size="size"
|
|
34
|
+
@click="showDataSourceFieldSelect = !showDataSourceFieldSelect"
|
|
35
|
+
><MIcon :icon="Coin"></MIcon
|
|
36
|
+
></TMagicButton>
|
|
37
|
+
</TMagicTooltip>
|
|
37
38
|
</div>
|
|
38
39
|
</template>
|
|
39
40
|
|
|
@@ -41,7 +42,7 @@
|
|
|
41
42
|
import { computed, inject, ref, resolveComponent, watch } from 'vue';
|
|
42
43
|
import { Coin } from '@element-plus/icons-vue';
|
|
43
44
|
|
|
44
|
-
import { TMagicButton, tMagicMessage } from '@tmagic/design';
|
|
45
|
+
import { TMagicButton, tMagicMessage, TMagicTooltip } from '@tmagic/design';
|
|
45
46
|
import type { FieldProps, FormState } from '@tmagic/form';
|
|
46
47
|
import { DataSchema } from '@tmagic/schema';
|
|
47
48
|
import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
@change="onChangeHandler"
|
|
10
10
|
></MContainer>
|
|
11
11
|
|
|
12
|
-
<
|
|
12
|
+
<TMagicTooltip
|
|
13
13
|
v-if="model[name] && isCustomMethod && hasDataSourceSidePanel"
|
|
14
|
-
|
|
15
|
-
:size="size"
|
|
16
|
-
@click="editCodeHandler"
|
|
14
|
+
:content="notEditable ? '查看' : '编辑'"
|
|
17
15
|
>
|
|
18
|
-
<
|
|
19
|
-
|
|
16
|
+
<TMagicButton class="m-fields-select-action-button" :size="size" @click="editCodeHandler">
|
|
17
|
+
<MIcon :icon="!notEditable ? Edit : View"></MIcon>
|
|
18
|
+
</TMagicButton>
|
|
19
|
+
</TMagicTooltip>
|
|
20
20
|
</div>
|
|
21
21
|
|
|
22
22
|
<CodeParams
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
import { computed, inject, ref } from 'vue';
|
|
36
36
|
import { Edit, View } from '@element-plus/icons-vue';
|
|
37
37
|
|
|
38
|
-
import { TMagicButton } from '@tmagic/design';
|
|
38
|
+
import { TMagicButton, TMagicTooltip } from '@tmagic/design';
|
|
39
39
|
import { createValues, type FieldProps, filterFunction, type FormState, MContainer } from '@tmagic/form';
|
|
40
40
|
import type { Id } from '@tmagic/schema';
|
|
41
41
|
|
|
@@ -91,7 +91,7 @@ const getParamItemsConfig = ([dataSourceId, methodName]: [Id, string] = ['', '']
|
|
|
91
91
|
}));
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
-
const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model.dataSourceMethod));
|
|
94
|
+
const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model[props.name || 'dataSourceMethod']));
|
|
95
95
|
|
|
96
96
|
const setParamsConfig = (dataSourceMethod: [Id, string], formState: any = {}) => {
|
|
97
97
|
// 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
|
|
@@ -11,13 +11,11 @@
|
|
|
11
11
|
@change="changeHandler"
|
|
12
12
|
></MSelect>
|
|
13
13
|
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
><MIcon :icon="!notEditable ? Edit : View"></MIcon
|
|
20
|
-
></TMagicButton>
|
|
14
|
+
<TMagicTooltip v-if="model[name] && hasDataSourceSidePanel" :content="notEditable ? '查看' : '编辑'">
|
|
15
|
+
<TMagicButton class="m-fields-select-action-button" :size="size" @click="editHandler"
|
|
16
|
+
><MIcon :icon="!notEditable ? Edit : View"></MIcon
|
|
17
|
+
></TMagicButton>
|
|
18
|
+
</TMagicTooltip>
|
|
21
19
|
</div>
|
|
22
20
|
</template>
|
|
23
21
|
|
|
@@ -25,7 +23,7 @@
|
|
|
25
23
|
import { computed, inject } from 'vue';
|
|
26
24
|
import { Edit, View } from '@element-plus/icons-vue';
|
|
27
25
|
|
|
28
|
-
import { TMagicButton } from '@tmagic/design';
|
|
26
|
+
import { TMagicButton, TMagicTooltip } from '@tmagic/design';
|
|
29
27
|
import { type FieldProps, filterFunction, type FormState, MSelect, type SelectConfig } from '@tmagic/form';
|
|
30
28
|
|
|
31
29
|
import MIcon from '@editor/components/Icon.vue';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, ComputedRef, inject, ref, watch } from 'vue';
|
|
1
|
+
import { computed, ComputedRef, inject, onBeforeUnmount, ref, watch } from 'vue';
|
|
2
2
|
|
|
3
3
|
import type { Services } from '@editor/type';
|
|
4
4
|
|
|
@@ -30,22 +30,62 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
|
|
|
30
30
|
const showingBoxKeys = computed(() =>
|
|
31
31
|
Object.keys(floatBoxStates.value).filter((key) => floatBoxStates.value[key].status),
|
|
32
32
|
);
|
|
33
|
-
const isDragging = ref(false);
|
|
34
33
|
|
|
35
|
-
const
|
|
34
|
+
const dragState = {
|
|
35
|
+
startOffset: {
|
|
36
|
+
x: 0,
|
|
37
|
+
y: 0,
|
|
38
|
+
},
|
|
39
|
+
isDragging: false,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const dragstartHandler = (e: DragEvent) => {
|
|
43
|
+
dragState.isDragging = true;
|
|
44
|
+
|
|
45
|
+
dragState.startOffset.x = e.clientX;
|
|
46
|
+
dragState.startOffset.y = e.clientY;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const effectiveDistance = 20;
|
|
50
|
+
|
|
36
51
|
const dragendHandler = (key: string, e: DragEvent) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
if (!dragState.isDragging) return;
|
|
53
|
+
|
|
54
|
+
const { startOffset } = dragState;
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
Math.abs(startOffset.x - e.clientX) > effectiveDistance ||
|
|
58
|
+
Math.abs(startOffset.y - e.clientY) > effectiveDistance
|
|
59
|
+
) {
|
|
60
|
+
const navMenuRect = services?.uiService?.get('navMenuRect');
|
|
61
|
+
floatBoxStates.value[key] = {
|
|
62
|
+
left: e.clientX,
|
|
63
|
+
top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
|
|
64
|
+
status: true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
dragState.isDragging = false;
|
|
44
69
|
};
|
|
45
70
|
|
|
46
|
-
|
|
47
|
-
if (!isDragging
|
|
71
|
+
const dragoverHandler = (e: DragEvent) => {
|
|
72
|
+
if (!dragState.isDragging) return;
|
|
48
73
|
e.preventDefault();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const blurHandler = () => {
|
|
77
|
+
dragState.startOffset.x = 0;
|
|
78
|
+
dragState.startOffset.y = 0;
|
|
79
|
+
|
|
80
|
+
dragState.isDragging = false;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
globalThis.document.body.addEventListener('dragover', dragoverHandler);
|
|
84
|
+
globalThis.addEventListener('blur', blurHandler);
|
|
85
|
+
|
|
86
|
+
onBeforeUnmount(() => {
|
|
87
|
+
globalThis.document.body.removeEventListener('dragover', dragoverHandler);
|
|
88
|
+
globalThis.removeEventListener('blur', blurHandler);
|
|
49
89
|
});
|
|
50
90
|
|
|
51
91
|
watch(
|
|
@@ -2,31 +2,34 @@
|
|
|
2
2
|
<TMagicScrollbar>
|
|
3
3
|
<slot name="component-list-panel-header"></slot>
|
|
4
4
|
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
5
|
+
<SearchInput @search="filterTextChangeHandler"></SearchInput>
|
|
6
|
+
|
|
7
|
+
<slot name="component-list" :component-group-list="list">
|
|
8
|
+
<TMagicCollapse class="ui-component-panel" :model-value="collapseValue">
|
|
9
|
+
<template v-for="(group, index) in list">
|
|
10
|
+
<TMagicCollapseItem v-if="group.items && group.items.length" :key="index" :name="`${index}`">
|
|
11
|
+
<template #title><MIcon :icon="Grid"></MIcon>{{ group.title }}</template>
|
|
12
|
+
<div
|
|
13
|
+
v-for="item in group.items"
|
|
14
|
+
class="component-item"
|
|
15
|
+
draggable="true"
|
|
16
|
+
:key="item.type"
|
|
17
|
+
@click="appendComponent(item)"
|
|
18
|
+
@dragstart="dragstartHandler(item, $event)"
|
|
19
|
+
@dragend="dragendHandler"
|
|
20
|
+
@drag="dragHandler"
|
|
21
|
+
>
|
|
22
|
+
<slot name="component-list-item" :component="item">
|
|
23
|
+
<TMagicTooltip placement="right" :disabled="!Boolean(item.desc)" :content="item.desc">
|
|
24
|
+
<MIcon :icon="item.icon"></MIcon>
|
|
25
|
+
</TMagicTooltip>
|
|
26
|
+
<span :title="item.text">{{ item.text }}</span>
|
|
27
|
+
</slot>
|
|
28
|
+
</div>
|
|
29
|
+
</TMagicCollapseItem>
|
|
30
|
+
</template>
|
|
31
|
+
</TMagicCollapse>
|
|
32
|
+
</slot>
|
|
30
33
|
</TMagicScrollbar>
|
|
31
34
|
</template>
|
|
32
35
|
|
|
@@ -65,8 +68,8 @@ const services = inject<Services>('services');
|
|
|
65
68
|
const stageOptions = inject<StageOptions>('stageOptions');
|
|
66
69
|
|
|
67
70
|
const stage = computed(() => services?.editorService.get('stage'));
|
|
68
|
-
const list = computed(() =>
|
|
69
|
-
services?.componentListService.getList().map((group: ComponentGroup) => ({
|
|
71
|
+
const list = computed<ComponentGroup[]>(() =>
|
|
72
|
+
(services?.componentListService.getList() || []).map((group: ComponentGroup) => ({
|
|
70
73
|
...group,
|
|
71
74
|
items: group.items.filter((item: ComponentItem) => item.text.includes(searchText.value)),
|
|
72
75
|
})),
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
class="m-editor-sidebar-header-item"
|
|
6
6
|
v-for="(config, index) in sideBarItems"
|
|
7
7
|
v-show="!floatBoxStates[config.$key]?.status"
|
|
8
|
-
draggable="true"
|
|
8
|
+
:draggable="config.draggable ?? true"
|
|
9
9
|
:key="config.$key ?? index"
|
|
10
10
|
:class="{ 'is-active': activeTabName === config.text }"
|
|
11
11
|
:style="config.tabStyle || {}"
|
|
12
|
-
@click="
|
|
12
|
+
@click="headerItemClickHandler(config, index)"
|
|
13
13
|
@dragstart="dragstartHandler"
|
|
14
14
|
@dragend="dragendHandler(config.$key, $event)"
|
|
15
15
|
>
|
|
@@ -24,11 +24,23 @@
|
|
|
24
24
|
v-show="[config.text, config.$key, `${index}`].includes(activeTabName)"
|
|
25
25
|
>
|
|
26
26
|
<component
|
|
27
|
-
v-if="config && !floatBoxStates[config.$key]?.status"
|
|
27
|
+
v-if="config?.component && !floatBoxStates[config.$key]?.status"
|
|
28
28
|
:is="config.component"
|
|
29
29
|
v-bind="config.props || {}"
|
|
30
30
|
v-on="config?.listeners || {}"
|
|
31
31
|
>
|
|
32
|
+
<template
|
|
33
|
+
#component-list="{ componentGroupList }"
|
|
34
|
+
v-if="config.$key === 'component-list' || config.slots?.componentList"
|
|
35
|
+
>
|
|
36
|
+
<slot
|
|
37
|
+
v-if="config.$key === 'component-list'"
|
|
38
|
+
name="component-list"
|
|
39
|
+
:component-group-list="componentGroupList"
|
|
40
|
+
></slot>
|
|
41
|
+
<component v-else-if="config.slots?.componentList" :is="config.slots.componentList" />
|
|
42
|
+
</template>
|
|
43
|
+
|
|
32
44
|
<template
|
|
33
45
|
#component-list-panel-header
|
|
34
46
|
v-if="config.$key === 'component-list' || config.slots?.componentListPanelHeader"
|
|
@@ -272,6 +284,15 @@ watch(
|
|
|
272
284
|
},
|
|
273
285
|
);
|
|
274
286
|
|
|
287
|
+
const headerItemClickHandler = async (config: SideComponent, index: number) => {
|
|
288
|
+
if (typeof config.beforeClick === 'function') {
|
|
289
|
+
if ((await config.beforeClick(config)) === false) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
activeTabName.value = config.text || config.$key || `${index}`;
|
|
294
|
+
};
|
|
295
|
+
|
|
275
296
|
defineExpose({
|
|
276
297
|
activeTabName,
|
|
277
298
|
});
|
|
@@ -53,7 +53,7 @@ import type { MNode } from '@tmagic/schema';
|
|
|
53
53
|
import SearchInput from '@editor/components/SearchInput.vue';
|
|
54
54
|
import Tree from '@editor/components/Tree.vue';
|
|
55
55
|
import { useFilter } from '@editor/hooks/use-filter';
|
|
56
|
-
import { LayerPanelSlots, MenuButton, MenuComponent, Services, TreeNodeData } from '@editor/type';
|
|
56
|
+
import type { LayerPanelSlots, MenuButton, MenuComponent, Services, TreeNodeData } from '@editor/type';
|
|
57
57
|
|
|
58
58
|
import LayerMenu from './LayerMenu.vue';
|
|
59
59
|
import LayerNodeTool from './LayerNodeTool.vue';
|
|
@@ -2,6 +2,7 @@ import { computed, type ComputedRef, nextTick, type Ref, ref } from 'vue';
|
|
|
2
2
|
import { throttle } from 'lodash-es';
|
|
3
3
|
|
|
4
4
|
import { Id, MNode } from '@tmagic/schema';
|
|
5
|
+
import { isPage, isPageFragment } from '@tmagic/utils';
|
|
5
6
|
|
|
6
7
|
import { LayerNodeStatus, Services, TreeNodeData, UI_SELECT_MODE_EVENT_NAME } from '@editor/type';
|
|
7
8
|
import { updateStatus } from '@editor/utils/tree';
|
|
@@ -31,6 +32,10 @@ export const useClick = (
|
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
const multiSelect = async (data: MNode) => {
|
|
35
|
+
if (isPage(data) || isPageFragment(data)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
const nodes = services?.editorService.get('nodes') || [];
|
|
35
40
|
|
|
36
41
|
const newNodes: Id[] = [];
|
|
@@ -41,6 +46,10 @@ export const useClick = (
|
|
|
41
46
|
return;
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
if (isPage(node) || isPageFragment(node)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
newNodes.push(node.id);
|
|
45
54
|
});
|
|
46
55
|
|
|
@@ -10,6 +10,7 @@ const dragState: {
|
|
|
10
10
|
dragOverNodeId: Id;
|
|
11
11
|
dropType: NodeDropType | '';
|
|
12
12
|
container: HTMLElement | null;
|
|
13
|
+
nodeId?: Id;
|
|
13
14
|
} = {
|
|
14
15
|
dragOverNodeId: '',
|
|
15
16
|
dropType: '',
|
|
@@ -50,6 +51,7 @@ export const useDrag = (services: Services | undefined) => {
|
|
|
50
51
|
if (!targetEl || targetEl !== event.currentTarget) return;
|
|
51
52
|
|
|
52
53
|
event.dataTransfer.effectAllowed = 'move';
|
|
54
|
+
dragState.nodeId = targetEl.dataset.nodeId;
|
|
53
55
|
|
|
54
56
|
try {
|
|
55
57
|
event.dataTransfer.setData(
|
|
@@ -70,30 +72,52 @@ export const useDrag = (services: Services | undefined) => {
|
|
|
70
72
|
const labelEl = targetEl.children[0];
|
|
71
73
|
if (!labelEl) return;
|
|
72
74
|
|
|
75
|
+
removeClassName(labelEl, 'drag-before', 'drag-after', 'drag-inner');
|
|
76
|
+
|
|
73
77
|
const { top: targetTop, height: targetHeight } = labelEl.getBoundingClientRect();
|
|
74
78
|
|
|
75
79
|
const distance = event.clientY - targetTop;
|
|
76
80
|
const isContainer = targetEl.dataset.isContainer === 'true';
|
|
77
81
|
|
|
82
|
+
const targetNodeId = targetEl.dataset.nodeId;
|
|
83
|
+
const { nodeId } = dragState;
|
|
84
|
+
const parentsId = targetEl.dataset.parentsId?.split(',');
|
|
85
|
+
|
|
86
|
+
if (!targetNodeId) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 如果是悬浮在拖动的节点上方,则不响应
|
|
91
|
+
if (parentsId) {
|
|
92
|
+
let targetIdIndex = -1;
|
|
93
|
+
for (let i = 0, l = parentsId.length; i < l; i++) {
|
|
94
|
+
const id = parentsId[i];
|
|
95
|
+
if (nodeId === id) {
|
|
96
|
+
targetIdIndex = i;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (parentsId.includes(`${nodeId}`) && i >= targetIdIndex) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
78
105
|
if (distance < targetHeight / 3) {
|
|
79
106
|
dragState.dropType = 'before';
|
|
80
107
|
addClassName(labelEl, globalThis.document, 'drag-before');
|
|
81
|
-
removeClassName(labelEl, 'drag-after', 'drag-inner');
|
|
82
108
|
} else if (distance > (targetHeight * 2) / 3) {
|
|
83
109
|
dragState.dropType = 'after';
|
|
84
110
|
addClassName(labelEl, globalThis.document, 'drag-after');
|
|
85
|
-
removeClassName(labelEl, 'drag-before', 'drag-inner');
|
|
86
111
|
} else if (isContainer) {
|
|
87
112
|
dragState.dropType = 'inner';
|
|
88
113
|
addClassName(labelEl, globalThis.document, 'drag-inner');
|
|
89
|
-
removeClassName(labelEl, 'drag-before', 'drag-after');
|
|
90
114
|
}
|
|
91
115
|
|
|
92
116
|
if (!dragState.dropType) {
|
|
93
117
|
return;
|
|
94
118
|
}
|
|
95
119
|
|
|
96
|
-
dragState.dragOverNodeId =
|
|
120
|
+
dragState.dragOverNodeId = targetNodeId;
|
|
97
121
|
dragState.container = event.currentTarget as HTMLElement;
|
|
98
122
|
|
|
99
123
|
event.preventDefault();
|
package/src/services/editor.ts
CHANGED
|
@@ -899,9 +899,20 @@ class Editor extends BaseService {
|
|
|
899
899
|
|
|
900
900
|
const newLayout = await this.getLayout(targetParent);
|
|
901
901
|
|
|
902
|
-
|
|
902
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
903
|
+
forConfigs: for (const config of configs) {
|
|
903
904
|
const { parent, node: curNode } = this.getNodeInfo(config.id, false);
|
|
904
|
-
if (!parent || !curNode)
|
|
905
|
+
if (!parent || !curNode) {
|
|
906
|
+
continue;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const path = getNodePath(curNode.id, parent.items);
|
|
910
|
+
|
|
911
|
+
for (const node of path) {
|
|
912
|
+
if (targetParent.id === node.id) {
|
|
913
|
+
continue forConfigs;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
905
916
|
|
|
906
917
|
const index = getNodeIndex(curNode.id, parent);
|
|
907
918
|
|