@tmagic/editor 1.0.0-beta.8 → 1.0.0-rc.2
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/README.md +1 -0
- package/coverage/clover.xml +1556 -0
- package/coverage/coverage-final.json +36 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +206 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov-report/src/Editor.vue.html +802 -0
- package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
- package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
- package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
- package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
- package/coverage/lcov-report/src/components/index.html +161 -0
- package/coverage/lcov-report/src/index.html +131 -0
- package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
- package/coverage/lcov-report/src/layouts/Framework.vue.html +343 -0
- package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
- package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +319 -0
- package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
- package/coverage/lcov-report/src/layouts/index.html +176 -0
- package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
- package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
- package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
- package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +226 -0
- package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +289 -0
- package/coverage/lcov-report/src/layouts/sidebar/index.html +176 -0
- package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
- package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +760 -0
- package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
- package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +598 -0
- package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
- package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
- package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
- package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
- package/coverage/lcov-report/src/services/events.ts.html +331 -0
- package/coverage/lcov-report/src/services/history.ts.html +478 -0
- package/coverage/lcov-report/src/services/index.html +206 -0
- package/coverage/lcov-report/src/services/props.ts.html +415 -0
- package/coverage/lcov-report/src/services/ui.ts.html +580 -0
- package/coverage/lcov-report/src/type.ts.html +850 -0
- package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
- package/coverage/lcov-report/src/utils/config.ts.html +172 -0
- package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
- package/coverage/lcov-report/src/utils/index.html +221 -0
- package/coverage/lcov-report/src/utils/index.ts.html +151 -0
- package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
- package/coverage/lcov-report/src/utils/props.ts.html +796 -0
- package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
- package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
- package/coverage/lcov.info +3747 -0
- package/dist/style.css +91 -45
- package/dist/tmagic-editor.es.js +1462 -2003
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +1461 -2003
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +10 -1
- package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
- package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
- package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
- package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
- package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +10 -3
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -6
- package/dist/types/src/services/BaseService.d.ts +4 -1
- package/dist/types/src/services/editor.d.ts +16 -6
- package/dist/types/src/services/history.d.ts +1 -0
- package/dist/types/src/services/props.d.ts +2 -2
- package/dist/types/src/services/ui.d.ts +2 -0
- package/dist/types/src/type.d.ts +16 -9
- package/dist/types/src/utils/editor.d.ts +5 -4
- package/dist/types/src/utils/polyfills.d.ts +0 -0
- package/package.json +44 -12
- package/src/Editor.vue +6 -1
- package/src/components/ContentMenu.vue +107 -0
- package/src/components/ScrollViewer.vue +1 -1
- package/src/components/ToolButton.vue +72 -31
- package/src/fields/UISelect.vue +14 -6
- package/src/index.ts +2 -0
- package/src/layouts/AddPageBox.vue +3 -1
- package/src/layouts/CodeEditor.vue +20 -13
- package/src/layouts/Framework.vue +20 -7
- package/src/layouts/PropsPanel.vue +5 -4
- package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
- package/src/layouts/sidebar/LayerMenu.vue +91 -96
- package/src/layouts/sidebar/LayerPanel.vue +80 -59
- package/src/layouts/sidebar/Sidebar.vue +13 -52
- package/src/layouts/sidebar/TabPane.vue +68 -0
- package/src/layouts/workspace/PageBar.vue +145 -17
- package/src/layouts/workspace/Stage.vue +56 -64
- package/src/layouts/workspace/ViewerMenu.vue +107 -68
- package/src/layouts/workspace/Workspace.vue +110 -18
- package/src/services/BaseService.ts +70 -22
- package/src/services/editor.ts +197 -64
- package/src/services/history.ts +7 -0
- package/src/services/props.ts +3 -3
- package/src/services/ui.ts +35 -5
- package/src/theme/common/var.scss +3 -2
- package/src/theme/component-list-panel.scss +2 -0
- package/src/theme/content-menu.scss +33 -26
- package/src/theme/layer-panel.scss +10 -0
- package/src/theme/nav-menu.scss +6 -2
- package/src/theme/page-bar.scss +42 -2
- package/src/theme/props-panel.scss +19 -17
- package/src/type.ts +17 -9
- package/src/utils/editor.ts +35 -9
- package/src/utils/polyfills.ts +8 -0
- package/src/utils/props.ts +20 -1
- package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
- package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -973
- package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -192
- package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
- package/tsconfig.json +0 -9
- package/vite.config.ts +0 -30
package/src/services/editor.ts
CHANGED
|
@@ -21,8 +21,9 @@ import { cloneDeep, mergeWith } from 'lodash-es';
|
|
|
21
21
|
import serialize from 'serialize-javascript';
|
|
22
22
|
|
|
23
23
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
24
|
-
import
|
|
25
|
-
import
|
|
24
|
+
import { NodeType } from '@tmagic/schema';
|
|
25
|
+
import StageCore from '@tmagic/stage';
|
|
26
|
+
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
26
27
|
|
|
27
28
|
import historyService, { StepValue } from '@editor/services/history';
|
|
28
29
|
import propsService from '@editor/services/props';
|
|
@@ -51,29 +52,37 @@ class Editor extends BaseService {
|
|
|
51
52
|
parent: null,
|
|
52
53
|
node: null,
|
|
53
54
|
stage: null,
|
|
55
|
+
highlightNode: null,
|
|
54
56
|
modifiedNodeIds: new Map(),
|
|
57
|
+
pageLength: 0,
|
|
55
58
|
});
|
|
56
59
|
|
|
57
60
|
constructor() {
|
|
58
|
-
super(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
61
|
+
super(
|
|
62
|
+
[
|
|
63
|
+
'getLayout',
|
|
64
|
+
'select',
|
|
65
|
+
'add',
|
|
66
|
+
'remove',
|
|
67
|
+
'update',
|
|
68
|
+
'sort',
|
|
69
|
+
'copy',
|
|
70
|
+
'paste',
|
|
71
|
+
'alignCenter',
|
|
72
|
+
'moveLayer',
|
|
73
|
+
'move',
|
|
74
|
+
'undo',
|
|
75
|
+
'redo',
|
|
76
|
+
'highlight',
|
|
77
|
+
],
|
|
78
|
+
// 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
|
|
79
|
+
['select', 'update', 'moveLayer'],
|
|
80
|
+
);
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
/**
|
|
75
84
|
* 设置当前指点节点配置
|
|
76
|
-
* @param name 'root' | 'page' | 'parent' | 'node'
|
|
85
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode'
|
|
77
86
|
* @param value MNode
|
|
78
87
|
* @returns MNode
|
|
79
88
|
*/
|
|
@@ -82,6 +91,7 @@ class Editor extends BaseService {
|
|
|
82
91
|
log('store set ', name, ' ', value);
|
|
83
92
|
|
|
84
93
|
if (name === 'root') {
|
|
94
|
+
this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
|
|
85
95
|
this.emit('root-change', value);
|
|
86
96
|
}
|
|
87
97
|
}
|
|
@@ -101,7 +111,7 @@ class Editor extends BaseService {
|
|
|
101
111
|
* @returns {EditorNodeInfo}
|
|
102
112
|
*/
|
|
103
113
|
public getNodeInfo(id: Id): EditorNodeInfo {
|
|
104
|
-
const root = this.get<MApp | null>('root');
|
|
114
|
+
const root = toRaw(this.get<MApp | null>('root'));
|
|
105
115
|
if (!root) return {};
|
|
106
116
|
|
|
107
117
|
if (id === root.id) {
|
|
@@ -119,7 +129,7 @@ class Editor extends BaseService {
|
|
|
119
129
|
info.parent = path[path.length - 2] as MContainer;
|
|
120
130
|
|
|
121
131
|
path.forEach((item) => {
|
|
122
|
-
if (item.type ===
|
|
132
|
+
if (item.type === NodeType.PAGE) {
|
|
123
133
|
info.page = item as MPage;
|
|
124
134
|
return;
|
|
125
135
|
}
|
|
@@ -152,13 +162,15 @@ class Editor extends BaseService {
|
|
|
152
162
|
/**
|
|
153
163
|
* 只有容器拥有布局
|
|
154
164
|
*/
|
|
155
|
-
public async getLayout(
|
|
156
|
-
if (node
|
|
157
|
-
|
|
165
|
+
public async getLayout(parent: MNode, node?: MNode): Promise<Layout> {
|
|
166
|
+
if (node && typeof node !== 'function' && isFixed(node)) return Layout.FIXED;
|
|
167
|
+
|
|
168
|
+
if (parent.layout) {
|
|
169
|
+
return parent.layout;
|
|
158
170
|
}
|
|
159
171
|
|
|
160
172
|
// 如果该节点没有设置position,则认为是流式布局,例如获取root的布局时
|
|
161
|
-
if (!
|
|
173
|
+
if (!parent.style?.position) {
|
|
162
174
|
return Layout.RELATIVE;
|
|
163
175
|
}
|
|
164
176
|
|
|
@@ -166,28 +178,12 @@ class Editor extends BaseService {
|
|
|
166
178
|
}
|
|
167
179
|
|
|
168
180
|
/**
|
|
169
|
-
*
|
|
170
|
-
* @param config
|
|
181
|
+
* 选中指定节点(将指定节点设置成当前选中状态)
|
|
182
|
+
* @param config 指定节点配置或者ID
|
|
171
183
|
* @returns 当前选中的节点配置
|
|
172
184
|
*/
|
|
173
|
-
public async select(config: MNode | Id): Promise<MNode> {
|
|
174
|
-
|
|
175
|
-
if (typeof config === 'string' || typeof config === 'number') {
|
|
176
|
-
id = config;
|
|
177
|
-
} else {
|
|
178
|
-
id = config.id;
|
|
179
|
-
}
|
|
180
|
-
if (!id) {
|
|
181
|
-
throw new Error('没有ID,无法选中');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const { node, parent, page } = this.getNodeInfo(id);
|
|
185
|
-
if (!node) throw new Error('获取不到组件信息');
|
|
186
|
-
|
|
187
|
-
if (node.id === this.state.root?.id) {
|
|
188
|
-
throw new Error('不能选根节点');
|
|
189
|
-
}
|
|
190
|
-
|
|
185
|
+
public async select(config: MNode | Id): Promise<MNode> | never {
|
|
186
|
+
const { node, page, parent } = this.selectedConfigExceptionHandler(config);
|
|
191
187
|
this.set('node', node);
|
|
192
188
|
this.set('page', page || null);
|
|
193
189
|
this.set('parent', parent || null);
|
|
@@ -198,7 +194,54 @@ class Editor extends BaseService {
|
|
|
198
194
|
historyService.empty();
|
|
199
195
|
}
|
|
200
196
|
|
|
201
|
-
|
|
197
|
+
this.emit('select', node);
|
|
198
|
+
|
|
199
|
+
return node!;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public async selectNextNode(): Promise<MNode> | never {
|
|
203
|
+
const node = toRaw(this.get('node'));
|
|
204
|
+
|
|
205
|
+
if (!node || isPage(node) || node.type === NodeType.ROOT) return node;
|
|
206
|
+
|
|
207
|
+
const parent = toRaw(this.getParentById(node.id));
|
|
208
|
+
|
|
209
|
+
if (!parent) return node;
|
|
210
|
+
|
|
211
|
+
const index = getNodeIndex(node, parent);
|
|
212
|
+
|
|
213
|
+
const nextNode = parent.items[index + 1] || parent.items[0];
|
|
214
|
+
|
|
215
|
+
await this.select(nextNode);
|
|
216
|
+
this.get<StageCore>('stage')?.select(nextNode.id);
|
|
217
|
+
|
|
218
|
+
return nextNode;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public async selectNextPage(): Promise<MNode> | never {
|
|
222
|
+
const root = toRaw(this.get<MApp>('root'));
|
|
223
|
+
const page = toRaw(this.get('page'));
|
|
224
|
+
|
|
225
|
+
const index = getNodeIndex(page, root);
|
|
226
|
+
|
|
227
|
+
const nextPage = root.items[index + 1] || root.items[0];
|
|
228
|
+
|
|
229
|
+
await this.select(nextPage);
|
|
230
|
+
this.get<StageCore>('stage')?.select(nextPage.id);
|
|
231
|
+
|
|
232
|
+
return nextPage;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 高亮指定节点
|
|
237
|
+
* @param config 指定节点配置或者ID
|
|
238
|
+
* @returns 当前高亮的节点配置
|
|
239
|
+
*/
|
|
240
|
+
public highlight(config: MNode | Id): void {
|
|
241
|
+
const { node } = this.selectedConfigExceptionHandler(config);
|
|
242
|
+
const currentHighlightNode = this.get('highlightNode');
|
|
243
|
+
if (currentHighlightNode === node) return;
|
|
244
|
+
this.set('highlightNode', node);
|
|
202
245
|
}
|
|
203
246
|
|
|
204
247
|
/**
|
|
@@ -207,12 +250,14 @@ class Editor extends BaseService {
|
|
|
207
250
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
208
251
|
* @returns 添加后的节点
|
|
209
252
|
*/
|
|
210
|
-
public async add(
|
|
253
|
+
public async add(addNode: AddMNode, parent?: MContainer | null): Promise<MNode> {
|
|
254
|
+
const { type, ...config } = addNode;
|
|
211
255
|
const curNode = this.get<MContainer>('node');
|
|
212
256
|
|
|
213
257
|
let parentNode: MNode | undefined;
|
|
258
|
+
const isPage = type === NodeType.PAGE;
|
|
214
259
|
|
|
215
|
-
if (
|
|
260
|
+
if (isPage) {
|
|
216
261
|
parentNode = this.get<MApp>('root');
|
|
217
262
|
// 由于支持中间件扩展,在parent参数为undefined时,parent会变成next函数
|
|
218
263
|
} else if (parent && typeof parent !== 'function') {
|
|
@@ -225,21 +270,38 @@ class Editor extends BaseService {
|
|
|
225
270
|
|
|
226
271
|
if (!parentNode) throw new Error('未找到父元素');
|
|
227
272
|
|
|
228
|
-
const layout = await this.getLayout(parentNode);
|
|
229
|
-
const newNode = initPosition(
|
|
273
|
+
const layout = await this.getLayout(toRaw(parentNode), addNode as MNode);
|
|
274
|
+
const newNode = initPosition(
|
|
275
|
+
{ ...toRaw(await propsService.getPropsValue(type, config)) },
|
|
276
|
+
layout,
|
|
277
|
+
parentNode,
|
|
278
|
+
this.get<StageCore>('stage'),
|
|
279
|
+
);
|
|
230
280
|
|
|
231
|
-
if ((parentNode?.type ===
|
|
281
|
+
if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
|
|
232
282
|
throw new Error('app下不能添加组件');
|
|
233
283
|
}
|
|
234
284
|
|
|
235
285
|
parentNode?.items?.push(newNode);
|
|
236
286
|
|
|
237
|
-
|
|
287
|
+
const stage = this.get<StageCore | null>('stage');
|
|
288
|
+
|
|
289
|
+
await stage?.add({ config: cloneDeep(newNode), root: cloneDeep(this.get('root')) });
|
|
238
290
|
|
|
239
291
|
await this.select(newNode);
|
|
240
292
|
|
|
241
293
|
this.addModifiedNodeId(newNode.id);
|
|
242
|
-
|
|
294
|
+
if (!isPage) {
|
|
295
|
+
this.pushHistoryState();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
stage?.select(newNode.id);
|
|
299
|
+
|
|
300
|
+
if (isPage) {
|
|
301
|
+
this.state.pageLength += 1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
this.emit('add', newNode);
|
|
243
305
|
|
|
244
306
|
return newNode;
|
|
245
307
|
}
|
|
@@ -265,17 +327,38 @@ class Editor extends BaseService {
|
|
|
265
327
|
if (typeof index !== 'number' || index === -1) throw new Error('找不要删除的节点');
|
|
266
328
|
|
|
267
329
|
parent.items?.splice(index, 1);
|
|
268
|
-
this.get<StageCore>('stage')
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
330
|
+
const stage = this.get<StageCore | null>('stage');
|
|
331
|
+
stage?.remove({ id: node.id, root: this.get('root') });
|
|
332
|
+
|
|
333
|
+
if (node.type === NodeType.PAGE) {
|
|
334
|
+
this.state.pageLength -= 1;
|
|
335
|
+
|
|
336
|
+
if (root.items[0]) {
|
|
337
|
+
await this.select(root.items[0]);
|
|
338
|
+
stage?.select(root.items[0].id);
|
|
339
|
+
} else {
|
|
340
|
+
this.set('node', null);
|
|
341
|
+
this.set('parent', null);
|
|
342
|
+
this.set('page', null);
|
|
343
|
+
this.set('stage', null);
|
|
344
|
+
this.set('highlightNode', null);
|
|
345
|
+
this.resetModifiedNodeId();
|
|
346
|
+
historyService.reset();
|
|
347
|
+
|
|
348
|
+
this.emit('remove', node);
|
|
349
|
+
|
|
350
|
+
return node;
|
|
351
|
+
}
|
|
272
352
|
} else {
|
|
273
353
|
await this.select(parent);
|
|
354
|
+
stage?.select(parent.id);
|
|
274
355
|
}
|
|
275
356
|
|
|
276
357
|
this.addModifiedNodeId(parent.id);
|
|
277
358
|
this.pushHistoryState();
|
|
278
359
|
|
|
360
|
+
this.emit('remove', node);
|
|
361
|
+
|
|
279
362
|
return node;
|
|
280
363
|
}
|
|
281
364
|
|
|
@@ -303,7 +386,7 @@ class Editor extends BaseService {
|
|
|
303
386
|
|
|
304
387
|
if (!newConfig.type) throw new Error('配置缺少type值');
|
|
305
388
|
|
|
306
|
-
if (newConfig.type ===
|
|
389
|
+
if (newConfig.type === NodeType.ROOT) {
|
|
307
390
|
this.set('root', newConfig);
|
|
308
391
|
return newConfig;
|
|
309
392
|
}
|
|
@@ -324,19 +407,21 @@ class Editor extends BaseService {
|
|
|
324
407
|
|
|
325
408
|
parentNodeItems[index] = newConfig;
|
|
326
409
|
|
|
327
|
-
if (newConfig.id === this.get('node').id) {
|
|
410
|
+
if (`${newConfig.id}` === `${this.get('node').id}`) {
|
|
328
411
|
this.set('node', newConfig);
|
|
329
412
|
}
|
|
330
413
|
|
|
331
|
-
this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
|
|
414
|
+
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
|
|
332
415
|
|
|
333
|
-
if (newConfig.type ===
|
|
416
|
+
if (newConfig.type === NodeType.PAGE) {
|
|
334
417
|
this.set('page', newConfig);
|
|
335
418
|
}
|
|
336
419
|
|
|
337
420
|
this.addModifiedNodeId(newConfig.id);
|
|
338
421
|
this.pushHistoryState();
|
|
339
422
|
|
|
423
|
+
this.emit('update', newConfig);
|
|
424
|
+
|
|
340
425
|
return newConfig;
|
|
341
426
|
}
|
|
342
427
|
|
|
@@ -359,7 +444,7 @@ class Editor extends BaseService {
|
|
|
359
444
|
await this.update(parent);
|
|
360
445
|
await this.select(node);
|
|
361
446
|
|
|
362
|
-
this.get<StageCore>('stage')?.update({ config: cloneDeep(node), root: this.get('root') });
|
|
447
|
+
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(node), root: this.get('root') });
|
|
363
448
|
|
|
364
449
|
this.addModifiedNodeId(parent.id);
|
|
365
450
|
this.pushHistoryState();
|
|
@@ -414,7 +499,7 @@ class Editor extends BaseService {
|
|
|
414
499
|
public async alignCenter(config: MNode): Promise<MNode | void> {
|
|
415
500
|
const parent = this.get<MContainer>('parent');
|
|
416
501
|
const node = this.get<MNode>('node');
|
|
417
|
-
const layout = await this.getLayout(parent);
|
|
502
|
+
const layout = await this.getLayout(toRaw(parent), toRaw(node));
|
|
418
503
|
if (layout === Layout.RELATIVE) {
|
|
419
504
|
return;
|
|
420
505
|
}
|
|
@@ -424,7 +509,7 @@ class Editor extends BaseService {
|
|
|
424
509
|
}
|
|
425
510
|
|
|
426
511
|
await this.update(node);
|
|
427
|
-
this.get<StageCore>('stage')?.update({ config: cloneDeep(toRaw(node)), root: this.get('root') });
|
|
512
|
+
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(toRaw(node)), root: this.get('root') });
|
|
428
513
|
this.addModifiedNodeId(config.id);
|
|
429
514
|
this.pushHistoryState();
|
|
430
515
|
|
|
@@ -449,7 +534,7 @@ class Editor extends BaseService {
|
|
|
449
534
|
brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
|
|
450
535
|
}
|
|
451
536
|
|
|
452
|
-
this.get<StageCore>('stage')?.update({ config: cloneDeep(toRaw(parent)), root: this.get('root') });
|
|
537
|
+
this.get<StageCore | null>('stage')?.update({ config: cloneDeep(toRaw(parent)), root: this.get('root') });
|
|
453
538
|
}
|
|
454
539
|
|
|
455
540
|
/**
|
|
@@ -472,6 +557,26 @@ class Editor extends BaseService {
|
|
|
472
557
|
return value;
|
|
473
558
|
}
|
|
474
559
|
|
|
560
|
+
public async move(left: number, top: number) {
|
|
561
|
+
const node = toRaw(this.get('node'));
|
|
562
|
+
if (!node || isPage(node)) return;
|
|
563
|
+
|
|
564
|
+
const { style, id } = node;
|
|
565
|
+
if (!style || style.position !== 'absolute') return;
|
|
566
|
+
|
|
567
|
+
if (top && !isNumber(style.top)) return;
|
|
568
|
+
if (left && !isNumber(style.left)) return;
|
|
569
|
+
|
|
570
|
+
this.update({
|
|
571
|
+
id,
|
|
572
|
+
style: {
|
|
573
|
+
...style,
|
|
574
|
+
left: Number(style.left) + left,
|
|
575
|
+
top: Number(style.top) + top,
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
475
580
|
public destroy() {
|
|
476
581
|
this.removeAllListeners();
|
|
477
582
|
this.set('root', null);
|
|
@@ -508,7 +613,11 @@ class Editor extends BaseService {
|
|
|
508
613
|
this.isHistoryStateChange = true;
|
|
509
614
|
await this.update(value.data);
|
|
510
615
|
this.set('modifiedNodeIds', value.modifiedNodeIds);
|
|
511
|
-
setTimeout(() =>
|
|
616
|
+
setTimeout(async () => {
|
|
617
|
+
if (!value.nodeId) return;
|
|
618
|
+
await this.select(value.nodeId);
|
|
619
|
+
this.get<StageCore | null>('stage')?.select(value.nodeId);
|
|
620
|
+
}, 0);
|
|
512
621
|
}
|
|
513
622
|
|
|
514
623
|
private async toggleFixedPosition(dist: MNode, src: MNode, root: MApp) {
|
|
@@ -524,6 +633,30 @@ class Editor extends BaseService {
|
|
|
524
633
|
|
|
525
634
|
return newConfig;
|
|
526
635
|
}
|
|
636
|
+
|
|
637
|
+
private selectedConfigExceptionHandler(config: MNode | Id): EditorNodeInfo {
|
|
638
|
+
let id: Id;
|
|
639
|
+
if (typeof config === 'string' || typeof config === 'number') {
|
|
640
|
+
id = config;
|
|
641
|
+
} else {
|
|
642
|
+
id = config.id;
|
|
643
|
+
}
|
|
644
|
+
if (!id) {
|
|
645
|
+
throw new Error('没有ID,无法选中');
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const { node, parent, page } = this.getNodeInfo(id);
|
|
649
|
+
if (!node) throw new Error('获取不到组件信息');
|
|
650
|
+
|
|
651
|
+
if (node.id === this.state.root?.id) {
|
|
652
|
+
throw new Error('不能选根节点');
|
|
653
|
+
}
|
|
654
|
+
return {
|
|
655
|
+
node,
|
|
656
|
+
parent,
|
|
657
|
+
page,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
527
660
|
}
|
|
528
661
|
|
|
529
662
|
export type EditorService = Editor;
|
package/src/services/history.ts
CHANGED
|
@@ -51,6 +51,13 @@ class History extends BaseService {
|
|
|
51
51
|
this.on('change', this.setCanUndoRedo);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
public reset() {
|
|
55
|
+
this.state.pageSteps = {};
|
|
56
|
+
this.state.pageId = undefined;
|
|
57
|
+
this.state.canRedo = false;
|
|
58
|
+
this.state.canUndo = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
54
61
|
public changePage(page: MPage): void {
|
|
55
62
|
if (!page) return;
|
|
56
63
|
|
package/src/services/props.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive } from 'vue';
|
|
20
|
-
import { cloneDeep } from 'lodash-es';
|
|
20
|
+
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
21
21
|
|
|
22
22
|
import type { FormConfig } from '@tmagic/form';
|
|
23
23
|
import type { MComponent, MNode } from '@tmagic/schema';
|
|
@@ -87,7 +87,7 @@ class Props extends BaseService {
|
|
|
87
87
|
* @param type 组件类型
|
|
88
88
|
* @returns 组件初始值
|
|
89
89
|
*/
|
|
90
|
-
public async getPropsValue(type: string) {
|
|
90
|
+
public async getPropsValue(type: string, defaultValue = {}) {
|
|
91
91
|
if (type === 'area') {
|
|
92
92
|
const value = (await this.getPropsValue('button')) as MComponent;
|
|
93
93
|
value.className = 'action-area';
|
|
@@ -100,7 +100,7 @@ class Props extends BaseService {
|
|
|
100
100
|
|
|
101
101
|
return cloneDeep({
|
|
102
102
|
...getDefaultPropsValue(type),
|
|
103
|
-
...(this.state.propsValueMap[type] || {}),
|
|
103
|
+
...mergeWith(this.state.propsValueMap[type] || {}, defaultValue),
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
106
|
}
|
package/src/services/ui.ts
CHANGED
|
@@ -25,6 +25,17 @@ import type { GetColumnWidth, SetColumnWidth, StageRect, UiState } from '@editor
|
|
|
25
25
|
|
|
26
26
|
import BaseService from './BaseService';
|
|
27
27
|
|
|
28
|
+
const DEFAULT_LEFT_COLUMN_WIDTH = 310;
|
|
29
|
+
const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
|
|
30
|
+
|
|
31
|
+
const COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorColumnWidthData';
|
|
32
|
+
|
|
33
|
+
const defaultColumnWidth = {
|
|
34
|
+
left: DEFAULT_LEFT_COLUMN_WIDTH,
|
|
35
|
+
center: globalThis.document.body.clientWidth - DEFAULT_LEFT_COLUMN_WIDTH - DEFAULT_RIGHT_COLUMN_WIDTH,
|
|
36
|
+
right: DEFAULT_RIGHT_COLUMN_WIDTH,
|
|
37
|
+
};
|
|
38
|
+
|
|
28
39
|
const state = reactive<UiState>({
|
|
29
40
|
uiSelectMode: false,
|
|
30
41
|
showSrc: false,
|
|
@@ -37,13 +48,10 @@ const state = reactive<UiState>({
|
|
|
37
48
|
width: 375,
|
|
38
49
|
height: 817,
|
|
39
50
|
},
|
|
40
|
-
columnWidth:
|
|
41
|
-
left: 310,
|
|
42
|
-
center: globalThis.document.body.clientWidth - 310 - 400,
|
|
43
|
-
right: 400,
|
|
44
|
-
},
|
|
51
|
+
columnWidth: defaultColumnWidth,
|
|
45
52
|
showGuides: true,
|
|
46
53
|
showRule: true,
|
|
54
|
+
propsPanelSize: 'small',
|
|
47
55
|
});
|
|
48
56
|
|
|
49
57
|
class Ui extends BaseService {
|
|
@@ -54,6 +62,16 @@ class Ui extends BaseService {
|
|
|
54
62
|
center: 'auto',
|
|
55
63
|
});
|
|
56
64
|
});
|
|
65
|
+
|
|
66
|
+
const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
|
|
67
|
+
if (columnWidthCacheData) {
|
|
68
|
+
try {
|
|
69
|
+
const columnWidthCache = JSON.parse(columnWidthCacheData);
|
|
70
|
+
this.setColumnWidth(columnWidthCache);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
console.error(e);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
public set<T = any>(name: keyof UiState, value: T) {
|
|
@@ -88,6 +106,11 @@ class Ui extends BaseService {
|
|
|
88
106
|
return (state as any)[name];
|
|
89
107
|
}
|
|
90
108
|
|
|
109
|
+
public zoom(zoom: number) {
|
|
110
|
+
this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
|
|
111
|
+
if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
|
|
112
|
+
}
|
|
113
|
+
|
|
91
114
|
private setColumnWidth({ left, center, right }: SetColumnWidth) {
|
|
92
115
|
const columnWidth = {
|
|
93
116
|
...toRaw(this.get<GetColumnWidth>('columnWidth')),
|
|
@@ -104,10 +127,17 @@ class Ui extends BaseService {
|
|
|
104
127
|
if (!center || center === 'auto') {
|
|
105
128
|
const bodyWidth = globalThis.document.body.clientWidth;
|
|
106
129
|
columnWidth.center = bodyWidth - (columnWidth?.left || 0) - (columnWidth?.right || 0);
|
|
130
|
+
if (columnWidth.center <= 0) {
|
|
131
|
+
columnWidth.left = defaultColumnWidth.left;
|
|
132
|
+
columnWidth.center = defaultColumnWidth.center;
|
|
133
|
+
columnWidth.right = defaultColumnWidth.right;
|
|
134
|
+
}
|
|
107
135
|
} else {
|
|
108
136
|
columnWidth.center = center;
|
|
109
137
|
}
|
|
110
138
|
|
|
139
|
+
globalThis.localStorage.setItem(COLUMN_WIDTH_STORAGE_KEY, JSON.stringify(columnWidth));
|
|
140
|
+
|
|
111
141
|
state.columnWidth = columnWidth;
|
|
112
142
|
}
|
|
113
143
|
|
|
@@ -2,12 +2,13 @@ $--theme-color: #2882e0;
|
|
|
2
2
|
|
|
3
3
|
$--font-color: #070303;
|
|
4
4
|
$--border-color: #d9dbdd;
|
|
5
|
+
$--hover-color: #f3f5f9;
|
|
5
6
|
|
|
6
7
|
$--nav-height: 35px;
|
|
7
8
|
$--nav-color: #070303;
|
|
8
|
-
$--nav--background-color: #
|
|
9
|
+
$--nav--background-color: #ffffff;
|
|
9
10
|
|
|
10
11
|
$--sidebar-heder-background-color: $--theme-color;
|
|
11
|
-
$--sidebar-content-background-color: #
|
|
12
|
+
$--sidebar-content-background-color: #ffffff;
|
|
12
13
|
|
|
13
14
|
$--page-bar-height: 32px;
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
top: 0;
|
|
13
13
|
left: 0;
|
|
14
14
|
box-sizing: border-box;
|
|
15
|
+
z-index: 1;
|
|
15
16
|
|
|
16
17
|
.el-input__prefix {
|
|
17
18
|
padding: 10px;
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
color: $--font-color;
|
|
63
64
|
flex-direction: column;
|
|
64
65
|
width: 42px;
|
|
66
|
+
cursor: pointer;
|
|
65
67
|
|
|
66
68
|
i {
|
|
67
69
|
font-size: 20px;
|
|
@@ -2,38 +2,45 @@
|
|
|
2
2
|
position: fixed;
|
|
3
3
|
font-size: 12px;
|
|
4
4
|
background: #fff;
|
|
5
|
-
color: #333;
|
|
6
5
|
box-shadow: 0 2px 8px 2px rgba(68, 73, 77, 0.16);
|
|
7
6
|
z-index: 9999;
|
|
8
7
|
transform-origin: 0% 0%;
|
|
9
8
|
font-weight: 600;
|
|
10
9
|
padding: 4px 0px;
|
|
10
|
+
overflow: auto;
|
|
11
|
+
max-height: 100%;
|
|
11
12
|
|
|
12
|
-
.
|
|
13
|
-
width: 100%;
|
|
14
|
-
height: 0;
|
|
15
|
-
border-color: rgba(155, 155, 155, 0.1);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.subMenu {
|
|
19
|
-
position: absolute;
|
|
20
|
-
right: 0;
|
|
21
|
-
transform: translate(100%, 0);
|
|
22
|
-
background-color: #fff;
|
|
13
|
+
.menu-item {
|
|
23
14
|
color: #333;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
display: flex;
|
|
16
|
+
-webkit-box-align: center;
|
|
17
|
+
align-items: center;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
min-width: 140px;
|
|
20
|
+
transition: all 0.2s ease 0s;
|
|
21
|
+
padding: 5px 14px;
|
|
22
|
+
border-left: 2px solid transparent;
|
|
23
|
+
|
|
24
|
+
.el-button {
|
|
25
|
+
width: 100%;
|
|
26
|
+
justify-content: flex-start;
|
|
27
|
+
}
|
|
29
28
|
|
|
30
|
-
.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
.el-button--text,
|
|
30
|
+
i {
|
|
31
|
+
color: $--font-color;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&.divider {
|
|
35
|
+
padding: 0 14px;
|
|
36
|
+
|
|
37
|
+
.el-divider {
|
|
38
|
+
margin: 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&:hover {
|
|
43
|
+
background-color: $--hover-color;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
39
46
|
}
|
|
@@ -50,6 +50,16 @@
|
|
|
50
50
|
color: #fff;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
.magic-editor-layer-panel .cus-tree-node {
|
|
54
|
+
width: 100%;
|
|
55
|
+
overflow: hidden;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.magic-editor-layer-panel .cus-tree-node-hover {
|
|
59
|
+
background-color: $--hover-color;
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
.magic-editor-layer-panel .el-tree-node:focus > .el-tree-node__content {
|
|
54
64
|
background-color: $--sidebar-heder-background-color;
|
|
55
65
|
color: #fff;
|