@tmagic/editor 1.7.14-beta.1 → 1.7.14-beta.3
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/es/components/ToolButton.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +11 -11
- package/dist/es/layouts/NavMenuColumn.js +5 -0
- package/dist/es/layouts/NavMenuColumn.vue_vue_type_script_setup_true_lang.js +201 -0
- package/dist/es/services/editor.js +88 -31
- package/dist/es/services/storage.js +5 -5
- package/dist/es/style.css +51 -0
- package/dist/es/utils/keybinding-config.js +19 -19
- package/dist/style.css +51 -0
- package/dist/tmagic-editor.umd.cjs +353 -93
- package/package.json +8 -8
- package/src/components/ToolButton.vue +7 -1
- package/src/layouts/CodeEditor.vue +18 -10
- package/src/layouts/NavMenu.vue +9 -4
- package/src/layouts/NavMenuColumn.vue +252 -0
- package/src/services/editor.ts +132 -40
- package/src/theme/nav-menu.scss +61 -0
- package/src/type.ts +42 -0
- package/src/utils/undo-redo.ts +2 -0
- package/types/index.d.ts +456 -437
package/src/services/editor.ts
CHANGED
|
@@ -65,6 +65,25 @@ import type { HistoryOpContext } from '@editor/utils/editor-history';
|
|
|
65
65
|
import { applyHistoryAddOp, applyHistoryRemoveOp, applyHistoryUpdateOp } from '@editor/utils/editor-history';
|
|
66
66
|
import { beforePaste, getAddParent } from '@editor/utils/operator';
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
|
|
70
|
+
* 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
|
|
71
|
+
*/
|
|
72
|
+
const safeOptions = <T extends object>(options: unknown): T => {
|
|
73
|
+
const empty = {};
|
|
74
|
+
if (!options || typeof options === 'function') return empty as T;
|
|
75
|
+
return options as T;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
|
|
80
|
+
* 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
|
|
81
|
+
*/
|
|
82
|
+
const safeParent = (parent: unknown): MContainer | null => {
|
|
83
|
+
if (!parent || typeof parent === 'function') return null;
|
|
84
|
+
return parent as MContainer;
|
|
85
|
+
};
|
|
86
|
+
|
|
68
87
|
class Editor extends BaseService {
|
|
69
88
|
public state: StoreState = reactive({
|
|
70
89
|
root: null,
|
|
@@ -349,9 +368,18 @@ class Editor extends BaseService {
|
|
|
349
368
|
* 向指点容器添加组件节点
|
|
350
369
|
* @param addConfig 将要添加的组件节点配置
|
|
351
370
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
371
|
+
* @param options 可选配置
|
|
372
|
+
* @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
|
|
352
373
|
* @returns 添加后的节点
|
|
353
374
|
*/
|
|
354
|
-
public async add(
|
|
375
|
+
public async add(
|
|
376
|
+
addNode: AddMNode | MNode[],
|
|
377
|
+
parent?: MContainer | null,
|
|
378
|
+
options?: { doNotSelect?: boolean },
|
|
379
|
+
): Promise<MNode | MNode[]> {
|
|
380
|
+
const safeParentNode = safeParent(parent);
|
|
381
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
382
|
+
|
|
355
383
|
this.captureSelectionBeforeOp();
|
|
356
384
|
|
|
357
385
|
const stage = this.get('stage');
|
|
@@ -374,25 +402,29 @@ class Editor extends BaseService {
|
|
|
374
402
|
if ((isPage(node) || isPageFragment(node)) && root) {
|
|
375
403
|
return this.doAdd(node, root);
|
|
376
404
|
}
|
|
377
|
-
const parentNode =
|
|
405
|
+
const parentNode = safeParentNode ?? getAddParent(node);
|
|
378
406
|
if (!parentNode) throw new Error('未找到父元素');
|
|
379
407
|
return this.doAdd(node, parentNode);
|
|
380
408
|
}),
|
|
381
409
|
);
|
|
382
410
|
|
|
383
411
|
if (newNodes.length > 1) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
412
|
+
if (!doNotSelect) {
|
|
413
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
414
|
+
// 触发选中样式
|
|
415
|
+
stage?.multiSelect(newNodeIds);
|
|
416
|
+
await this.multiSelect(newNodeIds);
|
|
417
|
+
}
|
|
388
418
|
} else {
|
|
389
|
-
|
|
419
|
+
if (!doNotSelect) {
|
|
420
|
+
await this.select(newNodes[0]);
|
|
421
|
+
}
|
|
390
422
|
|
|
391
423
|
if (isPage(newNodes[0])) {
|
|
392
424
|
this.state.pageLength += 1;
|
|
393
425
|
} else if (isPageFragment(newNodes[0])) {
|
|
394
426
|
this.state.pageFragmentLength += 1;
|
|
395
|
-
} else {
|
|
427
|
+
} else if (!doNotSelect) {
|
|
396
428
|
// 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
|
|
397
429
|
stage?.select(newNodes[0].id);
|
|
398
430
|
}
|
|
@@ -421,7 +453,9 @@ class Editor extends BaseService {
|
|
|
421
453
|
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
422
454
|
}
|
|
423
455
|
|
|
424
|
-
public async doRemove(node: MNode): Promise<void> {
|
|
456
|
+
public async doRemove(node: MNode, options?: { doNotSelect?: boolean }): Promise<void> {
|
|
457
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
458
|
+
|
|
425
459
|
const root = this.get('root');
|
|
426
460
|
if (!root) throw new Error('root不能为空');
|
|
427
461
|
|
|
@@ -437,6 +471,24 @@ class Editor extends BaseService {
|
|
|
437
471
|
const stage = this.get('stage');
|
|
438
472
|
stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
|
|
439
473
|
|
|
474
|
+
if (doNotSelect) {
|
|
475
|
+
// 当被删除节点正好在当前选中列表中时,必须从 state 中移除引用,避免 state 持有已删除节点(与 doNotSelect 无关)
|
|
476
|
+
const selectedNodes = this.get('nodes');
|
|
477
|
+
const removedSelectedIndex = selectedNodes.findIndex((n: MNode) => `${n.id}` === `${node.id}`);
|
|
478
|
+
if (removedSelectedIndex !== -1) {
|
|
479
|
+
const nextSelected = [...selectedNodes];
|
|
480
|
+
nextSelected.splice(removedSelectedIndex, 1);
|
|
481
|
+
this.set('nodes', nextSelected);
|
|
482
|
+
}
|
|
483
|
+
// 同理,如果被删除的是当前 page,也清空 state.page,避免持有已删除页面
|
|
484
|
+
if (isPage(node) || isPageFragment(node)) {
|
|
485
|
+
const currentPage = this.get('page');
|
|
486
|
+
if (currentPage && `${currentPage.id}` === `${node.id}`) {
|
|
487
|
+
this.set('page', null);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
440
492
|
const selectDefault = async (pages: MNode[]) => {
|
|
441
493
|
if (pages[0]) {
|
|
442
494
|
await this.select(pages[0]);
|
|
@@ -453,14 +505,20 @@ class Editor extends BaseService {
|
|
|
453
505
|
if (isPage(node)) {
|
|
454
506
|
this.state.pageLength -= 1;
|
|
455
507
|
|
|
456
|
-
|
|
508
|
+
if (!doNotSelect) {
|
|
509
|
+
await selectDefault(rootItems);
|
|
510
|
+
}
|
|
457
511
|
} else if (isPageFragment(node)) {
|
|
458
512
|
this.state.pageFragmentLength -= 1;
|
|
459
513
|
|
|
460
|
-
|
|
514
|
+
if (!doNotSelect) {
|
|
515
|
+
await selectDefault(rootItems);
|
|
516
|
+
}
|
|
461
517
|
} else {
|
|
462
|
-
|
|
463
|
-
|
|
518
|
+
if (!doNotSelect) {
|
|
519
|
+
await this.select(parent);
|
|
520
|
+
stage?.select(parent.id);
|
|
521
|
+
}
|
|
464
522
|
|
|
465
523
|
this.addModifiedNodeId(parent.id);
|
|
466
524
|
}
|
|
@@ -473,9 +531,13 @@ class Editor extends BaseService {
|
|
|
473
531
|
|
|
474
532
|
/**
|
|
475
533
|
* 删除组件
|
|
476
|
-
* @param {Object} node
|
|
534
|
+
* @param {Object} node 要删除的节点或节点集合
|
|
535
|
+
* @param options 可选配置
|
|
536
|
+
* @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
|
|
477
537
|
*/
|
|
478
|
-
public async remove(nodeOrNodeList: MNode | MNode[]): Promise<void> {
|
|
538
|
+
public async remove(nodeOrNodeList: MNode | MNode[], options?: { doNotSelect?: boolean }): Promise<void> {
|
|
539
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
540
|
+
|
|
479
541
|
this.captureSelectionBeforeOp();
|
|
480
542
|
|
|
481
543
|
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
@@ -499,7 +561,7 @@ class Editor extends BaseService {
|
|
|
499
561
|
}
|
|
500
562
|
}
|
|
501
563
|
|
|
502
|
-
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
564
|
+
await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
|
|
503
565
|
|
|
504
566
|
if (removedItems.length > 0 && pageForOp) {
|
|
505
567
|
this.pushOpHistory('remove', { removedItems }, pageForOp);
|
|
@@ -510,10 +572,7 @@ class Editor extends BaseService {
|
|
|
510
572
|
|
|
511
573
|
public async doUpdate(
|
|
512
574
|
config: MNode,
|
|
513
|
-
{
|
|
514
|
-
changeRecords = [],
|
|
515
|
-
selectedAfterUpdate = true,
|
|
516
|
-
}: { changeRecords?: ChangeRecord[]; selectedAfterUpdate?: boolean } = {},
|
|
575
|
+
{ changeRecords = [] }: { changeRecords?: ChangeRecord[] } = {},
|
|
517
576
|
): Promise<{ newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }> {
|
|
518
577
|
const root = this.get('root');
|
|
519
578
|
if (!root) throw new Error('root为空');
|
|
@@ -557,12 +616,12 @@ class Editor extends BaseService {
|
|
|
557
616
|
|
|
558
617
|
parentNodeItems[index] = newConfig;
|
|
559
618
|
|
|
560
|
-
//
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
this.set('nodes', [...
|
|
619
|
+
// 当被更新节点正好在当前选中列表中时,必须同步引用,否则 state 会持有已被替换的旧节点
|
|
620
|
+
const selectedNodes = this.get('nodes');
|
|
621
|
+
const targetIndex = selectedNodes.findIndex((nodeItem: MNode) => `${nodeItem.id}` === `${newConfig.id}`);
|
|
622
|
+
if (targetIndex !== -1) {
|
|
623
|
+
selectedNodes.splice(targetIndex, 1, newConfig);
|
|
624
|
+
this.set('nodes', [...selectedNodes]);
|
|
566
625
|
}
|
|
567
626
|
|
|
568
627
|
if (isPage(newConfig) || isPageFragment(newConfig)) {
|
|
@@ -586,7 +645,7 @@ class Editor extends BaseService {
|
|
|
586
645
|
*/
|
|
587
646
|
public async update(
|
|
588
647
|
config: MNode | MNode[],
|
|
589
|
-
data: { changeRecords?: ChangeRecord[]
|
|
648
|
+
data: { changeRecords?: ChangeRecord[] } = {},
|
|
590
649
|
): Promise<MNode | MNode[]> {
|
|
591
650
|
this.captureSelectionBeforeOp();
|
|
592
651
|
|
|
@@ -620,9 +679,13 @@ class Editor extends BaseService {
|
|
|
620
679
|
* 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
|
|
621
680
|
* @param id1 组件ID
|
|
622
681
|
* @param id2 组件ID
|
|
682
|
+
* @param options 可选配置
|
|
683
|
+
* @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
|
|
623
684
|
* @returns void
|
|
624
685
|
*/
|
|
625
|
-
public async sort(id1: Id, id2: Id): Promise<void> {
|
|
686
|
+
public async sort(id1: Id, id2: Id, options?: { doNotSelect?: boolean }): Promise<void> {
|
|
687
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
688
|
+
|
|
626
689
|
this.captureSelectionBeforeOp();
|
|
627
690
|
|
|
628
691
|
const root = this.get('root');
|
|
@@ -642,7 +705,9 @@ class Editor extends BaseService {
|
|
|
642
705
|
parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
|
|
643
706
|
|
|
644
707
|
await this.update(parent);
|
|
645
|
-
|
|
708
|
+
if (!doNotSelect) {
|
|
709
|
+
await this.select(node);
|
|
710
|
+
}
|
|
646
711
|
|
|
647
712
|
this.get('stage')?.update({
|
|
648
713
|
config: cloneDeep(node),
|
|
@@ -682,9 +747,18 @@ class Editor extends BaseService {
|
|
|
682
747
|
/**
|
|
683
748
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
684
749
|
* @param position 粘贴的坐标
|
|
750
|
+
* @param collectorOptions 可选的依赖收集器配置
|
|
751
|
+
* @param options 可选配置
|
|
752
|
+
* @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
|
|
685
753
|
* @returns 添加后的组件节点配置
|
|
686
754
|
*/
|
|
687
|
-
public async paste(
|
|
755
|
+
public async paste(
|
|
756
|
+
position: PastePosition = {},
|
|
757
|
+
collectorOptions?: TargetOptions,
|
|
758
|
+
options?: { doNotSelect?: boolean },
|
|
759
|
+
): Promise<MNode | MNode[] | void> {
|
|
760
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
761
|
+
|
|
688
762
|
const config: MNode[] = storageService.getItem(COPY_STORAGE_KEY);
|
|
689
763
|
if (!Array.isArray(config)) return;
|
|
690
764
|
|
|
@@ -704,7 +778,7 @@ class Editor extends BaseService {
|
|
|
704
778
|
propsService.replaceRelateId(config, pasteConfigs, collectorOptions);
|
|
705
779
|
}
|
|
706
780
|
|
|
707
|
-
return this.add(pasteConfigs, parent);
|
|
781
|
+
return this.add(pasteConfigs, parent, { doNotSelect });
|
|
708
782
|
}
|
|
709
783
|
|
|
710
784
|
public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
|
|
@@ -732,9 +806,13 @@ class Editor extends BaseService {
|
|
|
732
806
|
/**
|
|
733
807
|
* 将指点节点设置居中
|
|
734
808
|
* @param config 组件节点配置
|
|
809
|
+
* @param options 可选配置
|
|
810
|
+
* @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
|
|
735
811
|
* @returns 当前组件节点配置
|
|
736
812
|
*/
|
|
737
|
-
public async alignCenter(config: MNode | MNode[]): Promise<MNode | MNode[]> {
|
|
813
|
+
public async alignCenter(config: MNode | MNode[], options?: { doNotSelect?: boolean }): Promise<MNode | MNode[]> {
|
|
814
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
815
|
+
|
|
738
816
|
const nodes = Array.isArray(config) ? config : [config];
|
|
739
817
|
const stage = this.get('stage');
|
|
740
818
|
|
|
@@ -742,10 +820,12 @@ class Editor extends BaseService {
|
|
|
742
820
|
|
|
743
821
|
const newNode = await this.update(newNodes);
|
|
744
822
|
|
|
745
|
-
if (
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
823
|
+
if (!doNotSelect) {
|
|
824
|
+
if (newNodes.length > 1) {
|
|
825
|
+
await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
826
|
+
} else {
|
|
827
|
+
await stage?.select(newNodes[0].id);
|
|
828
|
+
}
|
|
749
829
|
}
|
|
750
830
|
|
|
751
831
|
return newNode;
|
|
@@ -808,8 +888,16 @@ class Editor extends BaseService {
|
|
|
808
888
|
* 移动到指定容器中
|
|
809
889
|
* @param config 需要移动的节点
|
|
810
890
|
* @param targetId 容器ID
|
|
891
|
+
* @param options 可选配置
|
|
892
|
+
* @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
|
|
811
893
|
*/
|
|
812
|
-
public async moveToContainer(
|
|
894
|
+
public async moveToContainer(
|
|
895
|
+
config: MNode,
|
|
896
|
+
targetId: Id,
|
|
897
|
+
options?: { doNotSelect?: boolean },
|
|
898
|
+
): Promise<MNode | undefined> {
|
|
899
|
+
const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
|
|
900
|
+
|
|
813
901
|
this.captureSelectionBeforeOp();
|
|
814
902
|
|
|
815
903
|
const root = this.get('root');
|
|
@@ -837,7 +925,9 @@ class Editor extends BaseService {
|
|
|
837
925
|
|
|
838
926
|
target.items.push(newConfig);
|
|
839
927
|
|
|
840
|
-
|
|
928
|
+
if (!doNotSelect) {
|
|
929
|
+
await stage.select(targetId);
|
|
930
|
+
}
|
|
841
931
|
|
|
842
932
|
const targetParent = this.getParentById(target.id);
|
|
843
933
|
await stage.update({
|
|
@@ -846,8 +936,10 @@ class Editor extends BaseService {
|
|
|
846
936
|
root: cloneDeep(root),
|
|
847
937
|
});
|
|
848
938
|
|
|
849
|
-
|
|
850
|
-
|
|
939
|
+
if (!doNotSelect) {
|
|
940
|
+
await this.select(newConfig);
|
|
941
|
+
stage.select(newConfig.id);
|
|
942
|
+
}
|
|
851
943
|
|
|
852
944
|
this.addModifiedNodeId(target.id);
|
|
853
945
|
this.addModifiedNodeId(parent.id);
|
package/src/theme/nav-menu.scss
CHANGED
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
height: 100%;
|
|
23
23
|
z-index: 1;
|
|
24
24
|
align-items: center;
|
|
25
|
+
flex-wrap: nowrap;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
position: relative;
|
|
28
|
+
min-width: 0;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
.menu-center {
|
|
@@ -32,8 +36,33 @@
|
|
|
32
36
|
justify-content: flex-end;
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
.m-editor-nav-menu-slot-hidden {
|
|
40
|
+
position: absolute;
|
|
41
|
+
left: -99999px;
|
|
42
|
+
top: 0;
|
|
43
|
+
visibility: hidden;
|
|
44
|
+
pointer-events: none;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.m-editor-nav-menu-more-wrapper {
|
|
48
|
+
flex: 0 0 auto;
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
height: 100%;
|
|
52
|
+
|
|
53
|
+
&.m-editor-nav-menu-more-wrapper-hidden {
|
|
54
|
+
visibility: hidden;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.m-editor-nav-menu-more {
|
|
60
|
+
flex: 0 0 auto;
|
|
61
|
+
}
|
|
62
|
+
|
|
35
63
|
.menu-item {
|
|
36
64
|
flex-direction: row;
|
|
65
|
+
flex: 0 0 auto;
|
|
37
66
|
-webkit-box-align: center;
|
|
38
67
|
align-items: center;
|
|
39
68
|
vertical-align: middle;
|
|
@@ -47,6 +76,7 @@
|
|
|
47
76
|
transition: all 0.3s ease 0s;
|
|
48
77
|
border-bottom: 2px solid transparent;
|
|
49
78
|
margin: 0;
|
|
79
|
+
white-space: nowrap;
|
|
50
80
|
|
|
51
81
|
.is-disabled {
|
|
52
82
|
opacity: 0.5;
|
|
@@ -70,6 +100,7 @@
|
|
|
70
100
|
|
|
71
101
|
.menu-item-text {
|
|
72
102
|
color: $nav-color;
|
|
103
|
+
white-space: nowrap;
|
|
73
104
|
}
|
|
74
105
|
|
|
75
106
|
&.rule {
|
|
@@ -84,3 +115,33 @@
|
|
|
84
115
|
}
|
|
85
116
|
}
|
|
86
117
|
}
|
|
118
|
+
|
|
119
|
+
.m-editor-nav-menu-popover {
|
|
120
|
+
.m-editor-nav-menu-overflow-list {
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
gap: 4px;
|
|
124
|
+
padding: 4px 0;
|
|
125
|
+
|
|
126
|
+
.menu-item {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
padding: 4px 8px;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
border-radius: 4px;
|
|
132
|
+
|
|
133
|
+
&:hover {
|
|
134
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&.divider {
|
|
138
|
+
padding: 0;
|
|
139
|
+
cursor: default;
|
|
140
|
+
|
|
141
|
+
&:hover {
|
|
142
|
+
background-color: transparent;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
package/src/type.ts
CHANGED
|
@@ -143,6 +143,7 @@ export interface EditorInstallOptions {
|
|
|
143
143
|
[key: string]: any;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
// #region Services
|
|
146
147
|
export interface Services {
|
|
147
148
|
editorService: EditorService;
|
|
148
149
|
historyService: HistoryService;
|
|
@@ -157,6 +158,7 @@ export interface Services {
|
|
|
157
158
|
keybindingService: KeybindingService;
|
|
158
159
|
stageOverlayService: StageOverlayService;
|
|
159
160
|
}
|
|
161
|
+
// #endregion Services
|
|
160
162
|
|
|
161
163
|
export interface StageOptions {
|
|
162
164
|
runtimeUrl?: string;
|
|
@@ -236,11 +238,13 @@ export interface ComponentGroupState {
|
|
|
236
238
|
list: ComponentGroup[];
|
|
237
239
|
}
|
|
238
240
|
|
|
241
|
+
// #region ColumnLayout
|
|
239
242
|
export enum ColumnLayout {
|
|
240
243
|
LEFT = 'left',
|
|
241
244
|
CENTER = 'center',
|
|
242
245
|
RIGHT = 'right',
|
|
243
246
|
}
|
|
247
|
+
// #endregion ColumnLayout
|
|
244
248
|
|
|
245
249
|
export interface SetColumnWidth {
|
|
246
250
|
[ColumnLayout.LEFT]?: number;
|
|
@@ -309,11 +313,13 @@ export interface UiState {
|
|
|
309
313
|
};
|
|
310
314
|
}
|
|
311
315
|
|
|
316
|
+
// #region EditorNodeInfo
|
|
312
317
|
export interface EditorNodeInfo {
|
|
313
318
|
node: MNode | null;
|
|
314
319
|
parent: MContainer | null;
|
|
315
320
|
page: MPage | MPageFragment | null;
|
|
316
321
|
}
|
|
322
|
+
// #endregion EditorNodeInfo
|
|
317
323
|
|
|
318
324
|
export interface AddMNode {
|
|
319
325
|
type: string;
|
|
@@ -322,6 +328,7 @@ export interface AddMNode {
|
|
|
322
328
|
[key: string]: any;
|
|
323
329
|
}
|
|
324
330
|
|
|
331
|
+
// #region PastePosition
|
|
325
332
|
export interface PastePosition {
|
|
326
333
|
left?: number;
|
|
327
334
|
top?: number;
|
|
@@ -334,7 +341,9 @@ export interface PastePosition {
|
|
|
334
341
|
*/
|
|
335
342
|
offsetY?: number;
|
|
336
343
|
}
|
|
344
|
+
// #endregion PastePosition
|
|
337
345
|
|
|
346
|
+
// #region MenuButton
|
|
338
347
|
/**
|
|
339
348
|
* 菜单按钮
|
|
340
349
|
*/
|
|
@@ -367,7 +376,9 @@ export interface MenuButton {
|
|
|
367
376
|
/** 唯一标识,用于高亮 */
|
|
368
377
|
id?: string | number;
|
|
369
378
|
}
|
|
379
|
+
// #endregion MenuButton
|
|
370
380
|
|
|
381
|
+
// #region MenuComponent
|
|
371
382
|
export interface MenuComponent {
|
|
372
383
|
type: 'component';
|
|
373
384
|
/** Vue3组件 */
|
|
@@ -382,6 +393,7 @@ export interface MenuComponent {
|
|
|
382
393
|
display?: boolean | ((data: Services) => Promise<boolean> | boolean);
|
|
383
394
|
[key: string]: any;
|
|
384
395
|
}
|
|
396
|
+
// #endregion MenuComponent
|
|
385
397
|
|
|
386
398
|
/**
|
|
387
399
|
* '/': 分隔符
|
|
@@ -396,6 +408,7 @@ export interface MenuComponent {
|
|
|
396
408
|
* 'scale-to-original': 缩放到实际大小
|
|
397
409
|
* 'scale-to-fit': 缩放以适应
|
|
398
410
|
*/
|
|
411
|
+
// #region MenuItem
|
|
399
412
|
export type MenuItem =
|
|
400
413
|
| '/'
|
|
401
414
|
| 'delete'
|
|
@@ -411,7 +424,9 @@ export type MenuItem =
|
|
|
411
424
|
| MenuButton
|
|
412
425
|
| MenuComponent
|
|
413
426
|
| string;
|
|
427
|
+
// #endregion MenuItem
|
|
414
428
|
|
|
429
|
+
// #region MenuBarData
|
|
415
430
|
/** 工具栏 */
|
|
416
431
|
export interface MenuBarData {
|
|
417
432
|
/** 顶部工具栏左边项 */
|
|
@@ -421,7 +436,9 @@ export interface MenuBarData {
|
|
|
421
436
|
/** 顶部工具栏右边项 */
|
|
422
437
|
[ColumnLayout.RIGHT]?: MenuItem[];
|
|
423
438
|
}
|
|
439
|
+
// #endregion MenuBarData
|
|
424
440
|
|
|
441
|
+
// #region SideComponent
|
|
425
442
|
export interface SideComponent extends MenuComponent {
|
|
426
443
|
/** 显示文案 */
|
|
427
444
|
text: string;
|
|
@@ -444,21 +461,27 @@ export interface SideComponent extends MenuComponent {
|
|
|
444
461
|
props?: Record<string, any>;
|
|
445
462
|
};
|
|
446
463
|
}
|
|
464
|
+
// #endregion SideComponent
|
|
447
465
|
|
|
466
|
+
// #region SideItemKey
|
|
448
467
|
export enum SideItemKey {
|
|
449
468
|
COMPONENT_LIST = 'component-list',
|
|
450
469
|
LAYER = 'layer',
|
|
451
470
|
CODE_BLOCK = 'code-block',
|
|
452
471
|
DATA_SOURCE = 'data-source',
|
|
453
472
|
}
|
|
473
|
+
// #endregion SideItemKey
|
|
454
474
|
|
|
475
|
+
// #region SideItem
|
|
455
476
|
/**
|
|
456
477
|
* component-list: 组件列表
|
|
457
478
|
* layer: 已选组件树
|
|
458
479
|
* code-block: 代码块
|
|
459
480
|
*/
|
|
460
481
|
export type SideItem = `${SideItemKey}` | SideComponent;
|
|
482
|
+
// #endregion SideItem
|
|
461
483
|
|
|
484
|
+
// #region SideBarData
|
|
462
485
|
/** 工具栏 */
|
|
463
486
|
export interface SideBarData {
|
|
464
487
|
/** 容器类型 */
|
|
@@ -468,7 +491,9 @@ export interface SideBarData {
|
|
|
468
491
|
/** panel列表 */
|
|
469
492
|
items: SideItem[];
|
|
470
493
|
}
|
|
494
|
+
// #endregion SideBarData
|
|
471
495
|
|
|
496
|
+
// #region ComponentItem
|
|
472
497
|
export interface ComponentItem {
|
|
473
498
|
/** 显示文案 */
|
|
474
499
|
text: string;
|
|
@@ -483,19 +508,23 @@ export interface ComponentItem {
|
|
|
483
508
|
[key: string]: any;
|
|
484
509
|
};
|
|
485
510
|
}
|
|
511
|
+
// #endregion ComponentItem
|
|
486
512
|
|
|
513
|
+
// #region ComponentGroup
|
|
487
514
|
export interface ComponentGroup {
|
|
488
515
|
/** 显示文案 */
|
|
489
516
|
title: string;
|
|
490
517
|
/** 组内列表 */
|
|
491
518
|
items: ComponentItem[];
|
|
492
519
|
}
|
|
520
|
+
// #endregion ComponentGroup
|
|
493
521
|
|
|
494
522
|
export enum LayerOffset {
|
|
495
523
|
TOP = 'top',
|
|
496
524
|
BOTTOM = 'bottom',
|
|
497
525
|
}
|
|
498
526
|
|
|
527
|
+
// #region Layout
|
|
499
528
|
/** 容器布局 */
|
|
500
529
|
export enum Layout {
|
|
501
530
|
FLEX = 'flex',
|
|
@@ -503,6 +532,7 @@ export enum Layout {
|
|
|
503
532
|
RELATIVE = 'relative',
|
|
504
533
|
ABSOLUTE = 'absolute',
|
|
505
534
|
}
|
|
535
|
+
// #endregion Layout
|
|
506
536
|
|
|
507
537
|
export enum Keys {
|
|
508
538
|
ESCAPE = 'Space',
|
|
@@ -575,8 +605,11 @@ export interface CodeParamStatement {
|
|
|
575
605
|
[key: string]: any;
|
|
576
606
|
}
|
|
577
607
|
|
|
608
|
+
// #region HistoryOpType
|
|
578
609
|
export type HistoryOpType = 'add' | 'remove' | 'update';
|
|
610
|
+
// #endregion HistoryOpType
|
|
579
611
|
|
|
612
|
+
// #region StepValue
|
|
580
613
|
export interface StepValue {
|
|
581
614
|
/** 页面信息 */
|
|
582
615
|
data: { name: string; id: Id };
|
|
@@ -597,6 +630,7 @@ export interface StepValue {
|
|
|
597
630
|
/** opType 'update': 变更前后的节点快照 */
|
|
598
631
|
updatedItems?: { oldNode: MNode; newNode: MNode }[];
|
|
599
632
|
}
|
|
633
|
+
// #endregion StepValue
|
|
600
634
|
|
|
601
635
|
export interface HistoryState {
|
|
602
636
|
pageId?: Id;
|
|
@@ -660,6 +694,7 @@ export interface KeyBindingCacheItem {
|
|
|
660
694
|
bound: boolean;
|
|
661
695
|
}
|
|
662
696
|
|
|
697
|
+
// #region DatasourceTypeOption
|
|
663
698
|
/** 可新增的数据源类型选项 */
|
|
664
699
|
export interface DatasourceTypeOption {
|
|
665
700
|
/** 数据源类型 */
|
|
@@ -667,6 +702,7 @@ export interface DatasourceTypeOption {
|
|
|
667
702
|
/** 数据源名称 */
|
|
668
703
|
text: string;
|
|
669
704
|
}
|
|
705
|
+
// #endregion DatasourceTypeOption
|
|
670
706
|
|
|
671
707
|
/** 组件树节点状态 */
|
|
672
708
|
export interface LayerNodeStatus {
|
|
@@ -688,12 +724,14 @@ export enum DragType {
|
|
|
688
724
|
LAYER_TREE = 'layer-tree',
|
|
689
725
|
}
|
|
690
726
|
|
|
727
|
+
// #region TreeNodeData
|
|
691
728
|
export interface TreeNodeData {
|
|
692
729
|
id: Id;
|
|
693
730
|
name?: string;
|
|
694
731
|
items?: TreeNodeData[];
|
|
695
732
|
[key: string]: any;
|
|
696
733
|
}
|
|
734
|
+
// #endregion TreeNodeData
|
|
697
735
|
|
|
698
736
|
/** 判断组件树节点是否可展开(即是否要展示为拥有子节点的形态)的函数 */
|
|
699
737
|
export type IsExpandableFunction = (_data: TreeNodeData, _nodeStatusMap: Map<Id, LayerNodeStatus>) => boolean;
|
|
@@ -775,9 +813,12 @@ export interface EventBus extends EventEmitter {
|
|
|
775
813
|
emit<Name extends keyof EventBusEvent, Param extends EventBusEvent[Name]>(eventName: Name, ...args: Param): boolean;
|
|
776
814
|
}
|
|
777
815
|
|
|
816
|
+
// #region PropsFormConfigFunction
|
|
778
817
|
export type PropsFormConfigFunction = (data: { editorService: EditorService }) => FormConfig;
|
|
818
|
+
// #endregion PropsFormConfigFunction
|
|
779
819
|
export type PropsFormValueFunction = (data: { editorService: EditorService }) => Partial<MNode>;
|
|
780
820
|
|
|
821
|
+
// #region PageBarSortOptions
|
|
781
822
|
export type PartSortableOptions = Omit<Options, 'onStart' | 'onUpdate'>;
|
|
782
823
|
export interface PageBarSortOptions extends PartSortableOptions {
|
|
783
824
|
/** 在onUpdate之后调用 */
|
|
@@ -785,6 +826,7 @@ export interface PageBarSortOptions extends PartSortableOptions {
|
|
|
785
826
|
/** 在onStart之前调用 */
|
|
786
827
|
beforeStart?: (event: SortableEvent, sortable: Sortable) => void | Promise<void>;
|
|
787
828
|
}
|
|
829
|
+
// #endregion PageBarSortOptions
|
|
788
830
|
|
|
789
831
|
export type CustomContentMenuFunction = (
|
|
790
832
|
menus: (MenuButton | MenuComponent)[],
|
package/src/utils/undo-redo.ts
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import { cloneDeep } from 'lodash-es';
|
|
20
20
|
|
|
21
|
+
// #region UndoRedo
|
|
21
22
|
export class UndoRedo<T = any> {
|
|
22
23
|
private elementList: T[];
|
|
23
24
|
private listCursor: number;
|
|
@@ -75,3 +76,4 @@ export class UndoRedo<T = any> {
|
|
|
75
76
|
return cloneDeep(this.elementList[this.listCursor - 1]);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
79
|
+
// #endregion UndoRedo
|