@tmagic/editor 1.0.3 → 1.1.0-beta.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/tmagic-editor.es.js +263 -89
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +268 -93
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +28 -1
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -0
- package/dist/types/src/services/editor.d.ts +6 -0
- package/dist/types/src/type.d.ts +3 -0
- package/dist/types/src/utils/editor.d.ts +8 -4
- package/package.json +7 -7
- package/src/Editor.vue +35 -5
- package/src/layouts/Framework.vue +1 -1
- package/src/layouts/PropsPanel.vue +12 -9
- package/src/layouts/sidebar/ComponentListPanel.vue +55 -1
- package/src/layouts/sidebar/LayerPanel.vue +2 -0
- package/src/layouts/sidebar/Sidebar.vue +9 -1
- package/src/layouts/sidebar/TabPane.vue +10 -0
- package/src/layouts/workspace/Stage.vue +52 -11
- package/src/services/editor.ts +74 -17
- package/src/type.ts +3 -0
- package/src/utils/editor.ts +45 -35
|
@@ -3,7 +3,7 @@ import { PropType } from 'vue';
|
|
|
3
3
|
import type { FormConfig } from '@tmagic/form';
|
|
4
4
|
import type { MApp, MNode } from '@tmagic/schema';
|
|
5
5
|
import type StageCore from '@tmagic/stage';
|
|
6
|
-
import
|
|
6
|
+
import { MoveableOptions } from '@tmagic/stage';
|
|
7
7
|
import type { ComponentGroup, MenuBarData, MenuItem, Services, SideBarData, StageRect } from './type';
|
|
8
8
|
declare const _default: DefineComponent<{
|
|
9
9
|
/** 页面初始值 */
|
|
@@ -72,6 +72,18 @@ declare const _default: DefineComponent<{
|
|
|
72
72
|
type: PropType<(el: HTMLElement) => boolean | Promise<boolean>>;
|
|
73
73
|
default: (el: HTMLElement) => boolean;
|
|
74
74
|
};
|
|
75
|
+
isContainer: {
|
|
76
|
+
type: PropType<(el: HTMLElement) => boolean | Promise<boolean>>;
|
|
77
|
+
default: (el: HTMLElement) => boolean;
|
|
78
|
+
};
|
|
79
|
+
containerHighlightClassName: {
|
|
80
|
+
type: StringConstructor;
|
|
81
|
+
default: string;
|
|
82
|
+
};
|
|
83
|
+
containerHighlightDuration: {
|
|
84
|
+
type: NumberConstructor;
|
|
85
|
+
default: number;
|
|
86
|
+
};
|
|
75
87
|
stageRect: {
|
|
76
88
|
type: PropType<StageRect>;
|
|
77
89
|
};
|
|
@@ -149,6 +161,18 @@ declare const _default: DefineComponent<{
|
|
|
149
161
|
type: PropType<(el: HTMLElement) => boolean | Promise<boolean>>;
|
|
150
162
|
default: (el: HTMLElement) => boolean;
|
|
151
163
|
};
|
|
164
|
+
isContainer: {
|
|
165
|
+
type: PropType<(el: HTMLElement) => boolean | Promise<boolean>>;
|
|
166
|
+
default: (el: HTMLElement) => boolean;
|
|
167
|
+
};
|
|
168
|
+
containerHighlightClassName: {
|
|
169
|
+
type: StringConstructor;
|
|
170
|
+
default: string;
|
|
171
|
+
};
|
|
172
|
+
containerHighlightDuration: {
|
|
173
|
+
type: NumberConstructor;
|
|
174
|
+
default: number;
|
|
175
|
+
};
|
|
152
176
|
stageRect: {
|
|
153
177
|
type: PropType<StageRect>;
|
|
154
178
|
};
|
|
@@ -174,5 +198,8 @@ declare const _default: DefineComponent<{
|
|
|
174
198
|
propsValues: Record<string, MNode>;
|
|
175
199
|
eventMethodList: Record<string, any>;
|
|
176
200
|
canSelect: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
201
|
+
isContainer: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
202
|
+
containerHighlightClassName: string;
|
|
203
|
+
containerHighlightDuration: number;
|
|
177
204
|
}>;
|
|
178
205
|
export default _default;
|
|
@@ -10,5 +10,7 @@ declare const _default: DefineComponent<{}, {
|
|
|
10
10
|
}[] | undefined>;
|
|
11
11
|
appendComponent({ text, type, data }: ComponentItem): void;
|
|
12
12
|
dragstartHandler({ text, type, data }: ComponentItem, e: DragEvent): void;
|
|
13
|
+
dragendHandler(): void;
|
|
14
|
+
dragHandler(e: DragEvent): void;
|
|
13
15
|
}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, EmitsOptions, string, VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{}>>, {}>;
|
|
14
16
|
export default _default;
|
|
@@ -111,6 +111,12 @@ declare class Editor extends BaseService {
|
|
|
111
111
|
* @param offset 偏移量
|
|
112
112
|
*/
|
|
113
113
|
moveLayer(offset: number | LayerOffset): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* 移动到指定容器中
|
|
116
|
+
* @param config 需要移动的节点
|
|
117
|
+
* @param targetId 容器ID
|
|
118
|
+
*/
|
|
119
|
+
moveToContainer(config: MNode, targetId: Id): Promise<MNode | undefined>;
|
|
114
120
|
/**
|
|
115
121
|
* 撤销当前操作
|
|
116
122
|
* @returns 上一次数据
|
package/dist/types/src/type.d.ts
CHANGED
|
@@ -25,9 +25,12 @@ export interface Services {
|
|
|
25
25
|
export interface StageOptions {
|
|
26
26
|
runtimeUrl: string;
|
|
27
27
|
autoScrollIntoView: boolean;
|
|
28
|
+
containerHighlightClassName: string;
|
|
29
|
+
containerHighlightDuration: number;
|
|
28
30
|
render: () => HTMLDivElement;
|
|
29
31
|
moveableOptions: MoveableOptions | ((core?: StageCore) => MoveableOptions);
|
|
30
32
|
canSelect: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
33
|
+
isContainer: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
31
34
|
updateDragEl: (el: HTMLDivElement) => void;
|
|
32
35
|
}
|
|
33
36
|
export interface StoreState {
|
|
@@ -32,9 +32,13 @@ export declare const generatePageNameByApp: (app: MApp) => string;
|
|
|
32
32
|
*/
|
|
33
33
|
export declare const isFixed: (node: MNode) => boolean;
|
|
34
34
|
export declare const getNodeIndex: (node: MNode, parent: MContainer | MApp) => number;
|
|
35
|
-
export declare const
|
|
36
|
-
export declare const
|
|
35
|
+
export declare const getRelativeStyle: (style?: Record<string, any>) => Record<string, any>;
|
|
36
|
+
export declare const getInitPositionStyle: (style: Record<string, any> | undefined, layout: Layout, parentNode: MNode, stage: StageCore) => Record<string, any>;
|
|
37
37
|
export declare const setLayout: (node: MNode, layout: Layout) => MNode;
|
|
38
|
-
export declare const change2Fixed: (node: MNode, root: MApp) =>
|
|
39
|
-
|
|
38
|
+
export declare const change2Fixed: (node: MNode, root: MApp) => {
|
|
39
|
+
left: number;
|
|
40
|
+
top: number;
|
|
41
|
+
};
|
|
42
|
+
export declare const Fixed2Other: (node: MNode, root: MApp, getLayout: (parent: MNode, node?: MNode | undefined) => Promise<Layout>) => Promise<Record<string, any>>;
|
|
40
43
|
export declare const getGuideLineFromCache: (key: string) => number[];
|
|
44
|
+
export declare const fixNodeLeft: (config: MNode, parent: MContainer, doc?: Document | undefined) => any;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.1.0-beta.0",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"dist/*",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@babel/core": "^7.18.0",
|
|
45
45
|
"@element-plus/icons": "0.0.11",
|
|
46
|
-
"@tmagic/core": "1.0.
|
|
47
|
-
"@tmagic/form": "1.0.
|
|
48
|
-
"@tmagic/schema": "1.0.
|
|
49
|
-
"@tmagic/stage": "1.0.
|
|
50
|
-
"@tmagic/utils": "1.0.
|
|
46
|
+
"@tmagic/core": "1.1.0-beta.0",
|
|
47
|
+
"@tmagic/form": "1.1.0-beta.0",
|
|
48
|
+
"@tmagic/schema": "1.1.0-beta.0",
|
|
49
|
+
"@tmagic/stage": "1.1.0-beta.0",
|
|
50
|
+
"@tmagic/utils": "1.1.0-beta.0",
|
|
51
51
|
"buffer": "^6.0.3",
|
|
52
52
|
"color": "^3.1.3",
|
|
53
53
|
"element-plus": "^2.2.6",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"vue": "^3.2.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"@tmagic/form": "1.0.
|
|
63
|
+
"@tmagic/form": "1.1.0-beta.0",
|
|
64
64
|
"element-plus": "^2.2.6",
|
|
65
65
|
"monaco-editor": "^0.32.1",
|
|
66
66
|
"vue": "^3.2.0"
|
package/src/Editor.vue
CHANGED
|
@@ -6,7 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
<template #sidebar>
|
|
8
8
|
<slot name="sidebar" :editorService="editorService">
|
|
9
|
-
<sidebar :data="sidebar"
|
|
9
|
+
<sidebar :data="sidebar">
|
|
10
|
+
<template #layer-panel-header>
|
|
11
|
+
<slot name="layer-panel-header"></slot>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<template #component-list-panel-header>
|
|
15
|
+
<slot name="component-list-panel-header"></slot>
|
|
16
|
+
</template>
|
|
17
|
+
</sidebar>
|
|
10
18
|
</slot>
|
|
11
19
|
</template>
|
|
12
20
|
|
|
@@ -20,9 +28,13 @@
|
|
|
20
28
|
</slot>
|
|
21
29
|
</template>
|
|
22
30
|
|
|
23
|
-
<template #
|
|
24
|
-
<slot name="
|
|
25
|
-
<props-panel ref="propsPanel" @mounted="(instance) => $emit('props-panel-mounted', instance)"
|
|
31
|
+
<template #props-panel>
|
|
32
|
+
<slot name="props-panel">
|
|
33
|
+
<props-panel ref="propsPanel" @mounted="(instance) => $emit('props-panel-mounted', instance)">
|
|
34
|
+
<template #props-panel-header>
|
|
35
|
+
<slot name="props-panel-header"></slot>
|
|
36
|
+
</template>
|
|
37
|
+
</props-panel>
|
|
26
38
|
</slot>
|
|
27
39
|
</template>
|
|
28
40
|
|
|
@@ -37,7 +49,7 @@ import { EventOption } from '@tmagic/core';
|
|
|
37
49
|
import type { FormConfig } from '@tmagic/form';
|
|
38
50
|
import type { MApp, MNode } from '@tmagic/schema';
|
|
39
51
|
import type StageCore from '@tmagic/stage';
|
|
40
|
-
import
|
|
52
|
+
import { CONTAINER_HIGHLIGHT_CLASS, MoveableOptions } from '@tmagic/stage';
|
|
41
53
|
|
|
42
54
|
import Framework from '@editor/layouts/Framework.vue';
|
|
43
55
|
import NavMenu from '@editor/layouts/NavMenu.vue';
|
|
@@ -142,6 +154,21 @@ export default defineComponent({
|
|
|
142
154
|
default: (el: HTMLElement) => Boolean(el.id),
|
|
143
155
|
},
|
|
144
156
|
|
|
157
|
+
isContainer: {
|
|
158
|
+
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
|
159
|
+
default: (el: HTMLElement) => el.classList.contains('magic-ui-container'),
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
containerHighlightClassName: {
|
|
163
|
+
type: String,
|
|
164
|
+
default: CONTAINER_HIGHLIGHT_CLASS,
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
containerHighlightDuration: {
|
|
168
|
+
type: Number,
|
|
169
|
+
default: 800,
|
|
170
|
+
},
|
|
171
|
+
|
|
145
172
|
stageRect: {
|
|
146
173
|
type: [String, Object] as PropType<StageRect>,
|
|
147
174
|
},
|
|
@@ -257,6 +284,9 @@ export default defineComponent({
|
|
|
257
284
|
moveableOptions: props.moveableOptions,
|
|
258
285
|
canSelect: props.canSelect,
|
|
259
286
|
updateDragEl: props.updateDragEl,
|
|
287
|
+
isContainer: props.isContainer,
|
|
288
|
+
containerHighlightClassName: props.containerHighlightClassName,
|
|
289
|
+
containerHighlightDuration: props.containerHighlightDuration,
|
|
260
290
|
}),
|
|
261
291
|
);
|
|
262
292
|
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<m-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
<div class="`m-editor-props-panel">
|
|
3
|
+
<slot name="props-panel-header"></slot>
|
|
4
|
+
<m-form
|
|
5
|
+
:class="`m-editor-props-panel ${propsPanelSize}`"
|
|
6
|
+
:popper-class="`m-editor-props-panel-popper ${propsPanelSize}`"
|
|
7
|
+
ref="configForm"
|
|
8
|
+
:size="propsPanelSize"
|
|
9
|
+
:init-values="values"
|
|
10
|
+
:config="curFormConfig"
|
|
11
|
+
@change="submit"
|
|
12
|
+
></m-form>
|
|
13
|
+
</div>
|
|
11
14
|
</template>
|
|
12
15
|
|
|
13
16
|
<script lang="ts">
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<el-scrollbar>
|
|
3
|
+
<slot name="component-list-panel-header"></slot>
|
|
4
|
+
|
|
3
5
|
<el-collapse class="ui-component-panel" :model-value="collapseValue">
|
|
4
6
|
<el-input
|
|
5
7
|
prefix-icon="el-icon-search"
|
|
@@ -19,6 +21,8 @@
|
|
|
19
21
|
:key="item.type"
|
|
20
22
|
@click="appendComponent(item)"
|
|
21
23
|
@dragstart="dragstartHandler(item, $event)"
|
|
24
|
+
@dragend="dragendHandler"
|
|
25
|
+
@drag="dragHandler"
|
|
22
26
|
>
|
|
23
27
|
<m-icon :icon="item.icon"></m-icon>
|
|
24
28
|
|
|
@@ -36,8 +40,12 @@
|
|
|
36
40
|
import { computed, defineComponent, inject, ref } from 'vue';
|
|
37
41
|
import serialize from 'serialize-javascript';
|
|
38
42
|
|
|
43
|
+
import type StageCore from '@tmagic/stage';
|
|
44
|
+
import { GHOST_EL_ID_PREFIX } from '@tmagic/stage';
|
|
45
|
+
import { addClassName, removeClassNameByClassName } from '@tmagic/utils';
|
|
46
|
+
|
|
39
47
|
import MIcon from '@editor/components/Icon.vue';
|
|
40
|
-
import type { ComponentGroup, ComponentItem, Services } from '@editor/type';
|
|
48
|
+
import type { ComponentGroup, ComponentItem, Services, StageOptions } from '@editor/type';
|
|
41
49
|
|
|
42
50
|
export default defineComponent({
|
|
43
51
|
name: 'ui-component-panel',
|
|
@@ -47,6 +55,9 @@ export default defineComponent({
|
|
|
47
55
|
setup() {
|
|
48
56
|
const searchText = ref('');
|
|
49
57
|
const services = inject<Services>('services');
|
|
58
|
+
const stageOptions = inject<StageOptions>('stageOptions');
|
|
59
|
+
|
|
60
|
+
const stage = computed(() => services?.editorService.get<StageCore>('stage'));
|
|
50
61
|
const list = computed(() =>
|
|
51
62
|
services?.componentListService.getList().map((group: ComponentGroup) => ({
|
|
52
63
|
...group,
|
|
@@ -59,6 +70,10 @@ export default defineComponent({
|
|
|
59
70
|
.map((x, i) => i),
|
|
60
71
|
);
|
|
61
72
|
|
|
73
|
+
let timeout: NodeJS.Timeout | undefined;
|
|
74
|
+
let clientX: number;
|
|
75
|
+
let clientY: number;
|
|
76
|
+
|
|
62
77
|
return {
|
|
63
78
|
searchText,
|
|
64
79
|
collapseValue,
|
|
@@ -85,6 +100,45 @@ export default defineComponent({
|
|
|
85
100
|
);
|
|
86
101
|
}
|
|
87
102
|
},
|
|
103
|
+
|
|
104
|
+
dragendHandler() {
|
|
105
|
+
if (timeout) {
|
|
106
|
+
globalThis.clearTimeout(timeout);
|
|
107
|
+
timeout = undefined;
|
|
108
|
+
}
|
|
109
|
+
const doc = stage.value?.renderer.contentWindow?.document;
|
|
110
|
+
if (doc && stageOptions) {
|
|
111
|
+
removeClassNameByClassName(doc, stageOptions.containerHighlightClassName);
|
|
112
|
+
}
|
|
113
|
+
clientX = 0;
|
|
114
|
+
clientY = 0;
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
dragHandler(e: DragEvent) {
|
|
118
|
+
if (e.clientX !== clientX || e.clientY !== clientY) {
|
|
119
|
+
clientX = e.clientX;
|
|
120
|
+
clientY = e.clientY;
|
|
121
|
+
if (timeout) {
|
|
122
|
+
globalThis.clearTimeout(timeout);
|
|
123
|
+
timeout = undefined;
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (timeout) return;
|
|
129
|
+
|
|
130
|
+
timeout = globalThis.setTimeout(async () => {
|
|
131
|
+
if (!stageOptions || !stage.value) return;
|
|
132
|
+
const doc = stage.value.renderer.contentWindow?.document;
|
|
133
|
+
const els = stage.value.getElementsFromPoint(e);
|
|
134
|
+
for (const el of els) {
|
|
135
|
+
if (doc && !el.id.startsWith(GHOST_EL_ID_PREFIX) && (await stageOptions.isContainer(el))) {
|
|
136
|
+
addClassName(el, doc, stageOptions?.containerHighlightClassName);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}, stageOptions?.containerHighlightDuration);
|
|
141
|
+
},
|
|
88
142
|
};
|
|
89
143
|
},
|
|
90
144
|
});
|
|
@@ -6,7 +6,15 @@
|
|
|
6
6
|
type="card"
|
|
7
7
|
tab-position="left"
|
|
8
8
|
>
|
|
9
|
-
<tab-pane v-for="(item, index) in data.items" :key="index" :data="item"
|
|
9
|
+
<tab-pane v-for="(item, index) in data.items" :key="index" :data="item">
|
|
10
|
+
<template #layer-panel-header v-if="item === 'layer'">
|
|
11
|
+
<slot name="layer-panel-header"></slot>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<template #component-list-panel-header v-if="item === 'component-list'">
|
|
15
|
+
<slot name="component-list-panel-header"></slot>
|
|
16
|
+
</template>
|
|
17
|
+
</tab-pane>
|
|
10
18
|
</el-tabs>
|
|
11
19
|
</template>
|
|
12
20
|
|
|
@@ -8,6 +8,16 @@
|
|
|
8
8
|
</template>
|
|
9
9
|
|
|
10
10
|
<component :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
|
|
11
|
+
<template #component-list-panel-header v-if="data === 'component-list' || config.slots?.componentListPanelHeader">
|
|
12
|
+
<slot v-if="data === 'component-list'" name="component-list-panel-header"></slot>
|
|
13
|
+
<component v-else-if="config.slots?.componentListPanelHeader" :is="config.slots.componentListPanelHeader" />
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<template #layer-panel-header v-if="data === 'layer' || config.slots?.layerPanelHeader">
|
|
17
|
+
<slot v-if="data === 'layer'" name="layer-panel-header"></slot>
|
|
18
|
+
<component v-else-if="config.slots?.layerPanelHeader" :is="config.slots.layerPanelHeader" />
|
|
19
|
+
</template>
|
|
20
|
+
|
|
11
21
|
<template #layer-node-content="{ data, node }" v-if="config.slots?.layerNodeContent">
|
|
12
22
|
<component :is="config.slots?.layerNodeContent" :data="data" :node="node" />
|
|
13
23
|
</template>
|
|
@@ -35,8 +35,15 @@ import {
|
|
|
35
35
|
} from 'vue';
|
|
36
36
|
import { cloneDeep } from 'lodash-es';
|
|
37
37
|
|
|
38
|
-
import type { MApp, MNode, MPage } from '@tmagic/schema';
|
|
39
|
-
import StageCore, {
|
|
38
|
+
import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
39
|
+
import StageCore, {
|
|
40
|
+
calcValueByFontsize,
|
|
41
|
+
getOffset,
|
|
42
|
+
GuidesType,
|
|
43
|
+
Runtime,
|
|
44
|
+
SortEventData,
|
|
45
|
+
UpdateEventData,
|
|
46
|
+
} from '@tmagic/stage';
|
|
40
47
|
|
|
41
48
|
import ScrollViewer from '@editor/components/ScrollViewer.vue';
|
|
42
49
|
import {
|
|
@@ -90,6 +97,9 @@ export default defineComponent({
|
|
|
90
97
|
runtimeUrl: stageOptions.runtimeUrl,
|
|
91
98
|
zoom: zoom.value,
|
|
92
99
|
autoScrollIntoView: stageOptions.autoScrollIntoView,
|
|
100
|
+
isContainer: stageOptions.isContainer,
|
|
101
|
+
containerHighlightClassName: stageOptions.containerHighlightClassName,
|
|
102
|
+
containerHighlightDuration: stageOptions.containerHighlightDuration,
|
|
93
103
|
canSelect: (el, event, stop) => {
|
|
94
104
|
const elCanSelect = stageOptions.canSelect(el);
|
|
95
105
|
// 在组件联动过程中不能再往下选择,返回并触发 ui-select
|
|
@@ -122,6 +132,10 @@ export default defineComponent({
|
|
|
122
132
|
});
|
|
123
133
|
|
|
124
134
|
stage?.on('update', (ev: UpdateEventData) => {
|
|
135
|
+
if (ev.parentEl) {
|
|
136
|
+
services?.editorService.moveToContainer({ id: ev.el.id, style: ev.style }, ev.parentEl.id);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
125
139
|
services?.editorService.update({ id: ev.el.id, style: ev.style });
|
|
126
140
|
});
|
|
127
141
|
|
|
@@ -207,23 +221,50 @@ export default defineComponent({
|
|
|
207
221
|
|
|
208
222
|
async dropHandler(e: DragEvent) {
|
|
209
223
|
e.preventDefault();
|
|
210
|
-
|
|
224
|
+
|
|
225
|
+
const doc = stage?.renderer.contentWindow?.document;
|
|
226
|
+
const parentEl: HTMLElement | null | undefined = doc?.querySelector(
|
|
227
|
+
`.${stageOptions?.containerHighlightClassName}`,
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
let parent: MContainer | undefined = page.value;
|
|
231
|
+
if (parentEl) {
|
|
232
|
+
parent = services?.editorService.getNodeById(parentEl.id, false) as MContainer;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (e.dataTransfer && parent && stageContainer.value && stage) {
|
|
211
236
|
// eslint-disable-next-line no-eval
|
|
212
237
|
const config = eval(`(${e.dataTransfer.getData('data')})`);
|
|
213
|
-
const layout = await services?.editorService.getLayout(
|
|
238
|
+
const layout = await services?.editorService.getLayout(parent);
|
|
214
239
|
|
|
215
240
|
const containerRect = stageContainer.value.getBoundingClientRect();
|
|
216
241
|
const { scrollTop, scrollLeft } = stage.mask;
|
|
242
|
+
const { style = {} } = config;
|
|
243
|
+
|
|
244
|
+
let top = 0;
|
|
245
|
+
let left = 0;
|
|
246
|
+
let position = 'relative';
|
|
247
|
+
|
|
217
248
|
if (layout === Layout.ABSOLUTE) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
249
|
+
position = 'absolute';
|
|
250
|
+
top = e.clientY - containerRect.top + scrollTop;
|
|
251
|
+
left = e.clientX - containerRect.left + scrollLeft;
|
|
252
|
+
|
|
253
|
+
if (parentEl && doc) {
|
|
254
|
+
const { left: parentLeft, top: parentTop } = getOffset(parentEl);
|
|
255
|
+
left = left - calcValueByFontsize(doc, parentLeft);
|
|
256
|
+
top = top - calcValueByFontsize(doc, parentTop);
|
|
257
|
+
}
|
|
224
258
|
}
|
|
225
259
|
|
|
226
|
-
|
|
260
|
+
config.style = {
|
|
261
|
+
...style,
|
|
262
|
+
position,
|
|
263
|
+
top,
|
|
264
|
+
left,
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
services?.editorService.add(config, parent);
|
|
227
268
|
}
|
|
228
269
|
},
|
|
229
270
|
};
|
package/src/services/editor.ts
CHANGED
|
@@ -33,9 +33,10 @@ import {
|
|
|
33
33
|
change2Fixed,
|
|
34
34
|
COPY_STORAGE_KEY,
|
|
35
35
|
Fixed2Other,
|
|
36
|
+
fixNodeLeft,
|
|
36
37
|
generatePageNameByApp,
|
|
38
|
+
getInitPositionStyle,
|
|
37
39
|
getNodeIndex,
|
|
38
|
-
initPosition,
|
|
39
40
|
isFixed,
|
|
40
41
|
setLayout,
|
|
41
42
|
} from '@editor/utils/editor';
|
|
@@ -70,6 +71,7 @@ class Editor extends BaseService {
|
|
|
70
71
|
'paste',
|
|
71
72
|
'alignCenter',
|
|
72
73
|
'moveLayer',
|
|
74
|
+
'moveToContainer',
|
|
73
75
|
'move',
|
|
74
76
|
'undo',
|
|
75
77
|
'redo',
|
|
@@ -274,7 +276,7 @@ class Editor extends BaseService {
|
|
|
274
276
|
const { type, ...config } = addNode;
|
|
275
277
|
const curNode = this.get<MContainer>('node');
|
|
276
278
|
|
|
277
|
-
let parentNode:
|
|
279
|
+
let parentNode: MContainer | undefined;
|
|
278
280
|
const isPage = type === NodeType.PAGE;
|
|
279
281
|
|
|
280
282
|
if (isPage) {
|
|
@@ -291,12 +293,8 @@ class Editor extends BaseService {
|
|
|
291
293
|
if (!parentNode) throw new Error('未找到父元素');
|
|
292
294
|
|
|
293
295
|
const layout = await this.getLayout(toRaw(parentNode), addNode as MNode);
|
|
294
|
-
const newNode =
|
|
295
|
-
|
|
296
|
-
layout,
|
|
297
|
-
parentNode,
|
|
298
|
-
this.get<StageCore>('stage'),
|
|
299
|
-
);
|
|
296
|
+
const newNode = { ...toRaw(await propsService.getPropsValue(type, config)) };
|
|
297
|
+
newNode.style = getInitPositionStyle(newNode.style, layout, parentNode, this.get<StageCore>('stage'));
|
|
300
298
|
|
|
301
299
|
if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
|
|
302
300
|
throw new Error('app下不能添加组件');
|
|
@@ -305,8 +303,17 @@ class Editor extends BaseService {
|
|
|
305
303
|
parentNode?.items?.push(newNode);
|
|
306
304
|
|
|
307
305
|
const stage = this.get<StageCore | null>('stage');
|
|
306
|
+
const root = this.get<MApp>('root');
|
|
307
|
+
|
|
308
|
+
await stage?.add({ config: cloneDeep(newNode), root: cloneDeep(root) });
|
|
308
309
|
|
|
309
|
-
|
|
310
|
+
if (layout === Layout.ABSOLUTE) {
|
|
311
|
+
const fixedLeft = fixNodeLeft(newNode, parentNode, stage?.renderer.contentWindow?.document);
|
|
312
|
+
if (typeof fixedLeft !== 'undefined') {
|
|
313
|
+
newNode.style.left = fixedLeft;
|
|
314
|
+
await stage?.update({ config: cloneDeep(newNode), root: cloneDeep(root) });
|
|
315
|
+
}
|
|
316
|
+
}
|
|
310
317
|
|
|
311
318
|
await this.select(newNode);
|
|
312
319
|
|
|
@@ -348,7 +355,7 @@ class Editor extends BaseService {
|
|
|
348
355
|
|
|
349
356
|
parent.items?.splice(index, 1);
|
|
350
357
|
const stage = this.get<StageCore | null>('stage');
|
|
351
|
-
stage?.remove({ id: node.id, root: this.get('root') });
|
|
358
|
+
stage?.remove({ id: node.id, root: cloneDeep(this.get('root')) });
|
|
352
359
|
|
|
353
360
|
if (node.type === NodeType.PAGE) {
|
|
354
361
|
this.state.pageLength -= 1;
|
|
@@ -431,7 +438,7 @@ class Editor extends BaseService {
|
|
|
431
438
|
this.set('node', newConfig);
|
|
432
439
|
}
|
|
433
440
|
|
|
434
|
-
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
|
|
441
|
+
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(newConfig), root: cloneDeep(this.get('root')) });
|
|
435
442
|
|
|
436
443
|
if (newConfig.type === NodeType.PAGE) {
|
|
437
444
|
this.set('page', newConfig);
|
|
@@ -464,7 +471,7 @@ class Editor extends BaseService {
|
|
|
464
471
|
await this.update(parent);
|
|
465
472
|
await this.select(node);
|
|
466
473
|
|
|
467
|
-
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(node), root: this.get('root') });
|
|
474
|
+
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(node), root: cloneDeep(this.get('root')) });
|
|
468
475
|
|
|
469
476
|
this.addModifiedNodeId(parent.id);
|
|
470
477
|
this.pushHistoryState();
|
|
@@ -544,7 +551,10 @@ class Editor extends BaseService {
|
|
|
544
551
|
}
|
|
545
552
|
|
|
546
553
|
await this.update(node);
|
|
547
|
-
this.get<StageCore | null>('stage')?.update({
|
|
554
|
+
this.get<StageCore | null>('stage')?.update({
|
|
555
|
+
config: cloneDeep(toRaw(node)),
|
|
556
|
+
root: cloneDeep(this.get<MApp>('root')),
|
|
557
|
+
});
|
|
548
558
|
this.addModifiedNodeId(config.id);
|
|
549
559
|
this.pushHistoryState();
|
|
550
560
|
|
|
@@ -569,7 +579,54 @@ class Editor extends BaseService {
|
|
|
569
579
|
brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
|
|
570
580
|
}
|
|
571
581
|
|
|
572
|
-
this.get<StageCore | null>('stage')?.update({
|
|
582
|
+
this.get<StageCore | null>('stage')?.update({
|
|
583
|
+
config: cloneDeep(toRaw(parent)),
|
|
584
|
+
root: cloneDeep(this.get<MApp>('root')),
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* 移动到指定容器中
|
|
590
|
+
* @param config 需要移动的节点
|
|
591
|
+
* @param targetId 容器ID
|
|
592
|
+
*/
|
|
593
|
+
public async moveToContainer(config: MNode, targetId: Id): Promise<MNode | undefined> {
|
|
594
|
+
const { node, parent } = this.getNodeInfo(config.id, false);
|
|
595
|
+
const target = this.getNodeById(targetId, false) as MContainer;
|
|
596
|
+
|
|
597
|
+
const stage = this.get<StageCore | null>('stage');
|
|
598
|
+
|
|
599
|
+
if (node && parent && stage) {
|
|
600
|
+
const root = cloneDeep(this.get<MApp>('root'));
|
|
601
|
+
const index = getNodeIndex(node, parent);
|
|
602
|
+
parent.items?.splice(index, 1);
|
|
603
|
+
|
|
604
|
+
await stage.remove({ id: node.id, root });
|
|
605
|
+
|
|
606
|
+
const layout = await this.getLayout(target);
|
|
607
|
+
|
|
608
|
+
const newConfig = mergeWith(cloneDeep(node), config, (objValue, srcValue) => {
|
|
609
|
+
if (Array.isArray(srcValue)) {
|
|
610
|
+
return srcValue;
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
newConfig.style = getInitPositionStyle(newConfig.style, layout, target, stage);
|
|
614
|
+
|
|
615
|
+
target.items.push(newConfig);
|
|
616
|
+
|
|
617
|
+
await stage.select(targetId);
|
|
618
|
+
|
|
619
|
+
await stage.update({ config: cloneDeep(target), root });
|
|
620
|
+
|
|
621
|
+
await this.select(newConfig);
|
|
622
|
+
stage.select(newConfig.id);
|
|
623
|
+
|
|
624
|
+
this.addModifiedNodeId(target.id);
|
|
625
|
+
this.addModifiedNodeId(parent.id);
|
|
626
|
+
this.pushHistoryState();
|
|
627
|
+
|
|
628
|
+
return newConfig;
|
|
629
|
+
}
|
|
573
630
|
}
|
|
574
631
|
|
|
575
632
|
/**
|
|
@@ -656,13 +713,13 @@ class Editor extends BaseService {
|
|
|
656
713
|
}
|
|
657
714
|
|
|
658
715
|
private async toggleFixedPosition(dist: MNode, src: MNode, root: MApp) {
|
|
659
|
-
|
|
716
|
+
const newConfig = cloneDeep(dist);
|
|
660
717
|
|
|
661
718
|
if (!isPop(src) && newConfig.style?.position) {
|
|
662
719
|
if (isFixed(newConfig) && !isFixed(src)) {
|
|
663
|
-
newConfig = change2Fixed(newConfig, root);
|
|
720
|
+
newConfig.style = change2Fixed(newConfig, root);
|
|
664
721
|
} else if (!isFixed(newConfig) && isFixed(src)) {
|
|
665
|
-
newConfig = await Fixed2Other(newConfig, root, this.getLayout);
|
|
722
|
+
newConfig.style = await Fixed2Other(newConfig, root, this.getLayout);
|
|
666
723
|
}
|
|
667
724
|
}
|
|
668
725
|
|