@tmagic/editor 1.5.0-beta.9 → 1.5.1

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 (99) hide show
  1. package/dist/{style.css → tmagic-editor.css} +228 -22
  2. package/dist/tmagic-editor.js +1670 -1012
  3. package/dist/tmagic-editor.umd.cjs +1705 -1048
  4. package/package.json +14 -12
  5. package/src/Editor.vue +24 -6
  6. package/src/components/CodeBlockEditor.vue +14 -8
  7. package/src/components/CodeParams.vue +5 -5
  8. package/src/components/ContentMenu.vue +18 -18
  9. package/src/components/FloatingBox.vue +3 -3
  10. package/src/components/Resizer.vue +4 -4
  11. package/src/components/ScrollBar.vue +3 -3
  12. package/src/components/ScrollViewer.vue +3 -3
  13. package/src/components/SplitView.vue +2 -2
  14. package/src/components/ToolButton.vue +2 -1
  15. package/src/editorProps.ts +6 -2
  16. package/src/fields/Code.vue +1 -2
  17. package/src/fields/CodeSelect.vue +13 -11
  18. package/src/fields/CodeSelectCol.vue +32 -5
  19. package/src/fields/CondOpSelect.vue +5 -2
  20. package/src/fields/DataSourceFields.vue +31 -12
  21. package/src/fields/DataSourceInput.vue +2 -2
  22. package/src/fields/DataSourceMethods.vue +72 -14
  23. package/src/fields/DataSourceMocks.vue +0 -1
  24. package/src/fields/DisplayConds.vue +8 -3
  25. package/src/fields/EventSelect.vue +28 -12
  26. package/src/fields/KeyValue.vue +17 -12
  27. package/src/fields/UISelect.vue +6 -3
  28. package/src/hooks/index.ts +0 -1
  29. package/src/hooks/use-code-block-edit.ts +3 -3
  30. package/src/hooks/use-data-source-edit.ts +3 -2
  31. package/src/hooks/use-filter.ts +1 -1
  32. package/src/hooks/use-getso.ts +7 -7
  33. package/src/hooks/use-node-status.ts +2 -2
  34. package/src/index.ts +2 -1
  35. package/src/initService.ts +177 -74
  36. package/src/layouts/CodeEditor.vue +2 -2
  37. package/src/layouts/Framework.vue +13 -12
  38. package/src/layouts/NavMenu.vue +2 -2
  39. package/src/layouts/page-bar/AddButton.vue +29 -9
  40. package/src/layouts/page-bar/PageBar.vue +79 -66
  41. package/src/layouts/page-bar/PageBarScrollContainer.vue +84 -98
  42. package/src/layouts/page-bar/PageList.vue +5 -3
  43. package/src/layouts/page-bar/Search.vue +67 -0
  44. package/src/layouts/props-panel/FormPanel.vue +123 -0
  45. package/src/layouts/props-panel/PropsPanel.vue +146 -0
  46. package/src/layouts/props-panel/use-style-panel.ts +29 -0
  47. package/src/layouts/sidebar/Sidebar.vue +7 -1
  48. package/src/layouts/sidebar/code-block/CodeBlockList.vue +18 -2
  49. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +35 -4
  50. package/src/layouts/sidebar/code-block/useContentMenu.ts +83 -0
  51. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +7 -5
  52. package/src/layouts/sidebar/data-source/DataSourceList.vue +13 -8
  53. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +40 -4
  54. package/src/layouts/sidebar/data-source/useContentMenu.ts +81 -0
  55. package/src/layouts/sidebar/layer/LayerMenu.vue +7 -13
  56. package/src/layouts/sidebar/layer/LayerPanel.vue +11 -4
  57. package/src/layouts/sidebar/layer/use-click.ts +2 -2
  58. package/src/layouts/sidebar/layer/use-keybinding.ts +2 -2
  59. package/src/layouts/sidebar/layer/use-node-status.ts +2 -3
  60. package/src/layouts/workspace/Workspace.vue +13 -3
  61. package/src/layouts/workspace/viewer/NodeListMenu.vue +3 -3
  62. package/src/layouts/workspace/viewer/Stage.vue +41 -11
  63. package/src/layouts/workspace/viewer/StageOverlay.vue +2 -2
  64. package/src/layouts/workspace/viewer/ViewerMenu.vue +4 -6
  65. package/src/services/dataSource.ts +12 -5
  66. package/src/services/dep.ts +61 -13
  67. package/src/services/editor.ts +46 -51
  68. package/src/services/storage.ts +2 -1
  69. package/src/services/ui.ts +1 -0
  70. package/src/theme/common/var.scss +12 -10
  71. package/src/theme/component-list-panel.scss +9 -7
  72. package/src/theme/content-menu.scss +7 -5
  73. package/src/theme/data-source.scss +3 -1
  74. package/src/theme/floating-box.scss +4 -2
  75. package/src/theme/framework.scss +7 -5
  76. package/src/theme/index.scss +4 -5
  77. package/src/theme/key-value.scss +2 -2
  78. package/src/theme/layer-panel.scss +3 -1
  79. package/src/theme/layout.scss +1 -1
  80. package/src/theme/nav-menu.scss +7 -5
  81. package/src/theme/page-bar.scss +51 -27
  82. package/src/theme/props-panel.scss +81 -1
  83. package/src/theme/resizer.scss +1 -1
  84. package/src/theme/search-input.scss +1 -0
  85. package/src/theme/sidebar.scss +4 -2
  86. package/src/theme/stage.scss +3 -1
  87. package/src/theme/theme.scss +28 -28
  88. package/src/theme/tree.scss +14 -12
  89. package/src/type.ts +10 -1
  90. package/src/utils/content-menu.ts +2 -2
  91. package/src/utils/data-source/formConfigs/http.ts +2 -0
  92. package/src/utils/data-source/index.ts +2 -2
  93. package/src/utils/editor.ts +78 -22
  94. package/src/utils/idle-task.ts +36 -4
  95. package/src/utils/props.ts +48 -6
  96. package/types/index.d.ts +2312 -2080
  97. package/src/hooks/use-data-source-method.ts +0 -100
  98. package/src/layouts/PropsPanel.vue +0 -131
  99. package/src/layouts/page-bar/SwitchTypeButton.vue +0 -45
@@ -1,4 +1,4 @@
1
- import { onBeforeUnmount, reactive, toRaw, watch } from 'vue';
1
+ import { computed, onBeforeUnmount, reactive, toRaw, watch } from 'vue';
2
2
  import { cloneDeep } from 'lodash-es';
3
3
 
4
4
  import type {
@@ -17,14 +17,16 @@ import {
17
17
  createDataSourceMethodTarget,
18
18
  createDataSourceTarget,
19
19
  DepTargetType,
20
+ NODE_CONDS_KEY,
20
21
  Target,
21
22
  } from '@tmagic/core';
22
- import { isPage } from '@tmagic/utils';
23
+ import { ChangeRecord } from '@tmagic/form';
24
+ import { getNodes, isPage, isValueIncludeDataSource, traverseNode } from '@tmagic/utils';
23
25
 
24
26
  import PropsPanel from './layouts/PropsPanel.vue';
27
+ import { isIncludeDataSource } from './utils/editor';
25
28
  import { EditorProps } from './editorProps';
26
29
  import { Services } from './type';
27
- import { traverseNode } from './utils';
28
30
 
29
31
  export declare type LooseRequired<T> = {
30
32
  [P in string & keyof T]: T[P];
@@ -220,6 +222,7 @@ export const initServiceEvents = (
220
222
  });
221
223
 
222
224
  if (Array.isArray(value.items)) {
225
+ depService.clearIdleTasks();
223
226
  collectIdle(value.items, true);
224
227
  } else {
225
228
  depService.clear();
@@ -248,67 +251,41 @@ export const initServiceEvents = (
248
251
  }
249
252
  };
250
253
 
251
- const getApp = () => {
252
- const stage = editorService.get('stage');
253
- return stage?.renderer?.runtime?.getApp?.();
254
- };
255
-
256
- const updateDataSourceSchema = () => {
257
- const root = editorService.get('root');
258
-
259
- if (root?.dataSources) {
260
- getApp()?.dataSourceManager?.updateSchema(root.dataSources);
261
- }
262
- };
254
+ const stage = computed(() => editorService.get('stage'));
263
255
 
264
- const targetAddHandler = (target: Target) => {
265
- const root = editorService.get('root');
266
- if (!root) return;
267
-
268
- if (target.type === DepTargetType.DATA_SOURCE) {
269
- if (!root.dataSourceDeps) {
270
- root.dataSourceDeps = {};
271
- }
272
- root.dataSourceDeps[target.id] = target.deps;
256
+ watch(stage, (stage) => {
257
+ if (!stage) {
258
+ return;
273
259
  }
274
260
 
275
- if (target.type === DepTargetType.DATA_SOURCE_COND) {
276
- if (!root.dataSourceCondDeps) {
277
- root.dataSourceCondDeps = {};
278
- }
279
- root.dataSourceCondDeps[target.id] = target.deps;
280
- }
281
- };
261
+ stage.on('rerender', () => {
262
+ const node = editorService.get('node');
282
263
 
283
- const targetRemoveHandler = (id: string | number) => {
284
- const root = editorService.get('root');
264
+ if (!node) return;
285
265
 
286
- if (root?.dataSourceDeps) {
287
- delete root.dataSourceDeps[id];
288
- }
266
+ collectIdle([node], true).then(() => {
267
+ afterUpdateNodes([node]);
268
+ });
269
+ });
270
+ });
289
271
 
290
- if (root?.dataSourceCondDeps) {
291
- delete root.dataSourceCondDeps[id];
292
- }
293
- };
272
+ const getApp = () => stage.value?.renderer?.runtime?.getApp?.();
294
273
 
295
- const collectedHandler = (nodes: MNode[], deep: boolean) => {
274
+ const updateDataSourceSchema = (nodes: MNode[], deep: boolean) => {
296
275
  const root = editorService.get('root');
297
- const stage = editorService.get('stage');
298
-
299
- if (!root || !stage) return;
300
-
301
276
  const app = getApp();
302
277
 
303
- if (!app) return;
304
-
305
- if (app.dsl) {
278
+ if (root && app?.dsl) {
306
279
  app.dsl.dataSourceDeps = root.dataSourceDeps;
307
280
  app.dsl.dataSourceCondDeps = root.dataSourceCondDeps;
308
281
  app.dsl.dataSources = root.dataSources;
309
282
  }
310
283
 
311
- updateDataSourceSchema();
284
+ if (root?.dataSources) {
285
+ getApp()?.dataSourceManager?.updateSchema(root.dataSources);
286
+ }
287
+
288
+ if (!root || !stage.value) return;
312
289
 
313
290
  const allNodes: MNode[] = [];
314
291
 
@@ -329,7 +306,7 @@ export const initServiceEvents = (
329
306
  Object.keys(dep).forEach((id) => {
330
307
  const node = allNodes.find((node) => node.id === id);
331
308
  node &&
332
- stage.update({
309
+ stage.value?.update({
333
310
  config: cloneDeep(node),
334
311
  parentId: editorService.getParentById(node.id)?.id,
335
312
  root: cloneDeep(root),
@@ -338,9 +315,63 @@ export const initServiceEvents = (
338
315
  });
339
316
  };
340
317
 
318
+ const afterUpdateNodes = (nodes: MNode[]) => {
319
+ const root = editorService.get('root');
320
+ if (!root) return;
321
+ for (const node of nodes) {
322
+ stage.value?.update({
323
+ config: cloneDeep(node),
324
+ parentId: editorService.getParentById(node.id)?.id,
325
+ root: cloneDeep(root),
326
+ });
327
+ }
328
+ };
329
+
330
+ const targetAddHandler = (target: Target) => {
331
+ const root = editorService.get('root');
332
+ if (!root) return;
333
+
334
+ if (target.type === DepTargetType.DATA_SOURCE) {
335
+ if (!root.dataSourceDeps) {
336
+ root.dataSourceDeps = {};
337
+ }
338
+ root.dataSourceDeps[target.id] = target.deps;
339
+ }
340
+
341
+ if (target.type === DepTargetType.DATA_SOURCE_COND) {
342
+ if (!root.dataSourceCondDeps) {
343
+ root.dataSourceCondDeps = {};
344
+ }
345
+ root.dataSourceCondDeps[target.id] = target.deps;
346
+ }
347
+ };
348
+
349
+ const targetRemoveHandler = (id: string | number) => {
350
+ const root = editorService.get('root');
351
+
352
+ if (!root) return;
353
+
354
+ if (root.dataSourceDeps) {
355
+ delete root.dataSourceDeps[id];
356
+ }
357
+
358
+ if (root.dataSourceCondDeps) {
359
+ delete root.dataSourceCondDeps[id];
360
+ }
361
+ };
362
+
363
+ const depCollectedHandler = () => {
364
+ const root = editorService.get('root');
365
+ if (!root) return;
366
+ const app = getApp();
367
+ if (app?.dsl) {
368
+ app.dsl.dataSourceDeps = root.dataSourceDeps;
369
+ }
370
+ };
371
+
341
372
  depService.on('add-target', targetAddHandler);
342
373
  depService.on('remove-target', targetRemoveHandler);
343
- depService.on('collected', collectedHandler);
374
+ depService.on('collected', depCollectedHandler);
344
375
 
345
376
  const initDataSourceDepTarget = (ds: DataSourceSchema) => {
346
377
  depService.addTarget(createDataSourceTarget(ds, reactive({})));
@@ -348,28 +379,63 @@ export const initServiceEvents = (
348
379
  depService.addTarget(createDataSourceCondTarget(ds, reactive({})));
349
380
  };
350
381
 
351
- const collectIdle = (nodes: MNode[], deep: boolean) => {
352
- nodes.forEach((node) => {
353
- let pageId: Id | undefined;
354
-
355
- if (isPage(node)) {
356
- pageId = node.id;
357
- } else {
358
- const info = editorService.getNodeInfo(node.id);
359
- pageId = info.page?.id;
360
- }
361
- depService.collectIdle([node], { pageId }, deep);
362
- });
363
- };
382
+ const collectIdle = (nodes: MNode[], deep: boolean) =>
383
+ Promise.all(
384
+ nodes.map((node) => {
385
+ let pageId: Id | undefined;
386
+
387
+ if (isPage(node)) {
388
+ pageId = node.id;
389
+ } else {
390
+ const info = editorService.getNodeInfo(node.id);
391
+ pageId = info.page?.id;
392
+ }
393
+ return depService.collectIdle([node], { pageId }, deep);
394
+ }),
395
+ );
364
396
 
365
397
  // 新增节点,收集依赖
366
398
  const nodeAddHandler = (nodes: MNode[]) => {
367
- collectIdle(nodes, true);
399
+ collectIdle(nodes, true).then(() => {
400
+ afterUpdateNodes(nodes);
401
+ });
368
402
  };
369
403
 
370
404
  // 节点更新,收集依赖
371
- const nodeUpdateHandler = (nodes: MNode[]) => {
372
- collectIdle(nodes, true);
405
+ // 仅当修改到数据源相关的才收集
406
+ const nodeUpdateHandler = (data: { newNode: MNode; oldNode: MNode; changeRecords?: ChangeRecord[] }[]) => {
407
+ const needRecollectNodes: MNode[] = [];
408
+ const normalNodes: MNode[] = [];
409
+ data.forEach(({ newNode, oldNode, changeRecords }) => {
410
+ if (changeRecords?.length) {
411
+ for (const record of changeRecords) {
412
+ // NODE_CONDS_KEY为显示条件key
413
+ if (
414
+ !record.propPath ||
415
+ new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond`).test(record.propPath) ||
416
+ new RegExp(`${NODE_CONDS_KEY}.(\\d)+.cond.(\\d)+.value`).test(record.propPath) ||
417
+ record.propPath === NODE_CONDS_KEY ||
418
+ isValueIncludeDataSource(record.value)
419
+ ) {
420
+ needRecollectNodes.push(newNode);
421
+ } else {
422
+ normalNodes.push(newNode);
423
+ }
424
+ }
425
+ } else if (isIncludeDataSource(newNode, oldNode)) {
426
+ needRecollectNodes.push(newNode);
427
+ } else {
428
+ normalNodes.push(newNode);
429
+ }
430
+ });
431
+
432
+ if (needRecollectNodes.length) {
433
+ collectIdle(needRecollectNodes, true).then(() => {
434
+ afterUpdateNodes(needRecollectNodes);
435
+ });
436
+ } else if (normalNodes.length) {
437
+ afterUpdateNodes(normalNodes);
438
+ }
373
439
  };
374
440
 
375
441
  // 节点删除,清除对齐的依赖收集
@@ -379,7 +445,9 @@ export const initServiceEvents = (
379
445
 
380
446
  // 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
381
447
  const historyChangeHandler = (page: MPage | MPageFragment) => {
382
- collectIdle([page], true);
448
+ collectIdle([page], true).then(() => {
449
+ updateDataSourceSchema([page], true);
450
+ });
383
451
  };
384
452
 
385
453
  editorService.on('history-change', historyChangeHandler);
@@ -409,12 +477,41 @@ export const initServiceEvents = (
409
477
  getApp()?.dataSourceManager?.addDataSource(config);
410
478
  };
411
479
 
412
- const dataSourceUpdateHandler = (config: DataSourceSchema) => {
480
+ const dataSourceUpdateHandler = (config: DataSourceSchema, { changeRecords }: { changeRecords: ChangeRecord[] }) => {
481
+ let needRecollectDep = false;
482
+ for (const changeRecord of changeRecords) {
483
+ if (!changeRecord.propPath) {
484
+ continue;
485
+ }
486
+
487
+ needRecollectDep =
488
+ changeRecord.propPath === 'fields' ||
489
+ changeRecord.propPath === 'methods' ||
490
+ /fields.(\d)+.name/.test(changeRecord.propPath) ||
491
+ /fields.(\d)+$/.test(changeRecord.propPath) ||
492
+ /methods.(\d)+.name/.test(changeRecord.propPath) ||
493
+ /methods.(\d)+$/.test(changeRecord.propPath);
494
+
495
+ if (needRecollectDep) {
496
+ break;
497
+ }
498
+ }
499
+
413
500
  const root = editorService.get('root');
414
- removeDataSourceTarget(config.id);
415
- initDataSourceDepTarget(config);
501
+ if (needRecollectDep) {
502
+ if (Array.isArray(root?.items)) {
503
+ depService.clearIdleTasks();
504
+
505
+ removeDataSourceTarget(config.id);
506
+ initDataSourceDepTarget(config);
416
507
 
417
- collectIdle(root?.items || [], true);
508
+ collectIdle(root.items, true).then(() => {
509
+ updateDataSourceSchema(root?.items || [], true);
510
+ });
511
+ }
512
+ } else if (root?.dataSources) {
513
+ getApp()?.dataSourceManager?.updateSchema(root.dataSources);
514
+ }
418
515
  };
419
516
 
420
517
  const removeDataSourceTarget = (id: string) => {
@@ -424,8 +521,14 @@ export const initServiceEvents = (
424
521
  };
425
522
 
426
523
  const dataSourceRemoveHandler = (id: string) => {
524
+ const root = editorService.get('root');
525
+ const nodeIds = Object.keys(root?.dataSourceDeps?.[id] || {});
526
+ const nodes = getNodes(nodeIds, root?.items);
527
+ collectIdle(nodes, false).then(() => {
528
+ updateDataSourceSchema(nodes, false);
529
+ });
530
+
427
531
  removeDataSourceTarget(id);
428
- getApp()?.dataSourceManager?.removeDataSource(id);
429
532
  };
430
533
 
431
534
  dataSourceService.on('add', dataSourceAddHandler);
@@ -435,7 +538,7 @@ export const initServiceEvents = (
435
538
  onBeforeUnmount(() => {
436
539
  depService.off('add-target', targetAddHandler);
437
540
  depService.off('remove-target', targetRemoveHandler);
438
- depService.off('collected', collectedHandler);
541
+ depService.off('collected', depCollectedHandler);
439
542
 
440
543
  editorService.off('history-change', historyChangeHandler);
441
544
  editorService.off('root-change', rootChangeHandler);
@@ -15,7 +15,7 @@
15
15
  </template>
16
16
 
17
17
  <script lang="ts" setup>
18
- import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
18
+ import { onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue';
19
19
  import { FullScreen } from '@element-plus/icons-vue';
20
20
  import { throttle } from 'lodash-es';
21
21
  import serialize from 'serialize-javascript';
@@ -93,7 +93,7 @@ let vsDiffEditor: monaco.editor.IStandaloneDiffEditor | null = null;
93
93
 
94
94
  const values = ref('');
95
95
  const loading = ref(false);
96
- const codeEditor = ref<HTMLDivElement>();
96
+ const codeEditor = useTemplateRef<HTMLDivElement>('codeEditor');
97
97
 
98
98
  const resizeObserver = new globalThis.ResizeObserver(
99
99
  throttle((): void => {
@@ -11,8 +11,6 @@
11
11
  </slot>
12
12
 
13
13
  <SplitView
14
- v-loading="stageLoading"
15
- element-loading-text="Runtime 加载中..."
16
14
  v-else
17
15
  ref="splitView"
18
16
  class="m-editor-content"
@@ -22,7 +20,7 @@
22
20
  v-model:left="columnWidth.left"
23
21
  v-model:right="columnWidth.right"
24
22
  :min-left="65"
25
- :min-right="20"
23
+ :min-right="420"
26
24
  :min-center="100"
27
25
  :width="frameworkRect?.width || 0"
28
26
  @change="columnWidthChange"
@@ -38,7 +36,12 @@
38
36
  </slot>
39
37
 
40
38
  <slot name="page-bar">
41
- <PageBar :disabled-page-fragment="disabledPageFragment" :page-bar-sort-options="pageBarSortOptions">
39
+ <PageBar
40
+ :disabled-page-fragment="disabledPageFragment"
41
+ :page-bar-sort-options="pageBarSortOptions"
42
+ :filter-function="pageFilterFunction"
43
+ >
44
+ <template #page-bar-add-button><slot name="page-bar-add-button"></slot></template>
42
45
  <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
43
46
  <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
44
47
  <template #page-list-popover="{ list }"><slot name="page-list-popover" :list="list"></slot></template>
@@ -47,9 +50,7 @@
47
50
  </template>
48
51
 
49
52
  <template v-if="page" #right>
50
- <TMagicScrollbar>
51
- <slot name="props-panel"></slot>
52
- </TMagicScrollbar>
53
+ <slot name="props-panel"></slot>
53
54
  </template>
54
55
  </SplitView>
55
56
 
@@ -59,9 +60,9 @@
59
60
  </template>
60
61
 
61
62
  <script lang="ts" setup>
62
- import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
63
+ import { computed, inject, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue';
63
64
 
64
- import { TMagicScrollbar } from '@tmagic/design';
65
+ import type { MPage, MPageFragment } from '@tmagic/core';
65
66
 
66
67
  import SplitView from '@editor/components/SplitView.vue';
67
68
  import type { FrameworkSlots, GetColumnWidth, PageBarSortOptions, Services } from '@editor/type';
@@ -80,6 +81,7 @@ defineOptions({
80
81
  defineProps<{
81
82
  disabledPageFragment: boolean;
82
83
  pageBarSortOptions?: PageBarSortOptions;
84
+ pageFilterFunction?: (page: MPage | MPageFragment, keyword: string) => boolean;
83
85
  }>();
84
86
 
85
87
  const DEFAULT_LEFT_COLUMN_WIDTH = 310;
@@ -88,14 +90,13 @@ const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
88
90
  const codeOptions = inject('codeOptions', {});
89
91
  const { editorService, uiService } = inject<Services>('services') || {};
90
92
 
91
- const content = ref<HTMLDivElement>();
92
- const splitView = ref<InstanceType<typeof SplitView>>();
93
+ const content = useTemplateRef<HTMLDivElement>('content');
94
+ const splitView = useTemplateRef<InstanceType<typeof SplitView>>('splitView');
93
95
 
94
96
  const root = computed(() => editorService?.get('root'));
95
97
  const page = computed(() => editorService?.get('page'));
96
98
 
97
99
  const pageLength = computed(() => editorService?.get('pageLength') || 0);
98
- const stageLoading = computed(() => editorService?.get('stageLoading') || false);
99
100
  const showSrc = computed(() => uiService?.get('showSrc'));
100
101
 
101
102
  const LEFT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorLeftColumnWidthData';
@@ -7,7 +7,7 @@
7
7
  </template>
8
8
 
9
9
  <script lang="ts" setup>
10
- import { computed, inject, markRaw, onBeforeUnmount, onMounted, ref } from 'vue';
10
+ import { computed, inject, markRaw, onBeforeUnmount, onMounted, useTemplateRef } from 'vue';
11
11
  import { Back, Delete, FullScreen, Grid, Memo, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons-vue';
12
12
 
13
13
  import { NodeType } from '@tmagic/core';
@@ -190,7 +190,7 @@ const resizeObserver = new ResizeObserver(() => {
190
190
  });
191
191
  }
192
192
  });
193
- const navMenu = ref<HTMLDivElement>();
193
+ const navMenu = useTemplateRef<HTMLDivElement>('navMenu');
194
194
  onMounted(() => {
195
195
  navMenu.value && resizeObserver.observe(navMenu.value);
196
196
  });
@@ -3,9 +3,31 @@
3
3
  v-if="showAddPageButton"
4
4
  id="m-editor-page-bar-add-icon"
5
5
  class="m-editor-page-bar-item m-editor-page-bar-item-icon"
6
- @click="addPage"
7
6
  >
8
- <Icon :icon="Plus"></Icon>
7
+ <TMagicPopover popper-class="data-source-list-panel-add-menu">
8
+ <template #reference>
9
+ <Icon :icon="Plus"></Icon>
10
+ </template>
11
+
12
+ <ToolButton
13
+ :data="{
14
+ type: 'button',
15
+ text: '页面',
16
+ handler: () => {
17
+ addPage(NodeType.PAGE);
18
+ },
19
+ }"
20
+ ></ToolButton>
21
+ <ToolButton
22
+ :data="{
23
+ type: 'button',
24
+ text: '页面片',
25
+ handler: () => {
26
+ addPage(NodeType.PAGE_FRAGMENT);
27
+ },
28
+ }"
29
+ ></ToolButton>
30
+ </TMagicPopover>
9
31
  </div>
10
32
  <div v-else style="width: 21px"></div>
11
33
  </template>
@@ -15,8 +37,10 @@ import { computed, inject, toRaw } from 'vue';
15
37
  import { Plus } from '@element-plus/icons-vue';
16
38
 
17
39
  import { NodeType } from '@tmagic/core';
40
+ import { TMagicPopover } from '@tmagic/design';
18
41
 
19
42
  import Icon from '@editor/components/Icon.vue';
43
+ import ToolButton from '@editor/components/ToolButton.vue';
20
44
  import type { Services } from '@editor/type';
21
45
  import { generatePageNameByApp } from '@editor/utils/editor';
22
46
 
@@ -24,23 +48,19 @@ defineOptions({
24
48
  name: 'MEditorPageBarAddButton',
25
49
  });
26
50
 
27
- const props = defineProps<{
28
- type: NodeType.PAGE | NodeType.PAGE_FRAGMENT;
29
- }>();
30
-
31
51
  const services = inject<Services>('services');
32
52
  const uiService = services?.uiService;
33
53
  const editorService = services?.editorService;
34
54
 
35
55
  const showAddPageButton = computed(() => uiService?.get('showAddPageButton'));
36
56
 
37
- const addPage = () => {
57
+ const addPage = (type: NodeType.PAGE | NodeType.PAGE_FRAGMENT) => {
38
58
  if (!editorService) return;
39
59
  const root = toRaw(editorService.get('root'));
40
60
  if (!root) throw new Error('root 不能为空');
41
61
  const pageConfig = {
42
- type: props.type,
43
- name: generatePageNameByApp(root, props.type),
62
+ type,
63
+ name: generatePageNameByApp(root, type),
44
64
  items: [],
45
65
  };
46
66
  editorService.add(pageConfig);