@tmagic/editor 1.5.7 → 1.5.8

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 (72) hide show
  1. package/dist/style.css +17 -0
  2. package/dist/tmagic-editor.js +463 -470
  3. package/dist/tmagic-editor.umd.cjs +471 -469
  4. package/package.json +7 -7
  5. package/src/components/CodeBlockEditor.vue +4 -4
  6. package/src/components/FloatingBox.vue +4 -4
  7. package/src/components/ToolButton.vue +6 -4
  8. package/src/components/TreeNode.vue +2 -2
  9. package/src/fields/CodeSelect.vue +6 -6
  10. package/src/fields/CodeSelectCol.vue +5 -4
  11. package/src/fields/CondOpSelect.vue +5 -4
  12. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +6 -5
  13. package/src/fields/DataSourceFieldSelect/Index.vue +4 -3
  14. package/src/fields/DataSourceFields.vue +3 -3
  15. package/src/fields/DataSourceInput.vue +4 -4
  16. package/src/fields/DataSourceMethodSelect.vue +8 -9
  17. package/src/fields/DataSourceMocks.vue +3 -3
  18. package/src/fields/DataSourceSelect.vue +6 -5
  19. package/src/fields/DisplayConds.vue +4 -4
  20. package/src/fields/EventSelect.vue +17 -23
  21. package/src/fields/PageFragmentSelect.vue +6 -5
  22. package/src/fields/UISelect.vue +16 -19
  23. package/src/hooks/index.ts +1 -0
  24. package/src/hooks/use-code-block-edit.ts +5 -10
  25. package/src/hooks/use-data-source-edit.ts +6 -6
  26. package/src/hooks/use-editor-content-height.ts +5 -5
  27. package/src/hooks/use-float-box.ts +5 -5
  28. package/src/hooks/use-next-float-box-position.ts +9 -9
  29. package/src/hooks/use-services.ts +13 -0
  30. package/src/hooks/use-stage.ts +2 -6
  31. package/src/layouts/AddPageBox.vue +3 -7
  32. package/src/layouts/Framework.vue +27 -27
  33. package/src/layouts/NavMenu.vue +16 -16
  34. package/src/layouts/page-bar/AddButton.vue +4 -7
  35. package/src/layouts/page-bar/PageBar.vue +10 -10
  36. package/src/layouts/page-bar/PageBarScrollContainer.vue +7 -8
  37. package/src/layouts/page-bar/PageList.vue +6 -8
  38. package/src/layouts/props-panel/FormPanel.vue +6 -4
  39. package/src/layouts/props-panel/PropsPanel.vue +39 -49
  40. package/src/layouts/props-panel/use-style-panel.ts +35 -19
  41. package/src/layouts/sidebar/ComponentListPanel.vue +5 -5
  42. package/src/layouts/sidebar/Sidebar.vue +15 -9
  43. package/src/layouts/sidebar/code-block/CodeBlockList.vue +13 -18
  44. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +4 -3
  45. package/src/layouts/sidebar/code-block/useContentMenu.ts +3 -3
  46. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +5 -5
  47. package/src/layouts/sidebar/data-source/DataSourceList.vue +13 -17
  48. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +6 -12
  49. package/src/layouts/sidebar/data-source/useContentMenu.ts +3 -3
  50. package/src/layouts/sidebar/layer/LayerMenu.vue +11 -8
  51. package/src/layouts/sidebar/layer/LayerNodeTool.vue +2 -6
  52. package/src/layouts/sidebar/layer/LayerPanel.vue +6 -12
  53. package/src/layouts/sidebar/layer/use-click.ts +16 -15
  54. package/src/layouts/sidebar/layer/use-drag.ts +6 -6
  55. package/src/layouts/sidebar/layer/use-keybinding.ts +6 -8
  56. package/src/layouts/sidebar/layer/use-node-status.ts +16 -7
  57. package/src/layouts/workspace/Breadcrumb.vue +8 -9
  58. package/src/layouts/workspace/Workspace.vue +4 -10
  59. package/src/layouts/workspace/viewer/NodeListMenu.vue +9 -8
  60. package/src/layouts/workspace/viewer/Stage.vue +24 -24
  61. package/src/layouts/workspace/viewer/StageOverlay.vue +15 -16
  62. package/src/layouts/workspace/viewer/ViewerMenu.vue +15 -14
  63. package/src/services/dep.ts +23 -8
  64. package/src/services/ui.ts +6 -2
  65. package/src/theme/common/var.scss +1 -0
  66. package/src/theme/sidebar.scss +20 -1
  67. package/src/type.ts +3 -9
  68. package/src/utils/const.ts +11 -0
  69. package/src/utils/content-menu.ts +28 -30
  70. package/src/utils/idle-task.ts +11 -0
  71. package/src/utils/index.ts +1 -0
  72. package/types/index.d.ts +28 -10
@@ -1,4 +1,4 @@
1
- import { computed, ref, watch } from 'vue';
1
+ import { computed, onBeforeUnmount, ref, watch } from 'vue';
2
2
 
3
3
  import type { Id, MNode, MPage, MPageFragment } from '@tmagic/core';
4
4
  import { getNodePath, isPage, isPageFragment, traverseNode } from '@tmagic/utils';
@@ -33,9 +33,9 @@ const createPageNodeStatus = (page: MPage | MPageFragment, initialLayerNodeStatu
33
33
  return map;
34
34
  };
35
35
 
36
- export const useNodeStatus = (services: Services | undefined) => {
37
- const page = computed(() => services?.editorService.get('page'));
38
- const nodes = computed(() => services?.editorService.get('nodes') || []);
36
+ export const useNodeStatus = ({ editorService }: Services) => {
37
+ const page = computed(() => editorService.get('page'));
38
+ const nodes = computed(() => editorService.get('nodes'));
39
39
 
40
40
  /** 所有页面的节点状态 */
41
41
  const nodeStatusMaps = ref(new Map<Id, Map<Id, LayerNodeStatus>>());
@@ -83,7 +83,7 @@ export const useNodeStatus = (services: Services | undefined) => {
83
83
  },
84
84
  );
85
85
 
86
- services?.editorService.on('add', (newNodes: MNode[]) => {
86
+ const addHandler = (newNodes: MNode[]) => {
87
87
  newNodes.forEach((node) => {
88
88
  if (isPage(node) || isPageFragment(node)) return;
89
89
 
@@ -96,14 +96,23 @@ export const useNodeStatus = (services: Services | undefined) => {
96
96
  });
97
97
  });
98
98
  });
99
- });
99
+ };
100
+
101
+ editorService.on('add', addHandler);
100
102
 
101
- services?.editorService.on('remove', (nodes: MNode[]) => {
103
+ const removeHandler = (nodes: MNode[]) => {
102
104
  nodes.forEach((node) => {
103
105
  traverseNode(node, (node: MNode) => {
104
106
  nodeStatusMap.value?.delete(node.id);
105
107
  });
106
108
  });
109
+ };
110
+
111
+ editorService.on('remove', removeHandler);
112
+
113
+ onBeforeUnmount(() => {
114
+ editorService.off('remove', removeHandler);
115
+ editorService.off('add', addHandler);
107
116
  });
108
117
 
109
118
  return {
@@ -8,28 +8,27 @@
8
8
  </template>
9
9
 
10
10
  <script setup lang="ts">
11
- import { computed, inject } from 'vue';
11
+ import { computed } from 'vue';
12
12
 
13
13
  import type { MNode } from '@tmagic/core';
14
14
  import { TMagicButton } from '@tmagic/design';
15
15
  import { getNodePath } from '@tmagic/utils';
16
16
 
17
- import type { Services } from '@editor/type';
17
+ import { useServices } from '@editor/hooks/use-services';
18
18
 
19
19
  defineOptions({
20
20
  name: 'MEditorBreadcrumb',
21
21
  });
22
22
 
23
- const services = inject<Services>('services');
24
- const editorService = services?.editorService;
23
+ const { editorService } = useServices();
25
24
 
26
- const node = computed(() => editorService?.get('node'));
27
- const nodes = computed(() => editorService?.get('nodes') || []);
28
- const root = computed(() => editorService?.get('root'));
25
+ const node = computed(() => editorService.get('node'));
26
+ const nodes = computed(() => editorService.get('nodes'));
27
+ const root = computed(() => editorService.get('root'));
29
28
  const path = computed(() => getNodePath(node.value?.id || '', root.value?.items || []));
30
29
 
31
30
  const select = async (node: MNode) => {
32
- await editorService?.select(node);
33
- editorService?.get('stage')?.select(node.id);
31
+ await editorService.select(node);
32
+ editorService.get('stage')?.select(node.id);
34
33
  };
35
34
  </script>
@@ -19,14 +19,8 @@
19
19
  <script lang="ts" setup>
20
20
  import { computed, inject } from 'vue';
21
21
 
22
- import type {
23
- CustomContentMenuFunction,
24
- MenuButton,
25
- MenuComponent,
26
- Services,
27
- StageOptions,
28
- WorkspaceSlots,
29
- } from '@editor/type';
22
+ import { useServices } from '@editor/hooks/use-services';
23
+ import type { CustomContentMenuFunction, MenuButton, MenuComponent, StageOptions, WorkspaceSlots } from '@editor/type';
30
24
 
31
25
  import MagicStage from './viewer/Stage.vue';
32
26
  import Breadcrumb from './Breadcrumb.vue';
@@ -50,7 +44,7 @@ withDefaults(
50
44
 
51
45
  const stageOptions = inject<StageOptions>('stageOptions');
52
46
 
53
- const services = inject<Services>('services');
47
+ const { editorService } = useServices();
54
48
 
55
- const page = computed(() => services?.editorService.get('page'));
49
+ const page = computed(() => editorService.get('page'));
56
50
  </script>
@@ -22,7 +22,7 @@
22
22
  </template>
23
23
 
24
24
  <script lang="ts" setup>
25
- import { computed, inject, nextTick, ref, useTemplateRef, watch } from 'vue';
25
+ import { computed, nextTick, ref, useTemplateRef, watch } from 'vue';
26
26
 
27
27
  import type { MNode } from '@tmagic/core';
28
28
  import { TMagicTooltip } from '@tmagic/design';
@@ -31,20 +31,21 @@ import { getIdFromEl } from '@tmagic/utils';
31
31
  import FloatingBox from '@editor/components/FloatingBox.vue';
32
32
  import Tree from '@editor/components/Tree.vue';
33
33
  import { useFilter } from '@editor/hooks/use-filter';
34
+ import { useServices } from '@editor/hooks/use-services';
34
35
  import { useNodeStatus } from '@editor/layouts/sidebar/layer/use-node-status';
35
- import type { Services, TreeNodeData } from '@editor/type';
36
+ import type { TreeNodeData } from '@editor/type';
36
37
 
37
- const services = inject<Services>('services');
38
- const editorService = services?.editorService;
38
+ const services = useServices();
39
+ const { editorService } = services;
39
40
 
40
41
  const visible = ref(false);
41
42
  const buttonVisible = ref(false);
42
43
  const buttonEl = useTemplateRef<HTMLDivElement>('button');
43
44
  const boxRef = useTemplateRef<InstanceType<typeof FloatingBox>>('box');
44
45
 
45
- const stage = computed(() => editorService?.get('stage'));
46
- const page = computed(() => editorService?.get('page'));
47
- const nodes = computed(() => editorService?.get('nodes') || []);
46
+ const stage = computed(() => editorService.get('stage'));
47
+ const page = computed(() => editorService.get('page'));
48
+ const nodes = computed(() => editorService.get('nodes'));
48
49
  const nodeData = computed<TreeNodeData[]>(() => (!page.value ? [] : [page.value]));
49
50
 
50
51
  const { nodeStatusMap } = useNodeStatus(services);
@@ -89,7 +90,7 @@ watch(
89
90
  );
90
91
 
91
92
  const clickHandler = async (event: MouseEvent, data: TreeNodeData) => {
92
- await editorService?.select(data.id);
93
+ await editorService.select(data.id);
93
94
  stage.value?.select(data.id);
94
95
  };
95
96
 
@@ -45,7 +45,6 @@
45
45
  <script lang="ts" setup>
46
46
  import {
47
47
  computed,
48
- inject,
49
48
  markRaw,
50
49
  nextTick,
51
50
  onBeforeUnmount,
@@ -62,8 +61,9 @@ import StageCore, { getOffset, Runtime } from '@tmagic/stage';
62
61
  import { calcValueByFontsize, getIdFromEl } from '@tmagic/utils';
63
62
 
64
63
  import ScrollViewer from '@editor/components/ScrollViewer.vue';
64
+ import { useServices } from '@editor/hooks';
65
65
  import { useStage } from '@editor/hooks/use-stage';
66
- import type { CustomContentMenuFunction, MenuButton, MenuComponent, Services, StageOptions } from '@editor/type';
66
+ import type { CustomContentMenuFunction, MenuButton, MenuComponent, StageOptions } from '@editor/type';
67
67
  import { DragType, Layout } from '@editor/type';
68
68
  import { getEditorConfig } from '@editor/utils/config';
69
69
  import { KeyBindingContainerKey } from '@editor/utils/keybinding-config';
@@ -91,22 +91,22 @@ const props = withDefaults(
91
91
  let stage: StageCore | null = null;
92
92
  let runtime: Runtime | null = null;
93
93
 
94
- const services = inject<Services>('services');
94
+ const { editorService, uiService, keybindingService } = useServices();
95
95
 
96
- const stageLoading = computed(() => services?.editorService.get('stageLoading') || false);
96
+ const stageLoading = computed(() => editorService.get('stageLoading'));
97
97
 
98
98
  const stageWrapRef = useTemplateRef<InstanceType<typeof ScrollViewer>>('stageWrap');
99
99
  const stageContainerEl = useTemplateRef<HTMLDivElement>('stageContainer');
100
100
  const menuRef = useTemplateRef<InstanceType<typeof ViewerMenu>>('menu');
101
101
 
102
- const nodes = computed(() => services?.editorService.get('nodes') || []);
102
+ const nodes = computed(() => editorService.get('nodes'));
103
103
  const isMultiSelect = computed(() => nodes.value.length > 1);
104
- const stageRect = computed(() => services?.uiService.get('stageRect'));
105
- const stageContainerRect = computed(() => services?.uiService.get('stageContainerRect'));
106
- const root = computed(() => services?.editorService.get('root'));
107
- const page = computed(() => services?.editorService.get('page'));
108
- const zoom = computed(() => services?.uiService.get('zoom') || 1);
109
- const node = computed(() => services?.editorService.get('node'));
104
+ const stageRect = computed(() => uiService.get('stageRect'));
105
+ const stageContainerRect = computed(() => uiService.get('stageContainerRect'));
106
+ const root = computed(() => editorService.get('root'));
107
+ const page = computed(() => editorService.get('page'));
108
+ const zoom = computed(() => uiService.get('zoom'));
109
+ const node = computed(() => editorService.get('node'));
110
110
 
111
111
  watchEffect(() => {
112
112
  if (stage || !page.value) return;
@@ -120,7 +120,7 @@ watchEffect(() => {
120
120
  stageWrapRef.value?.container?.focus();
121
121
  });
122
122
 
123
- services?.editorService.set('stage', markRaw(stage));
123
+ editorService.set('stage', markRaw(stage));
124
124
 
125
125
  stage.mount(stageContainerEl.value);
126
126
 
@@ -141,7 +141,7 @@ watchEffect(() => {
141
141
 
142
142
  onBeforeUnmount(() => {
143
143
  stage?.destroy();
144
- services?.editorService.set('stage', null);
144
+ editorService.set('stage', null);
145
145
  });
146
146
 
147
147
  watch(zoom, (zoom) => {
@@ -152,14 +152,14 @@ watch(zoom, (zoom) => {
152
152
  let timeoutId: NodeJS.Timeout | null = null;
153
153
  watch(page, (page) => {
154
154
  if (runtime && page) {
155
- services?.editorService.set('stageLoading', true);
155
+ editorService.set('stageLoading', true);
156
156
 
157
157
  if (timeoutId) {
158
158
  globalThis.clearTimeout(timeoutId);
159
159
  }
160
160
 
161
161
  timeoutId = globalThis.setTimeout(() => {
162
- services?.editorService.set('stageLoading', false);
162
+ editorService.set('stageLoading', false);
163
163
  timeoutId = null;
164
164
  }, 3000);
165
165
 
@@ -176,11 +176,11 @@ const rootChangeHandler = (root: MApp) => {
176
176
  }
177
177
  };
178
178
 
179
- services?.editorService.on('root-change', rootChangeHandler);
179
+ editorService.on('root-change', rootChangeHandler);
180
180
 
181
181
  const resizeObserver = new ResizeObserver((entries) => {
182
182
  for (const { contentRect } of entries) {
183
- services?.uiService.set('stageContainerRect', {
183
+ uiService.set('stageContainerRect', {
184
184
  width: contentRect.width,
185
185
  height: contentRect.height,
186
186
  });
@@ -190,16 +190,16 @@ const resizeObserver = new ResizeObserver((entries) => {
190
190
  onMounted(() => {
191
191
  if (stageWrapRef.value?.container) {
192
192
  resizeObserver.observe(stageWrapRef.value.container);
193
- services?.keybindingService.registerEl(KeyBindingContainerKey.STAGE, stageWrapRef.value.container);
193
+ keybindingService.registerEl(KeyBindingContainerKey.STAGE, stageWrapRef.value.container);
194
194
  }
195
195
  });
196
196
 
197
197
  onBeforeUnmount(() => {
198
198
  stage?.destroy();
199
199
  resizeObserver.disconnect();
200
- services?.editorService.set('stage', null);
201
- services?.keybindingService.unregisterEl('stage');
202
- services?.editorService.off('root-change', rootChangeHandler);
200
+ editorService.set('stage', null);
201
+ keybindingService.unregisterEl('stage');
202
+ editorService.off('root-change', rootChangeHandler);
203
203
  });
204
204
 
205
205
  const parseDSL = getEditorConfig('parseDSL');
@@ -236,11 +236,11 @@ const dropHandler = async (e: DragEvent) => {
236
236
  let parent: MContainer | undefined | null = page.value;
237
237
  const parentId = getIdFromEl()(parentEl);
238
238
  if (parentId) {
239
- parent = services?.editorService.getNodeById(parentId, false) as MContainer;
239
+ parent = editorService.getNodeById(parentId, false) as MContainer;
240
240
  }
241
241
 
242
242
  if (parent && stageContainerEl.value && stage) {
243
- const layout = await services?.editorService.getLayout(parent);
243
+ const layout = await editorService.getLayout(parent);
244
244
 
245
245
  const containerRect = stageContainerEl.value.getBoundingClientRect();
246
246
  const { scrollTop, scrollLeft } = stage.mask!;
@@ -275,7 +275,7 @@ const dropHandler = async (e: DragEvent) => {
275
275
 
276
276
  config.data.inputEvent = e;
277
277
 
278
- services?.editorService.add(config.data, parent);
278
+ editorService.add(config.data, parent);
279
279
  }
280
280
  };
281
281
  </script>
@@ -13,18 +13,19 @@ import { CloseBold } from '@element-plus/icons-vue';
13
13
 
14
14
  import { TMagicIcon } from '@tmagic/design';
15
15
 
16
- import type { Services, StageOptions } from '@editor/type';
16
+ import { useServices } from '@editor/hooks/use-services';
17
+ import type { StageOptions } from '@editor/type';
17
18
 
18
- const services = inject<Services>('services');
19
+ const { stageOverlayService, editorService } = useServices();
19
20
 
20
21
  const stageOptions = inject<StageOptions>('stageOptions');
21
22
 
22
23
  const stageOverlayEl = useTemplateRef<HTMLDivElement>('stageOverlay');
23
24
 
24
- const stageOverlayVisible = computed(() => services?.stageOverlayService.get('stageOverlayVisible'));
25
- const wrapWidth = computed(() => services?.stageOverlayService.get('wrapWidth') || 0);
26
- const wrapHeight = computed(() => services?.stageOverlayService.get('wrapHeight') || 0);
27
- const stage = computed(() => services?.editorService.get('stage'));
25
+ const stageOverlayVisible = computed(() => stageOverlayService.get('stageOverlayVisible'));
26
+ const wrapWidth = computed(() => stageOverlayService.get('wrapWidth'));
27
+ const wrapHeight = computed(() => stageOverlayService.get('wrapHeight'));
28
+ const stage = computed(() => editorService.get('stage'));
28
29
 
29
30
  const style = computed(() => ({
30
31
  width: `${wrapWidth.value}px`,
@@ -35,18 +36,16 @@ watch(stage, (stage) => {
35
36
  if (stage) {
36
37
  stage.on('dblclick', async (event: MouseEvent) => {
37
38
  const el = (await stage.actionManager?.getElementFromPoint(event)) || null;
38
- services?.stageOverlayService.openOverlay(el);
39
+ stageOverlayService.openOverlay(el);
39
40
  });
40
41
  } else {
41
- services?.stageOverlayService.closeOverlay();
42
+ stageOverlayService.closeOverlay();
42
43
  }
43
44
  });
44
45
 
45
46
  watch(stageOverlayEl, (stageOverlay) => {
46
- if (!services) return;
47
-
48
- const subStage = services.stageOverlayService.createStage(stageOptions);
49
- services?.stageOverlayService.set('stage', subStage);
47
+ const subStage = stageOverlayService.createStage(stageOptions);
48
+ stageOverlayService.set('stage', subStage);
50
49
 
51
50
  if (stageOverlay && subStage) {
52
51
  subStage.mount(stageOverlay);
@@ -56,18 +55,18 @@ watch(stageOverlayEl, (stageOverlay) => {
56
55
  const { contentWindow } = renderer!;
57
56
  mask?.showRule(false);
58
57
 
59
- services?.stageOverlayService.updateOverlay();
58
+ stageOverlayService.updateOverlay();
60
59
 
61
60
  contentWindow?.magic.onRuntimeReady({});
62
61
  }
63
62
  });
64
63
 
65
64
  onBeforeUnmount(() => {
66
- services?.stageOverlayService.get('stage')?.destroy();
67
- services?.stageOverlayService.set('stage', null);
65
+ stageOverlayService.get('stage')?.destroy();
66
+ stageOverlayService.set('stage', null);
68
67
  });
69
68
 
70
69
  const closeOverlayHandler = () => {
71
- services?.stageOverlayService.closeOverlay();
70
+ stageOverlayService.closeOverlay();
72
71
  };
73
72
  </script>
@@ -3,15 +3,16 @@
3
3
  </template>
4
4
 
5
5
  <script lang="ts" setup>
6
- import { computed, inject, markRaw, ref, useTemplateRef, watch } from 'vue';
6
+ import { computed, markRaw, ref, useTemplateRef, watch } from 'vue';
7
7
  import { Bottom, Top } from '@element-plus/icons-vue';
8
8
 
9
9
  import { NodeType } from '@tmagic/core';
10
10
  import { isPage, isPageFragment } from '@tmagic/utils';
11
11
 
12
12
  import ContentMenu from '@editor/components/ContentMenu.vue';
13
+ import { useServices } from '@editor/hooks/use-services';
13
14
  import CenterIcon from '@editor/icons/CenterIcon.vue';
14
- import { CustomContentMenuFunction, LayerOffset, Layout, MenuButton, MenuComponent, Services } from '@editor/type';
15
+ import { CustomContentMenuFunction, LayerOffset, Layout, MenuButton, MenuComponent } from '@editor/type';
15
16
  import { useCopyMenu, useDeleteMenu, useMoveToMenu, usePasteMenu } from '@editor/utils/content-menu';
16
17
 
17
18
  defineOptions({
@@ -29,14 +30,14 @@ const props = withDefaults(
29
30
  },
30
31
  );
31
32
 
32
- const services = inject<Services>('services');
33
- const editorService = services?.editorService;
33
+ const services = useServices();
34
+ const { editorService } = services;
34
35
  const menuRef = useTemplateRef<InstanceType<typeof ContentMenu>>('menu');
35
36
  const canCenter = ref(false);
36
37
 
37
- const node = computed(() => editorService?.get('node'));
38
- const nodes = computed(() => editorService?.get('nodes'));
39
- const parent = computed(() => editorService?.get('parent'));
38
+ const node = computed(() => editorService.get('node'));
39
+ const nodes = computed(() => editorService.get('nodes'));
40
+ const parent = computed(() => editorService.get('parent'));
40
41
 
41
42
  const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
42
43
  props.customContentMenu(
@@ -48,7 +49,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
48
49
  display: () => canCenter.value,
49
50
  handler: () => {
50
51
  if (!nodes.value) return;
51
- editorService?.alignCenter(nodes.value);
52
+ editorService.alignCenter(nodes.value);
52
53
  },
53
54
  },
54
55
  useCopyMenu(),
@@ -67,7 +68,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
67
68
  icon: markRaw(Top),
68
69
  display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
69
70
  handler: () => {
70
- editorService?.moveLayer(1);
71
+ editorService.moveLayer(1);
71
72
  },
72
73
  },
73
74
  {
@@ -76,7 +77,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
76
77
  icon: markRaw(Bottom),
77
78
  display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
78
79
  handler: () => {
79
- editorService?.moveLayer(-1);
80
+ editorService.moveLayer(-1);
80
81
  },
81
82
  },
82
83
  {
@@ -85,7 +86,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
85
86
  icon: markRaw(Top),
86
87
  display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
87
88
  handler: () => {
88
- editorService?.moveLayer(LayerOffset.TOP);
89
+ editorService.moveLayer(LayerOffset.TOP);
89
90
  },
90
91
  },
91
92
  {
@@ -94,7 +95,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
94
95
  icon: markRaw(Bottom),
95
96
  display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
96
97
  handler: () => {
97
- editorService?.moveLayer(LayerOffset.BOTTOM);
98
+ editorService.moveLayer(LayerOffset.BOTTOM);
98
99
  },
99
100
  },
100
101
  useMoveToMenu(services),
@@ -112,7 +113,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
112
113
  type: 'button',
113
114
  text: '清空参考线',
114
115
  handler: () => {
115
- editorService?.get('stage')?.clearGuides();
116
+ editorService.get('stage')?.clearGuides();
116
117
  },
117
118
  },
118
119
  ...props.stageContentMenu,
@@ -124,7 +125,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() =>
124
125
  watch(
125
126
  parent,
126
127
  async () => {
127
- if (!parent.value || !editorService) return (canCenter.value = false);
128
+ if (!parent.value) return (canCenter.value = false);
128
129
  const layout = await editorService.getLayout(parent.value);
129
130
  const isLayoutConform = [Layout.ABSOLUTE, Layout.FIXED].includes(layout);
130
131
  const isTypeConform = nodes.value?.every(
@@ -16,6 +16,7 @@
16
16
  * limitations under the License.
17
17
  */
18
18
  import { reactive, shallowReactive } from 'vue';
19
+ import { throttle } from 'lodash-es';
19
20
 
20
21
  import type { DepExtendedData, Id, MNode, Target, TargetNode } from '@tmagic/core';
21
22
  import { DepTargetType, Watcher } from '@tmagic/core';
@@ -34,19 +35,32 @@ export interface DepEvents {
34
35
 
35
36
  interface State {
36
37
  collecting: boolean;
38
+ taskLength: number;
37
39
  }
38
40
 
39
41
  type StateKey = keyof State;
40
42
 
41
- const idleTask = new IdleTask<{ node: TargetNode; deep: boolean; target: Target }>();
42
-
43
43
  class Dep extends BaseService {
44
44
  private state = shallowReactive<State>({
45
45
  collecting: false,
46
+ taskLength: 0,
46
47
  });
47
48
 
49
+ private idleTask = new IdleTask<{ node: TargetNode; deep: boolean; target: Target }>();
50
+
48
51
  private watcher = new Watcher({ initialTargets: reactive({}) });
49
52
 
53
+ constructor() {
54
+ super();
55
+
56
+ this.idleTask.on(
57
+ 'update-task-length',
58
+ throttle(({ length }) => {
59
+ this.set('taskLength', length);
60
+ }, 1000),
61
+ );
62
+ }
63
+
50
64
  public set<K extends StateKey, T extends State[K]>(name: K, value: T) {
51
65
  this.state[name] = value;
52
66
  }
@@ -116,11 +130,11 @@ class Dep extends BaseService {
116
130
  resolve();
117
131
  return;
118
132
  }
119
- idleTask.once('finish', () => {
133
+ this.idleTask.once('finish', () => {
120
134
  this.emit('collected', nodes, deep);
121
135
  this.set('collecting', false);
122
136
  });
123
- idleTask.once('hight-level-finish', () => {
137
+ this.idleTask.once('hight-level-finish', () => {
124
138
  this.emit('ds-collected', nodes, deep);
125
139
  resolve();
126
140
  });
@@ -159,7 +173,7 @@ class Dep extends BaseService {
159
173
  }
160
174
 
161
175
  public clearIdleTasks() {
162
- idleTask.clearTasks();
176
+ this.idleTask.clearTasks();
163
177
  }
164
178
 
165
179
  public on<Name extends keyof DepEvents, Param extends DepEvents[Name]>(
@@ -177,8 +191,8 @@ class Dep extends BaseService {
177
191
  }
178
192
 
179
193
  public reset() {
180
- idleTask.removeAllListeners();
181
- idleTask.clearTasks();
194
+ this.idleTask.removeAllListeners();
195
+ this.idleTask.clearTasks();
182
196
 
183
197
  for (const type of Object.keys(this.watcher.getTargetsList())) {
184
198
  this.removeTargets(type);
@@ -191,6 +205,7 @@ class Dep extends BaseService {
191
205
  this.removeAllListeners();
192
206
  this.reset();
193
207
  this.removeAllPlugins();
208
+ this.idleTask.removeAllListeners();
194
209
  }
195
210
 
196
211
  public emit<Name extends keyof DepEvents, Param extends DepEvents[Name]>(eventName: Name, ...args: Param) {
@@ -198,7 +213,7 @@ class Dep extends BaseService {
198
213
  }
199
214
 
200
215
  private enqueueTask(node: MNode, target: Target, depExtendedData: DepExtendedData, deep: boolean) {
201
- idleTask.enqueueTask(
216
+ this.idleTask.enqueueTask(
202
217
  ({ node, deep, target }) => {
203
218
  this.collectNode(node, target, depExtendedData, deep);
204
219
  },
@@ -31,6 +31,7 @@ import {
31
31
  } from '@editor/utils/const';
32
32
 
33
33
  import BaseService from './BaseService';
34
+ import storageService, { Protocol } from './storage';
34
35
 
35
36
  const state = shallowReactive<UiState>({
36
37
  uiSelectMode: false,
@@ -46,9 +47,12 @@ const state = shallowReactive<UiState>({
46
47
  height: 817,
47
48
  },
48
49
  columnWidth: {
49
- left: Number(globalThis.localStorage.getItem(LEFT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_LEFT_COLUMN_WIDTH,
50
+ left:
51
+ storageService.getItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, { protocol: Protocol.NUMBER }) || DEFAULT_LEFT_COLUMN_WIDTH,
50
52
  center: 0,
51
- right: Number(globalThis.localStorage.getItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_RIGHT_COLUMN_WIDTH,
53
+ right:
54
+ storageService.getItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY, { protocol: Protocol.NUMBER }) ||
55
+ DEFAULT_RIGHT_COLUMN_WIDTH,
52
56
  },
53
57
  showGuides: true,
54
58
  showRule: true,
@@ -10,6 +10,7 @@ $nav--background-color: #ffffff;
10
10
 
11
11
  $sidebar-heder-background-color: $theme-color;
12
12
  $sidebar-content-background-color: #ffffff;
13
+ $sidebar-heder-width: 40px;
13
14
 
14
15
  $page-bar-height: 32px;
15
16
 
@@ -3,11 +3,12 @@
3
3
  .m-editor-sidebar {
4
4
  display: flex;
5
5
  height: 100%;
6
+ position: relative;
6
7
 
7
8
  .m-editor-sidebar-header {
8
9
  background: $sidebar-heder-background-color;
9
10
  height: 100%;
10
- width: 40px;
11
+ width: $sidebar-heder-width;
11
12
 
12
13
  .m-editor-sidebar-header-item {
13
14
  line-height: 15px;
@@ -52,6 +53,24 @@
52
53
  overflow: auto;
53
54
  }
54
55
 
56
+ .m-editor-sidebar-tips {
57
+ position: absolute;
58
+ bottom: 0;
59
+ left: $sidebar-heder-width;
60
+ width: calc(100% - #{$sidebar-heder-width});
61
+ text-align: center;
62
+ background-color: rgba(252.5, 245.7, 235.5, 0.9);
63
+ color: #e6a23c;
64
+ padding: 5px 0;
65
+ font-size: 12px;
66
+
67
+ .close-icon {
68
+ cursor: pointer;
69
+ position: absolute;
70
+ right: 15px;
71
+ }
72
+ }
73
+
55
74
  .fold-icon {
56
75
  position: absolute;
57
76
  bottom: 8px;