@tmagic/editor 1.1.0-beta.6 → 1.1.0-beta.9
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 +4 -0
- package/dist/tmagic-editor.mjs +322 -320
- package/dist/tmagic-editor.mjs.map +1 -1
- package/dist/tmagic-editor.umd.js +321 -318
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/package.json +7 -7
- package/src/Editor.vue +8 -2
- package/src/components/Icon.vue +1 -1
- package/src/fields/UISelect.vue +0 -1
- package/src/index.ts +1 -1
- package/src/layouts/workspace/PageBar.vue +43 -161
- package/src/layouts/workspace/PageBarScrollContainer.vue +111 -0
- package/src/layouts/workspace/Stage.vue +6 -2
- package/src/layouts/workspace/ViewerMenu.vue +7 -10
- package/src/layouts/workspace/Workspace.vue +1 -1
- package/src/services/editor.ts +158 -106
- package/src/theme/component-list-panel.scss +5 -0
- package/src/type.ts +2 -1
- package/src/utils/editor.ts +17 -10
- package/src/utils/operator.ts +21 -122
- package/types/Editor.vue.d.ts +10 -1
- package/types/fields/UISelect.vue.d.ts +0 -4
- package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +48 -0
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +3 -3
- package/types/services/editor.d.ts +9 -17
- package/types/type.d.ts +2 -1
- package/types/utils/editor.d.ts +4 -1
- package/types/utils/operator.d.ts +3 -26
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,16 @@ 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
|
+
'duAlignCenter',
|
|
69
75
|
'alignCenter',
|
|
70
76
|
'moveLayer',
|
|
71
77
|
'moveToContainer',
|
|
@@ -281,34 +287,30 @@ class Editor extends BaseService {
|
|
|
281
287
|
this.set('nodes', nodes);
|
|
282
288
|
}
|
|
283
289
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
* @returns 添加后的节点
|
|
288
|
-
*/
|
|
289
|
-
public async multiAdd(configs: MNode[]): Promise<MNode[]> {
|
|
290
|
+
public async doAdd(node: MNode, parent: MContainer): Promise<MNode> {
|
|
291
|
+
const root = this.get<MApp>('root');
|
|
292
|
+
const curNode = this.get<MNode>('node');
|
|
290
293
|
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
294
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
295
|
+
if ((parent?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && node.type !== NodeType.PAGE) {
|
|
296
|
+
throw new Error('app下不能添加组件');
|
|
297
|
+
}
|
|
305
298
|
|
|
306
|
-
|
|
307
|
-
|
|
299
|
+
const layout = await this.getLayout(toRaw(parent), node as MNode);
|
|
300
|
+
node.style = getInitPositionStyle(node.style, layout);
|
|
308
301
|
|
|
309
|
-
|
|
302
|
+
await stage?.add({ config: cloneDeep(node), parent: cloneDeep(parent), root: cloneDeep(root) });
|
|
310
303
|
|
|
311
|
-
|
|
304
|
+
node.style = fixNodePosition(node, parent, stage);
|
|
305
|
+
|
|
306
|
+
await stage?.update({ config: cloneDeep(node), root: cloneDeep(root) });
|
|
307
|
+
|
|
308
|
+
// 新增节点添加到配置中
|
|
309
|
+
parent?.items?.push(node);
|
|
310
|
+
|
|
311
|
+
this.addModifiedNodeId(node.id);
|
|
312
|
+
|
|
313
|
+
return node;
|
|
312
314
|
}
|
|
313
315
|
|
|
314
316
|
/**
|
|
@@ -317,30 +319,89 @@ class Editor extends BaseService {
|
|
|
317
319
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
318
320
|
* @returns 添加后的节点
|
|
319
321
|
*/
|
|
320
|
-
public async add(addNode: AddMNode, parent?: MContainer | null): Promise<MNode> {
|
|
322
|
+
public async add(addNode: AddMNode | MNode[], parent?: MContainer | null): Promise<MNode | MNode[]> {
|
|
321
323
|
const stage = this.get<StageCore | null>('stage');
|
|
322
|
-
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
324
|
+
|
|
325
|
+
const parentNode = parent && typeof parent !== 'function' ? parent : getAddParent(addNode);
|
|
326
|
+
if (!parentNode) throw new Error('未找到父元素');
|
|
327
|
+
|
|
328
|
+
// 新增多个组件只存在于粘贴多个组件,粘贴的是一个完整的config,所以不再需要getPropsValue
|
|
329
|
+
const addNodes = [];
|
|
330
|
+
if (!Array.isArray(addNode)) {
|
|
331
|
+
const { type, inputEvent, ...config } = addNode;
|
|
332
|
+
|
|
333
|
+
if (!type) throw new Error('组件类型不能为空');
|
|
334
|
+
|
|
335
|
+
addNodes.push({ ...toRaw(await propsService.getPropsValue(type, config)) });
|
|
336
|
+
} else {
|
|
337
|
+
addNodes.push(...addNode);
|
|
332
338
|
}
|
|
333
339
|
|
|
334
|
-
|
|
335
|
-
|
|
340
|
+
const newNodes = await Promise.all(addNodes.map((node) => this.doAdd(node, parentNode)));
|
|
341
|
+
|
|
342
|
+
if (newNodes.length > 1) {
|
|
343
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
344
|
+
// 触发选中样式
|
|
345
|
+
stage?.multiSelect(newNodeIds);
|
|
346
|
+
await this.multiSelect(newNodeIds);
|
|
336
347
|
} else {
|
|
337
|
-
|
|
338
|
-
|
|
348
|
+
await this.select(newNodes[0]);
|
|
349
|
+
|
|
350
|
+
if (isPage(newNodes[0])) {
|
|
351
|
+
this.state.pageLength += 1;
|
|
352
|
+
} else {
|
|
353
|
+
// 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
|
|
354
|
+
stage?.select(newNodes[0].id);
|
|
355
|
+
}
|
|
339
356
|
}
|
|
340
357
|
|
|
341
|
-
this.
|
|
358
|
+
this.pushHistoryState();
|
|
342
359
|
|
|
343
|
-
|
|
360
|
+
this.emit('add', newNodes);
|
|
361
|
+
|
|
362
|
+
return newNodes.length > 1 ? newNodes[0] : newNodes;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
public async doRemove(node: MNode): Promise<void> {
|
|
366
|
+
const root = this.get<MApp | null>('root');
|
|
367
|
+
|
|
368
|
+
if (!root) throw new Error('没有root');
|
|
369
|
+
|
|
370
|
+
const { parent, node: curNode } = this.getNodeInfo(node.id);
|
|
371
|
+
|
|
372
|
+
if (!parent || !curNode) throw new Error('找不要删除的节点');
|
|
373
|
+
|
|
374
|
+
const index = getNodeIndex(curNode, parent);
|
|
375
|
+
|
|
376
|
+
if (typeof index !== 'number' || index === -1) throw new Error('找不要删除的节点');
|
|
377
|
+
|
|
378
|
+
parent.items?.splice(index, 1);
|
|
379
|
+
const stage = this.get<StageCore | null>('stage');
|
|
380
|
+
stage?.remove({ id: node.id, root: this.get('root') });
|
|
381
|
+
|
|
382
|
+
if (node.type === NodeType.PAGE) {
|
|
383
|
+
this.state.pageLength -= 1;
|
|
384
|
+
|
|
385
|
+
if (root.items[0]) {
|
|
386
|
+
await this.select(root.items[0]);
|
|
387
|
+
stage?.select(root.items[0].id);
|
|
388
|
+
} else {
|
|
389
|
+
this.set('node', null);
|
|
390
|
+
this.set('parent', null);
|
|
391
|
+
this.set('page', null);
|
|
392
|
+
this.set('stage', null);
|
|
393
|
+
this.set('highlightNode', null);
|
|
394
|
+
this.resetModifiedNodeId();
|
|
395
|
+
historyService.reset();
|
|
396
|
+
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
await this.select(parent);
|
|
401
|
+
stage?.select(parent.id);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
this.addModifiedNodeId(parent.id);
|
|
344
405
|
}
|
|
345
406
|
|
|
346
407
|
/**
|
|
@@ -348,50 +409,18 @@ class Editor extends BaseService {
|
|
|
348
409
|
* @param {Object} node
|
|
349
410
|
* @return {Object} 删除的组件配置
|
|
350
411
|
*/
|
|
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();
|
|
412
|
+
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
|
|
413
|
+
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
364
414
|
|
|
365
|
-
this.
|
|
415
|
+
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
366
416
|
|
|
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('-'));
|
|
417
|
+
// 更新历史记录
|
|
383
418
|
this.pushHistoryState();
|
|
384
419
|
|
|
385
|
-
this.emit('
|
|
386
|
-
return nodes;
|
|
420
|
+
this.emit('remove');
|
|
387
421
|
}
|
|
388
422
|
|
|
389
|
-
|
|
390
|
-
* 更新节点
|
|
391
|
-
* @param config 新的节点配置,配置中需要有id信息
|
|
392
|
-
* @returns 更新后的节点配置
|
|
393
|
-
*/
|
|
394
|
-
public async update(config: MNode): Promise<MNode> {
|
|
423
|
+
public async doUpdate(config: MNode) {
|
|
395
424
|
if (!config?.id) throw new Error('没有配置或者配置缺少id值');
|
|
396
425
|
|
|
397
426
|
const info = this.getNodeInfo(config.id, false);
|
|
@@ -444,11 +473,25 @@ class Editor extends BaseService {
|
|
|
444
473
|
}
|
|
445
474
|
|
|
446
475
|
this.addModifiedNodeId(newConfig.id);
|
|
476
|
+
|
|
477
|
+
return newConfig;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* 更新节点
|
|
482
|
+
* @param config 新的节点配置,配置中需要有id信息
|
|
483
|
+
* @returns 更新后的节点配置
|
|
484
|
+
*/
|
|
485
|
+
public async update(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
486
|
+
const nodes = Array.isArray(config) ? config : [config];
|
|
487
|
+
|
|
488
|
+
const newNodes = await Promise.all(nodes.map((node) => this.doUpdate(node)));
|
|
489
|
+
|
|
447
490
|
this.pushHistoryState();
|
|
448
491
|
|
|
449
|
-
this.emit('update',
|
|
492
|
+
this.emit('update', newNodes);
|
|
450
493
|
|
|
451
|
-
return
|
|
494
|
+
return newNodes.length > 1 ? newNodes[0] : newNodes;
|
|
452
495
|
}
|
|
453
496
|
|
|
454
497
|
/**
|
|
@@ -492,30 +535,28 @@ class Editor extends BaseService {
|
|
|
492
535
|
* @param position 粘贴的坐标
|
|
493
536
|
* @returns 添加后的组件节点配置
|
|
494
537
|
*/
|
|
495
|
-
public async paste(position: PastePosition = {}): Promise<MNode[] | void> {
|
|
496
|
-
const config = await storageService.getItem(COPY_STORAGE_KEY);
|
|
538
|
+
public async paste(position: PastePosition = {}): Promise<MNode | MNode[] | void> {
|
|
539
|
+
const config: MNode[] = await storageService.getItem(COPY_STORAGE_KEY);
|
|
497
540
|
|
|
498
|
-
if (!config) return;
|
|
541
|
+
if (!Array.isArray(config)) return;
|
|
499
542
|
|
|
500
543
|
const pasteConfigs = await beforePaste(position, config);
|
|
501
544
|
|
|
502
|
-
return
|
|
545
|
+
return this.add(pasteConfigs);
|
|
503
546
|
}
|
|
504
547
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const
|
|
512
|
-
const node = this.get<MNode>('node');
|
|
513
|
-
const layout = await this.getLayout(toRaw(parent), toRaw(node));
|
|
548
|
+
public async doAlignCenter(config: MNode): Promise<MNode> {
|
|
549
|
+
const parent = this.getParentById(config.id);
|
|
550
|
+
|
|
551
|
+
if (!parent) throw new Error('找不到父节点');
|
|
552
|
+
|
|
553
|
+
const node = cloneDeep(toRaw(config));
|
|
554
|
+
const layout = await this.getLayout(parent, node);
|
|
514
555
|
if (layout === Layout.RELATIVE) {
|
|
515
|
-
return;
|
|
556
|
+
return config;
|
|
516
557
|
}
|
|
517
558
|
|
|
518
|
-
if (!node.style) return;
|
|
559
|
+
if (!node.style) return config;
|
|
519
560
|
|
|
520
561
|
const stage = this.get<StageCore>('stage');
|
|
521
562
|
const doc = stage?.renderer.contentWindow?.document;
|
|
@@ -530,15 +571,25 @@ class Editor extends BaseService {
|
|
|
530
571
|
node.style.left = (parent.style.width - node.style.width) / 2;
|
|
531
572
|
}
|
|
532
573
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
config: cloneDeep(toRaw(node)),
|
|
536
|
-
root: cloneDeep(this.get<MApp>('root')),
|
|
537
|
-
});
|
|
538
|
-
this.addModifiedNodeId(config.id);
|
|
539
|
-
this.pushHistoryState();
|
|
574
|
+
return node;
|
|
575
|
+
}
|
|
540
576
|
|
|
541
|
-
|
|
577
|
+
/**
|
|
578
|
+
* 将指点节点设置居中
|
|
579
|
+
* @param config 组件节点配置
|
|
580
|
+
* @returns 当前组件节点配置
|
|
581
|
+
*/
|
|
582
|
+
public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
583
|
+
const nodes = Array.isArray(config) ? config : [config];
|
|
584
|
+
const stage = this.get<StageCore | null>('stage');
|
|
585
|
+
|
|
586
|
+
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
|
|
587
|
+
|
|
588
|
+
const newNode = await this.update(newNodes);
|
|
589
|
+
|
|
590
|
+
await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
591
|
+
|
|
592
|
+
return newNode;
|
|
542
593
|
}
|
|
543
594
|
|
|
544
595
|
/**
|
|
@@ -590,7 +641,7 @@ class Editor extends BaseService {
|
|
|
590
641
|
return srcValue;
|
|
591
642
|
}
|
|
592
643
|
});
|
|
593
|
-
newConfig.style = getInitPositionStyle(newConfig.style, layout
|
|
644
|
+
newConfig.style = getInitPositionStyle(newConfig.style, layout);
|
|
594
645
|
|
|
595
646
|
target.items.push(newConfig);
|
|
596
647
|
|
|
@@ -633,7 +684,7 @@ class Editor extends BaseService {
|
|
|
633
684
|
const node = toRaw(this.get('node'));
|
|
634
685
|
if (!node || isPage(node)) return;
|
|
635
686
|
|
|
636
|
-
const { style, id } = node;
|
|
687
|
+
const { style, id, type } = node;
|
|
637
688
|
if (!style || style.position !== 'absolute') return;
|
|
638
689
|
|
|
639
690
|
if (top && !isNumber(style.top)) return;
|
|
@@ -641,6 +692,7 @@ class Editor extends BaseService {
|
|
|
641
692
|
|
|
642
693
|
this.update({
|
|
643
694
|
id,
|
|
695
|
+
type,
|
|
644
696
|
style: {
|
|
645
697
|
...style,
|
|
646
698
|
left: Number(style.left) + left,
|
package/src/type.ts
CHANGED
|
@@ -21,7 +21,7 @@ import type { Component } from 'vue';
|
|
|
21
21
|
import type { FormConfig } from '@tmagic/form';
|
|
22
22
|
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
23
23
|
import type StageCore from '@tmagic/stage';
|
|
24
|
-
import type { MoveableOptions } from '@tmagic/stage';
|
|
24
|
+
import type { ContainerHighlightType, MoveableOptions } from '@tmagic/stage';
|
|
25
25
|
|
|
26
26
|
import type { ComponentListService } from './services/componentList';
|
|
27
27
|
import type { EditorService } from './services/editor';
|
|
@@ -53,6 +53,7 @@ export interface StageOptions {
|
|
|
53
53
|
autoScrollIntoView: boolean;
|
|
54
54
|
containerHighlightClassName: string;
|
|
55
55
|
containerHighlightDuration: number;
|
|
56
|
+
containerHighlightType: ContainerHighlightType;
|
|
56
57
|
render: () => HTMLDivElement;
|
|
57
58
|
moveableOptions: MoveableOptions | ((core?: StageCore) => MoveableOptions);
|
|
58
59
|
canSelect: (el: HTMLElement) => boolean | Promise<boolean>;
|
package/src/utils/editor.ts
CHANGED
|
@@ -88,10 +88,10 @@ export const getRelativeStyle = (style: Record<string, any> = {}): Record<string
|
|
|
88
88
|
left: 0,
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
const getMiddleTop = (
|
|
92
|
-
let height = style
|
|
91
|
+
const getMiddleTop = (node: MNode, parentNode: MNode, stage: StageCore | null) => {
|
|
92
|
+
let height = node.style?.height || 0;
|
|
93
93
|
|
|
94
|
-
if (!stage || typeof style
|
|
94
|
+
if (!stage || typeof node.style?.top !== 'undefined' || !parentNode.style) return node.style?.top;
|
|
95
95
|
|
|
96
96
|
if (!isNumber(height)) {
|
|
97
97
|
height = 0;
|
|
@@ -103,20 +103,15 @@ const getMiddleTop = (style: Record<string, any> = {}, parentNode: MNode, stage:
|
|
|
103
103
|
const { scrollTop = 0, wrapperHeight } = stage.mask;
|
|
104
104
|
return (wrapperHeight - height) / 2 + scrollTop;
|
|
105
105
|
}
|
|
106
|
+
|
|
106
107
|
return (parentHeight - height) / 2;
|
|
107
108
|
};
|
|
108
109
|
|
|
109
|
-
export const getInitPositionStyle = (
|
|
110
|
-
style: Record<string, any> = {},
|
|
111
|
-
layout: Layout,
|
|
112
|
-
parentNode: MNode,
|
|
113
|
-
stage: StageCore,
|
|
114
|
-
) => {
|
|
110
|
+
export const getInitPositionStyle = (style: Record<string, any> = {}, layout: Layout) => {
|
|
115
111
|
if (layout === Layout.ABSOLUTE) {
|
|
116
112
|
return {
|
|
117
113
|
...style,
|
|
118
114
|
position: 'absolute',
|
|
119
|
-
top: getMiddleTop(style, parentNode, stage),
|
|
120
115
|
};
|
|
121
116
|
}
|
|
122
117
|
|
|
@@ -230,3 +225,15 @@ export const fixNodeLeft = (config: MNode, parent: MContainer, doc?: Document) =
|
|
|
230
225
|
|
|
231
226
|
return config.style.left;
|
|
232
227
|
};
|
|
228
|
+
|
|
229
|
+
export const fixNodePosition = (config: MNode, parent: MContainer, stage: StageCore | null) => {
|
|
230
|
+
if (config.style?.position !== 'absolute') {
|
|
231
|
+
return config.style;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
...(config.style || {}),
|
|
236
|
+
top: getMiddleTop(config, parent, stage),
|
|
237
|
+
left: fixNodeLeft(config, parent, stage?.renderer.contentWindow?.document),
|
|
238
|
+
};
|
|
239
|
+
};
|
package/src/utils/operator.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { toRaw } from 'vue';
|
|
2
|
-
import {
|
|
2
|
+
import { isEmpty } from 'lodash-es';
|
|
3
3
|
|
|
4
|
-
import { Id, MApp, MContainer, MNode
|
|
4
|
+
import { Id, MApp, MContainer, MNode } from '@tmagic/schema';
|
|
5
5
|
import StageCore from '@tmagic/stage';
|
|
6
6
|
import { isPage } from '@tmagic/utils';
|
|
7
7
|
|
|
8
8
|
import editorService from '../services/editor';
|
|
9
|
-
import historyService from '../services/history';
|
|
10
9
|
import propsService from '../services/props';
|
|
11
|
-
import { AddMNode,
|
|
12
|
-
import {
|
|
10
|
+
import { AddMNode, PastePosition } from '../type';
|
|
11
|
+
import { generatePageNameByApp, getInitPositionStyle } from '../utils/editor';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* 粘贴前置操作:返回分配了新id以及校准了坐标的配置
|
|
@@ -17,7 +16,7 @@ import { fixNodeLeft, generatePageNameByApp, getInitPositionStyle, getNodeIndex
|
|
|
17
16
|
* @param config 待粘贴的元素配置(复制时保存的那份配置)
|
|
18
17
|
* @returns
|
|
19
18
|
*/
|
|
20
|
-
export const beforePaste = async (position: PastePosition, config: MNode[]) => {
|
|
19
|
+
export const beforePaste = async (position: PastePosition, config: MNode[]): Promise<MNode[]> => {
|
|
21
20
|
if (!config[0]?.style) return config;
|
|
22
21
|
const curNode = editorService.get<MContainer>('node');
|
|
23
22
|
// 将数组中第一个元素的坐标作为参照点
|
|
@@ -69,54 +68,6 @@ export const beforePaste = async (position: PastePosition, config: MNode[]) => {
|
|
|
69
68
|
return pasteConfigs;
|
|
70
69
|
};
|
|
71
70
|
|
|
72
|
-
/**
|
|
73
|
-
* 新增元素前置操作,实现了在编辑器中新增元素节点,并返回新增元素信息以供stage更新
|
|
74
|
-
* @param addNode 待添加元素的配置
|
|
75
|
-
* @param parent 父级容器(可选)
|
|
76
|
-
* @returns 新增的元素,父级元素,布局方式,是否为根页面
|
|
77
|
-
*/
|
|
78
|
-
export const beforeAdd = async (
|
|
79
|
-
addNode: AddMNode,
|
|
80
|
-
parent?: MContainer | null,
|
|
81
|
-
): Promise<{ parentNode: MContainer; newNode: MNode; layout: Layout; isPage: boolean }> => {
|
|
82
|
-
// 加入inputEvent是为给业务扩展时可以获取到更多的信息,只有在使用拖拽添加组件时才有改对象
|
|
83
|
-
const { type, inputEvent, ...config } = addNode;
|
|
84
|
-
const curNode = editorService.get<MContainer>('node');
|
|
85
|
-
|
|
86
|
-
let parentNode: MContainer | undefined;
|
|
87
|
-
const isPage = type === NodeType.PAGE;
|
|
88
|
-
|
|
89
|
-
if (isPage) {
|
|
90
|
-
parentNode = editorService.get<MApp>('root');
|
|
91
|
-
// 由于支持中间件扩展,在parent参数为undefined时,parent会变成next函数
|
|
92
|
-
} else if (parent && typeof parent !== 'function') {
|
|
93
|
-
parentNode = parent;
|
|
94
|
-
} else if (curNode.items) {
|
|
95
|
-
parentNode = curNode;
|
|
96
|
-
} else {
|
|
97
|
-
parentNode = editorService.getParentById(curNode.id, false);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!parentNode) throw new Error('未找到父元素');
|
|
101
|
-
|
|
102
|
-
const layout = await editorService.getLayout(toRaw(parentNode), addNode as MNode);
|
|
103
|
-
const newNode = { ...toRaw(await propsService.getPropsValue(type, config)) };
|
|
104
|
-
newNode.style = getInitPositionStyle(newNode.style, layout, parentNode, editorService.get<StageCore>('stage'));
|
|
105
|
-
|
|
106
|
-
if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
|
|
107
|
-
throw new Error('app下不能添加组件');
|
|
108
|
-
}
|
|
109
|
-
// 新增节点添加到配置中
|
|
110
|
-
parentNode?.items?.push(newNode);
|
|
111
|
-
// 返回新增信息以供stage更新
|
|
112
|
-
return {
|
|
113
|
-
parentNode,
|
|
114
|
-
newNode,
|
|
115
|
-
layout,
|
|
116
|
-
isPage,
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
|
|
120
71
|
/**
|
|
121
72
|
* 将元素粘贴到容器内时,将相对于画布坐标转换为相对于容器的坐标
|
|
122
73
|
* @param position PastePosition 粘贴时相对于画布的坐标
|
|
@@ -135,76 +86,24 @@ export const getPositionInContainer = (position: PastePosition = {}, id: Id) =>
|
|
|
135
86
|
};
|
|
136
87
|
};
|
|
137
88
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
* @param parentNode 父元素
|
|
141
|
-
* @param newNode 当前新增元素
|
|
142
|
-
* @param layout 布局方式
|
|
143
|
-
*/
|
|
144
|
-
export const notifyAddToStage = async (parentNode: MContainer, newNode: MNode, layout: Layout) => {
|
|
145
|
-
const stage = editorService.get<StageCore | null>('stage');
|
|
146
|
-
const root = editorService.get<MApp>('root');
|
|
147
|
-
|
|
148
|
-
await stage?.add({ config: cloneDeep(newNode), parent: cloneDeep(parentNode), root: cloneDeep(root) });
|
|
89
|
+
export const getAddParent = (addNode: AddMNode | MNode[]) => {
|
|
90
|
+
const curNode = editorService.get<MContainer>('node');
|
|
149
91
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
92
|
+
let parentNode;
|
|
93
|
+
if (!Array.isArray(addNode) && isPage(addNode as MNode)) {
|
|
94
|
+
parentNode = editorService.get<MApp>('root');
|
|
95
|
+
} else if (curNode.items) {
|
|
96
|
+
parentNode = curNode;
|
|
97
|
+
} else {
|
|
98
|
+
parentNode = editorService.getParentById(curNode.id, false);
|
|
156
99
|
}
|
|
100
|
+
return parentNode;
|
|
157
101
|
};
|
|
158
102
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (!node?.id) return;
|
|
166
|
-
|
|
167
|
-
const stage = editorService.get<StageCore | null>('stage');
|
|
168
|
-
const root = editorService.get<MApp | null>('root');
|
|
169
|
-
|
|
170
|
-
if (!root) throw new Error('没有root');
|
|
171
|
-
|
|
172
|
-
const { parent, node: curNode } = editorService.getNodeInfo(node.id, false);
|
|
173
|
-
|
|
174
|
-
if (!parent || !curNode) throw new Error('找不要删除的节点');
|
|
175
|
-
|
|
176
|
-
const index = getNodeIndex(curNode, parent);
|
|
177
|
-
|
|
178
|
-
if (typeof index !== 'number' || index === -1) throw new Error('找不要删除的节点');
|
|
179
|
-
// 从配置中删除元素
|
|
180
|
-
parent.items?.splice(index, 1);
|
|
181
|
-
|
|
182
|
-
// 通知stage更新
|
|
183
|
-
stage?.remove({ id: node.id, root: cloneDeep(root) });
|
|
184
|
-
|
|
185
|
-
if (node.type === NodeType.PAGE) {
|
|
186
|
-
editorService.state.pageLength -= 1;
|
|
187
|
-
|
|
188
|
-
if (root.items[0]) {
|
|
189
|
-
await editorService.select(root.items[0]);
|
|
190
|
-
stage?.select(root.items[0].id);
|
|
191
|
-
} else {
|
|
192
|
-
editorService.set('node', null);
|
|
193
|
-
editorService.set('nodes', []);
|
|
194
|
-
editorService.set('parent', null);
|
|
195
|
-
editorService.set('page', null);
|
|
196
|
-
editorService.set('stage', null);
|
|
197
|
-
editorService.set('highlightNode', null);
|
|
198
|
-
editorService.resetModifiedNodeId();
|
|
199
|
-
historyService.reset();
|
|
200
|
-
|
|
201
|
-
editorService.emit('remove', node);
|
|
202
|
-
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
} else {
|
|
206
|
-
await editorService.select(parent);
|
|
207
|
-
stage?.select(parent.id);
|
|
208
|
-
}
|
|
209
|
-
return parent;
|
|
103
|
+
export const getDefaultConfig = async (addNode: AddMNode, parentNode: MContainer) => {
|
|
104
|
+
const { type, inputEvent, ...config } = addNode;
|
|
105
|
+
const layout = await editorService.getLayout(toRaw(parentNode), addNode as MNode);
|
|
106
|
+
const newNode = { ...toRaw(await propsService.getPropsValue(type, config)) };
|
|
107
|
+
newNode.style = getInitPositionStyle(newNode.style, layout);
|
|
108
|
+
return newNode;
|
|
210
109
|
};
|
package/types/Editor.vue.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { PropType } from 'vue';
|
|
|
2
2
|
import type { FormConfig } from '@tmagic/form';
|
|
3
3
|
import type { MApp, MNode } from '@tmagic/schema';
|
|
4
4
|
import type StageCore from '@tmagic/stage';
|
|
5
|
-
import { MoveableOptions } from '@tmagic/stage';
|
|
5
|
+
import { ContainerHighlightType, MoveableOptions } from '@tmagic/stage';
|
|
6
6
|
import type { ComponentGroup, MenuBarData, MenuItem, Services, SideBarData, StageRect } from './type';
|
|
7
7
|
declare const _default: import("vue").DefineComponent<{
|
|
8
8
|
/** 页面初始值 */
|
|
@@ -83,6 +83,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
83
83
|
type: NumberConstructor;
|
|
84
84
|
default: number;
|
|
85
85
|
};
|
|
86
|
+
containerHighlightType: {
|
|
87
|
+
type: PropType<ContainerHighlightType>;
|
|
88
|
+
default: ContainerHighlightType;
|
|
89
|
+
};
|
|
86
90
|
stageRect: {
|
|
87
91
|
type: PropType<StageRect>;
|
|
88
92
|
};
|
|
@@ -172,6 +176,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
172
176
|
type: NumberConstructor;
|
|
173
177
|
default: number;
|
|
174
178
|
};
|
|
179
|
+
containerHighlightType: {
|
|
180
|
+
type: PropType<ContainerHighlightType>;
|
|
181
|
+
default: ContainerHighlightType;
|
|
182
|
+
};
|
|
175
183
|
stageRect: {
|
|
176
184
|
type: PropType<StageRect>;
|
|
177
185
|
};
|
|
@@ -200,5 +208,6 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
200
208
|
isContainer: (el: HTMLElement) => boolean | Promise<boolean>;
|
|
201
209
|
containerHighlightClassName: string;
|
|
202
210
|
containerHighlightDuration: number;
|
|
211
|
+
containerHighlightType: ContainerHighlightType;
|
|
203
212
|
}>;
|
|
204
213
|
export default _default;
|