@tmagic/editor 1.0.0-rc.1 → 1.0.0-rc.10
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 +6 -3
- package/dist/tmagic-editor.es.js +292 -1394
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +292 -1396
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +49 -1
- package/dist/types/src/fields/Code.vue.d.ts +4 -4
- package/dist/types/src/fields/CodeLink.vue.d.ts +1 -3
- package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
- package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -4
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +3 -27
- package/dist/types/src/services/BaseService.d.ts +1 -1
- package/dist/types/src/services/history.d.ts +1 -18
- package/dist/types/src/services/props.d.ts +8 -2
- package/dist/types/src/type.d.ts +9 -0
- package/dist/types/src/utils/editor.d.ts +0 -6
- package/dist/types/src/utils/props.d.ts +8 -1
- package/package.json +17 -18
- package/src/Editor.vue +44 -9
- package/src/components/ContentMenu.vue +59 -26
- package/src/layouts/CodeEditor.vue +1 -4
- package/src/layouts/Framework.vue +14 -1
- package/src/layouts/PropsPanel.vue +1 -1
- package/src/layouts/sidebar/LayerMenu.vue +3 -0
- package/src/layouts/sidebar/TabPane.vue +1 -1
- package/src/layouts/workspace/Stage.vue +12 -29
- package/src/layouts/workspace/ViewerMenu.vue +17 -2
- package/src/layouts/workspace/Workspace.vue +21 -26
- package/src/services/BaseService.ts +1 -1
- package/src/services/editor.ts +34 -5
- package/src/services/props.ts +64 -9
- package/src/theme/props-panel.scss +6 -4
- package/src/theme/workspace.scss +4 -0
- package/src/type.ts +10 -0
- package/src/utils/editor.ts +7 -52
- package/src/utils/polyfills.ts +5 -19
- package/src/utils/props.ts +30 -7
- package/LICENSE +0 -5432
- package/coverage/clover.xml +0 -1560
- package/coverage/coverage-final.json +0 -36
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -206
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov-report/src/Editor.vue.html +0 -787
- package/coverage/lcov-report/src/components/ContentMenu.vue.html +0 -406
- package/coverage/lcov-report/src/components/Icon.vue.html +0 -172
- package/coverage/lcov-report/src/components/ScrollViewer.vue.html +0 -283
- package/coverage/lcov-report/src/components/ToolButton.vue.html +0 -772
- package/coverage/lcov-report/src/components/index.html +0 -161
- package/coverage/lcov-report/src/index.html +0 -131
- package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +0 -214
- package/coverage/lcov-report/src/layouts/Framework.vue.html +0 -304
- package/coverage/lcov-report/src/layouts/NavMenu.vue.html +0 -208
- package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +0 -319
- package/coverage/lcov-report/src/layouts/Resizer.vue.html +0 -268
- package/coverage/lcov-report/src/layouts/index.html +0 -176
- package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +0 -358
- package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +0 -421
- package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +0 -775
- package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +0 -226
- package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +0 -289
- package/coverage/lcov-report/src/layouts/sidebar/index.html +0 -176
- package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +0 -718
- package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +0 -757
- package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +0 -532
- package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +0 -586
- package/coverage/lcov-report/src/layouts/workspace/index.html +0 -161
- package/coverage/lcov-report/src/services/BaseService.ts.html +0 -643
- package/coverage/lcov-report/src/services/componentList.ts.html +0 -229
- package/coverage/lcov-report/src/services/editor.ts.html +0 -2077
- package/coverage/lcov-report/src/services/events.ts.html +0 -331
- package/coverage/lcov-report/src/services/history.ts.html +0 -478
- package/coverage/lcov-report/src/services/index.html +0 -206
- package/coverage/lcov-report/src/services/props.ts.html +0 -415
- package/coverage/lcov-report/src/services/ui.ts.html +0 -580
- package/coverage/lcov-report/src/type.ts.html +0 -850
- package/coverage/lcov-report/src/utils/compose.ts.html +0 -184
- package/coverage/lcov-report/src/utils/config.ts.html +0 -172
- package/coverage/lcov-report/src/utils/editor.ts.html +0 -838
- package/coverage/lcov-report/src/utils/index.html +0 -221
- package/coverage/lcov-report/src/utils/index.ts.html +0 -151
- package/coverage/lcov-report/src/utils/logger.ts.html +0 -226
- package/coverage/lcov-report/src/utils/props.ts.html +0 -796
- package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +0 -733
- package/coverage/lcov-report/src/utils/undo-redo.ts.html +0 -313
- package/coverage/lcov.info +0 -3708
- package/dist/types/src/components/ToolButton.vue.d.ts +0 -46
- package/dist/types/src/fields/UISelect.vue.d.ts +0 -35
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +0 -18
|
@@ -94,11 +94,7 @@ export default defineComponent({
|
|
|
94
94
|
const options = {
|
|
95
95
|
value: values.value,
|
|
96
96
|
language: props.language,
|
|
97
|
-
tabSize: 2,
|
|
98
97
|
theme: 'vs-dark',
|
|
99
|
-
fontFamily: 'dm, Menlo, Monaco, "Courier New", monospace',
|
|
100
|
-
fontSize: 14,
|
|
101
|
-
formatOnPaste: true,
|
|
102
98
|
...props.options,
|
|
103
99
|
};
|
|
104
100
|
|
|
@@ -117,6 +113,7 @@ export default defineComponent({
|
|
|
117
113
|
codeEditor.value.addEventListener('keydown', (e) => {
|
|
118
114
|
if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
|
|
119
115
|
e.preventDefault();
|
|
116
|
+
e.stopPropagation();
|
|
120
117
|
emit('save', getEditorValue());
|
|
121
118
|
}
|
|
122
119
|
});
|
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
<div class="m-editor">
|
|
3
3
|
<slot name="nav" class="m-editor-nav-menu"></slot>
|
|
4
4
|
|
|
5
|
-
<magic-code-editor
|
|
5
|
+
<magic-code-editor
|
|
6
|
+
v-if="showSrc"
|
|
7
|
+
class="m-editor-content"
|
|
8
|
+
:init-values="root"
|
|
9
|
+
:options="codeOptions"
|
|
10
|
+
@save="saveCode"
|
|
11
|
+
></magic-code-editor>
|
|
6
12
|
|
|
7
13
|
<div class="m-editor-content" v-else>
|
|
8
14
|
<div class="m-editor-framework-left" :style="`width: ${columnWidth?.left}px`">
|
|
@@ -48,6 +54,13 @@ export default defineComponent({
|
|
|
48
54
|
Resizer,
|
|
49
55
|
},
|
|
50
56
|
|
|
57
|
+
props: {
|
|
58
|
+
codeOptions: {
|
|
59
|
+
type: Object,
|
|
60
|
+
default: () => ({}),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
|
|
51
64
|
setup() {
|
|
52
65
|
const { editorService, uiService } = inject<Services>('services') || {};
|
|
53
66
|
|
|
@@ -22,6 +22,8 @@ export default defineComponent({
|
|
|
22
22
|
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
|
23
23
|
const componentList = computed(() => services?.componentListService.getList() || []);
|
|
24
24
|
|
|
25
|
+
const layerContentMenu = inject<MenuItem[]>('layerContentMenu', []);
|
|
26
|
+
|
|
25
27
|
const createMenuItems = (group: ComponentGroup): MenuButton[] =>
|
|
26
28
|
group.items.map((component) => ({
|
|
27
29
|
text: component.text,
|
|
@@ -101,6 +103,7 @@ export default defineComponent({
|
|
|
101
103
|
node.value && services?.editorService.remove(node.value);
|
|
102
104
|
},
|
|
103
105
|
},
|
|
106
|
+
...layerContentMenu,
|
|
104
107
|
]),
|
|
105
108
|
|
|
106
109
|
show(e: MouseEvent) {
|
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
markRaw,
|
|
29
29
|
onMounted,
|
|
30
30
|
onUnmounted,
|
|
31
|
-
PropType,
|
|
32
31
|
ref,
|
|
33
32
|
toRaw,
|
|
34
33
|
watch,
|
|
@@ -37,11 +36,11 @@ import {
|
|
|
37
36
|
import { cloneDeep } from 'lodash-es';
|
|
38
37
|
|
|
39
38
|
import type { MApp, MNode, MPage } from '@tmagic/schema';
|
|
40
|
-
import type {
|
|
39
|
+
import type { Runtime, SortEventData, UpdateEventData } from '@tmagic/stage';
|
|
41
40
|
import StageCore from '@tmagic/stage';
|
|
42
41
|
|
|
43
42
|
import ScrollViewer from '@editor/components/ScrollViewer.vue';
|
|
44
|
-
import { Layout, Services, StageRect } from '@editor/type';
|
|
43
|
+
import { Layout, Services, StageOptions, StageRect } from '@editor/type';
|
|
45
44
|
|
|
46
45
|
import ViewerMenu from './ViewerMenu.vue';
|
|
47
46
|
|
|
@@ -53,28 +52,9 @@ export default defineComponent({
|
|
|
53
52
|
ScrollViewer,
|
|
54
53
|
},
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
render: {
|
|
58
|
-
type: Function as PropType<() => HTMLDivElement>,
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
runtimeUrl: String,
|
|
62
|
-
|
|
63
|
-
canSelect: {
|
|
64
|
-
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
|
65
|
-
default: (el: HTMLElement) => Boolean(el.id),
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
moveableOptions: {
|
|
69
|
-
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
|
|
70
|
-
default: () => (core?: StageCore) => ({
|
|
71
|
-
container: core?.renderer?.contentWindow?.document.getElementById('app'),
|
|
72
|
-
}),
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
setup(props) {
|
|
55
|
+
setup() {
|
|
77
56
|
const services = inject<Services>('services');
|
|
57
|
+
const stageOptions = inject<StageOptions>('stageOptions');
|
|
78
58
|
|
|
79
59
|
const stageWrap = ref<InstanceType<typeof ScrollViewer>>();
|
|
80
60
|
const stageContainer = ref<HTMLDivElement>();
|
|
@@ -94,14 +74,15 @@ export default defineComponent({
|
|
|
94
74
|
if (stage) return;
|
|
95
75
|
|
|
96
76
|
if (!stageContainer.value) return;
|
|
97
|
-
if (!(
|
|
77
|
+
if (!(stageOptions?.runtimeUrl || stageOptions?.render) || !root.value) return;
|
|
98
78
|
|
|
99
79
|
stage = new StageCore({
|
|
100
|
-
render:
|
|
101
|
-
runtimeUrl:
|
|
80
|
+
render: stageOptions.render,
|
|
81
|
+
runtimeUrl: stageOptions.runtimeUrl,
|
|
102
82
|
zoom: zoom.value,
|
|
83
|
+
autoScrollIntoView: stageOptions.autoScrollIntoView,
|
|
103
84
|
canSelect: (el, event, stop) => {
|
|
104
|
-
const elCanSelect =
|
|
85
|
+
const elCanSelect = stageOptions.canSelect(el);
|
|
105
86
|
// 在组件联动过程中不能再往下选择,返回并触发 ui-select
|
|
106
87
|
if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
|
|
107
88
|
document.dispatchEvent(new CustomEvent('ui-select', { detail: el }));
|
|
@@ -110,7 +91,8 @@ export default defineComponent({
|
|
|
110
91
|
|
|
111
92
|
return elCanSelect;
|
|
112
93
|
},
|
|
113
|
-
moveableOptions:
|
|
94
|
+
moveableOptions: stageOptions.moveableOptions,
|
|
95
|
+
updateDragEl: stageOptions.updateDragEl,
|
|
114
96
|
});
|
|
115
97
|
|
|
116
98
|
services?.editorService.set('stage', markRaw(stage));
|
|
@@ -209,6 +191,7 @@ export default defineComponent({
|
|
|
209
191
|
const { scrollTop, scrollLeft } = stage.mask;
|
|
210
192
|
if (layout === Layout.ABSOLUTE) {
|
|
211
193
|
config.style = {
|
|
194
|
+
...(config.style || {}),
|
|
212
195
|
position: 'absolute',
|
|
213
196
|
top: e.clientY - containerRect.top + scrollTop,
|
|
214
197
|
left: e.clientX - containerRect.left + scrollLeft,
|
|
@@ -27,6 +27,8 @@ export default defineComponent({
|
|
|
27
27
|
const parent = computed(() => editorService?.get('parent'));
|
|
28
28
|
const isPage = computed(() => node.value?.type === NodeType.PAGE);
|
|
29
29
|
|
|
30
|
+
const stageContentMenu = inject<MenuItem[]>('stageContentMenu', []);
|
|
31
|
+
|
|
30
32
|
onMounted(() => {
|
|
31
33
|
const data = globalThis.localStorage.getItem(COPY_STORAGE_KEY);
|
|
32
34
|
canPaste.value = data !== 'undefined' && !!data;
|
|
@@ -69,8 +71,20 @@ export default defineComponent({
|
|
|
69
71
|
text: '粘贴',
|
|
70
72
|
display: () => canPaste.value,
|
|
71
73
|
handler: () => {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
+
const stage = editorService?.get<StageCore>('stage');
|
|
75
|
+
|
|
76
|
+
const rect = menu.value?.$el.getBoundingClientRect();
|
|
77
|
+
const parentRect = stage?.container?.getBoundingClientRect();
|
|
78
|
+
let left = (rect?.left || 0) - (parentRect?.left || 0);
|
|
79
|
+
let top = (rect?.top || 0) - (parentRect?.top || 0);
|
|
80
|
+
|
|
81
|
+
if (node.value?.items && stage) {
|
|
82
|
+
const parentEl = stage.renderer.contentWindow?.document.getElementById(`${node.value.id}`);
|
|
83
|
+
const parentElRect = parentEl?.getBoundingClientRect();
|
|
84
|
+
left = left - (parentElRect?.left || 0);
|
|
85
|
+
top = top - (parentElRect?.top || 0);
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
editorService?.paste({ left, top });
|
|
75
89
|
},
|
|
76
90
|
},
|
|
@@ -138,6 +152,7 @@ export default defineComponent({
|
|
|
138
152
|
editorService?.get<StageCore>('stage').clearGuides();
|
|
139
153
|
},
|
|
140
154
|
},
|
|
155
|
+
...stageContentMenu,
|
|
141
156
|
]),
|
|
142
157
|
|
|
143
158
|
show(e: MouseEvent) {
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="m-editor-workspace" tabindex="1" ref="workspace">
|
|
3
|
-
<magic-stage
|
|
4
|
-
:key="page?.id"
|
|
5
|
-
:runtime-url="runtimeUrl"
|
|
6
|
-
:render="render"
|
|
7
|
-
:moveable-options="moveableOptions"
|
|
8
|
-
:can-select="canSelect"
|
|
9
|
-
></magic-stage>
|
|
3
|
+
<magic-stage :key="page?.id"></magic-stage>
|
|
10
4
|
|
|
11
5
|
<slot name="workspace-content"></slot>
|
|
12
6
|
|
|
@@ -18,12 +12,10 @@
|
|
|
18
12
|
</template>
|
|
19
13
|
|
|
20
14
|
<script lang="ts">
|
|
21
|
-
import { computed, defineComponent, inject, onMounted, onUnmounted,
|
|
15
|
+
import { computed, defineComponent, inject, onMounted, onUnmounted, ref } from 'vue';
|
|
22
16
|
import KeyController from 'keycon';
|
|
23
17
|
|
|
24
18
|
import type { MNode, MPage } from '@tmagic/schema';
|
|
25
|
-
import type { MoveableOptions } from '@tmagic/stage';
|
|
26
|
-
import StageCore from '@tmagic/stage';
|
|
27
19
|
import { isPage } from '@tmagic/utils';
|
|
28
20
|
|
|
29
21
|
import type { Services } from '@editor/type';
|
|
@@ -39,22 +31,6 @@ export default defineComponent({
|
|
|
39
31
|
MagicStage,
|
|
40
32
|
},
|
|
41
33
|
|
|
42
|
-
props: {
|
|
43
|
-
runtimeUrl: String,
|
|
44
|
-
|
|
45
|
-
render: {
|
|
46
|
-
type: Function as PropType<() => HTMLDivElement>,
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
moveableOptions: {
|
|
50
|
-
type: [Object, Function] as PropType<MoveableOptions | ((core?: StageCore) => MoveableOptions)>,
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
canSelect: {
|
|
54
|
-
type: Function as PropType<(el: HTMLElement) => boolean | Promise<boolean>>,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
|
|
58
34
|
setup() {
|
|
59
35
|
const services = inject<Services>('services');
|
|
60
36
|
const workspace = ref<HTMLDivElement>();
|
|
@@ -65,8 +41,13 @@ export default defineComponent({
|
|
|
65
41
|
workspace.value?.focus();
|
|
66
42
|
};
|
|
67
43
|
|
|
44
|
+
const mouseleaveHandler = () => {
|
|
45
|
+
workspace.value?.blur();
|
|
46
|
+
};
|
|
47
|
+
|
|
68
48
|
onMounted(() => {
|
|
69
49
|
workspace.value?.addEventListener('mouseenter', mouseenterHandler);
|
|
50
|
+
workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
|
|
70
51
|
|
|
71
52
|
keycon = new KeyController(workspace.value);
|
|
72
53
|
|
|
@@ -80,6 +61,11 @@ export default defineComponent({
|
|
|
80
61
|
if (!node.value || isPage(node.value)) return;
|
|
81
62
|
services?.editorService.remove(node.value);
|
|
82
63
|
})
|
|
64
|
+
.keyup('backspace', (e) => {
|
|
65
|
+
e.inputEvent.preventDefault();
|
|
66
|
+
if (!node.value || isPage(node.value)) return;
|
|
67
|
+
services?.editorService.remove(node.value);
|
|
68
|
+
})
|
|
83
69
|
.keydown([ctrl, 'c'], (e) => {
|
|
84
70
|
e.inputEvent.preventDefault();
|
|
85
71
|
node.value && services?.editorService.copy(node.value);
|
|
@@ -146,14 +132,23 @@ export default defineComponent({
|
|
|
146
132
|
e.inputEvent.preventDefault();
|
|
147
133
|
services?.uiService.zoom(0.1);
|
|
148
134
|
})
|
|
135
|
+
.keydown([ctrl, 'numpadplus'], (e) => {
|
|
136
|
+
e.inputEvent.preventDefault();
|
|
137
|
+
services?.uiService.zoom(0.1);
|
|
138
|
+
})
|
|
149
139
|
.keydown([ctrl, '-'], (e) => {
|
|
150
140
|
e.inputEvent.preventDefault();
|
|
151
141
|
services?.uiService.zoom(-0.1);
|
|
142
|
+
})
|
|
143
|
+
.keydown([ctrl, 'numpad-'], (e) => {
|
|
144
|
+
e.inputEvent.preventDefault();
|
|
145
|
+
services?.uiService.zoom(-0.1);
|
|
152
146
|
});
|
|
153
147
|
});
|
|
154
148
|
|
|
155
149
|
onUnmounted(() => {
|
|
156
150
|
workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
|
|
151
|
+
workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
|
|
157
152
|
keycon.destroy();
|
|
158
153
|
});
|
|
159
154
|
|
|
@@ -91,7 +91,7 @@ const doAction = async (
|
|
|
91
91
|
* editorService.afterAdd();
|
|
92
92
|
* }
|
|
93
93
|
*
|
|
94
|
-
* 调用时的参数会透传到before方法的参数中, 然后before的return 会作为原方法的参数和after的参数,after
|
|
94
|
+
* 调用时的参数会透传到before方法的参数中, 然后before的return 会作为原方法的参数和after的参数,after第一个参数则是原方法的return值;
|
|
95
95
|
* 如需终止后续方法调用可以return new Error();
|
|
96
96
|
*
|
|
97
97
|
* 方法2:
|
package/src/services/editor.ts
CHANGED
|
@@ -33,11 +33,11 @@ import {
|
|
|
33
33
|
change2Fixed,
|
|
34
34
|
COPY_STORAGE_KEY,
|
|
35
35
|
Fixed2Other,
|
|
36
|
+
generatePageNameByApp,
|
|
36
37
|
getNodeIndex,
|
|
37
38
|
initPosition,
|
|
38
39
|
isFixed,
|
|
39
40
|
setLayout,
|
|
40
|
-
setNewItemId,
|
|
41
41
|
} from '@editor/utils/editor';
|
|
42
42
|
import { log } from '@editor/utils/logger';
|
|
43
43
|
|
|
@@ -194,6 +194,20 @@ class Editor extends BaseService {
|
|
|
194
194
|
historyService.empty();
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
if (node?.id) {
|
|
198
|
+
this.get<StageCore>('stage')
|
|
199
|
+
?.renderer.runtime?.getApp?.()
|
|
200
|
+
?.emit(
|
|
201
|
+
'editor:select',
|
|
202
|
+
{
|
|
203
|
+
node,
|
|
204
|
+
page,
|
|
205
|
+
parent,
|
|
206
|
+
},
|
|
207
|
+
getNodePath(node.id, this.get<MApp>('root').items),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
197
211
|
this.emit('select', node);
|
|
198
212
|
|
|
199
213
|
return node!;
|
|
@@ -480,7 +494,7 @@ class Editor extends BaseService {
|
|
|
480
494
|
return;
|
|
481
495
|
}
|
|
482
496
|
|
|
483
|
-
setNewItemId(config, this.get('root'));
|
|
497
|
+
await propsService.setNewItemId(config, this.get('root'));
|
|
484
498
|
if (config.style) {
|
|
485
499
|
config.style = {
|
|
486
500
|
...config.style,
|
|
@@ -488,6 +502,10 @@ class Editor extends BaseService {
|
|
|
488
502
|
};
|
|
489
503
|
}
|
|
490
504
|
|
|
505
|
+
if (isPage(config)) {
|
|
506
|
+
config.name = generatePageNameByApp(this.get('root'));
|
|
507
|
+
}
|
|
508
|
+
|
|
491
509
|
return await this.add(config);
|
|
492
510
|
}
|
|
493
511
|
|
|
@@ -504,7 +522,18 @@ class Editor extends BaseService {
|
|
|
504
522
|
return;
|
|
505
523
|
}
|
|
506
524
|
|
|
507
|
-
if (
|
|
525
|
+
if (!node.style) return;
|
|
526
|
+
|
|
527
|
+
const stage = this.get<StageCore>('stage');
|
|
528
|
+
const doc = stage?.renderer.contentWindow?.document;
|
|
529
|
+
|
|
530
|
+
if (doc) {
|
|
531
|
+
const parentEl = doc.getElementById(`${parent.id}`);
|
|
532
|
+
const el = doc.getElementById(`${node.id}`);
|
|
533
|
+
if (parentEl && el) {
|
|
534
|
+
node.style.left = (parentEl.clientWidth - el.clientWidth) / 2;
|
|
535
|
+
}
|
|
536
|
+
} else if (parent.style && isNumber(parent.style?.width) && isNumber(node.style?.width)) {
|
|
508
537
|
node.style.left = (parent.style.width - node.style.width) / 2;
|
|
509
538
|
}
|
|
510
539
|
|
|
@@ -526,9 +555,9 @@ class Editor extends BaseService {
|
|
|
526
555
|
const brothers: MNode[] = parent?.items || [];
|
|
527
556
|
const index = brothers.findIndex((item) => `${item.id}` === `${node?.id}`);
|
|
528
557
|
|
|
529
|
-
if (offset === LayerOffset.
|
|
558
|
+
if (offset === LayerOffset.TOP) {
|
|
530
559
|
brothers.splice(brothers.length - 1, 0, brothers.splice(index, 1)[0]);
|
|
531
|
-
} else if (offset === LayerOffset.
|
|
560
|
+
} else if (offset === LayerOffset.BOTTOM) {
|
|
532
561
|
brothers.splice(0, 0, brothers.splice(index, 1)[0]);
|
|
533
562
|
} else {
|
|
534
563
|
brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
|
package/src/services/props.ts
CHANGED
|
@@ -17,11 +17,12 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive } from 'vue';
|
|
20
|
-
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
20
|
+
import { cloneDeep, mergeWith, random } from 'lodash-es';
|
|
21
21
|
|
|
22
22
|
import type { FormConfig } from '@tmagic/form';
|
|
23
|
-
import type { MComponent, MNode } from '@tmagic/schema';
|
|
24
|
-
import {
|
|
23
|
+
import type { Id, MComponent, MNode, MPage } from '@tmagic/schema';
|
|
24
|
+
import { NodeType } from '@tmagic/schema';
|
|
25
|
+
import { isPop, toLine } from '@tmagic/utils';
|
|
25
26
|
|
|
26
27
|
import type { PropsState } from '@editor/type';
|
|
27
28
|
import { DEFAULT_CONFIG, fillConfig, getDefaultPropsValue } from '@editor/utils/props';
|
|
@@ -35,7 +36,7 @@ class Props extends BaseService {
|
|
|
35
36
|
});
|
|
36
37
|
|
|
37
38
|
constructor() {
|
|
38
|
-
super(['setPropsConfig', 'getPropsConfig', 'setPropsValue', 'getPropsValue']);
|
|
39
|
+
super(['setPropsConfig', 'getPropsConfig', 'setPropsValue', 'getPropsValue', 'createId', 'setNewItemId']);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
public setPropsConfigs(configs: Record<string, FormConfig>) {
|
|
@@ -87,7 +88,7 @@ class Props extends BaseService {
|
|
|
87
88
|
* @param type 组件类型
|
|
88
89
|
* @returns 组件初始值
|
|
89
90
|
*/
|
|
90
|
-
public async getPropsValue(type: string, defaultValue = {}) {
|
|
91
|
+
public async getPropsValue(type: string, defaultValue: Record<string, any> = {}) {
|
|
91
92
|
if (type === 'area') {
|
|
92
93
|
const value = (await this.getPropsValue('button')) as MComponent;
|
|
93
94
|
value.className = 'action-area';
|
|
@@ -98,13 +99,67 @@ class Props extends BaseService {
|
|
|
98
99
|
return value;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
const data = cloneDeep(defaultValue as any);
|
|
103
|
+
|
|
104
|
+
await this.setNewItemId(data);
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
...getDefaultPropsValue(type, await this.createId(type)),
|
|
108
|
+
...mergeWith(cloneDeep(this.state.propsValueMap[type] || {}), data),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public async createId(type: string | number): Promise<string> {
|
|
113
|
+
return `${type}_${random(10000, false)}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 将组件与组件的子元素配置中的id都设置成一个新的ID
|
|
118
|
+
* @param {Object} config 组件配置
|
|
119
|
+
*/
|
|
120
|
+
/* eslint no-param-reassign: ["error", { "props": false }] */
|
|
121
|
+
public async setNewItemId(config: MNode, parent?: MPage) {
|
|
122
|
+
const oldId = config.id;
|
|
123
|
+
|
|
124
|
+
config.id = await this.createId(config.type || 'component');
|
|
125
|
+
|
|
126
|
+
// 只有弹窗在页面下的一级子元素才有效
|
|
127
|
+
if (isPop(config) && parent?.type === NodeType.PAGE) {
|
|
128
|
+
updatePopId(oldId, config.id, parent);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (config.items && Array.isArray(config.items)) {
|
|
132
|
+
for (const item of config.items) {
|
|
133
|
+
await this.setNewItemId(item, config as MPage);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
105
136
|
}
|
|
106
137
|
}
|
|
107
138
|
|
|
139
|
+
/**
|
|
140
|
+
* 复制页面时,需要把组件下关联的弹窗id换测复制出来的弹窗的id
|
|
141
|
+
* @param {number} oldId 复制的源弹窗id
|
|
142
|
+
* @param {number} popId 新的弹窗id
|
|
143
|
+
* @param {Object} pageConfig 页面配置
|
|
144
|
+
*/
|
|
145
|
+
const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
|
|
146
|
+
pageConfig.items?.forEach((config) => {
|
|
147
|
+
if (config.pop === oldId) {
|
|
148
|
+
config.pop = popId;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (config.popId === oldId) {
|
|
153
|
+
config.popId = popId;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (Array.isArray(config.items)) {
|
|
158
|
+
updatePopId(oldId, popId, config as MPage);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
108
163
|
export type PropsService = Props;
|
|
109
164
|
|
|
110
165
|
export default new Props();
|
package/src/theme/workspace.scss
CHANGED
package/src/type.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type { Component } from 'vue';
|
|
|
21
21
|
import type { FormConfig } from '@tmagic/form';
|
|
22
22
|
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
23
23
|
import type StageCore from '@tmagic/stage';
|
|
24
|
+
import type { MoveableOptions } from '@tmagic/stage';
|
|
24
25
|
|
|
25
26
|
import type { ComponentListService } from '@editor/services/componentList';
|
|
26
27
|
import type { EditorService } from '@editor/services/editor';
|
|
@@ -45,6 +46,15 @@ export interface Services {
|
|
|
45
46
|
uiService: UiService;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
export interface StageOptions {
|
|
50
|
+
runtimeUrl: string;
|
|
51
|
+
autoScrollIntoView: boolean;
|
|
52
|
+
render: () => HTMLDivElement;
|
|
53
|
+
moveableOptions: MoveableOptions | ((core?: StageCore) => MoveableOptions);
|
|
54
|
+
canSelect: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
55
|
+
updateDragEl: (el: HTMLDivElement) => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
export interface StoreState {
|
|
49
59
|
root: MApp | null;
|
|
50
60
|
page: MPage | null;
|
package/src/utils/editor.ts
CHANGED
|
@@ -16,9 +16,7 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
19
|
+
import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
22
20
|
import { NodeType } from '@tmagic/schema';
|
|
23
21
|
import type StageCore from '@tmagic/stage';
|
|
24
22
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
@@ -27,8 +25,6 @@ import { Layout } from '@editor/type';
|
|
|
27
25
|
|
|
28
26
|
export const COPY_STORAGE_KEY = '$MagicEditorCopyData';
|
|
29
27
|
|
|
30
|
-
export const generateId = (type: string | number): string => `${type}_${random(10000, false)}`;
|
|
31
|
-
|
|
32
28
|
/**
|
|
33
29
|
* 获取所有页面配置
|
|
34
30
|
* @param app DSL跟节点
|
|
@@ -74,51 +70,6 @@ export const generatePageName = (pageNameList: string[]): string => {
|
|
|
74
70
|
*/
|
|
75
71
|
export const generatePageNameByApp = (app: MApp): string => generatePageName(getPageNameList(getPageList(app)));
|
|
76
72
|
|
|
77
|
-
/**
|
|
78
|
-
* 复制页面时,需要把组件下关联的弹窗id换测复制出来的弹窗的id
|
|
79
|
-
* @param {number} oldId 复制的源弹窗id
|
|
80
|
-
* @param {number} popId 新的弹窗id
|
|
81
|
-
* @param {Object} pageConfig 页面配置
|
|
82
|
-
*/
|
|
83
|
-
const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
|
|
84
|
-
pageConfig.items?.forEach((config) => {
|
|
85
|
-
if (config.pop === oldId) {
|
|
86
|
-
config.pop = popId;
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (config.popId === oldId) {
|
|
91
|
-
config.popId = popId;
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (Array.isArray(config.items)) {
|
|
96
|
-
updatePopId(oldId, popId, config as MPage);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* 将组件与组件的子元素配置中的id都设置成一个新的ID
|
|
103
|
-
* @param {Object} config 组件配置
|
|
104
|
-
*/
|
|
105
|
-
/* eslint no-param-reassign: ["error", { "props": false }] */
|
|
106
|
-
export const setNewItemId = (config: MNode, parent?: MPage) => {
|
|
107
|
-
const oldId = config.id;
|
|
108
|
-
|
|
109
|
-
config.id = generateId(config.type || 'component');
|
|
110
|
-
config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
|
|
111
|
-
|
|
112
|
-
// 只有弹窗在页面下的一级子元素才有效
|
|
113
|
-
if (isPop(config) && parent?.type === NodeType.PAGE) {
|
|
114
|
-
updatePopId(oldId, config.id, parent);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (config.items && Array.isArray(config.items)) {
|
|
118
|
-
config.items.forEach((item) => setNewItemId(item, config as MPage));
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
73
|
/**
|
|
123
74
|
* @param {Object} node
|
|
124
75
|
* @returns {boolean}
|
|
@@ -142,9 +93,13 @@ export const toRelative = (node: MNode) => {
|
|
|
142
93
|
|
|
143
94
|
const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
|
|
144
95
|
const style = node.style || {};
|
|
145
|
-
|
|
96
|
+
let height = style.height || 0;
|
|
146
97
|
|
|
147
|
-
if (!stage || typeof style.top !== 'undefined' || !parentNode.style
|
|
98
|
+
if (!stage || typeof style.top !== 'undefined' || !parentNode.style) return style;
|
|
99
|
+
|
|
100
|
+
if (!isNumber(height)) {
|
|
101
|
+
height = 0;
|
|
102
|
+
}
|
|
148
103
|
|
|
149
104
|
const { height: parentHeight } = parentNode.style;
|
|
150
105
|
|
package/src/utils/polyfills.ts
CHANGED
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
|
-
*
|
|
4
|
-
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
|
-
*
|
|
6
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
-
* you may not use this file except in compliance with the License.
|
|
8
|
-
* You may obtain a copy of the License at
|
|
9
|
-
*
|
|
10
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
*
|
|
12
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
-
* See the License for the specific language governing permissions and
|
|
16
|
-
* limitations under the License.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
1
|
// serialize-javascript 依赖的 randombytes 依赖全局的 global 对象,因此此处需添加 global polyfill
|
|
20
|
-
if (typeof
|
|
2
|
+
if (typeof global === 'undefined') {
|
|
21
3
|
(window as any).global = window;
|
|
22
4
|
}
|
|
5
|
+
|
|
6
|
+
if (typeof globalThis === 'undefined') {
|
|
7
|
+
(window as any).globalThis = window;
|
|
8
|
+
}
|