@tmagic/editor 1.3.11 → 1.3.13
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 +3 -2
- package/dist/tmagic-editor.js +453 -363
- package/dist/tmagic-editor.umd.cjs +452 -361
- package/package.json +11 -11
- package/src/Editor.vue +28 -21
- package/src/components/SplitView.vue +1 -1
- package/src/editorProps.ts +25 -12
- package/src/fields/UISelect.vue +3 -0
- package/src/hooks/use-stage.ts +3 -1
- package/src/index.ts +1 -0
- package/src/layouts/sidebar/ComponentListPanel.vue +2 -2
- package/src/layouts/sidebar/layer/use-click.ts +3 -0
- package/src/layouts/workspace/Workspace.vue +11 -4
- package/src/layouts/workspace/viewer/Stage.vue +11 -5
- package/src/layouts/workspace/viewer/StageOverlay.vue +55 -5
- package/src/services/editor.ts +7 -6
- package/src/services/stageOverlay.ts +204 -0
- package/src/theme/stage.scss +3 -2
- package/src/type.ts +25 -12
- package/types/editorProps.d.ts +25 -12
- package/types/index.d.ts +1 -0
- package/types/layouts/workspace/Workspace.vue.d.ts +19 -3
- package/types/layouts/workspace/viewer/Stage.vue.d.ts +19 -3
- package/types/services/editor.d.ts +1 -1
- package/types/services/stageOverlay.d.ts +23 -0
- package/types/type.d.ts +24 -12
- package/src/hooks/use-stage-overlay.ts +0 -158
- package/types/hooks/use-stage-overlay.d.ts +0 -7
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.3.
|
|
2
|
+
"version": "1.3.13",
|
|
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.13",
|
|
46
|
+
"@tmagic/dep": "1.3.13",
|
|
47
|
+
"@tmagic/design": "1.3.13",
|
|
48
|
+
"@tmagic/form": "1.3.13",
|
|
49
|
+
"@tmagic/schema": "1.3.13",
|
|
50
|
+
"@tmagic/stage": "1.3.13",
|
|
51
|
+
"@tmagic/table": "1.3.13",
|
|
52
|
+
"@tmagic/utils": "1.3.13",
|
|
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.13",
|
|
67
|
+
"@tmagic/form": "1.3.13",
|
|
68
68
|
"monaco-editor": "^0.41.0",
|
|
69
69
|
"vue": "^3.3.8"
|
|
70
70
|
},
|
package/src/Editor.vue
CHANGED
|
@@ -58,7 +58,11 @@
|
|
|
58
58
|
|
|
59
59
|
<template #workspace>
|
|
60
60
|
<slot name="workspace" :editorService="editorService">
|
|
61
|
-
<Workspace
|
|
61
|
+
<Workspace
|
|
62
|
+
:disabled-stage-overlay="disabledStageOverlay"
|
|
63
|
+
:stage-content-menu="stageContentMenu"
|
|
64
|
+
:custom-content-menu="customContentMenu"
|
|
65
|
+
>
|
|
62
66
|
<template #stage><slot name="stage"></slot></template>
|
|
63
67
|
<template #workspace-content><slot name="workspace-content" :editorService="editorService"></slot></template>
|
|
64
68
|
</Workspace>
|
|
@@ -97,7 +101,7 @@
|
|
|
97
101
|
</template>
|
|
98
102
|
|
|
99
103
|
<script lang="ts" setup>
|
|
100
|
-
import { provide
|
|
104
|
+
import { provide } from 'vue';
|
|
101
105
|
|
|
102
106
|
import type { MApp } from '@tmagic/schema';
|
|
103
107
|
|
|
@@ -115,6 +119,7 @@ import eventsService from './services/events';
|
|
|
115
119
|
import historyService from './services/history';
|
|
116
120
|
import keybindingService from './services/keybinding';
|
|
117
121
|
import propsService from './services/props';
|
|
122
|
+
import stageOverlayService from './services/stageOverlay';
|
|
118
123
|
import storageService from './services/storage';
|
|
119
124
|
import uiService from './services/ui';
|
|
120
125
|
import keybindingConfig from './utils/keybinding-config';
|
|
@@ -157,6 +162,7 @@ const services: Services = {
|
|
|
157
162
|
depService,
|
|
158
163
|
dataSourceService,
|
|
159
164
|
keybindingService,
|
|
165
|
+
stageOverlayService,
|
|
160
166
|
};
|
|
161
167
|
|
|
162
168
|
initServiceEvents(props, emit, services);
|
|
@@ -164,28 +170,29 @@ initServiceState(props, services);
|
|
|
164
170
|
keybindingService.register(keybindingConfig);
|
|
165
171
|
keybindingService.registerEl('global');
|
|
166
172
|
|
|
173
|
+
const stageOptions = {
|
|
174
|
+
runtimeUrl: props.runtimeUrl,
|
|
175
|
+
autoScrollIntoView: props.autoScrollIntoView,
|
|
176
|
+
render: props.render,
|
|
177
|
+
moveableOptions: props.moveableOptions,
|
|
178
|
+
canSelect: props.canSelect,
|
|
179
|
+
updateDragEl: props.updateDragEl,
|
|
180
|
+
isContainer: props.isContainer,
|
|
181
|
+
containerHighlightClassName: props.containerHighlightClassName,
|
|
182
|
+
containerHighlightDuration: props.containerHighlightDuration,
|
|
183
|
+
containerHighlightType: props.containerHighlightType,
|
|
184
|
+
disabledDragStart: props.disabledDragStart,
|
|
185
|
+
renderType: props.renderType,
|
|
186
|
+
guidesOptions: props.guidesOptions,
|
|
187
|
+
disabledMultiSelect: props.disabledMultiSelect,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
stageOverlayService.set('stageOptions', stageOptions);
|
|
191
|
+
|
|
167
192
|
provide('services', services);
|
|
168
193
|
|
|
169
194
|
provide('codeOptions', props.codeOptions);
|
|
170
|
-
provide(
|
|
171
|
-
'stageOptions',
|
|
172
|
-
reactive({
|
|
173
|
-
runtimeUrl: props.runtimeUrl,
|
|
174
|
-
autoScrollIntoView: props.autoScrollIntoView,
|
|
175
|
-
render: props.render,
|
|
176
|
-
moveableOptions: props.moveableOptions,
|
|
177
|
-
canSelect: props.canSelect,
|
|
178
|
-
updateDragEl: props.updateDragEl,
|
|
179
|
-
isContainer: props.isContainer,
|
|
180
|
-
containerHighlightClassName: props.containerHighlightClassName,
|
|
181
|
-
containerHighlightDuration: props.containerHighlightDuration,
|
|
182
|
-
containerHighlightType: props.containerHighlightType,
|
|
183
|
-
disabledDragStart: props.disabledDragStart,
|
|
184
|
-
renderType: props.renderType,
|
|
185
|
-
guidesOptions: props.guidesOptions,
|
|
186
|
-
disabledMultiSelect: props.disabledMultiSelect,
|
|
187
|
-
}),
|
|
188
|
-
);
|
|
195
|
+
provide('stageOptions', stageOptions);
|
|
189
196
|
|
|
190
197
|
defineExpose(services);
|
|
191
198
|
</script>
|
package/src/editorProps.ts
CHANGED
|
@@ -37,8 +37,6 @@ export interface EditorProps {
|
|
|
37
37
|
layerContentMenu?: (MenuButton | MenuComponent)[];
|
|
38
38
|
/** 画布右键菜单 */
|
|
39
39
|
stageContentMenu?: (MenuButton | MenuComponent)[];
|
|
40
|
-
/** 中间工作区域中画布渲染的内容 */
|
|
41
|
-
render?: (stage: StageCore) => HTMLDivElement | Promise<HTMLDivElement>;
|
|
42
40
|
/** 中间工作区域中画布通过iframe渲染时的页面url */
|
|
43
41
|
runtimeUrl?: string;
|
|
44
42
|
/** 是用iframe渲染还是直接渲染 */
|
|
@@ -60,16 +58,18 @@ export interface EditorProps {
|
|
|
60
58
|
moveableOptions?: MoveableOptions | ((config?: CustomizeMoveableOptionsCallbackConfig) => MoveableOptions);
|
|
61
59
|
/** 编辑器初始化时默认选中的组件ID */
|
|
62
60
|
defaultSelected?: Id;
|
|
63
|
-
|
|
64
|
-
isContainer?: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
61
|
+
/** 拖入画布中容器时,识别到容器后给容器根dom加上的class */
|
|
65
62
|
containerHighlightClassName?: string;
|
|
63
|
+
/** 拖入画布中容器时,悬停识别容器的时间 */
|
|
66
64
|
containerHighlightDuration?: number;
|
|
65
|
+
/** 拖入画布中容器时,识别容器的操作类型 */
|
|
67
66
|
containerHighlightType?: ContainerHighlightType;
|
|
67
|
+
/** 画布大小 */
|
|
68
68
|
stageRect?: StageRect;
|
|
69
|
+
/** monaco editor 的配置 */
|
|
69
70
|
codeOptions?: { [key: string]: any };
|
|
70
|
-
|
|
71
|
+
/** 禁用鼠标左键按下时就开始拖拽,需要先选中再可以拖拽 */
|
|
71
72
|
disabledDragStart?: boolean;
|
|
72
|
-
extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
73
73
|
/** 自定义依赖收集器,复制组件时会将关联依赖一并复制 */
|
|
74
74
|
collectorOptions?: CustomTargetOptions;
|
|
75
75
|
/** 标尺配置 */
|
|
@@ -78,10 +78,29 @@ export interface EditorProps {
|
|
|
78
78
|
disabledMultiSelect?: boolean;
|
|
79
79
|
/** 禁用页面片 */
|
|
80
80
|
disabledPageFragment?: boolean;
|
|
81
|
+
/** 禁用双击在浮层中单独编辑选中组件 */
|
|
82
|
+
disabledStageOverlay?: boolean;
|
|
83
|
+
/** 中间工作区域中画布渲染的内容 */
|
|
84
|
+
render?: (stage: StageCore) => HTMLDivElement | Promise<HTMLDivElement>;
|
|
85
|
+
/** 选中时会在画布上复制出一个大小相同的dom,实际拖拽的是这个dom,此方法用于干预这个dom的生成方式 */
|
|
86
|
+
updateDragEl?: UpdateDragEl;
|
|
87
|
+
/** 用于设置画布上的dom是否可以被选中 */
|
|
88
|
+
canSelect?: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
89
|
+
/** 用于设置画布上的dom是否可以被拖入其中 */
|
|
90
|
+
isContainer?: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
91
|
+
/** 用于自定义组件树与画布的右键菜单 */
|
|
81
92
|
customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
|
|
93
|
+
extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
export const defaultEditorProps = {
|
|
97
|
+
renderType: RenderType.IFRAME,
|
|
98
|
+
disabledMultiSelect: false,
|
|
99
|
+
disabledPageFragment: false,
|
|
100
|
+
disabledStageOverlay: false,
|
|
101
|
+
containerHighlightClassName: CONTAINER_HIGHLIGHT_CLASS_NAME,
|
|
102
|
+
containerHighlightDuration: 800,
|
|
103
|
+
containerHighlightType: ContainerHighlightType.DEFAULT,
|
|
85
104
|
componentGroupList: () => [],
|
|
86
105
|
datasourceList: () => [],
|
|
87
106
|
menu: () => ({ left: [], right: [] }),
|
|
@@ -94,11 +113,5 @@ export const defaultEditorProps = {
|
|
|
94
113
|
datasourceConfigs: () => ({}),
|
|
95
114
|
canSelect: (el: HTMLElement) => Boolean(el.id),
|
|
96
115
|
isContainer: (el: HTMLElement) => el.classList.contains('magic-ui-container'),
|
|
97
|
-
containerHighlightClassName: CONTAINER_HIGHLIGHT_CLASS_NAME,
|
|
98
|
-
containerHighlightDuration: 800,
|
|
99
|
-
containerHighlightType: ContainerHighlightType.DEFAULT,
|
|
100
116
|
codeOptions: () => ({}),
|
|
101
|
-
renderType: RenderType.IFRAME,
|
|
102
|
-
disabledMultiSelect: false,
|
|
103
|
-
disabledPageFragment: false,
|
|
104
117
|
};
|
package/src/fields/UISelect.vue
CHANGED
|
@@ -106,16 +106,19 @@ const deleteHandler = () => {
|
|
|
106
106
|
const selectNode = async (id: Id) => {
|
|
107
107
|
await services?.editorService.select(id);
|
|
108
108
|
services?.editorService.get('stage')?.select(id);
|
|
109
|
+
services?.stageOverlayService.get('stage')?.select(id);
|
|
109
110
|
};
|
|
110
111
|
|
|
111
112
|
const highlight = throttle((id: Id) => {
|
|
112
113
|
services?.editorService.highlight(id);
|
|
113
114
|
services?.editorService.get('stage')?.highlight(id);
|
|
115
|
+
services?.stageOverlayService.get('stage')?.highlight(id);
|
|
114
116
|
}, 150);
|
|
115
117
|
|
|
116
118
|
const unhightlight = () => {
|
|
117
119
|
services?.editorService.set('highlightNode', null);
|
|
118
120
|
services?.editorService.get('stage')?.clearHighlight();
|
|
121
|
+
services?.stageOverlayService.get('stage')?.clearHighlight();
|
|
119
122
|
};
|
|
120
123
|
</script>
|
|
121
124
|
|
package/src/hooks/use-stage.ts
CHANGED
|
@@ -33,7 +33,9 @@ export const useStage = (stageOptions: StageOptions) => {
|
|
|
33
33
|
disabledDragStart: stageOptions.disabledDragStart,
|
|
34
34
|
renderType: stageOptions.renderType,
|
|
35
35
|
canSelect: (el, event, stop) => {
|
|
36
|
-
|
|
36
|
+
if (!stageOptions.canSelect) return true;
|
|
37
|
+
|
|
38
|
+
const elCanSelect = stageOptions.canSelect?.(el);
|
|
37
39
|
// 在组件联动过程中不能再往下选择,返回并触发 ui-select
|
|
38
40
|
if (uiSelectMode.value && elCanSelect && event.type === 'mousedown') {
|
|
39
41
|
document.dispatchEvent(new CustomEvent(UI_SELECT_MODE_EVENT_NAME, { detail: el }));
|
package/src/index.ts
CHANGED
|
@@ -54,6 +54,7 @@ export { default as historyService } from './services/history';
|
|
|
54
54
|
export { default as storageService } from './services/storage';
|
|
55
55
|
export { default as eventsService } from './services/events';
|
|
56
56
|
export { default as dataSourceService } from './services/dataSource';
|
|
57
|
+
export { default as stageOverlayService } from './services/stageOverlay';
|
|
57
58
|
export { default as uiService } from './services/ui';
|
|
58
59
|
export { default as codeBlockService } from './services/codeBlock';
|
|
59
60
|
export { default as depService } from './services/dep';
|
|
@@ -108,8 +108,8 @@ const dragendHandler = () => {
|
|
|
108
108
|
globalThis.clearTimeout(timeout);
|
|
109
109
|
timeout = undefined;
|
|
110
110
|
}
|
|
111
|
-
const doc = stage.value?.renderer.
|
|
112
|
-
if (doc && stageOptions) {
|
|
111
|
+
const doc = stage.value?.renderer.getDocument();
|
|
112
|
+
if (doc && stageOptions?.containerHighlightClassName) {
|
|
113
113
|
removeClassNameByClassName(doc, stageOptions.containerHighlightClassName);
|
|
114
114
|
}
|
|
115
115
|
clientX = 0;
|
|
@@ -26,6 +26,7 @@ export const useClick = (
|
|
|
26
26
|
} else {
|
|
27
27
|
await services?.editorService.select(data);
|
|
28
28
|
services?.editorService.get('stage')?.select(data.id);
|
|
29
|
+
services?.stageOverlayService.get('stage')?.select(data.id);
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
32
|
|
|
@@ -50,6 +51,7 @@ export const useClick = (
|
|
|
50
51
|
|
|
51
52
|
await services?.editorService.multiSelect(newNodes);
|
|
52
53
|
services?.editorService.get('stage')?.multiSelect(newNodes);
|
|
54
|
+
services?.stageOverlayService.get('stage')?.multiSelect(newNodes);
|
|
53
55
|
};
|
|
54
56
|
|
|
55
57
|
const throttleTime = 300;
|
|
@@ -62,6 +64,7 @@ export const useClick = (
|
|
|
62
64
|
const highlight = (data: TreeNodeData) => {
|
|
63
65
|
services?.editorService?.highlight(data);
|
|
64
66
|
services?.editorService?.get('stage')?.highlight(data.id);
|
|
67
|
+
services?.stageOverlayService?.get('stage')?.highlight(data.id);
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
const nodeClickHandler = (event: MouseEvent, data: TreeNodeData) => {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<slot name="stage">
|
|
6
6
|
<MagicStage
|
|
7
7
|
v-if="page"
|
|
8
|
+
:disabled-stage-overlay="disabledStageOverlay"
|
|
8
9
|
:stage-content-menu="stageContentMenu"
|
|
9
10
|
:custom-content-menu="customContentMenu"
|
|
10
11
|
></MagicStage>
|
|
@@ -28,10 +29,16 @@ defineOptions({
|
|
|
28
29
|
name: 'MEditorWorkspace',
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
withDefaults(
|
|
33
|
+
defineProps<{
|
|
34
|
+
stageContentMenu: (MenuButton | MenuComponent)[];
|
|
35
|
+
disabledStageOverlay?: boolean;
|
|
36
|
+
customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
|
|
37
|
+
}>(),
|
|
38
|
+
{
|
|
39
|
+
disabledStageOverlay: false,
|
|
40
|
+
},
|
|
41
|
+
);
|
|
35
42
|
|
|
36
43
|
const services = inject<Services>('services');
|
|
37
44
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<NodeListMenu></NodeListMenu>
|
|
27
27
|
|
|
28
28
|
<template #content>
|
|
29
|
-
<StageOverlay></StageOverlay>
|
|
29
|
+
<StageOverlay v-if="!disabledStageOverlay"></StageOverlay>
|
|
30
30
|
|
|
31
31
|
<Teleport to="body">
|
|
32
32
|
<ViewerMenu
|
|
@@ -61,10 +61,16 @@ defineOptions({
|
|
|
61
61
|
name: 'MEditorStage',
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
withDefaults(
|
|
65
|
+
defineProps<{
|
|
66
|
+
stageContentMenu: (MenuButton | MenuComponent)[];
|
|
67
|
+
disabledStageOverlay?: boolean;
|
|
68
|
+
customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
|
|
69
|
+
}>(),
|
|
70
|
+
{
|
|
71
|
+
disabledStageOverlay: false,
|
|
72
|
+
},
|
|
73
|
+
);
|
|
68
74
|
|
|
69
75
|
let stage: StageCore | null = null;
|
|
70
76
|
let runtime: Runtime | null = null;
|
|
@@ -1,16 +1,66 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div v-if="stageOverlayVisible" class="m-editor-stage-overlay" @click="
|
|
3
|
-
<TMagicIcon class="m-editor-stage-overlay-close" :size="20" @click="
|
|
4
|
-
<div ref="stageOverlay" class="m-editor-stage-overlay-container" @click.stop></div>
|
|
2
|
+
<div v-if="stageOverlayVisible" class="m-editor-stage-overlay" @click="closeOverlayHandler">
|
|
3
|
+
<TMagicIcon class="m-editor-stage-overlay-close" :size="20" @click="closeOverlayHandler"><CloseBold /></TMagicIcon>
|
|
4
|
+
<div ref="stageOverlay" class="m-editor-stage-overlay-container" :style="style" @click.stop></div>
|
|
5
5
|
</div>
|
|
6
6
|
</template>
|
|
7
7
|
|
|
8
8
|
<script setup lang="ts">
|
|
9
|
+
import { computed, inject, ref, watch } from 'vue';
|
|
9
10
|
import { CloseBold } from '@element-plus/icons-vue';
|
|
10
11
|
|
|
11
12
|
import { TMagicIcon } from '@tmagic/design';
|
|
12
13
|
|
|
13
|
-
import {
|
|
14
|
+
import type { Services, StageOptions } from '@editor/type';
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
+
const services = inject<Services>('services');
|
|
17
|
+
|
|
18
|
+
const stageOptions = inject<StageOptions>('stageOptions');
|
|
19
|
+
|
|
20
|
+
const stageOverlay = ref<HTMLDivElement>();
|
|
21
|
+
|
|
22
|
+
const stageOverlayVisible = computed(() => services?.stageOverlayService.get('stageOverlayVisible'));
|
|
23
|
+
const wrapWidth = computed(() => services?.stageOverlayService.get('wrapWidth') || 0);
|
|
24
|
+
const wrapHeight = computed(() => services?.stageOverlayService.get('wrapHeight') || 0);
|
|
25
|
+
const stage = computed(() => services?.editorService.get('stage'));
|
|
26
|
+
|
|
27
|
+
const style = computed(() => ({
|
|
28
|
+
width: `${wrapWidth.value}px`,
|
|
29
|
+
height: `${wrapHeight.value}px`,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
watch(stage, (stage) => {
|
|
33
|
+
if (stage) {
|
|
34
|
+
stage.on('dblclick', async (event: MouseEvent) => {
|
|
35
|
+
const el = await stage.actionManager.getElementFromPoint(event);
|
|
36
|
+
services?.stageOverlayService.openOverlay(el);
|
|
37
|
+
});
|
|
38
|
+
} else {
|
|
39
|
+
services?.stageOverlayService.closeOverlay();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
watch(stageOverlay, (stageOverlay) => {
|
|
44
|
+
if (!services) return;
|
|
45
|
+
|
|
46
|
+
const subStage = services.stageOverlayService.createStage(stageOptions);
|
|
47
|
+
services?.stageOverlayService.set('stage', subStage);
|
|
48
|
+
|
|
49
|
+
if (stageOverlay && subStage) {
|
|
50
|
+
subStage.mount(stageOverlay);
|
|
51
|
+
|
|
52
|
+
const { mask, renderer } = subStage;
|
|
53
|
+
|
|
54
|
+
const { contentWindow } = renderer;
|
|
55
|
+
mask.showRule(false);
|
|
56
|
+
|
|
57
|
+
services?.stageOverlayService.updateOverlay();
|
|
58
|
+
|
|
59
|
+
contentWindow?.magic.onRuntimeReady({});
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const closeOverlayHandler = () => {
|
|
64
|
+
services?.stageOverlayService.closeOverlay();
|
|
65
|
+
};
|
|
16
66
|
</script>
|
package/src/services/editor.ts
CHANGED
|
@@ -24,6 +24,8 @@ import type { Id, MApp, MComponent, MContainer, MNode, MPage, MPageFragment } fr
|
|
|
24
24
|
import { NodeType } from '@tmagic/schema';
|
|
25
25
|
import { getNodePath, isNumber, isPage, isPageFragment, isPop } from '@tmagic/utils';
|
|
26
26
|
|
|
27
|
+
import BaseService from '@editor/services//BaseService';
|
|
28
|
+
import propsService from '@editor/services//props';
|
|
27
29
|
import depService from '@editor/services/dep';
|
|
28
30
|
import historyService from '@editor/services/history';
|
|
29
31
|
import storageService, { Protocol } from '@editor/services/storage';
|
|
@@ -44,9 +46,6 @@ import {
|
|
|
44
46
|
} from '@editor/utils/editor';
|
|
45
47
|
import { beforePaste, getAddParent } from '@editor/utils/operator';
|
|
46
48
|
|
|
47
|
-
import BaseService from './BaseService';
|
|
48
|
-
import propsService from './props';
|
|
49
|
-
|
|
50
49
|
class Editor extends BaseService {
|
|
51
50
|
public state: StoreState = reactive({
|
|
52
51
|
root: null,
|
|
@@ -810,7 +809,7 @@ class Editor extends BaseService {
|
|
|
810
809
|
* @param targetId 容器ID
|
|
811
810
|
*/
|
|
812
811
|
public async moveToContainer(config: MNode, targetId: Id): Promise<MNode | undefined> {
|
|
813
|
-
const root =
|
|
812
|
+
const root = this.get('root');
|
|
814
813
|
const { node, parent } = this.getNodeInfo(config.id, false);
|
|
815
814
|
const target = this.getNodeById(targetId, false) as MContainer;
|
|
816
815
|
|
|
@@ -819,7 +818,7 @@ class Editor extends BaseService {
|
|
|
819
818
|
const index = getNodeIndex(node.id, parent);
|
|
820
819
|
parent.items?.splice(index, 1);
|
|
821
820
|
|
|
822
|
-
await stage.remove({ id: node.id, parentId: parent.id, root });
|
|
821
|
+
await stage.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
|
|
823
822
|
|
|
824
823
|
const layout = await this.getLayout(target);
|
|
825
824
|
|
|
@@ -835,7 +834,7 @@ class Editor extends BaseService {
|
|
|
835
834
|
await stage.select(targetId);
|
|
836
835
|
|
|
837
836
|
const targetParent = this.getParentById(target.id);
|
|
838
|
-
await stage.update({ config: cloneDeep(target), parentId: targetParent?.id, root });
|
|
837
|
+
await stage.update({ config: cloneDeep(target), parentId: targetParent?.id, root: cloneDeep(root) });
|
|
839
838
|
|
|
840
839
|
await this.select(newConfig);
|
|
841
840
|
stage.select(newConfig.id);
|
|
@@ -893,6 +892,8 @@ class Editor extends BaseService {
|
|
|
893
892
|
this.addModifiedNodeId(parent.id);
|
|
894
893
|
|
|
895
894
|
this.pushHistoryState();
|
|
895
|
+
|
|
896
|
+
this.emit('drag-to', { index, targetIndex, config, parent, targetParent });
|
|
896
897
|
}
|
|
897
898
|
|
|
898
899
|
/**
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { reactive } from 'vue';
|
|
2
|
+
|
|
3
|
+
import StageCore from '@tmagic/stage';
|
|
4
|
+
|
|
5
|
+
import { useStage } from '@editor/hooks/use-stage';
|
|
6
|
+
import BaseService from '@editor/services//BaseService';
|
|
7
|
+
import editorService from '@editor/services//editor';
|
|
8
|
+
import type { StageOptions, StageOverlayState } from '@editor/type';
|
|
9
|
+
|
|
10
|
+
class StageOverlay extends BaseService {
|
|
11
|
+
private state: StageOverlayState = reactive({
|
|
12
|
+
wrapDiv: document.createElement('div'),
|
|
13
|
+
sourceEl: null,
|
|
14
|
+
contentEl: null,
|
|
15
|
+
stage: null,
|
|
16
|
+
stageOptions: null,
|
|
17
|
+
wrapWidth: 0,
|
|
18
|
+
wrapHeight: 0,
|
|
19
|
+
stageOverlayVisible: false,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
super([
|
|
24
|
+
{ name: 'openOverlay', isAsync: false },
|
|
25
|
+
{ name: 'closeOverlay', isAsync: false },
|
|
26
|
+
{ name: 'updateOverlay', isAsync: false },
|
|
27
|
+
{ name: 'createStage', isAsync: false },
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
this.get('wrapDiv').classList.add('tmagic-editor-sub-stage-wrap');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public get<K extends keyof StageOverlayState>(name: K): StageOverlayState[K] {
|
|
34
|
+
return this.state[name];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public set<K extends keyof StageOverlayState, T extends StageOverlayState[K]>(name: K, value: T) {
|
|
38
|
+
this.state[name] = value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public openOverlay(el: HTMLElement | undefined | null) {
|
|
42
|
+
const stageOptions = this.get('stageOptions');
|
|
43
|
+
if (!el || !stageOptions) return;
|
|
44
|
+
|
|
45
|
+
this.set('sourceEl', el);
|
|
46
|
+
|
|
47
|
+
this.createContentEl();
|
|
48
|
+
|
|
49
|
+
this.set('stageOverlayVisible', true);
|
|
50
|
+
|
|
51
|
+
editorService.on('update', this.updateHandler);
|
|
52
|
+
editorService.on('add', this.addHandler);
|
|
53
|
+
editorService.on('remove', this.removeHandler);
|
|
54
|
+
editorService.on('drag-to', this.updateHandler);
|
|
55
|
+
editorService.on('move-layer', this.updateHandler);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public closeOverlay() {
|
|
59
|
+
this.set('stageOverlayVisible', false);
|
|
60
|
+
const subStage = this.get('stage');
|
|
61
|
+
const wrapDiv = this.get('wrapDiv');
|
|
62
|
+
subStage?.destroy();
|
|
63
|
+
wrapDiv.remove();
|
|
64
|
+
|
|
65
|
+
this.set('stage', null);
|
|
66
|
+
this.set('sourceEl', null);
|
|
67
|
+
this.set('contentEl', null);
|
|
68
|
+
|
|
69
|
+
editorService.off('update', this.updateHandler);
|
|
70
|
+
editorService.off('add', this.addHandler);
|
|
71
|
+
editorService.off('remove', this.removeHandler);
|
|
72
|
+
editorService.off('drag-to', this.updateHandler);
|
|
73
|
+
editorService.off('move-layer', this.updateHandler);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public updateOverlay() {
|
|
77
|
+
const sourceEl = this.get('sourceEl');
|
|
78
|
+
|
|
79
|
+
if (!sourceEl) return;
|
|
80
|
+
|
|
81
|
+
const { scrollWidth, scrollHeight } = sourceEl;
|
|
82
|
+
|
|
83
|
+
this.set('wrapWidth', scrollWidth);
|
|
84
|
+
this.set('wrapHeight', scrollHeight);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public createStage(stageOptions: StageOptions = {}) {
|
|
88
|
+
return useStage({
|
|
89
|
+
...stageOptions,
|
|
90
|
+
runtimeUrl: '',
|
|
91
|
+
autoScrollIntoView: false,
|
|
92
|
+
render: async (stage: StageCore) => {
|
|
93
|
+
this.copyDocumentElement();
|
|
94
|
+
|
|
95
|
+
const rootEls = stage.renderer.getDocument()?.body.children;
|
|
96
|
+
if (rootEls) {
|
|
97
|
+
Array.from(rootEls).forEach((element) => {
|
|
98
|
+
if (['SCRIPT', 'STYLE'].includes(element.tagName)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
element.remove();
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const wrapDiv = this.get('wrapDiv');
|
|
106
|
+
|
|
107
|
+
await this.render();
|
|
108
|
+
|
|
109
|
+
return wrapDiv;
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private createContentEl() {
|
|
115
|
+
const sourceEl = this.get('sourceEl');
|
|
116
|
+
if (!sourceEl) return;
|
|
117
|
+
|
|
118
|
+
const contentEl = sourceEl.cloneNode(true) as HTMLElement;
|
|
119
|
+
this.set('contentEl', contentEl);
|
|
120
|
+
|
|
121
|
+
contentEl.style.position = 'static';
|
|
122
|
+
contentEl.style.overflow = 'visible';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private copyDocumentElement() {
|
|
126
|
+
const subStage = this.get('stage');
|
|
127
|
+
const stage = editorService.get('stage');
|
|
128
|
+
|
|
129
|
+
const doc = subStage?.renderer.getDocument();
|
|
130
|
+
const documentElement = stage?.renderer.getDocument()?.documentElement;
|
|
131
|
+
|
|
132
|
+
if (doc && documentElement) {
|
|
133
|
+
doc.replaceChild(documentElement.cloneNode(true), doc.documentElement);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private async render() {
|
|
138
|
+
this.createContentEl();
|
|
139
|
+
|
|
140
|
+
const contentEl = this.get('contentEl');
|
|
141
|
+
const sourceEl = this.get('sourceEl');
|
|
142
|
+
const wrapDiv = this.get('wrapDiv');
|
|
143
|
+
const subStage = this.get('stage');
|
|
144
|
+
const stageOptions = this.get('stageOptions');
|
|
145
|
+
|
|
146
|
+
if (!contentEl) return;
|
|
147
|
+
|
|
148
|
+
wrapDiv.style.cssText = `
|
|
149
|
+
width: ${sourceEl?.scrollWidth}px;
|
|
150
|
+
height: ${sourceEl?.scrollHeight}px;
|
|
151
|
+
background-color: #fff;
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
Array.from(wrapDiv.children).forEach((element) => {
|
|
155
|
+
element.remove();
|
|
156
|
+
});
|
|
157
|
+
wrapDiv.appendChild(contentEl);
|
|
158
|
+
|
|
159
|
+
setTimeout(() => {
|
|
160
|
+
subStage?.renderer.contentWindow?.magic.onPageElUpdate(wrapDiv);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (await stageOptions?.canSelect?.(contentEl)) {
|
|
164
|
+
subStage?.select(contentEl);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private updateHandler = () => {
|
|
169
|
+
setTimeout(() => {
|
|
170
|
+
this.render();
|
|
171
|
+
this.updateOverlay();
|
|
172
|
+
|
|
173
|
+
this.updateSelectStatus();
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
private addHandler = () => {
|
|
178
|
+
this.render();
|
|
179
|
+
this.updateOverlay();
|
|
180
|
+
|
|
181
|
+
this.updateSelectStatus();
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
private removeHandler = () => {
|
|
185
|
+
this.render();
|
|
186
|
+
this.updateOverlay();
|
|
187
|
+
|
|
188
|
+
this.updateSelectStatus();
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
private updateSelectStatus() {
|
|
192
|
+
const subStage = this.get('stage');
|
|
193
|
+
const nodes = editorService.get('nodes');
|
|
194
|
+
if (nodes.length > 1) {
|
|
195
|
+
subStage?.multiSelect(nodes.map((n) => n.id));
|
|
196
|
+
} else {
|
|
197
|
+
subStage?.select(nodes[0].id);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type StageOverlayService = StageOverlay;
|
|
203
|
+
|
|
204
|
+
export default new StageOverlay();
|