@tmagic/editor 1.0.0-beta.12 → 1.0.0-beta.15

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.
Files changed (102) hide show
  1. package/coverage/clover.xml +1540 -0
  2. package/coverage/coverage-final.json +35 -0
  3. package/coverage/lcov-report/base.css +224 -0
  4. package/coverage/lcov-report/block-navigation.js +87 -0
  5. package/coverage/lcov-report/favicon.png +0 -0
  6. package/coverage/lcov-report/index.html +206 -0
  7. package/coverage/lcov-report/prettify.css +1 -0
  8. package/coverage/lcov-report/prettify.js +2 -0
  9. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  10. package/coverage/lcov-report/sorter.js +196 -0
  11. package/coverage/lcov-report/src/Editor.vue.html +787 -0
  12. package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
  13. package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
  14. package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
  15. package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
  16. package/coverage/lcov-report/src/components/index.html +161 -0
  17. package/coverage/lcov-report/src/index.html +131 -0
  18. package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
  19. package/coverage/lcov-report/src/layouts/Framework.vue.html +304 -0
  20. package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
  21. package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +316 -0
  22. package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
  23. package/coverage/lcov-report/src/layouts/index.html +176 -0
  24. package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
  25. package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
  26. package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
  27. package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +343 -0
  28. package/coverage/lcov-report/src/layouts/sidebar/index.html +161 -0
  29. package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
  30. package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +757 -0
  31. package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
  32. package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +586 -0
  33. package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
  34. package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
  35. package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
  36. package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
  37. package/coverage/lcov-report/src/services/events.ts.html +331 -0
  38. package/coverage/lcov-report/src/services/history.ts.html +478 -0
  39. package/coverage/lcov-report/src/services/index.html +206 -0
  40. package/coverage/lcov-report/src/services/props.ts.html +415 -0
  41. package/coverage/lcov-report/src/services/ui.ts.html +514 -0
  42. package/coverage/lcov-report/src/type.ts.html +844 -0
  43. package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
  44. package/coverage/lcov-report/src/utils/config.ts.html +172 -0
  45. package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
  46. package/coverage/lcov-report/src/utils/index.html +221 -0
  47. package/coverage/lcov-report/src/utils/index.ts.html +151 -0
  48. package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
  49. package/coverage/lcov-report/src/utils/props.ts.html +796 -0
  50. package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
  51. package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
  52. package/coverage/lcov-report/undo-redo.ts.html +313 -0
  53. package/coverage/lcov.info +3676 -0
  54. package/dist/style.css +47 -22
  55. package/dist/tmagic-editor.es.js +921 -603
  56. package/dist/tmagic-editor.es.js.map +1 -1
  57. package/dist/tmagic-editor.umd.js +920 -602
  58. package/dist/tmagic-editor.umd.js.map +1 -1
  59. package/dist/types/src/Editor.vue.d.ts +1 -1
  60. package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
  61. package/dist/types/src/index.d.ts +1 -0
  62. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -0
  63. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +2 -0
  64. package/dist/types/src/services/editor.d.ts +5 -2
  65. package/dist/types/src/services/history.d.ts +1 -0
  66. package/dist/types/src/services/props.d.ts +2 -2
  67. package/dist/types/src/services/ui.d.ts +1 -0
  68. package/dist/types/src/type.d.ts +6 -8
  69. package/dist/types/src/utils/editor.d.ts +2 -2
  70. package/dist/types/src/utils/polyfills.d.ts +0 -0
  71. package/package.json +26 -12
  72. package/src/components/ContentMenu.vue +107 -0
  73. package/src/components/ScrollViewer.vue +1 -1
  74. package/src/components/ToolButton.vue +69 -30
  75. package/src/index.ts +2 -0
  76. package/src/layouts/Framework.vue +6 -6
  77. package/src/layouts/sidebar/ComponentListPanel.vue +23 -1
  78. package/src/layouts/sidebar/LayerMenu.vue +91 -72
  79. package/src/layouts/sidebar/LayerPanel.vue +23 -49
  80. package/src/layouts/workspace/PageBar.vue +35 -6
  81. package/src/layouts/workspace/Stage.vue +41 -44
  82. package/src/layouts/workspace/ViewerMenu.vue +104 -67
  83. package/src/layouts/workspace/Workspace.vue +74 -16
  84. package/src/services/BaseService.ts +1 -1
  85. package/src/services/editor.ts +97 -10
  86. package/src/services/history.ts +7 -0
  87. package/src/services/props.ts +2 -3
  88. package/src/services/ui.ts +5 -0
  89. package/src/theme/common/var.scss +1 -0
  90. package/src/theme/component-list-panel.scss +2 -0
  91. package/src/theme/content-menu.scss +33 -26
  92. package/src/theme/layer-panel.scss +2 -1
  93. package/src/theme/nav-menu.scss +6 -2
  94. package/src/theme/page-bar.scss +22 -1
  95. package/src/type.ts +6 -8
  96. package/src/utils/editor.ts +7 -3
  97. package/{vite.config.ts → src/utils/polyfills.ts} +4 -12
  98. package/src/utils/props.ts +19 -0
  99. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -980
  100. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -188
  101. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
  102. package/tsconfig.json +0 -9
@@ -1,47 +1,31 @@
1
1
  <template>
2
- <div class="magic-editor-content-menu" ref="menu">
3
- <div>
4
- <div class="magic-editor-content-menu-item" @click="() => center()" v-if="canCenter">水平居中</div>
5
- <div class="magic-editor-content-menu-item" @click="() => copy()">复制</div>
6
- <div class="magic-editor-content-menu-item" @click="paste" v-if="canPaste">粘贴</div>
7
- <template v-if="canMoveZPos">
8
- <div class="separation"></div>
9
- <div class="magic-editor-content-menu-item" @click="topItem">上移一层</div>
10
- <div class="magic-editor-content-menu-item" @click="bottomItem">下移一层</div>
11
- <div class="magic-editor-content-menu-item" @click="top">置顶</div>
12
- <div class="magic-editor-content-menu-item" @click="bottom">置底</div>
13
- </template>
14
- <template v-if="canDelete">
15
- <div class="separation"></div>
16
- <div class="magic-editor-content-menu-item" @click="() => remove()">删除</div>
17
- </template>
18
- <div class="separation"></div>
19
- <div class="magic-editor-content-menu-item" @click="clearGuides">清空参考线</div>
20
- </div>
21
- </div>
2
+ <content-menu :menu-data="menuData" ref="menu"></content-menu>
22
3
  </template>
23
4
 
24
5
  <script lang="ts">
25
- import { computed, defineComponent, inject, onMounted, ref, watch } from 'vue';
6
+ import { computed, defineComponent, inject, markRaw, onMounted, reactive, ref, watch } from 'vue';
7
+ import { Bottom, Delete, DocumentCopy, Top } from '@element-plus/icons';
26
8
 
27
9
  import { NodeType } from '@tmagic/schema';
28
10
  import type StageCore from '@tmagic/stage';
29
11
 
30
- import { LayerOffset, Layout, Services } from '@editor/type';
12
+ import ContentMenu from '@editor/components/ContentMenu.vue';
13
+ import { LayerOffset, Layout, MenuItem, Services } from '@editor/type';
31
14
  import { COPY_STORAGE_KEY } from '@editor/utils/editor';
32
15
 
33
16
  export default defineComponent({
34
- name: 'magic-editor-ui-viewer-menu',
17
+ components: { ContentMenu },
35
18
 
36
19
  setup() {
37
20
  const services = inject<Services>('services');
38
21
  const editorService = services?.editorService;
39
- const menu = ref<HTMLDivElement>();
22
+ const menu = ref<InstanceType<typeof ContentMenu>>();
40
23
  const canPaste = ref(false);
41
24
  const canCenter = ref(false);
42
25
 
43
26
  const node = computed(() => editorService?.get('node'));
44
27
  const parent = computed(() => editorService?.get('parent'));
28
+ const isPage = computed(() => node.value?.type === NodeType.PAGE);
45
29
 
46
30
  onMounted(() => {
47
31
  const data = globalThis.localStorage.getItem(COPY_STORAGE_KEY);
@@ -62,49 +46,102 @@ export default defineComponent({
62
46
 
63
47
  return {
64
48
  menu,
65
- canPaste,
66
-
67
- canDelete: computed(() => node.value?.type !== NodeType.PAGE),
68
- canMoveZPos: computed(() => node.value?.type !== NodeType.PAGE),
69
- canCenter,
70
-
71
- center() {
72
- node.value && editorService?.alignCenter(node.value);
73
- },
74
-
75
- copy() {
76
- node.value && editorService?.copy(node.value);
77
- canPaste.value = true;
78
- },
79
-
80
- paste() {
81
- const top = menu.value?.offsetTop || 0;
82
- const left = menu.value?.offsetLeft || 0;
83
- editorService?.paste({ left, top });
84
- },
85
-
86
- remove() {
87
- node.value && editorService?.remove(node.value);
88
- },
89
-
90
- top() {
91
- editorService?.moveLayer(LayerOffset.TOP);
92
- },
93
-
94
- bottom() {
95
- editorService?.moveLayer(LayerOffset.BOTTOM);
96
- },
97
-
98
- topItem() {
99
- editorService?.moveLayer(1);
100
- },
101
-
102
- bottomItem() {
103
- editorService?.moveLayer(-1);
104
- },
105
-
106
- clearGuides() {
107
- editorService?.get<StageCore>('stage').clearGuides();
49
+ menuData: reactive<MenuItem[]>([
50
+ {
51
+ type: 'button',
52
+ text: '水平居中',
53
+ display: () => canCenter.value,
54
+ handler: () => {
55
+ node.value && editorService?.alignCenter(node.value);
56
+ },
57
+ },
58
+ {
59
+ type: 'button',
60
+ text: '复制',
61
+ icon: markRaw(DocumentCopy),
62
+ handler: () => {
63
+ node.value && editorService?.copy(node.value);
64
+ canPaste.value = true;
65
+ },
66
+ },
67
+ {
68
+ type: 'button',
69
+ text: '粘贴',
70
+ display: () => canPaste.value,
71
+ handler: () => {
72
+ const top = menu.value?.$el.offsetTop || 0;
73
+ const left = menu.value?.$el.offsetLeft || 0;
74
+ editorService?.paste({ left, top });
75
+ },
76
+ },
77
+ {
78
+ type: 'divider',
79
+ direction: 'horizontal',
80
+ display: () => !isPage.value,
81
+ },
82
+ {
83
+ type: 'button',
84
+ text: '上移一层',
85
+ icon: markRaw(Top),
86
+ display: () => !isPage.value,
87
+ handler: () => {
88
+ editorService?.moveLayer(1);
89
+ },
90
+ },
91
+ {
92
+ type: 'button',
93
+ text: '下移一层',
94
+ icon: markRaw(Bottom),
95
+ display: () => !isPage.value,
96
+ handler: () => {
97
+ editorService?.moveLayer(-1);
98
+ },
99
+ },
100
+ {
101
+ type: 'button',
102
+ text: '置顶',
103
+ display: () => !isPage.value,
104
+ handler: () => {
105
+ editorService?.moveLayer(LayerOffset.TOP);
106
+ },
107
+ },
108
+ {
109
+ type: 'button',
110
+ text: '置底',
111
+ display: () => !isPage.value,
112
+ handler: () => {
113
+ editorService?.moveLayer(LayerOffset.BOTTOM);
114
+ },
115
+ },
116
+ {
117
+ type: 'divider',
118
+ direction: 'horizontal',
119
+ display: () => !isPage.value,
120
+ },
121
+ {
122
+ type: 'button',
123
+ text: '删除',
124
+ icon: Delete,
125
+ display: () => !isPage.value,
126
+ handler: () => {
127
+ node.value && editorService?.remove(node.value);
128
+ },
129
+ },
130
+ {
131
+ type: 'divider',
132
+ direction: 'horizontal',
133
+ },
134
+ {
135
+ type: 'button',
136
+ text: '清空参考线',
137
+ handler: () => {
138
+ editorService?.get<StageCore>('stage').clearGuides();
139
+ },
140
+ },
141
+ ]),
142
+
143
+ show(e: MouseEvent) {
144
+ menu.value?.show(e);
108
145
  },
109
146
  };
110
147
  },
@@ -24,6 +24,7 @@ import KeyController from 'keycon';
24
24
  import type { MNode, MPage } from '@tmagic/schema';
25
25
  import type { MoveableOptions } from '@tmagic/stage';
26
26
  import StageCore from '@tmagic/stage';
27
+ import { isPage } from '@tmagic/utils';
27
28
 
28
29
  import type { Services } from '@editor/type';
29
30
 
@@ -64,38 +65,95 @@ export default defineComponent({
64
65
  workspace.value?.focus();
65
66
  };
66
67
 
67
- const mouseleaveHandler = () => {
68
- workspace.value?.blur();
69
- };
70
-
71
68
  onMounted(() => {
72
69
  workspace.value?.addEventListener('mouseenter', mouseenterHandler);
73
70
 
74
- workspace.value?.addEventListener('mouseleave', mouseleaveHandler);
75
-
76
71
  keycon = new KeyController(workspace.value);
77
72
 
73
+ const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
74
+
75
+ const ctrl = isMac ? 'meta' : 'ctrl';
76
+
78
77
  keycon
79
- .keyup('delete', () => {
80
- node.value && services?.editorService.remove(node.value);
78
+ .keyup('delete', (e) => {
79
+ e.inputEvent.preventDefault();
80
+ if (!node.value || isPage(node.value)) return;
81
+ services?.editorService.remove(node.value);
81
82
  })
82
- .keyup(['ctrl', 'c'], () => {
83
+ .keydown([ctrl, 'c'], (e) => {
84
+ e.inputEvent.preventDefault();
83
85
  node.value && services?.editorService.copy(node.value);
84
86
  })
85
- .keyup(['ctrl', 'v'], () => {
87
+ .keydown([ctrl, 'v'], (e) => {
88
+ e.inputEvent.preventDefault();
86
89
  node.value && services?.editorService.paste();
87
90
  })
88
- .keyup(['ctrl', 'x'], () => {
89
- if (node.value && services) {
90
- services.editorService.copy(node.value);
91
- services.editorService.remove(node.value);
92
- }
91
+ .keydown([ctrl, 'x'], (e) => {
92
+ e.inputEvent.preventDefault();
93
+ if (!node.value || isPage(node.value)) return;
94
+ services?.editorService.copy(node.value);
95
+ services?.editorService.remove(node.value);
96
+ })
97
+ .keydown([ctrl, 'z'], (e) => {
98
+ e.inputEvent.preventDefault();
99
+ services?.editorService.undo();
100
+ })
101
+ .keydown([ctrl, 'shift', 'z'], (e) => {
102
+ e.inputEvent.preventDefault();
103
+ services?.editorService.redo();
104
+ })
105
+ .keydown('up', (e) => {
106
+ e.inputEvent.preventDefault();
107
+ services?.editorService.move(0, -1);
108
+ })
109
+ .keydown('down', (e) => {
110
+ e.inputEvent.preventDefault();
111
+ services?.editorService.move(0, 1);
112
+ })
113
+ .keydown('left', (e) => {
114
+ e.inputEvent.preventDefault();
115
+ services?.editorService.move(-1, 0);
116
+ })
117
+ .keydown('right', (e) => {
118
+ e.inputEvent.preventDefault();
119
+ services?.editorService.move(1, 0);
120
+ })
121
+ .keydown([ctrl, 'up'], (e) => {
122
+ e.inputEvent.preventDefault();
123
+ services?.editorService.move(0, -10);
124
+ })
125
+ .keydown([ctrl, 'down'], (e) => {
126
+ e.inputEvent.preventDefault();
127
+ services?.editorService.move(0, 10);
128
+ })
129
+ .keydown([ctrl, 'left'], (e) => {
130
+ e.inputEvent.preventDefault();
131
+ services?.editorService.move(-10, 0);
132
+ })
133
+ .keydown([ctrl, 'right'], (e) => {
134
+ e.inputEvent.preventDefault();
135
+ services?.editorService.move(10, 0);
136
+ })
137
+ .keydown('tab', (e) => {
138
+ e.inputEvent.preventDefault();
139
+ services?.editorService.selectNextNode();
140
+ })
141
+ .keydown([ctrl, 'tab'], (e) => {
142
+ e.inputEvent.preventDefault();
143
+ services?.editorService.selectNextPage();
144
+ })
145
+ .keydown([ctrl, '='], (e) => {
146
+ e.inputEvent.preventDefault();
147
+ services?.uiService.zoom(0.1);
148
+ })
149
+ .keydown([ctrl, '-'], (e) => {
150
+ e.inputEvent.preventDefault();
151
+ services?.uiService.zoom(-0.1);
93
152
  });
94
153
  });
95
154
 
96
155
  onUnmounted(() => {
97
156
  workspace.value?.removeEventListener('mouseenter', mouseenterHandler);
98
- workspace.value?.removeEventListener('mouseleave', mouseleaveHandler);
99
157
  keycon.destroy();
100
158
  });
101
159
 
@@ -53,7 +53,7 @@ const doAction = async (
53
53
  let returnValue: any = await fn(beforeArgs, sourceMethod.bind(scope));
54
54
 
55
55
  for (const afterMethod of scope.pluginOptionsList[afterMethodName]) {
56
- returnValue = await afterMethod(...beforeArgs, returnValue);
56
+ returnValue = await afterMethod(returnValue, ...beforeArgs);
57
57
 
58
58
  if (isError(returnValue)) throw returnValue;
59
59
  }
@@ -23,7 +23,7 @@ import serialize from 'serialize-javascript';
23
23
  import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
24
24
  import { NodeType } from '@tmagic/schema';
25
25
  import StageCore from '@tmagic/stage';
26
- import { getNodePath, isPop } from '@tmagic/utils';
26
+ import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
27
27
 
28
28
  import historyService, { StepValue } from '@editor/services/history';
29
29
  import propsService from '@editor/services/props';
@@ -54,6 +54,7 @@ class Editor extends BaseService {
54
54
  stage: null,
55
55
  highlightNode: null,
56
56
  modifiedNodeIds: new Map(),
57
+ pageLength: 0,
57
58
  });
58
59
 
59
60
  constructor() {
@@ -69,6 +70,7 @@ class Editor extends BaseService {
69
70
  'paste',
70
71
  'alignCenter',
71
72
  'moveLayer',
73
+ 'move',
72
74
  'undo',
73
75
  'redo',
74
76
  'highlight',
@@ -89,6 +91,7 @@ class Editor extends BaseService {
89
91
  log('store set ', name, ' ', value);
90
92
 
91
93
  if (name === 'root') {
94
+ this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
92
95
  this.emit('root-change', value);
93
96
  }
94
97
  }
@@ -108,7 +111,7 @@ class Editor extends BaseService {
108
111
  * @returns {EditorNodeInfo}
109
112
  */
110
113
  public getNodeInfo(id: Id): EditorNodeInfo {
111
- const root = this.get<MApp | null>('root');
114
+ const root = toRaw(this.get<MApp | null>('root'));
112
115
  if (!root) return {};
113
116
 
114
117
  if (id === root.id) {
@@ -159,13 +162,15 @@ class Editor extends BaseService {
159
162
  /**
160
163
  * 只有容器拥有布局
161
164
  */
162
- public async getLayout(node: MNode): Promise<Layout> {
163
- if (node.layout) {
164
- return node.layout;
165
+ public async getLayout(parent: MNode, node?: MNode): Promise<Layout> {
166
+ if (node && typeof node !== 'function' && isFixed(node)) return Layout.FIXED;
167
+
168
+ if (parent.layout) {
169
+ return parent.layout;
165
170
  }
166
171
 
167
172
  // 如果该节点没有设置position,则认为是流式布局,例如获取root的布局时
168
- if (!node.style?.position) {
173
+ if (!parent.style?.position) {
169
174
  return Layout.RELATIVE;
170
175
  }
171
176
 
@@ -188,9 +193,45 @@ class Editor extends BaseService {
188
193
  } else {
189
194
  historyService.empty();
190
195
  }
196
+
197
+ this.emit('select', node);
198
+
191
199
  return node!;
192
200
  }
193
201
 
202
+ public async selectNextNode(): Promise<MNode> | never {
203
+ const node = toRaw(this.get('node'));
204
+
205
+ if (!node || isPage(node) || node.type === NodeType.ROOT) return node;
206
+
207
+ const parent = toRaw(this.getParentById(node.id));
208
+
209
+ if (!parent) return node;
210
+
211
+ const index = getNodeIndex(node, parent);
212
+
213
+ const nextNode = parent.items[index + 1] || parent.items[0];
214
+
215
+ await this.select(nextNode);
216
+ this.get<StageCore>('stage')?.select(nextNode.id);
217
+
218
+ return nextNode;
219
+ }
220
+
221
+ public async selectNextPage(): Promise<MNode> | never {
222
+ const root = toRaw(this.get<MApp>('root'));
223
+ const page = toRaw(this.get('page'));
224
+
225
+ const index = getNodeIndex(page, root);
226
+
227
+ const nextPage = root.items[index + 1] || root.items[0];
228
+
229
+ await this.select(nextPage);
230
+ this.get<StageCore>('stage')?.select(nextPage.id);
231
+
232
+ return nextPage;
233
+ }
234
+
194
235
  /**
195
236
  * 高亮指定节点
196
237
  * @param config 指定节点配置或者ID
@@ -209,12 +250,14 @@ class Editor extends BaseService {
209
250
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
210
251
  * @returns 添加后的节点
211
252
  */
212
- public async add({ type, ...config }: AddMNode, parent?: MContainer | null): Promise<MNode> {
253
+ public async add(addNode: AddMNode, parent?: MContainer | null): Promise<MNode> {
254
+ const { type, ...config } = addNode;
213
255
  const curNode = this.get<MContainer>('node');
214
256
 
215
257
  let parentNode: MNode | undefined;
258
+ const isPage = type === NodeType.PAGE;
216
259
 
217
- if (type === NodeType.PAGE) {
260
+ if (isPage) {
218
261
  parentNode = this.get<MApp>('root');
219
262
  // 由于支持中间件扩展,在parent参数为undefined时,parent会变成next函数
220
263
  } else if (parent && typeof parent !== 'function') {
@@ -227,7 +270,7 @@ class Editor extends BaseService {
227
270
 
228
271
  if (!parentNode) throw new Error('未找到父元素');
229
272
 
230
- const layout = await this.getLayout(parentNode);
273
+ const layout = await this.getLayout(toRaw(parentNode), addNode as MNode);
231
274
  const newNode = initPosition(
232
275
  { ...toRaw(await propsService.getPropsValue(type, config)) },
233
276
  layout,
@@ -254,6 +297,12 @@ class Editor extends BaseService {
254
297
 
255
298
  stage?.select(newNode.id);
256
299
 
300
+ if (isPage) {
301
+ this.state.pageLength += 1;
302
+ }
303
+
304
+ this.emit('add', newNode);
305
+
257
306
  return newNode;
258
307
  }
259
308
 
@@ -282,9 +331,23 @@ class Editor extends BaseService {
282
331
  stage?.remove({ id: node.id, root: this.get('root') });
283
332
 
284
333
  if (node.type === NodeType.PAGE) {
334
+ this.state.pageLength -= 1;
335
+
285
336
  if (root.items[0]) {
286
337
  await this.select(root.items[0]);
287
338
  stage?.select(root.items[0].id);
339
+ } else {
340
+ this.set('node', null);
341
+ this.set('parent', null);
342
+ this.set('page', null);
343
+ this.set('stage', null);
344
+ this.set('highlightNode', null);
345
+ this.resetModifiedNodeId();
346
+ historyService.reset();
347
+
348
+ this.emit('remove', node);
349
+
350
+ return node;
288
351
  }
289
352
  } else {
290
353
  await this.select(parent);
@@ -294,6 +357,8 @@ class Editor extends BaseService {
294
357
  this.addModifiedNodeId(parent.id);
295
358
  this.pushHistoryState();
296
359
 
360
+ this.emit('remove', node);
361
+
297
362
  return node;
298
363
  }
299
364
 
@@ -355,6 +420,8 @@ class Editor extends BaseService {
355
420
  this.addModifiedNodeId(newConfig.id);
356
421
  this.pushHistoryState();
357
422
 
423
+ this.emit('update', newConfig);
424
+
358
425
  return newConfig;
359
426
  }
360
427
 
@@ -432,7 +499,7 @@ class Editor extends BaseService {
432
499
  public async alignCenter(config: MNode): Promise<MNode | void> {
433
500
  const parent = this.get<MContainer>('parent');
434
501
  const node = this.get<MNode>('node');
435
- const layout = await this.getLayout(parent);
502
+ const layout = await this.getLayout(toRaw(parent), toRaw(node));
436
503
  if (layout === Layout.RELATIVE) {
437
504
  return;
438
505
  }
@@ -490,6 +557,26 @@ class Editor extends BaseService {
490
557
  return value;
491
558
  }
492
559
 
560
+ public async move(left: number, top: number) {
561
+ const node = toRaw(this.get('node'));
562
+ if (!node || isPage(node)) return;
563
+
564
+ const { style, id } = node;
565
+ if (!style || style.position !== 'absolute') return;
566
+
567
+ if (top && !isNumber(style.top)) return;
568
+ if (left && !isNumber(style.left)) return;
569
+
570
+ this.update({
571
+ id,
572
+ style: {
573
+ ...style,
574
+ left: Number(style.left) + left,
575
+ top: Number(style.top) + top,
576
+ },
577
+ });
578
+ }
579
+
493
580
  public destroy() {
494
581
  this.removeAllListeners();
495
582
  this.set('root', null);
@@ -51,6 +51,13 @@ class History extends BaseService {
51
51
  this.on('change', this.setCanUndoRedo);
52
52
  }
53
53
 
54
+ public reset() {
55
+ this.state.pageSteps = {};
56
+ this.state.pageId = undefined;
57
+ this.state.canRedo = false;
58
+ this.state.canUndo = false;
59
+ }
60
+
54
61
  public changePage(page: MPage): void {
55
62
  if (!page) return;
56
63
 
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  import { reactive } from 'vue';
20
- import { cloneDeep } from 'lodash-es';
20
+ import { cloneDeep, mergeWith } from 'lodash-es';
21
21
 
22
22
  import type { FormConfig } from '@tmagic/form';
23
23
  import type { MComponent, MNode } from '@tmagic/schema';
@@ -100,8 +100,7 @@ class Props extends BaseService {
100
100
 
101
101
  return cloneDeep({
102
102
  ...getDefaultPropsValue(type),
103
- ...defaultValue,
104
- ...(this.state.propsValueMap[type] || {}),
103
+ ...mergeWith(this.state.propsValueMap[type] || {}, defaultValue),
105
104
  });
106
105
  }
107
106
  }
@@ -91,6 +91,11 @@ class Ui extends BaseService {
91
91
  return (state as any)[name];
92
92
  }
93
93
 
94
+ public zoom(zoom: number) {
95
+ this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
96
+ if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
97
+ }
98
+
94
99
  private setColumnWidth({ left, center, right }: SetColumnWidth) {
95
100
  const columnWidth = {
96
101
  ...toRaw(this.get<GetColumnWidth>('columnWidth')),
@@ -2,6 +2,7 @@ $--theme-color: #2882e0;
2
2
 
3
3
  $--font-color: #070303;
4
4
  $--border-color: #d9dbdd;
5
+ $--hover-color: #f3f5f9;
5
6
 
6
7
  $--nav-height: 35px;
7
8
  $--nav-color: #070303;
@@ -12,6 +12,7 @@
12
12
  top: 0;
13
13
  left: 0;
14
14
  box-sizing: border-box;
15
+ z-index: 1;
15
16
 
16
17
  .el-input__prefix {
17
18
  padding: 10px;
@@ -62,6 +63,7 @@
62
63
  color: $--font-color;
63
64
  flex-direction: column;
64
65
  width: 42px;
66
+ cursor: pointer;
65
67
 
66
68
  i {
67
69
  font-size: 20px;