@tmagic/editor 1.0.0-beta.8 → 1.0.0-rc.2

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 (121) hide show
  1. package/README.md +1 -0
  2. package/coverage/clover.xml +1556 -0
  3. package/coverage/coverage-final.json +36 -0
  4. package/coverage/lcov-report/base.css +224 -0
  5. package/coverage/lcov-report/block-navigation.js +87 -0
  6. package/coverage/lcov-report/favicon.png +0 -0
  7. package/coverage/lcov-report/index.html +206 -0
  8. package/coverage/lcov-report/prettify.css +1 -0
  9. package/coverage/lcov-report/prettify.js +2 -0
  10. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  11. package/coverage/lcov-report/sorter.js +196 -0
  12. package/coverage/lcov-report/src/Editor.vue.html +802 -0
  13. package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
  14. package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
  15. package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
  16. package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
  17. package/coverage/lcov-report/src/components/index.html +161 -0
  18. package/coverage/lcov-report/src/index.html +131 -0
  19. package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
  20. package/coverage/lcov-report/src/layouts/Framework.vue.html +343 -0
  21. package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
  22. package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +319 -0
  23. package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
  24. package/coverage/lcov-report/src/layouts/index.html +176 -0
  25. package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
  26. package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
  27. package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
  28. package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +226 -0
  29. package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +289 -0
  30. package/coverage/lcov-report/src/layouts/sidebar/index.html +176 -0
  31. package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
  32. package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +760 -0
  33. package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
  34. package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +598 -0
  35. package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
  36. package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
  37. package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
  38. package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
  39. package/coverage/lcov-report/src/services/events.ts.html +331 -0
  40. package/coverage/lcov-report/src/services/history.ts.html +478 -0
  41. package/coverage/lcov-report/src/services/index.html +206 -0
  42. package/coverage/lcov-report/src/services/props.ts.html +415 -0
  43. package/coverage/lcov-report/src/services/ui.ts.html +580 -0
  44. package/coverage/lcov-report/src/type.ts.html +850 -0
  45. package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
  46. package/coverage/lcov-report/src/utils/config.ts.html +172 -0
  47. package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
  48. package/coverage/lcov-report/src/utils/index.html +221 -0
  49. package/coverage/lcov-report/src/utils/index.ts.html +151 -0
  50. package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
  51. package/coverage/lcov-report/src/utils/props.ts.html +796 -0
  52. package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
  53. package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
  54. package/coverage/lcov.info +3747 -0
  55. package/dist/style.css +91 -45
  56. package/dist/tmagic-editor.es.js +1462 -2003
  57. package/dist/tmagic-editor.es.js.map +1 -1
  58. package/dist/tmagic-editor.umd.js +1461 -2003
  59. package/dist/tmagic-editor.umd.js.map +1 -1
  60. package/dist/types/src/Editor.vue.d.ts +10 -1
  61. package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
  62. package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
  63. package/dist/types/src/index.d.ts +1 -0
  64. package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
  65. package/dist/types/src/layouts/Framework.vue.d.ts +15 -3
  66. package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -1
  67. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
  68. package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
  69. package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
  70. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +10 -3
  71. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -6
  72. package/dist/types/src/services/BaseService.d.ts +4 -1
  73. package/dist/types/src/services/editor.d.ts +16 -6
  74. package/dist/types/src/services/history.d.ts +1 -0
  75. package/dist/types/src/services/props.d.ts +2 -2
  76. package/dist/types/src/services/ui.d.ts +2 -0
  77. package/dist/types/src/type.d.ts +16 -9
  78. package/dist/types/src/utils/editor.d.ts +5 -4
  79. package/dist/types/src/utils/polyfills.d.ts +0 -0
  80. package/package.json +44 -12
  81. package/src/Editor.vue +6 -1
  82. package/src/components/ContentMenu.vue +107 -0
  83. package/src/components/ScrollViewer.vue +1 -1
  84. package/src/components/ToolButton.vue +72 -31
  85. package/src/fields/UISelect.vue +14 -6
  86. package/src/index.ts +2 -0
  87. package/src/layouts/AddPageBox.vue +3 -1
  88. package/src/layouts/CodeEditor.vue +20 -13
  89. package/src/layouts/Framework.vue +20 -7
  90. package/src/layouts/PropsPanel.vue +5 -4
  91. package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
  92. package/src/layouts/sidebar/LayerMenu.vue +91 -96
  93. package/src/layouts/sidebar/LayerPanel.vue +80 -59
  94. package/src/layouts/sidebar/Sidebar.vue +13 -52
  95. package/src/layouts/sidebar/TabPane.vue +68 -0
  96. package/src/layouts/workspace/PageBar.vue +145 -17
  97. package/src/layouts/workspace/Stage.vue +56 -64
  98. package/src/layouts/workspace/ViewerMenu.vue +107 -68
  99. package/src/layouts/workspace/Workspace.vue +110 -18
  100. package/src/services/BaseService.ts +70 -22
  101. package/src/services/editor.ts +197 -64
  102. package/src/services/history.ts +7 -0
  103. package/src/services/props.ts +3 -3
  104. package/src/services/ui.ts +35 -5
  105. package/src/theme/common/var.scss +3 -2
  106. package/src/theme/component-list-panel.scss +2 -0
  107. package/src/theme/content-menu.scss +33 -26
  108. package/src/theme/layer-panel.scss +10 -0
  109. package/src/theme/nav-menu.scss +6 -2
  110. package/src/theme/page-bar.scss +42 -2
  111. package/src/theme/props-panel.scss +19 -17
  112. package/src/type.ts +17 -9
  113. package/src/utils/editor.ts +35 -9
  114. package/src/utils/polyfills.ts +8 -0
  115. package/src/utils/props.ts +20 -1
  116. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
  117. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -973
  118. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -192
  119. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
  120. package/tsconfig.json +0 -9
  121. package/vite.config.ts +0 -30
@@ -21,8 +21,9 @@ import { cloneDeep, mergeWith } from 'lodash-es';
21
21
  import serialize from 'serialize-javascript';
22
22
 
23
23
  import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
24
- import type StageCore from '@tmagic/stage';
25
- import { getNodePath, isPop } from '@tmagic/utils';
24
+ import { NodeType } from '@tmagic/schema';
25
+ import StageCore from '@tmagic/stage';
26
+ import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
26
27
 
27
28
  import historyService, { StepValue } from '@editor/services/history';
28
29
  import propsService from '@editor/services/props';
@@ -51,29 +52,37 @@ class Editor extends BaseService {
51
52
  parent: null,
52
53
  node: null,
53
54
  stage: null,
55
+ highlightNode: null,
54
56
  modifiedNodeIds: new Map(),
57
+ pageLength: 0,
55
58
  });
56
59
 
57
60
  constructor() {
58
- super([
59
- 'getLayout',
60
- 'select',
61
- 'add',
62
- 'remove',
63
- 'update',
64
- 'sort',
65
- 'copy',
66
- 'paste',
67
- 'alignCenter',
68
- 'moveLayer',
69
- 'undo',
70
- 'redo',
71
- ]);
61
+ super(
62
+ [
63
+ 'getLayout',
64
+ 'select',
65
+ 'add',
66
+ 'remove',
67
+ 'update',
68
+ 'sort',
69
+ 'copy',
70
+ 'paste',
71
+ 'alignCenter',
72
+ 'moveLayer',
73
+ 'move',
74
+ 'undo',
75
+ 'redo',
76
+ 'highlight',
77
+ ],
78
+ // 需要注意循环依赖问题,如果函数间有相互调用的话,不能设置为串行调用
79
+ ['select', 'update', 'moveLayer'],
80
+ );
72
81
  }
73
82
 
74
83
  /**
75
84
  * 设置当前指点节点配置
76
- * @param name 'root' | 'page' | 'parent' | 'node'
85
+ * @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode'
77
86
  * @param value MNode
78
87
  * @returns MNode
79
88
  */
@@ -82,6 +91,7 @@ class Editor extends BaseService {
82
91
  log('store set ', name, ' ', value);
83
92
 
84
93
  if (name === 'root') {
94
+ this.state.pageLength = (value as unknown as MApp)?.items?.length || 0;
85
95
  this.emit('root-change', value);
86
96
  }
87
97
  }
@@ -101,7 +111,7 @@ class Editor extends BaseService {
101
111
  * @returns {EditorNodeInfo}
102
112
  */
103
113
  public getNodeInfo(id: Id): EditorNodeInfo {
104
- const root = this.get<MApp | null>('root');
114
+ const root = toRaw(this.get<MApp | null>('root'));
105
115
  if (!root) return {};
106
116
 
107
117
  if (id === root.id) {
@@ -119,7 +129,7 @@ class Editor extends BaseService {
119
129
  info.parent = path[path.length - 2] as MContainer;
120
130
 
121
131
  path.forEach((item) => {
122
- if (item.type === 'page') {
132
+ if (item.type === NodeType.PAGE) {
123
133
  info.page = item as MPage;
124
134
  return;
125
135
  }
@@ -152,13 +162,15 @@ class Editor extends BaseService {
152
162
  /**
153
163
  * 只有容器拥有布局
154
164
  */
155
- public async getLayout(node: MNode): Promise<Layout> {
156
- if (node.layout) {
157
- 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;
158
170
  }
159
171
 
160
172
  // 如果该节点没有设置position,则认为是流式布局,例如获取root的布局时
161
- if (!node.style?.position) {
173
+ if (!parent.style?.position) {
162
174
  return Layout.RELATIVE;
163
175
  }
164
176
 
@@ -166,28 +178,12 @@ class Editor extends BaseService {
166
178
  }
167
179
 
168
180
  /**
169
- * 选中指点节点(将指点节点设置成当前选中状态)
170
- * @param config 指点节点配置或者ID
181
+ * 选中指定节点(将指定节点设置成当前选中状态)
182
+ * @param config 指定节点配置或者ID
171
183
  * @returns 当前选中的节点配置
172
184
  */
173
- public async select(config: MNode | Id): Promise<MNode> {
174
- let id: Id;
175
- if (typeof config === 'string' || typeof config === 'number') {
176
- id = config;
177
- } else {
178
- id = config.id;
179
- }
180
- if (!id) {
181
- throw new Error('没有ID,无法选中');
182
- }
183
-
184
- const { node, parent, page } = this.getNodeInfo(id);
185
- if (!node) throw new Error('获取不到组件信息');
186
-
187
- if (node.id === this.state.root?.id) {
188
- throw new Error('不能选根节点');
189
- }
190
-
185
+ public async select(config: MNode | Id): Promise<MNode> | never {
186
+ const { node, page, parent } = this.selectedConfigExceptionHandler(config);
191
187
  this.set('node', node);
192
188
  this.set('page', page || null);
193
189
  this.set('parent', parent || null);
@@ -198,7 +194,54 @@ class Editor extends BaseService {
198
194
  historyService.empty();
199
195
  }
200
196
 
201
- return node;
197
+ this.emit('select', node);
198
+
199
+ return node!;
200
+ }
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
+
235
+ /**
236
+ * 高亮指定节点
237
+ * @param config 指定节点配置或者ID
238
+ * @returns 当前高亮的节点配置
239
+ */
240
+ public highlight(config: MNode | Id): void {
241
+ const { node } = this.selectedConfigExceptionHandler(config);
242
+ const currentHighlightNode = this.get('highlightNode');
243
+ if (currentHighlightNode === node) return;
244
+ this.set('highlightNode', node);
202
245
  }
203
246
 
204
247
  /**
@@ -207,12 +250,14 @@ class Editor extends BaseService {
207
250
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
208
251
  * @returns 添加后的节点
209
252
  */
210
- 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;
211
255
  const curNode = this.get<MContainer>('node');
212
256
 
213
257
  let parentNode: MNode | undefined;
258
+ const isPage = type === NodeType.PAGE;
214
259
 
215
- if (type === 'page') {
260
+ if (isPage) {
216
261
  parentNode = this.get<MApp>('root');
217
262
  // 由于支持中间件扩展,在parent参数为undefined时,parent会变成next函数
218
263
  } else if (parent && typeof parent !== 'function') {
@@ -225,21 +270,38 @@ class Editor extends BaseService {
225
270
 
226
271
  if (!parentNode) throw new Error('未找到父元素');
227
272
 
228
- const layout = await this.getLayout(parentNode);
229
- const newNode = initPosition({ ...toRaw(await propsService.getPropsValue(type)), ...config }, layout);
273
+ const layout = await this.getLayout(toRaw(parentNode), addNode as MNode);
274
+ const newNode = initPosition(
275
+ { ...toRaw(await propsService.getPropsValue(type, config)) },
276
+ layout,
277
+ parentNode,
278
+ this.get<StageCore>('stage'),
279
+ );
230
280
 
231
- if ((parentNode?.type === 'app' || curNode.type === 'app') && newNode.type !== 'page') {
281
+ if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
232
282
  throw new Error('app下不能添加组件');
233
283
  }
234
284
 
235
285
  parentNode?.items?.push(newNode);
236
286
 
237
- await this.get<StageCore>('stage')?.add({ config: cloneDeep(newNode), root: cloneDeep(this.get('root')) });
287
+ const stage = this.get<StageCore | null>('stage');
288
+
289
+ await stage?.add({ config: cloneDeep(newNode), root: cloneDeep(this.get('root')) });
238
290
 
239
291
  await this.select(newNode);
240
292
 
241
293
  this.addModifiedNodeId(newNode.id);
242
- this.pushHistoryState();
294
+ if (!isPage) {
295
+ this.pushHistoryState();
296
+ }
297
+
298
+ stage?.select(newNode.id);
299
+
300
+ if (isPage) {
301
+ this.state.pageLength += 1;
302
+ }
303
+
304
+ this.emit('add', newNode);
243
305
 
244
306
  return newNode;
245
307
  }
@@ -265,17 +327,38 @@ class Editor extends BaseService {
265
327
  if (typeof index !== 'number' || index === -1) throw new Error('找不要删除的节点');
266
328
 
267
329
  parent.items?.splice(index, 1);
268
- this.get<StageCore>('stage')?.remove({ id: node.id, root: this.get('root') });
269
-
270
- if (node.type === 'page') {
271
- await this.select(root.items[0] || root);
330
+ const stage = this.get<StageCore | null>('stage');
331
+ stage?.remove({ id: node.id, root: this.get('root') });
332
+
333
+ if (node.type === NodeType.PAGE) {
334
+ this.state.pageLength -= 1;
335
+
336
+ if (root.items[0]) {
337
+ await this.select(root.items[0]);
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;
351
+ }
272
352
  } else {
273
353
  await this.select(parent);
354
+ stage?.select(parent.id);
274
355
  }
275
356
 
276
357
  this.addModifiedNodeId(parent.id);
277
358
  this.pushHistoryState();
278
359
 
360
+ this.emit('remove', node);
361
+
279
362
  return node;
280
363
  }
281
364
 
@@ -303,7 +386,7 @@ class Editor extends BaseService {
303
386
 
304
387
  if (!newConfig.type) throw new Error('配置缺少type值');
305
388
 
306
- if (newConfig.type === 'app') {
389
+ if (newConfig.type === NodeType.ROOT) {
307
390
  this.set('root', newConfig);
308
391
  return newConfig;
309
392
  }
@@ -324,19 +407,21 @@ class Editor extends BaseService {
324
407
 
325
408
  parentNodeItems[index] = newConfig;
326
409
 
327
- if (newConfig.id === this.get('node').id) {
410
+ if (`${newConfig.id}` === `${this.get('node').id}`) {
328
411
  this.set('node', newConfig);
329
412
  }
330
413
 
331
- this.get<StageCore>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
414
+ this.get<StageCore | null>('stage')?.update({ config: cloneDeep(newConfig), root: this.get('root') });
332
415
 
333
- if (newConfig.type === 'page') {
416
+ if (newConfig.type === NodeType.PAGE) {
334
417
  this.set('page', newConfig);
335
418
  }
336
419
 
337
420
  this.addModifiedNodeId(newConfig.id);
338
421
  this.pushHistoryState();
339
422
 
423
+ this.emit('update', newConfig);
424
+
340
425
  return newConfig;
341
426
  }
342
427
 
@@ -359,7 +444,7 @@ class Editor extends BaseService {
359
444
  await this.update(parent);
360
445
  await this.select(node);
361
446
 
362
- this.get<StageCore>('stage')?.update({ config: cloneDeep(node), root: this.get('root') });
447
+ this.get<StageCore | null>('stage')?.update({ config: cloneDeep(node), root: this.get('root') });
363
448
 
364
449
  this.addModifiedNodeId(parent.id);
365
450
  this.pushHistoryState();
@@ -414,7 +499,7 @@ class Editor extends BaseService {
414
499
  public async alignCenter(config: MNode): Promise<MNode | void> {
415
500
  const parent = this.get<MContainer>('parent');
416
501
  const node = this.get<MNode>('node');
417
- const layout = await this.getLayout(parent);
502
+ const layout = await this.getLayout(toRaw(parent), toRaw(node));
418
503
  if (layout === Layout.RELATIVE) {
419
504
  return;
420
505
  }
@@ -424,7 +509,7 @@ class Editor extends BaseService {
424
509
  }
425
510
 
426
511
  await this.update(node);
427
- this.get<StageCore>('stage')?.update({ config: cloneDeep(toRaw(node)), root: this.get('root') });
512
+ this.get<StageCore | null>('stage')?.update({ config: cloneDeep(toRaw(node)), root: this.get('root') });
428
513
  this.addModifiedNodeId(config.id);
429
514
  this.pushHistoryState();
430
515
 
@@ -449,7 +534,7 @@ class Editor extends BaseService {
449
534
  brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
450
535
  }
451
536
 
452
- this.get<StageCore>('stage')?.update({ config: cloneDeep(toRaw(parent)), root: this.get('root') });
537
+ this.get<StageCore | null>('stage')?.update({ config: cloneDeep(toRaw(parent)), root: this.get('root') });
453
538
  }
454
539
 
455
540
  /**
@@ -472,6 +557,26 @@ class Editor extends BaseService {
472
557
  return value;
473
558
  }
474
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
+
475
580
  public destroy() {
476
581
  this.removeAllListeners();
477
582
  this.set('root', null);
@@ -508,7 +613,11 @@ class Editor extends BaseService {
508
613
  this.isHistoryStateChange = true;
509
614
  await this.update(value.data);
510
615
  this.set('modifiedNodeIds', value.modifiedNodeIds);
511
- setTimeout(() => value.nodeId && this.select(value.nodeId), 0);
616
+ setTimeout(async () => {
617
+ if (!value.nodeId) return;
618
+ await this.select(value.nodeId);
619
+ this.get<StageCore | null>('stage')?.select(value.nodeId);
620
+ }, 0);
512
621
  }
513
622
 
514
623
  private async toggleFixedPosition(dist: MNode, src: MNode, root: MApp) {
@@ -524,6 +633,30 @@ class Editor extends BaseService {
524
633
 
525
634
  return newConfig;
526
635
  }
636
+
637
+ private selectedConfigExceptionHandler(config: MNode | Id): EditorNodeInfo {
638
+ let id: Id;
639
+ if (typeof config === 'string' || typeof config === 'number') {
640
+ id = config;
641
+ } else {
642
+ id = config.id;
643
+ }
644
+ if (!id) {
645
+ throw new Error('没有ID,无法选中');
646
+ }
647
+
648
+ const { node, parent, page } = this.getNodeInfo(id);
649
+ if (!node) throw new Error('获取不到组件信息');
650
+
651
+ if (node.id === this.state.root?.id) {
652
+ throw new Error('不能选根节点');
653
+ }
654
+ return {
655
+ node,
656
+ parent,
657
+ page,
658
+ };
659
+ }
527
660
  }
528
661
 
529
662
  export type EditorService = Editor;
@@ -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';
@@ -87,7 +87,7 @@ class Props extends BaseService {
87
87
  * @param type 组件类型
88
88
  * @returns 组件初始值
89
89
  */
90
- public async getPropsValue(type: string) {
90
+ public async getPropsValue(type: string, defaultValue = {}) {
91
91
  if (type === 'area') {
92
92
  const value = (await this.getPropsValue('button')) as MComponent;
93
93
  value.className = 'action-area';
@@ -100,7 +100,7 @@ class Props extends BaseService {
100
100
 
101
101
  return cloneDeep({
102
102
  ...getDefaultPropsValue(type),
103
- ...(this.state.propsValueMap[type] || {}),
103
+ ...mergeWith(this.state.propsValueMap[type] || {}, defaultValue),
104
104
  });
105
105
  }
106
106
  }
@@ -25,6 +25,17 @@ import type { GetColumnWidth, SetColumnWidth, StageRect, UiState } from '@editor
25
25
 
26
26
  import BaseService from './BaseService';
27
27
 
28
+ const DEFAULT_LEFT_COLUMN_WIDTH = 310;
29
+ const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
30
+
31
+ const COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorColumnWidthData';
32
+
33
+ const defaultColumnWidth = {
34
+ left: DEFAULT_LEFT_COLUMN_WIDTH,
35
+ center: globalThis.document.body.clientWidth - DEFAULT_LEFT_COLUMN_WIDTH - DEFAULT_RIGHT_COLUMN_WIDTH,
36
+ right: DEFAULT_RIGHT_COLUMN_WIDTH,
37
+ };
38
+
28
39
  const state = reactive<UiState>({
29
40
  uiSelectMode: false,
30
41
  showSrc: false,
@@ -37,13 +48,10 @@ const state = reactive<UiState>({
37
48
  width: 375,
38
49
  height: 817,
39
50
  },
40
- columnWidth: {
41
- left: 310,
42
- center: globalThis.document.body.clientWidth - 310 - 400,
43
- right: 400,
44
- },
51
+ columnWidth: defaultColumnWidth,
45
52
  showGuides: true,
46
53
  showRule: true,
54
+ propsPanelSize: 'small',
47
55
  });
48
56
 
49
57
  class Ui extends BaseService {
@@ -54,6 +62,16 @@ class Ui extends BaseService {
54
62
  center: 'auto',
55
63
  });
56
64
  });
65
+
66
+ const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
67
+ if (columnWidthCacheData) {
68
+ try {
69
+ const columnWidthCache = JSON.parse(columnWidthCacheData);
70
+ this.setColumnWidth(columnWidthCache);
71
+ } catch (e) {
72
+ console.error(e);
73
+ }
74
+ }
57
75
  }
58
76
 
59
77
  public set<T = any>(name: keyof UiState, value: T) {
@@ -88,6 +106,11 @@ class Ui extends BaseService {
88
106
  return (state as any)[name];
89
107
  }
90
108
 
109
+ public zoom(zoom: number) {
110
+ this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
111
+ if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
112
+ }
113
+
91
114
  private setColumnWidth({ left, center, right }: SetColumnWidth) {
92
115
  const columnWidth = {
93
116
  ...toRaw(this.get<GetColumnWidth>('columnWidth')),
@@ -104,10 +127,17 @@ class Ui extends BaseService {
104
127
  if (!center || center === 'auto') {
105
128
  const bodyWidth = globalThis.document.body.clientWidth;
106
129
  columnWidth.center = bodyWidth - (columnWidth?.left || 0) - (columnWidth?.right || 0);
130
+ if (columnWidth.center <= 0) {
131
+ columnWidth.left = defaultColumnWidth.left;
132
+ columnWidth.center = defaultColumnWidth.center;
133
+ columnWidth.right = defaultColumnWidth.right;
134
+ }
107
135
  } else {
108
136
  columnWidth.center = center;
109
137
  }
110
138
 
139
+ globalThis.localStorage.setItem(COLUMN_WIDTH_STORAGE_KEY, JSON.stringify(columnWidth));
140
+
111
141
  state.columnWidth = columnWidth;
112
142
  }
113
143
 
@@ -2,12 +2,13 @@ $--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;
8
- $--nav--background-color: #f8fbff;
9
+ $--nav--background-color: #ffffff;
9
10
 
10
11
  $--sidebar-heder-background-color: $--theme-color;
11
- $--sidebar-content-background-color: #f8fbff;
12
+ $--sidebar-content-background-color: #ffffff;
12
13
 
13
14
  $--page-bar-height: 32px;
@@ -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;
@@ -2,38 +2,45 @@
2
2
  position: fixed;
3
3
  font-size: 12px;
4
4
  background: #fff;
5
- color: #333;
6
5
  box-shadow: 0 2px 8px 2px rgba(68, 73, 77, 0.16);
7
6
  z-index: 9999;
8
7
  transform-origin: 0% 0%;
9
8
  font-weight: 600;
10
9
  padding: 4px 0px;
10
+ overflow: auto;
11
+ max-height: 100%;
11
12
 
12
- .separation {
13
- width: 100%;
14
- height: 0;
15
- border-color: rgba(155, 155, 155, 0.1);
16
- }
17
-
18
- .subMenu {
19
- position: absolute;
20
- right: 0;
21
- transform: translate(100%, 0);
22
- background-color: #fff;
13
+ .menu-item {
23
14
  color: #333;
24
- box-shadow: 0 2px 8px 2px rgba(68, 73, 77, 0.16);
25
- top: 0;
26
- height: 223px;
27
- }
28
- }
15
+ display: flex;
16
+ -webkit-box-align: center;
17
+ align-items: center;
18
+ cursor: pointer;
19
+ min-width: 140px;
20
+ transition: all 0.2s ease 0s;
21
+ padding: 5px 14px;
22
+ border-left: 2px solid transparent;
23
+
24
+ .el-button {
25
+ width: 100%;
26
+ justify-content: flex-start;
27
+ }
29
28
 
30
- .magic-editor-content-menu-item {
31
- display: flex;
32
- -webkit-box-align: center;
33
- align-items: center;
34
- cursor: pointer;
35
- min-width: 140px;
36
- transition: all 0.2s ease 0s;
37
- padding: 10px 14px;
38
- border-left: 2px solid transparent;
29
+ .el-button--text,
30
+ i {
31
+ color: $--font-color;
32
+ }
33
+
34
+ &.divider {
35
+ padding: 0 14px;
36
+
37
+ .el-divider {
38
+ margin: 0;
39
+ }
40
+ }
41
+
42
+ &:hover {
43
+ background-color: $--hover-color;
44
+ }
45
+ }
39
46
  }
@@ -50,6 +50,16 @@
50
50
  color: #fff;
51
51
  }
52
52
 
53
+ .magic-editor-layer-panel .cus-tree-node {
54
+ width: 100%;
55
+ overflow: hidden;
56
+ }
57
+
58
+ .magic-editor-layer-panel .cus-tree-node-hover {
59
+ background-color: $--hover-color;
60
+ width: 100%;
61
+ }
62
+
53
63
  .magic-editor-layer-panel .el-tree-node:focus > .el-tree-node__content {
54
64
  background-color: $--sidebar-heder-background-color;
55
65
  color: #fff;