@tmagic/editor 1.0.6 → 1.1.0-beta.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 +5 -1
- package/dist/{tmagic-editor.es.js → tmagic-editor.mjs} +1522 -1177
- package/dist/tmagic-editor.mjs.map +1 -0
- package/dist/tmagic-editor.umd.js +1606 -1259
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/package.json +22 -20
- package/src/Editor.vue +41 -15
- package/src/components/ContentMenu.vue +87 -99
- package/src/components/Icon.vue +2 -2
- package/src/components/ScrollViewer.vue +2 -2
- package/src/components/ToolButton.vue +151 -168
- package/src/fields/UISelect.vue +49 -70
- package/src/index.ts +2 -1
- package/src/layouts/AddPageBox.vue +3 -3
- package/src/layouts/Framework.vue +1 -1
- package/src/layouts/NavMenu.vue +2 -2
- package/src/layouts/PropsPanel.vue +1 -1
- package/src/layouts/Resizer.vue +1 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +43 -2
- package/src/layouts/sidebar/LayerMenu.vue +3 -3
- package/src/layouts/sidebar/LayerPanel.vue +13 -4
- package/src/layouts/sidebar/Sidebar.vue +1 -1
- package/src/layouts/sidebar/TabPane.vue +3 -3
- package/src/layouts/workspace/PageBar.vue +63 -192
- package/src/layouts/workspace/PageBarScrollContainer.vue +111 -0
- package/src/layouts/workspace/Stage.vue +208 -188
- package/src/layouts/workspace/ViewerMenu.vue +141 -148
- package/src/layouts/workspace/Workspace.vue +11 -11
- package/src/services/BaseService.ts +5 -10
- package/src/services/componentList.ts +3 -3
- package/src/services/editor.ts +247 -140
- package/src/services/events.ts +1 -1
- package/src/services/history.ts +1 -1
- package/src/services/props.ts +63 -11
- package/src/services/storage.ts +133 -0
- package/src/services/ui.ts +10 -4
- package/src/theme/component-list-panel.scss +5 -0
- package/src/theme/framework.scss +1 -1
- package/src/theme/stage.scss +2 -2
- package/src/type.ts +28 -7
- package/src/utils/config.ts +1 -1
- package/src/utils/editor.ts +53 -35
- package/src/utils/operator.ts +109 -0
- package/src/utils/props.ts +2 -24
- package/src/utils/scroll-viewer.ts +1 -1
- package/tsconfig.build.json +13 -0
- package/{dist/types/src → types}/Editor.vue.d.ts +44 -9
- package/types/components/ContentMenu.vue.d.ts +116 -0
- package/types/components/Icon.vue.d.ts +13 -0
- package/types/components/ScrollViewer.vue.d.ts +22 -0
- package/types/components/ToolButton.vue.d.ts +109 -0
- package/types/fields/Code.vue.d.ts +23 -0
- package/{dist/types/src → types}/fields/CodeLink.vue.d.ts +4 -6
- package/types/fields/UISelect.vue.d.ts +83 -0
- package/{dist/types/src → types}/index.d.ts +4 -1
- package/types/layouts/AddPageBox.vue.d.ts +4 -0
- package/{dist/types/src → types}/layouts/CodeEditor.vue.d.ts +11 -13
- package/types/layouts/Framework.vue.d.ts +22 -0
- package/types/layouts/NavMenu.vue.d.ts +25 -0
- package/types/layouts/PropsPanel.vue.d.ts +245 -0
- package/types/layouts/Resizer.vue.d.ts +12 -0
- package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +14 -0
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +100 -0
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +1099 -0
- package/{dist/types/src → types}/layouts/sidebar/Sidebar.vue.d.ts +3 -5
- package/types/layouts/sidebar/TabPane.vue.d.ts +14 -0
- package/types/layouts/workspace/PageBar.vue.d.ts +54 -0
- package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +48 -0
- package/types/layouts/workspace/Stage.vue.d.ts +46 -0
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +88 -0
- package/types/layouts/workspace/Workspace.vue.d.ts +6 -0
- package/{dist/types/src → types}/services/BaseService.d.ts +0 -0
- package/types/services/componentList.d.ts +14 -0
- package/{dist/types/src → types}/services/editor.d.ts +27 -14
- package/{dist/types/src → types}/services/events.d.ts +0 -0
- package/{dist/types/src → types}/services/history.d.ts +0 -0
- package/{dist/types/src → types}/services/props.d.ts +26 -2
- package/types/services/storage.d.ts +56 -0
- package/{dist/types/src → types}/services/ui.d.ts +1 -1
- package/{dist/types/src → types}/type.d.ts +21 -1
- package/{dist/types/src → types}/utils/compose.d.ts +1 -1
- package/{dist/types/src → types}/utils/config.d.ts +0 -0
- package/{dist/types/src → types}/utils/editor.d.ts +11 -4
- package/{dist/types/src → types}/utils/index.d.ts +0 -0
- package/{dist/types/src → types}/utils/logger.d.ts +0 -0
- package/types/utils/operator.d.ts +21 -0
- package/{dist/types/src → types}/utils/polyfills.d.ts +0 -0
- package/{dist/types/src → types}/utils/props.d.ts +2 -22
- package/{dist/types/src → types}/utils/scroll-viewer.d.ts +0 -0
- package/{dist/types/src → types}/utils/undo-redo.d.ts +0 -0
- package/dist/tmagic-editor.es.js.map +0 -1
- package/dist/types/src/components/Icon.vue.d.ts +0 -14
- package/dist/types/src/components/ScrollViewer.vue.d.ts +0 -24
- package/dist/types/src/fields/Code.vue.d.ts +0 -25
- package/dist/types/src/layouts/AddPageBox.vue.d.ts +0 -5
- package/dist/types/src/layouts/Framework.vue.d.ts +0 -24
- package/dist/types/src/layouts/NavMenu.vue.d.ts +0 -27
- package/dist/types/src/layouts/PropsPanel.vue.d.ts +0 -13
- package/dist/types/src/layouts/Resizer.vue.d.ts +0 -14
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +0 -14
- package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +0 -16
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +0 -8
- package/dist/types/src/shims-vue.d.ts +0 -6
- package/dist/types/src/vite-env.d.ts +0 -1
- package/src/vite-env.d.ts +0 -1
package/src/services/editor.ts
CHANGED
|
@@ -17,59 +17,64 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { reactive, toRaw } from 'vue';
|
|
20
|
-
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
21
|
-
import serialize from 'serialize-javascript';
|
|
20
|
+
import { cloneDeep, mergeWith, uniq } from 'lodash-es';
|
|
22
21
|
|
|
23
22
|
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
24
23
|
import { NodeType } from '@tmagic/schema';
|
|
25
24
|
import StageCore from '@tmagic/stage';
|
|
26
25
|
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
27
26
|
|
|
28
|
-
import historyService, { StepValue } from '
|
|
29
|
-
import
|
|
30
|
-
import type { AddMNode, EditorNodeInfo, StoreState } from '
|
|
31
|
-
import { LayerOffset, Layout } from '
|
|
27
|
+
import historyService, { StepValue } from '../services/history';
|
|
28
|
+
import storageService, { Protocol } from '../services/storage';
|
|
29
|
+
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '../type';
|
|
30
|
+
import { LayerOffset, Layout } from '../type';
|
|
32
31
|
import {
|
|
33
32
|
change2Fixed,
|
|
34
33
|
COPY_STORAGE_KEY,
|
|
35
34
|
Fixed2Other,
|
|
36
|
-
|
|
35
|
+
fixNodePosition,
|
|
36
|
+
getInitPositionStyle,
|
|
37
37
|
getNodeIndex,
|
|
38
|
-
initPosition,
|
|
39
38
|
isFixed,
|
|
40
39
|
setLayout,
|
|
41
|
-
} from '
|
|
42
|
-
import {
|
|
40
|
+
} from '../utils/editor';
|
|
41
|
+
import { beforePaste, getAddParent } from '../utils/operator';
|
|
43
42
|
|
|
44
43
|
import BaseService from './BaseService';
|
|
44
|
+
import propsService from './props';
|
|
45
45
|
|
|
46
46
|
class Editor extends BaseService {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
private state = reactive<StoreState>({
|
|
47
|
+
public state: StoreState = reactive({
|
|
50
48
|
root: null,
|
|
51
49
|
page: null,
|
|
52
50
|
parent: null,
|
|
53
51
|
node: null,
|
|
52
|
+
nodes: [],
|
|
54
53
|
stage: null,
|
|
55
54
|
highlightNode: null,
|
|
56
55
|
modifiedNodeIds: new Map(),
|
|
57
56
|
pageLength: 0,
|
|
58
57
|
});
|
|
58
|
+
private isHistoryStateChange = false;
|
|
59
59
|
|
|
60
60
|
constructor() {
|
|
61
61
|
super(
|
|
62
62
|
[
|
|
63
63
|
'getLayout',
|
|
64
64
|
'select',
|
|
65
|
+
'doAdd',
|
|
65
66
|
'add',
|
|
67
|
+
'doRemove',
|
|
66
68
|
'remove',
|
|
69
|
+
'doUpdate',
|
|
67
70
|
'update',
|
|
68
71
|
'sort',
|
|
69
72
|
'copy',
|
|
70
73
|
'paste',
|
|
74
|
+
'duAlignCenter',
|
|
71
75
|
'alignCenter',
|
|
72
76
|
'moveLayer',
|
|
77
|
+
'moveToContainer',
|
|
73
78
|
'move',
|
|
74
79
|
'undo',
|
|
75
80
|
'redo',
|
|
@@ -82,14 +87,16 @@ class Editor extends BaseService {
|
|
|
82
87
|
|
|
83
88
|
/**
|
|
84
89
|
* 设置当前指点节点配置
|
|
85
|
-
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode'
|
|
90
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes'
|
|
86
91
|
* @param value MNode
|
|
87
92
|
* @returns MNode
|
|
88
93
|
*/
|
|
89
94
|
public set<T = MNode>(name: keyof StoreState, value: T) {
|
|
90
95
|
this.state[name] = value as any;
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
// set nodes时将node设置为nodes第一个元素
|
|
97
|
+
if (name === 'nodes') {
|
|
98
|
+
this.set('node', (value as unknown as MNode[])[0]);
|
|
99
|
+
}
|
|
93
100
|
if (name === 'root') {
|
|
94
101
|
this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
|
|
95
102
|
this.emit('root-change', value);
|
|
@@ -98,7 +105,7 @@ class Editor extends BaseService {
|
|
|
98
105
|
|
|
99
106
|
/**
|
|
100
107
|
* 获取当前指点节点配置
|
|
101
|
-
* @param name 'root' | 'page' | 'parent' | 'node'
|
|
108
|
+
* @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes'
|
|
102
109
|
* @returns MNode
|
|
103
110
|
*/
|
|
104
111
|
public get<T = MNode>(name: keyof StoreState): T {
|
|
@@ -190,7 +197,7 @@ class Editor extends BaseService {
|
|
|
190
197
|
*/
|
|
191
198
|
public async select(config: MNode | Id): Promise<MNode> | never {
|
|
192
199
|
const { node, page, parent } = this.selectedConfigExceptionHandler(config);
|
|
193
|
-
this.set('
|
|
200
|
+
this.set('nodes', [node]);
|
|
194
201
|
this.set('page', page || null);
|
|
195
202
|
this.set('parent', parent || null);
|
|
196
203
|
|
|
@@ -265,80 +272,110 @@ class Editor extends BaseService {
|
|
|
265
272
|
}
|
|
266
273
|
|
|
267
274
|
/**
|
|
268
|
-
*
|
|
269
|
-
* @param
|
|
270
|
-
* @
|
|
271
|
-
* @returns 添加后的节点
|
|
275
|
+
* 多选
|
|
276
|
+
* @param ids 指定节点ID
|
|
277
|
+
* @returns 加入多选的节点配置
|
|
272
278
|
*/
|
|
273
|
-
public
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
} else if (parent && typeof parent !== 'function') {
|
|
284
|
-
parentNode = parent;
|
|
285
|
-
} else if (curNode.items) {
|
|
286
|
-
parentNode = curNode;
|
|
287
|
-
} else {
|
|
288
|
-
parentNode = this.getParentById(curNode.id, false);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (!parentNode) throw new Error('未找到父元素');
|
|
279
|
+
public multiSelect(ids: Id[]): void {
|
|
280
|
+
const nodes: MNode[] = [];
|
|
281
|
+
const idsUnique = uniq(ids);
|
|
282
|
+
idsUnique.forEach((id) => {
|
|
283
|
+
const { node } = this.getNodeInfo(id);
|
|
284
|
+
if (!node) return;
|
|
285
|
+
nodes.push(node);
|
|
286
|
+
});
|
|
287
|
+
this.set('nodes', nodes);
|
|
288
|
+
}
|
|
292
289
|
|
|
293
|
-
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
parentNode,
|
|
298
|
-
this.get<StageCore>('stage'),
|
|
299
|
-
);
|
|
290
|
+
public async doAdd(node: MNode, parent: MContainer): Promise<MNode> {
|
|
291
|
+
const root = this.get<MApp>('root');
|
|
292
|
+
const curNode = this.get<MNode>('node');
|
|
293
|
+
const stage = this.get<StageCore | null>('stage');
|
|
300
294
|
|
|
301
|
-
if ((
|
|
295
|
+
if ((parent?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && node.type !== NodeType.PAGE) {
|
|
302
296
|
throw new Error('app下不能添加组件');
|
|
303
297
|
}
|
|
304
298
|
|
|
305
|
-
|
|
299
|
+
// 新增节点添加到配置中
|
|
300
|
+
parent?.items?.push(node);
|
|
301
|
+
|
|
302
|
+
const layout = await this.getLayout(toRaw(parent), node as MNode);
|
|
303
|
+
node.style = getInitPositionStyle(node.style, layout);
|
|
306
304
|
|
|
305
|
+
await stage?.add({
|
|
306
|
+
config: cloneDeep(node),
|
|
307
|
+
parent: cloneDeep(parent),
|
|
308
|
+
parentId: parent.id,
|
|
309
|
+
root: cloneDeep(root),
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
node.style = fixNodePosition(node, parent, stage);
|
|
313
|
+
|
|
314
|
+
await stage?.update({ config: cloneDeep(node), parentId: parent.id, root: cloneDeep(root) });
|
|
315
|
+
|
|
316
|
+
this.addModifiedNodeId(node.id);
|
|
317
|
+
|
|
318
|
+
return node;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* 向指点容器添加组件节点
|
|
323
|
+
* @param addConfig 将要添加的组件节点配置
|
|
324
|
+
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
325
|
+
* @returns 添加后的节点
|
|
326
|
+
*/
|
|
327
|
+
public async add(addNode: AddMNode | MNode[], parent?: MContainer | null): Promise<MNode | MNode[]> {
|
|
307
328
|
const stage = this.get<StageCore | null>('stage');
|
|
308
329
|
|
|
309
|
-
|
|
330
|
+
// 新增多个组件只存在于粘贴多个组件,粘贴的是一个完整的config,所以不再需要getPropsValue
|
|
331
|
+
const addNodes = [];
|
|
332
|
+
if (!Array.isArray(addNode)) {
|
|
333
|
+
const { type, inputEvent, ...config } = addNode;
|
|
310
334
|
|
|
311
|
-
|
|
335
|
+
if (!type) throw new Error('组件类型不能为空');
|
|
312
336
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
337
|
+
addNodes.push({ ...toRaw(await propsService.getPropsValue(type, config)) });
|
|
338
|
+
} else {
|
|
339
|
+
addNodes.push(...addNode);
|
|
316
340
|
}
|
|
317
341
|
|
|
318
|
-
|
|
342
|
+
const newNodes = await Promise.all(
|
|
343
|
+
addNodes.map((node) => {
|
|
344
|
+
const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(node);
|
|
345
|
+
if (!parentNode) throw new Error('未找到父元素');
|
|
346
|
+
return this.doAdd(node, parentNode);
|
|
347
|
+
}),
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
if (newNodes.length > 1) {
|
|
351
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
352
|
+
// 触发选中样式
|
|
353
|
+
stage?.multiSelect(newNodeIds);
|
|
354
|
+
await this.multiSelect(newNodeIds);
|
|
355
|
+
} else {
|
|
356
|
+
await this.select(newNodes[0]);
|
|
319
357
|
|
|
320
|
-
|
|
321
|
-
|
|
358
|
+
if (isPage(newNodes[0])) {
|
|
359
|
+
this.state.pageLength += 1;
|
|
360
|
+
} else {
|
|
361
|
+
// 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
|
|
362
|
+
stage?.select(newNodes[0].id);
|
|
363
|
+
}
|
|
322
364
|
}
|
|
323
365
|
|
|
324
|
-
this.
|
|
366
|
+
this.pushHistoryState();
|
|
325
367
|
|
|
326
|
-
|
|
327
|
-
}
|
|
368
|
+
this.emit('add', newNodes);
|
|
328
369
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
* @param {Object} node
|
|
332
|
-
* @return {Object} 删除的组件配置
|
|
333
|
-
*/
|
|
334
|
-
public async remove(node: MNode): Promise<MNode | void> {
|
|
335
|
-
if (!node?.id) return;
|
|
370
|
+
return newNodes.length > 1 ? newNodes[0] : newNodes;
|
|
371
|
+
}
|
|
336
372
|
|
|
373
|
+
public async doRemove(node: MNode): Promise<void> {
|
|
337
374
|
const root = this.get<MApp | null>('root');
|
|
338
375
|
|
|
339
376
|
if (!root) throw new Error('没有root');
|
|
340
377
|
|
|
341
|
-
const { parent, node: curNode } = this.getNodeInfo(node.id
|
|
378
|
+
const { parent, node: curNode } = this.getNodeInfo(node.id);
|
|
342
379
|
|
|
343
380
|
if (!parent || !curNode) throw new Error('找不要删除的节点');
|
|
344
381
|
|
|
@@ -348,7 +385,7 @@ class Editor extends BaseService {
|
|
|
348
385
|
|
|
349
386
|
parent.items?.splice(index, 1);
|
|
350
387
|
const stage = this.get<StageCore | null>('stage');
|
|
351
|
-
stage?.remove({ id: node.id, root:
|
|
388
|
+
stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
|
|
352
389
|
|
|
353
390
|
if (node.type === NodeType.PAGE) {
|
|
354
391
|
this.state.pageLength -= 1;
|
|
@@ -365,9 +402,7 @@ class Editor extends BaseService {
|
|
|
365
402
|
this.resetModifiedNodeId();
|
|
366
403
|
historyService.reset();
|
|
367
404
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
return node;
|
|
405
|
+
return;
|
|
371
406
|
}
|
|
372
407
|
} else {
|
|
373
408
|
await this.select(parent);
|
|
@@ -375,19 +410,25 @@ class Editor extends BaseService {
|
|
|
375
410
|
}
|
|
376
411
|
|
|
377
412
|
this.addModifiedNodeId(parent.id);
|
|
378
|
-
this.pushHistoryState();
|
|
379
|
-
|
|
380
|
-
this.emit('remove', node);
|
|
381
|
-
|
|
382
|
-
return node;
|
|
383
413
|
}
|
|
384
414
|
|
|
385
415
|
/**
|
|
386
|
-
*
|
|
387
|
-
* @param
|
|
388
|
-
* @
|
|
416
|
+
* 删除组件
|
|
417
|
+
* @param {Object} node
|
|
418
|
+
* @return {Object} 删除的组件配置
|
|
389
419
|
*/
|
|
390
|
-
public async
|
|
420
|
+
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
|
|
421
|
+
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
422
|
+
|
|
423
|
+
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
424
|
+
|
|
425
|
+
// 更新历史记录
|
|
426
|
+
this.pushHistoryState();
|
|
427
|
+
|
|
428
|
+
this.emit('remove');
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
public async doUpdate(config: MNode) {
|
|
391
432
|
if (!config?.id) throw new Error('没有配置或者配置缺少id值');
|
|
392
433
|
|
|
393
434
|
const info = this.getNodeInfo(config.id, false);
|
|
@@ -427,22 +468,42 @@ class Editor extends BaseService {
|
|
|
427
468
|
|
|
428
469
|
parentNodeItems[index] = newConfig;
|
|
429
470
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
471
|
+
// 将update后的配置更新到nodes中
|
|
472
|
+
const nodes = this.get('nodes');
|
|
473
|
+
const targetIndex = nodes.findIndex((nodeItem: MNode) => `${nodeItem.id}` === `${newConfig.id}`);
|
|
474
|
+
nodes.splice(targetIndex, 1, newConfig);
|
|
475
|
+
this.set('nodes', nodes);
|
|
433
476
|
|
|
434
|
-
this.get<StageCore | null>('stage')?.update({
|
|
477
|
+
this.get<StageCore | null>('stage')?.update({
|
|
478
|
+
config: cloneDeep(newConfig),
|
|
479
|
+
parentId: parent.id,
|
|
480
|
+
root: cloneDeep(this.get('root')),
|
|
481
|
+
});
|
|
435
482
|
|
|
436
483
|
if (newConfig.type === NodeType.PAGE) {
|
|
437
484
|
this.set('page', newConfig);
|
|
438
485
|
}
|
|
439
486
|
|
|
440
487
|
this.addModifiedNodeId(newConfig.id);
|
|
488
|
+
|
|
489
|
+
return newConfig;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 更新节点
|
|
494
|
+
* @param config 新的节点配置,配置中需要有id信息
|
|
495
|
+
* @returns 更新后的节点配置
|
|
496
|
+
*/
|
|
497
|
+
public async update(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
498
|
+
const nodes = Array.isArray(config) ? config : [config];
|
|
499
|
+
|
|
500
|
+
const newNodes = await Promise.all(nodes.map((node) => this.doUpdate(node)));
|
|
501
|
+
|
|
441
502
|
this.pushHistoryState();
|
|
442
503
|
|
|
443
|
-
this.emit('update',
|
|
504
|
+
this.emit('update', newNodes);
|
|
444
505
|
|
|
445
|
-
return
|
|
506
|
+
return newNodes.length > 1 ? newNodes[0] : newNodes;
|
|
446
507
|
}
|
|
447
508
|
|
|
448
509
|
/**
|
|
@@ -464,7 +525,11 @@ class Editor extends BaseService {
|
|
|
464
525
|
await this.update(parent);
|
|
465
526
|
await this.select(node);
|
|
466
527
|
|
|
467
|
-
this.get<StageCore | null>('stage')?.update({
|
|
528
|
+
this.get<StageCore | null>('stage')?.update({
|
|
529
|
+
config: cloneDeep(node),
|
|
530
|
+
parentId: parent.id,
|
|
531
|
+
root: cloneDeep(this.get('root')),
|
|
532
|
+
});
|
|
468
533
|
|
|
469
534
|
this.addModifiedNodeId(parent.id);
|
|
470
535
|
this.pushHistoryState();
|
|
@@ -475,67 +540,46 @@ class Editor extends BaseService {
|
|
|
475
540
|
* @param config 组件节点配置
|
|
476
541
|
* @returns 组件节点配置
|
|
477
542
|
*/
|
|
478
|
-
public async copy(config: MNode): Promise<void> {
|
|
479
|
-
|
|
543
|
+
public async copy(config: MNode | MNode[]): Promise<void> {
|
|
544
|
+
await storageService.setItem(COPY_STORAGE_KEY, Array.isArray(config) ? config : [config], {
|
|
545
|
+
protocol: Protocol.OBJECT,
|
|
546
|
+
});
|
|
480
547
|
}
|
|
481
548
|
|
|
482
549
|
/**
|
|
483
550
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
484
|
-
* @param position
|
|
551
|
+
* @param position 粘贴的坐标
|
|
485
552
|
* @returns 添加后的组件节点配置
|
|
486
553
|
*/
|
|
487
|
-
public async paste(position:
|
|
488
|
-
const
|
|
489
|
-
// eslint-disable-next-line prefer-const
|
|
490
|
-
let config: any = {};
|
|
491
|
-
if (!configStr) {
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
554
|
+
public async paste(position: PastePosition = {}): Promise<MNode | MNode[] | void> {
|
|
555
|
+
const config: MNode[] = await storageService.getItem(COPY_STORAGE_KEY);
|
|
494
556
|
|
|
495
|
-
|
|
496
|
-
// eslint-disable-next-line no-eval
|
|
497
|
-
eval(`config = ${configStr}`);
|
|
498
|
-
} catch (e) {
|
|
499
|
-
console.error(e);
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
await propsService.setNewItemId(config, this.get('root'));
|
|
504
|
-
if (config.style) {
|
|
505
|
-
config.style = {
|
|
506
|
-
...config.style,
|
|
507
|
-
...position,
|
|
508
|
-
};
|
|
509
|
-
}
|
|
557
|
+
if (!Array.isArray(config)) return;
|
|
510
558
|
|
|
511
|
-
|
|
512
|
-
config.name = generatePageNameByApp(this.get('root'));
|
|
513
|
-
}
|
|
559
|
+
const pasteConfigs = await beforePaste(position, config);
|
|
514
560
|
|
|
515
|
-
return
|
|
561
|
+
return this.add(pasteConfigs);
|
|
516
562
|
}
|
|
517
563
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
const
|
|
525
|
-
const node = this.get<MNode>('node');
|
|
526
|
-
const layout = await this.getLayout(toRaw(parent), toRaw(node));
|
|
564
|
+
public async doAlignCenter(config: MNode): Promise<MNode> {
|
|
565
|
+
const parent = this.getParentById(config.id);
|
|
566
|
+
|
|
567
|
+
if (!parent) throw new Error('找不到父节点');
|
|
568
|
+
|
|
569
|
+
const node = cloneDeep(toRaw(config));
|
|
570
|
+
const layout = await this.getLayout(parent, node);
|
|
527
571
|
if (layout === Layout.RELATIVE) {
|
|
528
|
-
return;
|
|
572
|
+
return config;
|
|
529
573
|
}
|
|
530
574
|
|
|
531
|
-
if (!node.style) return;
|
|
575
|
+
if (!node.style) return config;
|
|
532
576
|
|
|
533
577
|
const stage = this.get<StageCore>('stage');
|
|
534
578
|
const doc = stage?.renderer.contentWindow?.document;
|
|
535
579
|
|
|
536
580
|
if (doc) {
|
|
537
|
-
const parentEl = doc.getElementById(`${parent.id}`);
|
|
538
581
|
const el = doc.getElementById(`${node.id}`);
|
|
582
|
+
const parentEl = el?.offsetParent;
|
|
539
583
|
if (parentEl && el) {
|
|
540
584
|
node.style.left = (parentEl.clientWidth - el.clientWidth) / 2;
|
|
541
585
|
}
|
|
@@ -543,12 +587,25 @@ class Editor extends BaseService {
|
|
|
543
587
|
node.style.left = (parent.style.width - node.style.width) / 2;
|
|
544
588
|
}
|
|
545
589
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
this.addModifiedNodeId(config.id);
|
|
549
|
-
this.pushHistoryState();
|
|
590
|
+
return node;
|
|
591
|
+
}
|
|
550
592
|
|
|
551
|
-
|
|
593
|
+
/**
|
|
594
|
+
* 将指点节点设置居中
|
|
595
|
+
* @param config 组件节点配置
|
|
596
|
+
* @returns 当前组件节点配置
|
|
597
|
+
*/
|
|
598
|
+
public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
599
|
+
const nodes = Array.isArray(config) ? config : [config];
|
|
600
|
+
const stage = this.get<StageCore | null>('stage');
|
|
601
|
+
|
|
602
|
+
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
|
|
603
|
+
|
|
604
|
+
const newNode = await this.update(newNodes);
|
|
605
|
+
|
|
606
|
+
await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
607
|
+
|
|
608
|
+
return newNode;
|
|
552
609
|
}
|
|
553
610
|
|
|
554
611
|
/**
|
|
@@ -569,7 +626,55 @@ class Editor extends BaseService {
|
|
|
569
626
|
brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
|
|
570
627
|
}
|
|
571
628
|
|
|
572
|
-
this.get<StageCore | null>('stage')?.update({
|
|
629
|
+
this.get<StageCore | null>('stage')?.update({
|
|
630
|
+
config: cloneDeep(toRaw(parent)),
|
|
631
|
+
parentId: parent.id,
|
|
632
|
+
root: cloneDeep(this.get<MApp>('root')),
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* 移动到指定容器中
|
|
638
|
+
* @param config 需要移动的节点
|
|
639
|
+
* @param targetId 容器ID
|
|
640
|
+
*/
|
|
641
|
+
public async moveToContainer(config: MNode, targetId: Id): Promise<MNode | undefined> {
|
|
642
|
+
const { node, parent } = this.getNodeInfo(config.id, false);
|
|
643
|
+
const target = this.getNodeById(targetId, false) as MContainer;
|
|
644
|
+
|
|
645
|
+
const stage = this.get<StageCore | null>('stage');
|
|
646
|
+
|
|
647
|
+
if (node && parent && stage) {
|
|
648
|
+
const root = cloneDeep(this.get<MApp>('root'));
|
|
649
|
+
const index = getNodeIndex(node, parent);
|
|
650
|
+
parent.items?.splice(index, 1);
|
|
651
|
+
|
|
652
|
+
await stage.remove({ id: node.id, parentId: parent.id, root });
|
|
653
|
+
|
|
654
|
+
const layout = await this.getLayout(target);
|
|
655
|
+
|
|
656
|
+
const newConfig = mergeWith(cloneDeep(node), config, (objValue, srcValue) => {
|
|
657
|
+
if (Array.isArray(srcValue)) {
|
|
658
|
+
return srcValue;
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
newConfig.style = getInitPositionStyle(newConfig.style, layout);
|
|
662
|
+
|
|
663
|
+
target.items.push(newConfig);
|
|
664
|
+
|
|
665
|
+
await stage.select(targetId);
|
|
666
|
+
|
|
667
|
+
await stage.update({ config: cloneDeep(target), parentId: parent.id, root });
|
|
668
|
+
|
|
669
|
+
await this.select(newConfig);
|
|
670
|
+
stage.select(newConfig.id);
|
|
671
|
+
|
|
672
|
+
this.addModifiedNodeId(target.id);
|
|
673
|
+
this.addModifiedNodeId(parent.id);
|
|
674
|
+
this.pushHistoryState();
|
|
675
|
+
|
|
676
|
+
return newConfig;
|
|
677
|
+
}
|
|
573
678
|
}
|
|
574
679
|
|
|
575
680
|
/**
|
|
@@ -596,7 +701,7 @@ class Editor extends BaseService {
|
|
|
596
701
|
const node = toRaw(this.get('node'));
|
|
597
702
|
if (!node || isPage(node)) return;
|
|
598
703
|
|
|
599
|
-
const { style, id } = node;
|
|
704
|
+
const { style, id, type } = node;
|
|
600
705
|
if (!style || style.position !== 'absolute') return;
|
|
601
706
|
|
|
602
707
|
if (top && !isNumber(style.top)) return;
|
|
@@ -604,6 +709,7 @@ class Editor extends BaseService {
|
|
|
604
709
|
|
|
605
710
|
this.update({
|
|
606
711
|
id,
|
|
712
|
+
type,
|
|
607
713
|
style: {
|
|
608
714
|
...style,
|
|
609
715
|
left: Number(style.left) + left,
|
|
@@ -616,6 +722,7 @@ class Editor extends BaseService {
|
|
|
616
722
|
this.removeAllListeners();
|
|
617
723
|
this.set('root', null);
|
|
618
724
|
this.set('node', null);
|
|
725
|
+
this.set('nodes', []);
|
|
619
726
|
this.set('page', null);
|
|
620
727
|
this.set('parent', null);
|
|
621
728
|
}
|
|
@@ -656,13 +763,13 @@ class Editor extends BaseService {
|
|
|
656
763
|
}
|
|
657
764
|
|
|
658
765
|
private async toggleFixedPosition(dist: MNode, src: MNode, root: MApp) {
|
|
659
|
-
|
|
766
|
+
const newConfig = cloneDeep(dist);
|
|
660
767
|
|
|
661
768
|
if (!isPop(src) && newConfig.style?.position) {
|
|
662
769
|
if (isFixed(newConfig) && !isFixed(src)) {
|
|
663
|
-
newConfig = change2Fixed(newConfig, root);
|
|
770
|
+
newConfig.style = change2Fixed(newConfig, root);
|
|
664
771
|
} else if (!isFixed(newConfig) && isFixed(src)) {
|
|
665
|
-
newConfig = await Fixed2Other(newConfig, root, this.getLayout);
|
|
772
|
+
newConfig.style = await Fixed2Other(newConfig, root, this.getLayout);
|
|
666
773
|
}
|
|
667
774
|
}
|
|
668
775
|
|
package/src/services/events.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { cloneDeep } from 'lodash-es';
|
|
|
22
22
|
import { DEFAULT_EVENTS, DEFAULT_METHODS, EventOption } from '@tmagic/core';
|
|
23
23
|
import { toLine } from '@tmagic/utils';
|
|
24
24
|
|
|
25
|
-
import type { ComponentGroup } from '
|
|
25
|
+
import type { ComponentGroup } from '../type';
|
|
26
26
|
|
|
27
27
|
import BaseService from './BaseService';
|
|
28
28
|
|
package/src/services/history.ts
CHANGED