@tmagic/editor 1.1.0-beta.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +50 -0
- package/dist/tmagic-editor.mjs +1198 -1027
- package/dist/tmagic-editor.mjs.map +1 -1
- package/dist/tmagic-editor.umd.js +1201 -1026
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/package.json +10 -10
- package/src/Editor.vue +22 -6
- package/src/components/ContentMenu.vue +4 -4
- package/src/components/Icon.vue +7 -21
- package/src/components/ScrollBar.vue +147 -0
- package/src/components/ScrollViewer.vue +89 -44
- package/src/components/ToolButton.vue +40 -138
- package/src/fields/UISelect.vue +2 -2
- package/src/index.ts +2 -0
- package/src/layouts/NavMenu.vue +156 -23
- package/src/layouts/PropsPanel.vue +49 -51
- package/src/layouts/sidebar/LayerMenu.vue +3 -3
- package/src/layouts/sidebar/LayerPanel.vue +39 -8
- package/src/layouts/workspace/PageBar.vue +1 -1
- package/src/layouts/workspace/Stage.vue +8 -86
- package/src/layouts/workspace/ViewerMenu.vue +10 -13
- package/src/layouts/workspace/Workspace.vue +133 -138
- package/src/services/componentList.ts +5 -0
- package/src/services/editor.ts +201 -112
- package/src/services/events.ts +8 -2
- package/src/services/props.ts +31 -52
- package/src/services/storage.ts +4 -0
- package/src/services/ui.ts +32 -30
- package/src/theme/component-list-panel.scss +5 -0
- package/src/theme/nav-menu.scss +6 -0
- package/src/type.ts +28 -11
- package/src/utils/editor.ts +17 -10
- package/src/utils/index.ts +1 -0
- package/src/utils/operator.ts +22 -123
- package/src/utils/props.ts +0 -3
- package/src/utils/scroll-viewer.ts +90 -158
- package/src/utils/stage.ts +91 -0
- package/types/Editor.vue.d.ts +17 -8
- package/types/components/ContentMenu.vue.d.ts +8 -8
- package/types/components/Icon.vue.d.ts +62 -12
- package/types/components/ScrollBar.vue.d.ts +83 -0
- package/types/components/ScrollViewer.vue.d.ts +131 -19
- package/types/components/ToolButton.vue.d.ts +56 -59
- package/types/index.d.ts +2 -0
- package/types/layouts/NavMenu.vue.d.ts +92 -23
- package/types/layouts/PropsPanel.vue.d.ts +25 -208
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +7 -7
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +17 -15
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +3 -3
- package/types/layouts/workspace/Workspace.vue.d.ts +54 -4
- package/types/services/componentList.d.ts +1 -0
- package/types/services/editor.d.ts +10 -17
- package/types/services/events.d.ts +1 -0
- package/types/services/props.d.ts +41 -9
- package/types/services/storage.d.ts +1 -0
- package/types/services/ui.d.ts +3 -1
- package/types/type.d.ts +25 -11
- package/types/utils/editor.d.ts +4 -1
- package/types/utils/index.d.ts +1 -0
- package/types/utils/operator.d.ts +3 -26
- package/types/utils/props.d.ts +0 -1
- package/types/utils/scroll-viewer.d.ts +16 -18
- package/types/utils/stage.d.ts +3 -0
package/src/services/editor.ts
CHANGED
|
@@ -32,14 +32,16 @@ import {
|
|
|
32
32
|
change2Fixed,
|
|
33
33
|
COPY_STORAGE_KEY,
|
|
34
34
|
Fixed2Other,
|
|
35
|
+
fixNodePosition,
|
|
35
36
|
getInitPositionStyle,
|
|
36
37
|
getNodeIndex,
|
|
37
38
|
isFixed,
|
|
38
39
|
setLayout,
|
|
39
40
|
} from '../utils/editor';
|
|
40
|
-
import {
|
|
41
|
+
import { beforePaste, getAddParent } from '../utils/operator';
|
|
41
42
|
|
|
42
43
|
import BaseService from './BaseService';
|
|
44
|
+
import propsService from './props';
|
|
43
45
|
|
|
44
46
|
class Editor extends BaseService {
|
|
45
47
|
public state: StoreState = reactive({
|
|
@@ -60,12 +62,17 @@ class Editor extends BaseService {
|
|
|
60
62
|
[
|
|
61
63
|
'getLayout',
|
|
62
64
|
'select',
|
|
65
|
+
'doAdd',
|
|
63
66
|
'add',
|
|
67
|
+
'doRemove',
|
|
64
68
|
'remove',
|
|
69
|
+
'doUpdate',
|
|
65
70
|
'update',
|
|
66
71
|
'sort',
|
|
67
72
|
'copy',
|
|
68
73
|
'paste',
|
|
74
|
+
'doPaste',
|
|
75
|
+
'duAlignCenter',
|
|
69
76
|
'alignCenter',
|
|
70
77
|
'moveLayer',
|
|
71
78
|
'moveToContainer',
|
|
@@ -281,34 +288,40 @@ class Editor extends BaseService {
|
|
|
281
288
|
this.set('nodes', nodes);
|
|
282
289
|
}
|
|
283
290
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
* @returns 添加后的节点
|
|
288
|
-
*/
|
|
289
|
-
public async multiAdd(configs: MNode[]): Promise<MNode[]> {
|
|
291
|
+
public async doAdd(node: MNode, parent: MContainer): Promise<MNode> {
|
|
292
|
+
const root = this.get<MApp>('root');
|
|
293
|
+
const curNode = this.get<MNode>('node');
|
|
290
294
|
const stage = this.get<StageCore | null>('stage');
|
|
291
|
-
const newNodes: MNode[] = await Promise.all(
|
|
292
|
-
configs.map(async (configItem: MNode): Promise<MNode> => {
|
|
293
|
-
// 新增元素到配置
|
|
294
|
-
const { parentNode, newNode, layout } = await beforeAdd(configItem as AddMNode);
|
|
295
|
-
// 将新增元素事件通知到stage以更新渲染
|
|
296
|
-
await notifyAddToStage(parentNode, newNode, layout);
|
|
297
|
-
return newNode;
|
|
298
|
-
}),
|
|
299
|
-
);
|
|
300
|
-
const newNodeIds: Id[] = newNodes.map((node) => node.id);
|
|
301
295
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
296
|
+
if ((parent?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && node.type !== NodeType.PAGE) {
|
|
297
|
+
throw new Error('app下不能添加组件');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (parent.id !== curNode.id) {
|
|
301
|
+
const index = parent.items.indexOf(curNode);
|
|
302
|
+
parent?.items?.splice(index + 1, 0, node);
|
|
303
|
+
} else {
|
|
304
|
+
// 新增节点添加到配置中
|
|
305
|
+
parent?.items?.push(node);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const layout = await this.getLayout(toRaw(parent), node as MNode);
|
|
309
|
+
node.style = getInitPositionStyle(node.style, layout);
|
|
310
|
+
|
|
311
|
+
await stage?.add({
|
|
312
|
+
config: cloneDeep(node),
|
|
313
|
+
parent: cloneDeep(parent),
|
|
314
|
+
parentId: parent.id,
|
|
315
|
+
root: cloneDeep(root),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
node.style = fixNodePosition(node, parent, stage);
|
|
305
319
|
|
|
306
|
-
|
|
307
|
-
stage?.multiSelect(newNodeIds);
|
|
320
|
+
await stage?.update({ config: cloneDeep(node), parentId: parent.id, root: cloneDeep(root) });
|
|
308
321
|
|
|
309
|
-
this.
|
|
322
|
+
this.addModifiedNodeId(node.id);
|
|
310
323
|
|
|
311
|
-
return
|
|
324
|
+
return node;
|
|
312
325
|
}
|
|
313
326
|
|
|
314
327
|
/**
|
|
@@ -317,30 +330,92 @@ class Editor extends BaseService {
|
|
|
317
330
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
318
331
|
* @returns 添加后的节点
|
|
319
332
|
*/
|
|
320
|
-
public async add(addNode: AddMNode, parent?: MContainer | null): Promise<MNode> {
|
|
333
|
+
public async add(addNode: AddMNode | MNode[], parent?: MContainer | null): Promise<MNode | MNode[]> {
|
|
321
334
|
const stage = this.get<StageCore | null>('stage');
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
335
|
+
|
|
336
|
+
// 新增多个组件只存在于粘贴多个组件,粘贴的是一个完整的config,所以不再需要getPropsValue
|
|
337
|
+
const addNodes = [];
|
|
338
|
+
if (!Array.isArray(addNode)) {
|
|
339
|
+
const { type, inputEvent, ...config } = addNode;
|
|
340
|
+
|
|
341
|
+
if (!type) throw new Error('组件类型不能为空');
|
|
342
|
+
|
|
343
|
+
addNodes.push({ ...toRaw(await propsService.getPropsValue(type, config)) });
|
|
344
|
+
} else {
|
|
345
|
+
addNodes.push(...addNode);
|
|
332
346
|
}
|
|
333
347
|
|
|
334
|
-
|
|
335
|
-
|
|
348
|
+
const newNodes = await Promise.all(
|
|
349
|
+
addNodes.map((node) => {
|
|
350
|
+
const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(node);
|
|
351
|
+
if (!parentNode) throw new Error('未找到父元素');
|
|
352
|
+
return this.doAdd(node, parentNode);
|
|
353
|
+
}),
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
if (newNodes.length > 1) {
|
|
357
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
358
|
+
// 触发选中样式
|
|
359
|
+
stage?.multiSelect(newNodeIds);
|
|
360
|
+
await this.multiSelect(newNodeIds);
|
|
336
361
|
} else {
|
|
337
|
-
|
|
338
|
-
|
|
362
|
+
await this.select(newNodes[0]);
|
|
363
|
+
|
|
364
|
+
if (isPage(newNodes[0])) {
|
|
365
|
+
this.state.pageLength += 1;
|
|
366
|
+
} else {
|
|
367
|
+
// 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
|
|
368
|
+
stage?.select(newNodes[0].id);
|
|
369
|
+
}
|
|
339
370
|
}
|
|
340
371
|
|
|
341
|
-
this.
|
|
372
|
+
this.pushHistoryState();
|
|
342
373
|
|
|
343
|
-
|
|
374
|
+
this.emit('add', newNodes);
|
|
375
|
+
|
|
376
|
+
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
public async doRemove(node: MNode): Promise<void> {
|
|
380
|
+
const root = this.get<MApp | null>('root');
|
|
381
|
+
|
|
382
|
+
if (!root) throw new Error('没有root');
|
|
383
|
+
|
|
384
|
+
const { parent, node: curNode } = this.getNodeInfo(node.id);
|
|
385
|
+
|
|
386
|
+
if (!parent || !curNode) throw new Error('找不要删除的节点');
|
|
387
|
+
|
|
388
|
+
const index = getNodeIndex(curNode, parent);
|
|
389
|
+
|
|
390
|
+
if (typeof index !== 'number' || index === -1) throw new Error('找不要删除的节点');
|
|
391
|
+
|
|
392
|
+
parent.items?.splice(index, 1);
|
|
393
|
+
const stage = this.get<StageCore | null>('stage');
|
|
394
|
+
stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
|
|
395
|
+
|
|
396
|
+
if (node.type === NodeType.PAGE) {
|
|
397
|
+
this.state.pageLength -= 1;
|
|
398
|
+
|
|
399
|
+
if (root.items[0]) {
|
|
400
|
+
await this.select(root.items[0]);
|
|
401
|
+
stage?.select(root.items[0].id);
|
|
402
|
+
} else {
|
|
403
|
+
this.set('node', null);
|
|
404
|
+
this.set('parent', null);
|
|
405
|
+
this.set('page', null);
|
|
406
|
+
this.set('stage', null);
|
|
407
|
+
this.set('highlightNode', null);
|
|
408
|
+
this.resetModifiedNodeId();
|
|
409
|
+
historyService.reset();
|
|
410
|
+
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
await this.select(parent);
|
|
415
|
+
stage?.select(parent.id);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
this.addModifiedNodeId(parent.id);
|
|
344
419
|
}
|
|
345
420
|
|
|
346
421
|
/**
|
|
@@ -348,50 +423,18 @@ class Editor extends BaseService {
|
|
|
348
423
|
* @param {Object} node
|
|
349
424
|
* @return {Object} 删除的组件配置
|
|
350
425
|
*/
|
|
351
|
-
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<
|
|
352
|
-
|
|
353
|
-
// 多选批量删除
|
|
354
|
-
const nodes = nodeOrNodeList;
|
|
355
|
-
return this.multiRemove(nodes);
|
|
356
|
-
}
|
|
357
|
-
const node = nodeOrNodeList;
|
|
358
|
-
const removeParent = await beforeRemove(node);
|
|
359
|
-
// 删除的是页面
|
|
360
|
-
if (!removeParent) return node;
|
|
361
|
-
// 更新历史记录
|
|
362
|
-
this.addModifiedNodeId(removeParent.id);
|
|
363
|
-
this.pushHistoryState();
|
|
426
|
+
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
|
|
427
|
+
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
364
428
|
|
|
365
|
-
this.
|
|
429
|
+
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
366
430
|
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* 批量删除
|
|
372
|
-
* @param nodes 批量删除的节点
|
|
373
|
-
* @returns 批量删除的节点
|
|
374
|
-
*/
|
|
375
|
-
public async multiRemove(nodes: MNode[]): Promise<MNode[]> {
|
|
376
|
-
await Promise.all(
|
|
377
|
-
nodes.map(async (removeNode) => {
|
|
378
|
-
await beforeRemove(removeNode);
|
|
379
|
-
}),
|
|
380
|
-
);
|
|
381
|
-
const nodeIds = nodes.map((node) => node.id);
|
|
382
|
-
this.addModifiedNodeId(nodeIds.join('-'));
|
|
431
|
+
// 更新历史记录
|
|
383
432
|
this.pushHistoryState();
|
|
384
433
|
|
|
385
|
-
this.emit('
|
|
386
|
-
return nodes;
|
|
434
|
+
this.emit('remove', nodes);
|
|
387
435
|
}
|
|
388
436
|
|
|
389
|
-
|
|
390
|
-
* 更新节点
|
|
391
|
-
* @param config 新的节点配置,配置中需要有id信息
|
|
392
|
-
* @returns 更新后的节点配置
|
|
393
|
-
*/
|
|
394
|
-
public async update(config: MNode): Promise<MNode> {
|
|
437
|
+
public async doUpdate(config: MNode) {
|
|
395
438
|
if (!config?.id) throw new Error('没有配置或者配置缺少id值');
|
|
396
439
|
|
|
397
440
|
const info = this.getNodeInfo(config.id, false);
|
|
@@ -437,18 +480,36 @@ class Editor extends BaseService {
|
|
|
437
480
|
nodes.splice(targetIndex, 1, newConfig);
|
|
438
481
|
this.set('nodes', nodes);
|
|
439
482
|
|
|
440
|
-
this.get<StageCore | null>('stage')?.update({
|
|
483
|
+
this.get<StageCore | null>('stage')?.update({
|
|
484
|
+
config: cloneDeep(newConfig),
|
|
485
|
+
parentId: parent.id,
|
|
486
|
+
root: cloneDeep(this.get('root')),
|
|
487
|
+
});
|
|
441
488
|
|
|
442
489
|
if (newConfig.type === NodeType.PAGE) {
|
|
443
490
|
this.set('page', newConfig);
|
|
444
491
|
}
|
|
445
492
|
|
|
446
493
|
this.addModifiedNodeId(newConfig.id);
|
|
494
|
+
|
|
495
|
+
return newConfig;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* 更新节点
|
|
500
|
+
* @param config 新的节点配置,配置中需要有id信息
|
|
501
|
+
* @returns 更新后的节点配置
|
|
502
|
+
*/
|
|
503
|
+
public async update(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
504
|
+
const nodes = Array.isArray(config) ? config : [config];
|
|
505
|
+
|
|
506
|
+
const newNodes = await Promise.all(nodes.map((node) => this.doUpdate(node)));
|
|
507
|
+
|
|
447
508
|
this.pushHistoryState();
|
|
448
509
|
|
|
449
|
-
this.emit('update',
|
|
510
|
+
this.emit('update', newNodes);
|
|
450
511
|
|
|
451
|
-
return
|
|
512
|
+
return Array.isArray(config) ? newNodes : newNodes[0];
|
|
452
513
|
}
|
|
453
514
|
|
|
454
515
|
/**
|
|
@@ -470,7 +531,11 @@ class Editor extends BaseService {
|
|
|
470
531
|
await this.update(parent);
|
|
471
532
|
await this.select(node);
|
|
472
533
|
|
|
473
|
-
this.get<StageCore | null>('stage')?.update({
|
|
534
|
+
this.get<StageCore | null>('stage')?.update({
|
|
535
|
+
config: cloneDeep(node),
|
|
536
|
+
parentId: parent.id,
|
|
537
|
+
root: cloneDeep(this.get('root')),
|
|
538
|
+
});
|
|
474
539
|
|
|
475
540
|
this.addModifiedNodeId(parent.id);
|
|
476
541
|
this.pushHistoryState();
|
|
@@ -492,30 +557,33 @@ class Editor extends BaseService {
|
|
|
492
557
|
* @param position 粘贴的坐标
|
|
493
558
|
* @returns 添加后的组件节点配置
|
|
494
559
|
*/
|
|
495
|
-
public async paste(position: PastePosition = {}): Promise<MNode[] | void> {
|
|
496
|
-
const config = await storageService.getItem(COPY_STORAGE_KEY);
|
|
560
|
+
public async paste(position: PastePosition = {}): Promise<MNode | MNode[] | void> {
|
|
561
|
+
const config: MNode[] = await storageService.getItem(COPY_STORAGE_KEY);
|
|
497
562
|
|
|
498
|
-
if (!config) return;
|
|
563
|
+
if (!Array.isArray(config)) return;
|
|
499
564
|
|
|
500
|
-
const pasteConfigs = await
|
|
565
|
+
const pasteConfigs = await this.doPaste(config, position);
|
|
501
566
|
|
|
502
|
-
return
|
|
567
|
+
return this.add(pasteConfigs);
|
|
503
568
|
}
|
|
504
569
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
public async
|
|
511
|
-
const parent = this.
|
|
512
|
-
|
|
513
|
-
|
|
570
|
+
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
|
571
|
+
const pasteConfigs = await beforePaste(position, cloneDeep(config));
|
|
572
|
+
return pasteConfigs;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
public async doAlignCenter(config: MNode): Promise<MNode> {
|
|
576
|
+
const parent = this.getParentById(config.id);
|
|
577
|
+
|
|
578
|
+
if (!parent) throw new Error('找不到父节点');
|
|
579
|
+
|
|
580
|
+
const node = cloneDeep(toRaw(config));
|
|
581
|
+
const layout = await this.getLayout(parent, node);
|
|
514
582
|
if (layout === Layout.RELATIVE) {
|
|
515
|
-
return;
|
|
583
|
+
return config;
|
|
516
584
|
}
|
|
517
585
|
|
|
518
|
-
if (!node.style) return;
|
|
586
|
+
if (!node.style) return config;
|
|
519
587
|
|
|
520
588
|
const stage = this.get<StageCore>('stage');
|
|
521
589
|
const doc = stage?.renderer.contentWindow?.document;
|
|
@@ -530,15 +598,25 @@ class Editor extends BaseService {
|
|
|
530
598
|
node.style.left = (parent.style.width - node.style.width) / 2;
|
|
531
599
|
}
|
|
532
600
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
config: cloneDeep(toRaw(node)),
|
|
536
|
-
root: cloneDeep(this.get<MApp>('root')),
|
|
537
|
-
});
|
|
538
|
-
this.addModifiedNodeId(config.id);
|
|
539
|
-
this.pushHistoryState();
|
|
601
|
+
return node;
|
|
602
|
+
}
|
|
540
603
|
|
|
541
|
-
|
|
604
|
+
/**
|
|
605
|
+
* 将指点节点设置居中
|
|
606
|
+
* @param config 组件节点配置
|
|
607
|
+
* @returns 当前组件节点配置
|
|
608
|
+
*/
|
|
609
|
+
public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
610
|
+
const nodes = Array.isArray(config) ? config : [config];
|
|
611
|
+
const stage = this.get<StageCore | null>('stage');
|
|
612
|
+
|
|
613
|
+
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
|
|
614
|
+
|
|
615
|
+
const newNode = await this.update(newNodes);
|
|
616
|
+
|
|
617
|
+
await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
618
|
+
|
|
619
|
+
return newNode;
|
|
542
620
|
}
|
|
543
621
|
|
|
544
622
|
/**
|
|
@@ -547,7 +625,7 @@ class Editor extends BaseService {
|
|
|
547
625
|
*/
|
|
548
626
|
public async moveLayer(offset: number | LayerOffset): Promise<void> {
|
|
549
627
|
const parent = this.get<MContainer>('parent');
|
|
550
|
-
const node = this.get('node');
|
|
628
|
+
const node = this.get<MNode>('node');
|
|
551
629
|
const brothers: MNode[] = parent?.items || [];
|
|
552
630
|
const index = brothers.findIndex((item) => `${item.id}` === `${node?.id}`);
|
|
553
631
|
|
|
@@ -559,10 +637,15 @@ class Editor extends BaseService {
|
|
|
559
637
|
brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
|
|
560
638
|
}
|
|
561
639
|
|
|
640
|
+
const grandparent = this.getParentById(parent.id);
|
|
562
641
|
this.get<StageCore | null>('stage')?.update({
|
|
563
642
|
config: cloneDeep(toRaw(parent)),
|
|
643
|
+
parentId: grandparent?.id,
|
|
564
644
|
root: cloneDeep(this.get<MApp>('root')),
|
|
565
645
|
});
|
|
646
|
+
|
|
647
|
+
this.addModifiedNodeId(parent.id);
|
|
648
|
+
this.pushHistoryState();
|
|
566
649
|
}
|
|
567
650
|
|
|
568
651
|
/**
|
|
@@ -581,7 +664,7 @@ class Editor extends BaseService {
|
|
|
581
664
|
const index = getNodeIndex(node, parent);
|
|
582
665
|
parent.items?.splice(index, 1);
|
|
583
666
|
|
|
584
|
-
await stage.remove({ id: node.id, root });
|
|
667
|
+
await stage.remove({ id: node.id, parentId: parent.id, root });
|
|
585
668
|
|
|
586
669
|
const layout = await this.getLayout(target);
|
|
587
670
|
|
|
@@ -590,13 +673,14 @@ class Editor extends BaseService {
|
|
|
590
673
|
return srcValue;
|
|
591
674
|
}
|
|
592
675
|
});
|
|
593
|
-
newConfig.style = getInitPositionStyle(newConfig.style, layout
|
|
676
|
+
newConfig.style = getInitPositionStyle(newConfig.style, layout);
|
|
594
677
|
|
|
595
678
|
target.items.push(newConfig);
|
|
596
679
|
|
|
597
680
|
await stage.select(targetId);
|
|
598
681
|
|
|
599
|
-
|
|
682
|
+
const targetParent = this.getParentById(target.id);
|
|
683
|
+
await stage.update({ config: cloneDeep(target), parentId: targetParent?.id, root });
|
|
600
684
|
|
|
601
685
|
await this.select(newConfig);
|
|
602
686
|
stage.select(newConfig.id);
|
|
@@ -633,7 +717,7 @@ class Editor extends BaseService {
|
|
|
633
717
|
const node = toRaw(this.get('node'));
|
|
634
718
|
if (!node || isPage(node)) return;
|
|
635
719
|
|
|
636
|
-
const { style, id } = node;
|
|
720
|
+
const { style, id, type } = node;
|
|
637
721
|
if (!style || style.position !== 'absolute') return;
|
|
638
722
|
|
|
639
723
|
if (top && !isNumber(style.top)) return;
|
|
@@ -641,6 +725,7 @@ class Editor extends BaseService {
|
|
|
641
725
|
|
|
642
726
|
this.update({
|
|
643
727
|
id,
|
|
728
|
+
type,
|
|
644
729
|
style: {
|
|
645
730
|
...style,
|
|
646
731
|
left: Number(style.left) + left,
|
|
@@ -656,6 +741,10 @@ class Editor extends BaseService {
|
|
|
656
741
|
this.set('nodes', []);
|
|
657
742
|
this.set('page', null);
|
|
658
743
|
this.set('parent', null);
|
|
744
|
+
this.set('stage', null);
|
|
745
|
+
this.set('highlightNode', null);
|
|
746
|
+
this.set('modifiedNodeIds', new Map());
|
|
747
|
+
this.set('pageLength', new Map());
|
|
659
748
|
}
|
|
660
749
|
|
|
661
750
|
public resetModifiedNodeId() {
|
package/src/services/events.ts
CHANGED
|
@@ -26,8 +26,8 @@ import type { ComponentGroup } from '../type';
|
|
|
26
26
|
|
|
27
27
|
import BaseService from './BaseService';
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
let eventMap: Record<string, EventOption[]> = reactive({});
|
|
30
|
+
let methodMap: Record<string, EventOption[]> = reactive({});
|
|
31
31
|
|
|
32
32
|
class Events extends BaseService {
|
|
33
33
|
constructor() {
|
|
@@ -75,6 +75,12 @@ class Events extends BaseService {
|
|
|
75
75
|
public getMethod(type: string) {
|
|
76
76
|
return cloneDeep(methodMap[type] || DEFAULT_METHODS);
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
public destroy() {
|
|
80
|
+
eventMap = reactive({});
|
|
81
|
+
methodMap = reactive({});
|
|
82
|
+
this.removeAllListeners();
|
|
83
|
+
}
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
export type EventsService = Events;
|
package/src/services/props.ts
CHANGED
|
@@ -20,12 +20,11 @@ import { reactive } from 'vue';
|
|
|
20
20
|
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
21
21
|
|
|
22
22
|
import type { FormConfig } from '@tmagic/form';
|
|
23
|
-
import type {
|
|
24
|
-
import {
|
|
25
|
-
import { isPop, toLine } from '@tmagic/utils';
|
|
23
|
+
import type { MComponent, MNode } from '@tmagic/schema';
|
|
24
|
+
import { toLine } from '@tmagic/utils';
|
|
26
25
|
|
|
27
26
|
import type { PropsState } from '../type';
|
|
28
|
-
import {
|
|
27
|
+
import { fillConfig } from '../utils/props';
|
|
29
28
|
|
|
30
29
|
import BaseService from './BaseService';
|
|
31
30
|
|
|
@@ -43,6 +42,7 @@ class Props extends BaseService {
|
|
|
43
42
|
'getPropsValue',
|
|
44
43
|
'createId',
|
|
45
44
|
'setNewItemId',
|
|
45
|
+
'fillConfig',
|
|
46
46
|
'getDefaultPropsValue',
|
|
47
47
|
]);
|
|
48
48
|
}
|
|
@@ -54,13 +54,17 @@ class Props extends BaseService {
|
|
|
54
54
|
this.emit('props-configs-change');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
public async fillConfig(config: FormConfig) {
|
|
58
|
+
return fillConfig(config);
|
|
59
|
+
}
|
|
60
|
+
|
|
57
61
|
/**
|
|
58
62
|
* 为指定类型组件设置组件属性表单配置
|
|
59
63
|
* @param type 组件类型
|
|
60
64
|
* @param config 组件属性表单配置
|
|
61
65
|
*/
|
|
62
|
-
public setPropsConfig(type: string, config: FormConfig) {
|
|
63
|
-
this.state.propsConfigMap[type] = fillConfig(Array.isArray(config) ? config : [config]);
|
|
66
|
+
public async setPropsConfig(type: string, config: FormConfig) {
|
|
67
|
+
this.state.propsConfigMap[type] = await this.fillConfig(Array.isArray(config) ? config : [config]);
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
/**
|
|
@@ -73,7 +77,7 @@ class Props extends BaseService {
|
|
|
73
77
|
return await this.getPropsConfig('button');
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
return cloneDeep(this.state.propsConfigMap[type] ||
|
|
80
|
+
return cloneDeep(this.state.propsConfigMap[type] || (await this.fillConfig([])));
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
public setPropsValues(values: Record<string, MNode>) {
|
|
@@ -125,19 +129,6 @@ class Props extends BaseService {
|
|
|
125
129
|
};
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
/**
|
|
129
|
-
* 生成指定位数的GUID,无【-】格式
|
|
130
|
-
* @param digit 位数,默认值8
|
|
131
|
-
* @returns
|
|
132
|
-
*/
|
|
133
|
-
guid(digit = 8): string {
|
|
134
|
-
return 'x'.repeat(digit).replace(/[xy]/g, (c) => {
|
|
135
|
-
const r = (Math.random() * 16) | 0;
|
|
136
|
-
const v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
137
|
-
return v.toString(16);
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
132
|
public async createId(type: string | number): Promise<string> {
|
|
142
133
|
return `${type}_${this.guid()}`;
|
|
143
134
|
}
|
|
@@ -147,19 +138,12 @@ class Props extends BaseService {
|
|
|
147
138
|
* @param {Object} config 组件配置
|
|
148
139
|
*/
|
|
149
140
|
/* eslint no-param-reassign: ["error", { "props": false }] */
|
|
150
|
-
public async setNewItemId(config: MNode
|
|
151
|
-
const oldId = config.id;
|
|
152
|
-
|
|
141
|
+
public async setNewItemId(config: MNode) {
|
|
153
142
|
config.id = await this.createId(config.type || 'component');
|
|
154
143
|
|
|
155
|
-
// 只有弹窗在页面下的一级子元素才有效
|
|
156
|
-
if (isPop(config) && parent?.type === NodeType.PAGE) {
|
|
157
|
-
updatePopId(oldId, config.id, parent);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
144
|
if (config.items && Array.isArray(config.items)) {
|
|
161
145
|
for (const item of config.items) {
|
|
162
|
-
await this.setNewItemId(item
|
|
146
|
+
await this.setNewItemId(item);
|
|
163
147
|
}
|
|
164
148
|
}
|
|
165
149
|
|
|
@@ -186,31 +170,26 @@ class Props extends BaseService {
|
|
|
186
170
|
name: type,
|
|
187
171
|
};
|
|
188
172
|
}
|
|
189
|
-
}
|
|
190
173
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
*/
|
|
197
|
-
const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
|
|
198
|
-
pageConfig.items?.forEach((config) => {
|
|
199
|
-
if (config.pop === oldId) {
|
|
200
|
-
config.pop = popId;
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (config.popId === oldId) {
|
|
205
|
-
config.popId = popId;
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
174
|
+
public destroy() {
|
|
175
|
+
this.state.propsConfigMap = {};
|
|
176
|
+
this.state.propsValueMap = {};
|
|
177
|
+
this.removeAllListeners();
|
|
178
|
+
}
|
|
208
179
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
180
|
+
/**
|
|
181
|
+
* 生成指定位数的GUID,无【-】格式
|
|
182
|
+
* @param digit 位数,默认值8
|
|
183
|
+
* @returns
|
|
184
|
+
*/
|
|
185
|
+
private guid(digit = 8): string {
|
|
186
|
+
return 'x'.repeat(digit).replace(/[xy]/g, (c) => {
|
|
187
|
+
const r = (Math.random() * 16) | 0;
|
|
188
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
189
|
+
return v.toString(16);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
214
193
|
|
|
215
194
|
export type PropsService = Props;
|
|
216
195
|
|
package/src/services/storage.ts
CHANGED
|
@@ -107,6 +107,10 @@ export class WebStorage extends BaseService {
|
|
|
107
107
|
storage.setItem(`${options.namespace || namespace}:${key}`, item);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
public destroy() {
|
|
111
|
+
this.removeAllListeners();
|
|
112
|
+
}
|
|
113
|
+
|
|
110
114
|
private getValueAndProtocol(value: string | null) {
|
|
111
115
|
let protocol = '';
|
|
112
116
|
|