@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
@@ -50,7 +50,7 @@
50
50
  </template>
51
51
 
52
52
  <script lang="ts" setup>
53
- import { computed, inject } from 'vue';
53
+ import { computed } from 'vue';
54
54
  import { Delete } from '@element-plus/icons-vue';
55
55
  import { has } from 'lodash-es';
56
56
 
@@ -68,7 +68,8 @@ import type {
68
68
  import { MContainer as MFormContainer, MPanel } from '@tmagic/form';
69
69
  import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX, traverseNode } from '@tmagic/utils';
70
70
 
71
- import type { CodeSelectColConfig, DataSourceMethodSelectConfig, EventSelectConfig, Services } from '@editor/type';
71
+ import { useServices } from '@editor/hooks/use-services';
72
+ import type { CodeSelectColConfig, DataSourceMethodSelectConfig, EventSelectConfig } from '@editor/type';
72
73
  import { getCascaderOptionsFromFields } from '@editor/utils';
73
74
 
74
75
  defineOptions({
@@ -81,12 +82,7 @@ const emit = defineEmits<{
81
82
  change: [v: any, eventData?: ContainerChangeEventData];
82
83
  }>();
83
84
 
84
- const services = inject<Services>('services');
85
-
86
- const editorService = services?.editorService;
87
- const dataSourceService = services?.dataSourceService;
88
- const eventsService = services?.eventsService;
89
- const codeBlockService = services?.codeBlockService;
85
+ const { editorService, dataSourceService, eventsService, codeBlockService } = useServices();
90
86
 
91
87
  // 事件名称下拉框表单配置
92
88
  const eventNameConfig = computed(() => {
@@ -108,13 +104,11 @@ const eventNameConfig = computed(() => {
108
104
  options: (mForm: FormState, { formValue }: any) => {
109
105
  let events: EventOption[] | CascaderOption[] = [];
110
106
 
111
- if (!eventsService || !dataSourceService) return events;
112
-
113
107
  if (props.config.src === 'component') {
114
108
  events = eventsService.getEvent(formValue.type);
115
109
 
116
110
  if (formValue.type === 'page-fragment-container' && formValue.pageFragmentId) {
117
- const pageFragment = editorService?.get('root')?.items?.find((page) => page.id === formValue.pageFragmentId);
111
+ const pageFragment = editorService.get('root')?.items?.find((page) => page.id === formValue.pageFragmentId);
118
112
  if (pageFragment) {
119
113
  events = [
120
114
  {
@@ -185,7 +179,7 @@ const actionTypeConfig = computed(() => {
185
179
  {
186
180
  text: '代码',
187
181
  label: '代码',
188
- disabled: !Object.keys(codeBlockService?.getCodeDsl() || {}).length,
182
+ disabled: !Object.keys(codeBlockService.getCodeDsl() || {}).length,
189
183
  value: ActionType.CODE,
190
184
  },
191
185
  {
@@ -193,7 +187,7 @@ const actionTypeConfig = computed(() => {
193
187
  label: '数据源',
194
188
  disabled: !dataSourceService
195
189
  ?.get('dataSources')
196
- ?.filter((ds) => ds.methods?.length || dataSourceService?.getFormMethod(ds.type).length).length,
190
+ ?.filter((ds) => ds.methods?.length || dataSourceService.getFormMethod(ds.type).length).length,
197
191
  value: ActionType.DATA_SOURCE,
198
192
  },
199
193
  ],
@@ -222,7 +216,7 @@ const compActionConfig = computed(() => {
222
216
  name: 'method',
223
217
  text: '动作',
224
218
  type: (mForm, { model }: any) => {
225
- const to = editorService?.getNodeById(model.to);
219
+ const to = editorService.getNodeById(model.to);
226
220
 
227
221
  if (to && to.type === 'page-fragment-container' && to.pageFragmentId) {
228
222
  return 'cascader';
@@ -233,20 +227,20 @@ const compActionConfig = computed(() => {
233
227
  checkStrictly: () => props.config.src !== 'component',
234
228
  display: (mForm, { model }: any) => model.actionType === ActionType.COMP,
235
229
  options: (mForm: FormState, { model }: any) => {
236
- const node = editorService?.getNodeById(model.to);
230
+ const node = editorService.getNodeById(model.to);
237
231
  if (!node?.type) return [];
238
232
 
239
233
  let methods: EventOption[] | CascaderOption[] = [];
240
234
 
241
- methods = eventsService?.getMethod(node.type) || [];
235
+ methods = eventsService.getMethod(node.type);
242
236
 
243
237
  if (node.type === 'page-fragment-container' && node.pageFragmentId) {
244
- const pageFragment = editorService?.get('root')?.items?.find((page) => page.id === node.pageFragmentId);
238
+ const pageFragment = editorService.get('root')?.items?.find((page) => page.id === node.pageFragmentId);
245
239
  if (pageFragment) {
246
240
  methods = [];
247
241
  pageFragment.items.forEach((node: MComponent | MContainer) => {
248
242
  traverseNode<MComponent | MContainer>(node, (node) => {
249
- const nodeMethods = (node.type && eventsService?.getMethod(node.type)) || [];
243
+ const nodeMethods = (node.type && eventsService.getMethod(node.type)) || [];
250
244
 
251
245
  if (nodeMethods.length) {
252
246
  methods.push({
@@ -277,7 +271,7 @@ const codeActionConfig = computed(() => {
277
271
  type: 'code-select-col',
278
272
  text: '代码块',
279
273
  name: 'codeId',
280
- notEditable: () => !codeBlockService?.getEditStatus(),
274
+ notEditable: () => !codeBlockService.getEditStatus(),
281
275
  display: (mForm, { model }) => model.actionType === ActionType.CODE,
282
276
  };
283
277
  return { ...defaultCodeActionConfig, ...props.config.codeActionConfig };
@@ -289,7 +283,7 @@ const dataSourceActionConfig = computed(() => {
289
283
  type: 'data-source-method-select',
290
284
  text: '数据源方法',
291
285
  name: 'dataSourceMethod',
292
- notEditable: () => !services?.dataSourceService.get('editable'),
286
+ notEditable: () => !dataSourceService.get('editable'),
293
287
  display: (mForm, { model }) => model.actionType === ActionType.DATA_SOURCE,
294
288
  };
295
289
  return { ...defaultDataSourceActionConfig, ...props.config.dataSourceActionConfig };
@@ -305,7 +299,7 @@ const tableConfig = computed(() => ({
305
299
  label: '事件名',
306
300
  type: eventNameConfig.value.type,
307
301
  options: (mForm: FormState, { formValue }: any) =>
308
- eventsService?.getEvent(formValue.type).map((option: any) => ({
302
+ eventsService.getEvent(formValue.type).map((option: any) => ({
309
303
  text: option.label,
310
304
  value: option.value,
311
305
  })),
@@ -320,10 +314,10 @@ const tableConfig = computed(() => ({
320
314
  label: '动作',
321
315
  type: compActionConfig.value.type,
322
316
  options: (mForm: FormState, { model }: any) => {
323
- const node = editorService?.getNodeById(model.to);
317
+ const node = editorService.getNodeById(model.to);
324
318
  if (!node?.type) return [];
325
319
 
326
- return eventsService?.getMethod(node.type).map((option: any) => ({
320
+ return eventsService.getMethod(node.type).map((option: any) => ({
327
321
  text: option.label,
328
322
  value: option.value,
329
323
  }));
@@ -16,27 +16,28 @@
16
16
  </template>
17
17
 
18
18
  <script lang="ts" setup>
19
- import { computed, inject } from 'vue';
19
+ import { computed } from 'vue';
20
20
  import { Edit } from '@element-plus/icons-vue';
21
21
 
22
22
  import { Id, NodeType } from '@tmagic/core';
23
23
  import { FieldProps } from '@tmagic/form';
24
24
 
25
25
  import Icon from '@editor/components/Icon.vue';
26
- import type { PageFragmentSelectConfig, Services } from '@editor/type';
26
+ import { useServices } from '@editor/hooks/use-services';
27
+ import type { PageFragmentSelectConfig } from '@editor/type';
27
28
 
28
29
  defineOptions({
29
30
  name: 'MFieldsPageFragmentSelect',
30
31
  });
31
32
 
32
- const services = inject<Services>('services');
33
+ const { editorService } = useServices();
33
34
  const emit = defineEmits(['change']);
34
35
 
35
36
  const props = withDefaults(defineProps<FieldProps<PageFragmentSelectConfig>>(), {
36
37
  disabled: false,
37
38
  });
38
39
  const pageList = computed(() =>
39
- services?.editorService.get('root')?.items.filter((item) => item.type === NodeType.PAGE_FRAGMENT),
40
+ editorService.get('root')?.items.filter((item) => item.type === NodeType.PAGE_FRAGMENT),
40
41
  );
41
42
 
42
43
  const selectConfig = {
@@ -58,6 +59,6 @@ const changeHandler = async () => {
58
59
  };
59
60
 
60
61
  const editPageFragment = (id: Id) => {
61
- services?.editorService.select(id);
62
+ editorService.select(id);
62
63
  };
63
64
  </script>
@@ -50,7 +50,8 @@ import { TMagicButton, TMagicTooltip } from '@tmagic/design';
50
50
  import type { FieldProps, FormItem, FormState } from '@tmagic/form';
51
51
  import { getIdFromEl } from '@tmagic/utils';
52
52
 
53
- import { type Services, UI_SELECT_MODE_EVENT_NAME } from '@editor/type';
53
+ import { useServices } from '@editor/hooks/use-services';
54
+ import { UI_SELECT_MODE_EVENT_NAME } from '@editor/utils/const';
54
55
 
55
56
  defineOptions({
56
57
  name: 'MFieldsUISelect',
@@ -60,14 +61,14 @@ const props = defineProps<FieldProps<{ type: 'ui-select' } & FormItem>>();
60
61
 
61
62
  const emit = defineEmits(['change']);
62
63
 
63
- const services = inject<Services>('services');
64
+ const { editorService, uiService, stageOverlayService } = useServices();
64
65
  const mForm = inject<FormState>('mForm');
66
+
65
67
  const val = computed(() => props.model[props.name]);
66
68
  const uiSelectMode = ref(false);
67
69
 
68
70
  const cancelHandler = () => {
69
- if (!services?.uiService) return;
70
- services.uiService.set('uiSelectMode', false);
71
+ uiService.set('uiSelectMode', false);
71
72
  uiSelectMode.value = false;
72
73
  globalThis.document.removeEventListener(UI_SELECT_MODE_EVENT_NAME, clickHandler as EventListener);
73
74
  };
@@ -89,13 +90,12 @@ const clickHandler = ({ detail }: Event & { detail: HTMLElement | MNode }) => {
89
90
  };
90
91
 
91
92
  const toName = computed(() => {
92
- const config = services?.editorService.getNodeById(val.value);
93
+ const config = editorService.getNodeById(val.value);
93
94
  return config?.name || '';
94
95
  });
95
96
 
96
97
  const startSelect = () => {
97
- if (!services?.uiService) return;
98
- services.uiService.set('uiSelectMode', true);
98
+ uiService.set('uiSelectMode', true);
99
99
  uiSelectMode.value = true;
100
100
  globalThis.document.addEventListener(UI_SELECT_MODE_EVENT_NAME, clickHandler as EventListener);
101
101
  };
@@ -109,24 +109,21 @@ const deleteHandler = () => {
109
109
  };
110
110
 
111
111
  const selectNode = async (id: Id) => {
112
- if (!services) return;
113
- await services.editorService.select(id);
114
- services.editorService.get('stage')?.select(id);
115
- services.stageOverlayService.get('stage')?.select(id);
112
+ await editorService.select(id);
113
+ editorService.get('stage')?.select(id);
114
+ stageOverlayService.get('stage')?.select(id);
116
115
  };
117
116
 
118
117
  const highlight = throttle((id: Id) => {
119
- if (!services) return;
120
- services.editorService.highlight(id);
121
- services.editorService.get('stage')?.highlight(id);
122
- services.stageOverlayService.get('stage')?.highlight(id);
118
+ editorService.highlight(id);
119
+ editorService.get('stage')?.highlight(id);
120
+ stageOverlayService.get('stage')?.highlight(id);
123
121
  }, 150);
124
122
 
125
123
  const unhighlight = () => {
126
- if (!services) return;
127
- services.editorService.set('highlightNode', null);
128
- services.editorService.get('stage')?.clearHighlight();
129
- services.stageOverlayService.get('stage')?.clearHighlight();
124
+ editorService.set('highlightNode', null);
125
+ editorService.get('stage')?.clearHighlight();
126
+ stageOverlayService.get('stage')?.clearHighlight();
130
127
  };
131
128
  </script>
132
129
 
@@ -28,3 +28,4 @@ export * from './use-next-float-box-position';
28
28
  export * from './use-node-status';
29
29
  export * from './use-stage';
30
30
  export * from './use-window-rect';
31
+ export * from './use-services';
@@ -5,20 +5,15 @@ import type { CodeBlockContent } from '@tmagic/core';
5
5
  import { tMagicMessage } from '@tmagic/design';
6
6
 
7
7
  import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
8
- import type { CodeBlockService } from '@editor/services/codeBlock';
8
+ import type { Services } from '@editor/type';
9
9
 
10
- export const useCodeBlockEdit = (codeBlockService?: CodeBlockService) => {
10
+ export const useCodeBlockEdit = (codeBlockService: Services['codeBlockService']) => {
11
11
  const codeConfig = ref<CodeBlockContent>();
12
12
  const codeId = ref<string>();
13
13
  const codeBlockEditorRef = useTemplateRef<InstanceType<typeof CodeBlockEditor>>('codeBlockEditor');
14
14
 
15
15
  // 新增代码块
16
16
  const createCodeBlock = async () => {
17
- if (!codeBlockService) {
18
- tMagicMessage.error('新增代码块失败');
19
- return;
20
- }
21
-
22
17
  codeConfig.value = {
23
18
  name: '',
24
19
  content: `({app, params, flowState}) => {\n // place your code here\n}`,
@@ -34,7 +29,7 @@ export const useCodeBlockEdit = (codeBlockService?: CodeBlockService) => {
34
29
 
35
30
  // 编辑代码块
36
31
  const editCode = async (id: string) => {
37
- const codeBlock = await codeBlockService?.getCodeContentById(id);
32
+ const codeBlock = await codeBlockService.getCodeContentById(id);
38
33
 
39
34
  if (!codeBlock) {
40
35
  tMagicMessage.error('获取代码块内容失败');
@@ -59,13 +54,13 @@ export const useCodeBlockEdit = (codeBlockService?: CodeBlockService) => {
59
54
 
60
55
  // 删除代码块
61
56
  const deleteCode = async (key: string) => {
62
- codeBlockService?.deleteCodeDslByIds([key]);
57
+ codeBlockService.deleteCodeDslByIds([key]);
63
58
  };
64
59
 
65
60
  const submitCodeBlockHandler = async (values: CodeBlockContent) => {
66
61
  if (!codeId.value) return;
67
62
 
68
- await codeBlockService?.setCodeDslById(codeId.value, values);
63
+ await codeBlockService.setCodeDslById(codeId.value, values);
69
64
 
70
65
  codeBlockEditorRef.value?.hide();
71
66
  };
@@ -4,20 +4,20 @@ import type { DataSourceSchema } from '@tmagic/core';
4
4
  import type { ContainerChangeEventData } from '@tmagic/form';
5
5
 
6
6
  import DataSourceConfigPanel from '@editor/layouts/sidebar/data-source/DataSourceConfigPanel.vue';
7
- import type { DataSourceService } from '@editor/services/dataSource';
7
+ import type { Services } from '@editor/type';
8
8
 
9
- export const useDataSourceEdit = (dataSourceService?: DataSourceService) => {
9
+ export const useDataSourceEdit = (dataSourceService: Services['dataSourceService']) => {
10
10
  const dialogTitle = ref('');
11
11
  const editDialog = ref<InstanceType<typeof DataSourceConfigPanel>>();
12
12
  const dataSourceValues = ref<Record<string, any>>({});
13
13
 
14
- const editable = computed(() => dataSourceService?.get('editable') ?? true);
14
+ const editable = computed(() => dataSourceService.get('editable'));
15
15
 
16
16
  const editHandler = (id: string) => {
17
17
  if (!editDialog.value) return;
18
18
 
19
19
  dataSourceValues.value = {
20
- ...dataSourceService?.getDataSourceById(id),
20
+ ...(dataSourceService.getDataSourceById(id) || {}),
21
21
  };
22
22
 
23
23
  dialogTitle.value = `编辑${dataSourceValues.value.title || ''}`;
@@ -27,9 +27,9 @@ export const useDataSourceEdit = (dataSourceService?: DataSourceService) => {
27
27
 
28
28
  const submitDataSourceHandler = (value: DataSourceSchema, eventData: ContainerChangeEventData) => {
29
29
  if (value.id) {
30
- dataSourceService?.update(value, { changeRecords: eventData.changeRecords });
30
+ dataSourceService.update(value, { changeRecords: eventData.changeRecords });
31
31
  } else {
32
- dataSourceService?.add(value);
32
+ dataSourceService.add(value);
33
33
  }
34
34
 
35
35
  editDialog.value?.hide();
@@ -1,11 +1,11 @@
1
- import { computed, inject, ref, watch } from 'vue';
1
+ import { computed, ref, watch } from 'vue';
2
2
 
3
- import type { Services } from '@editor/type';
3
+ import { useServices } from './use-services';
4
4
 
5
5
  export const useEditorContentHeight = () => {
6
- const services = inject<Services>('services');
7
- const frameworkHeight = computed(() => services?.uiService.get('frameworkRect').height || 0);
8
- const navMenuHeight = computed(() => services?.uiService.get('navMenuRect').height || 0);
6
+ const { uiService } = useServices();
7
+ const frameworkHeight = computed(() => uiService.get('frameworkRect').height);
8
+ const navMenuHeight = computed(() => uiService.get('navMenuRect').height);
9
9
  const editorContentHeight = computed(() => frameworkHeight.value - navMenuHeight.value);
10
10
 
11
11
  const height = ref(0);
@@ -1,6 +1,6 @@
1
- import { computed, ComputedRef, inject, onBeforeUnmount, ref, watch } from 'vue';
1
+ import { computed, ComputedRef, onBeforeUnmount, ref, watch } from 'vue';
2
2
 
3
- import type { Services } from '@editor/type';
3
+ import { useServices } from './use-services';
4
4
 
5
5
  interface State {
6
6
  status: boolean;
@@ -9,7 +9,7 @@ interface State {
9
9
  }
10
10
 
11
11
  export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
12
- const services = inject<Services>('services');
12
+ const { uiService } = useServices();
13
13
 
14
14
  const floatBoxStates = ref<{
15
15
  [key in (typeof slideKeys.value)[number]]: State;
@@ -57,10 +57,10 @@ export const useFloatBox = (slideKeys: ComputedRef<string[]>) => {
57
57
  Math.abs(startOffset.x - e.clientX) > effectiveDistance ||
58
58
  Math.abs(startOffset.y - e.clientY) > effectiveDistance
59
59
  ) {
60
- const navMenuRect = services?.uiService?.get('navMenuRect');
60
+ const navMenuRect = uiService.get('navMenuRect');
61
61
  floatBoxStates.value[key] = {
62
62
  left: e.clientX,
63
- top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
63
+ top: navMenuRect.top + navMenuRect.height,
64
64
  status: true,
65
65
  };
66
66
  }
@@ -1,24 +1,24 @@
1
- import { Ref, ref } from 'vue';
1
+ import { type Ref, ref } from 'vue';
2
2
 
3
- import { UiService } from '@editor/services/ui';
3
+ import type { Services } from '@editor/type';
4
4
 
5
- export const useNextFloatBoxPosition = (uiService?: UiService, parent?: Ref<HTMLDivElement | null>) => {
5
+ export const useNextFloatBoxPosition = (uiService: Services['uiService'], parent?: Ref<HTMLDivElement | null>) => {
6
6
  const boxPosition = ref({
7
7
  left: 0,
8
8
  top: 0,
9
9
  });
10
10
 
11
11
  const calcBoxPosition = () => {
12
- const columnWidth = uiService?.get('columnWidth');
13
- const navMenuRect = uiService?.get('navMenuRect');
14
- let left = columnWidth?.left ?? 0;
12
+ const columnWidth = uiService.get('columnWidth');
13
+ const navMenuRect = uiService.get('navMenuRect');
14
+ let left = columnWidth.left ?? 0;
15
15
  if (parent?.value) {
16
- const rect = parent?.value?.getBoundingClientRect();
17
- left = (rect?.left ?? 0) + (rect?.width ?? 0);
16
+ const rect = parent.value.getBoundingClientRect();
17
+ left = rect.left + rect.width;
18
18
  }
19
19
  boxPosition.value = {
20
20
  left,
21
- top: (navMenuRect?.top ?? 0) + (navMenuRect?.height ?? 0),
21
+ top: navMenuRect.top + navMenuRect.height,
22
22
  };
23
23
  };
24
24
 
@@ -0,0 +1,13 @@
1
+ import { inject } from 'vue';
2
+
3
+ import type { Services } from '@editor/type';
4
+
5
+ export const useServices = () => {
6
+ const services = inject<Services>('services');
7
+
8
+ if (!services) {
9
+ throw new Error('services is required');
10
+ }
11
+
12
+ return services;
13
+ };
@@ -6,12 +6,8 @@ import { getIdFromEl } from '@tmagic/utils';
6
6
 
7
7
  import editorService from '@editor/services/editor';
8
8
  import uiService from '@editor/services/ui';
9
- import {
10
- H_GUIDE_LINE_STORAGE_KEY,
11
- StageOptions,
12
- UI_SELECT_MODE_EVENT_NAME,
13
- V_GUIDE_LINE_STORAGE_KEY,
14
- } from '@editor/type';
9
+ import type { StageOptions } from '@editor/type';
10
+ import { H_GUIDE_LINE_STORAGE_KEY, UI_SELECT_MODE_EVENT_NAME, V_GUIDE_LINE_STORAGE_KEY } from '@editor/utils/const';
15
11
  import { getGuideLineFromCache } from '@editor/utils/editor';
16
12
 
17
13
  const root = computed(() => editorService.get('root'));
@@ -19,13 +19,13 @@
19
19
  </template>
20
20
 
21
21
  <script lang="ts" setup>
22
- import { inject, toRaw } from 'vue';
22
+ import { toRaw } from 'vue';
23
23
  import { Plus } from '@element-plus/icons-vue';
24
24
 
25
25
  import { NodeType } from '@tmagic/core';
26
26
 
27
27
  import MIcon from '@editor/components/Icon.vue';
28
- import type { Services } from '@editor/type';
28
+ import { useServices } from '@editor/hooks/use-services';
29
29
  import { generatePageNameByApp } from '@editor/utils';
30
30
 
31
31
  defineOptions({
@@ -36,13 +36,9 @@ defineProps<{
36
36
  disabledPageFragment: boolean;
37
37
  }>();
38
38
 
39
- const services = inject<Services>('services');
39
+ const { editorService } = useServices();
40
40
 
41
41
  const clickHandler = (type: NodeType.PAGE | NodeType.PAGE_FRAGMENT) => {
42
- const { editorService } = services || {};
43
-
44
- if (!editorService) return;
45
-
46
42
  const root = toRaw(editorService.get('root'));
47
43
  if (!root) throw new Error('root 不能为空');
48
44
 
@@ -19,10 +19,10 @@
19
19
  right-class="m-editor-framework-right"
20
20
  :left="columnWidth.left"
21
21
  :right="columnWidth.right"
22
- :min-left="200"
23
- :min-right="300"
24
- :min-center="400"
25
- :width="frameworkRect?.width || 0"
22
+ :min-left="MIN_LEFT_COLUMN_WIDTH"
23
+ :min-right="MIN_RIGHT_COLUMN_WIDTH"
24
+ :min-center="MIN_CENTER_COLUMN_WIDTH"
25
+ :width="frameworkRect.width"
26
26
  @change="columnWidthChange"
27
27
  >
28
28
  <template #left>
@@ -65,11 +65,16 @@ import { computed, inject, onBeforeUnmount, onMounted, useTemplateRef, watch } f
65
65
  import type { MPage, MPageFragment } from '@tmagic/core';
66
66
 
67
67
  import SplitView from '@editor/components/SplitView.vue';
68
- import type { FrameworkSlots, GetColumnWidth, PageBarSortOptions, Services } from '@editor/type';
68
+ import { useServices } from '@editor/hooks/use-services';
69
+ import { Protocol } from '@editor/services/storage';
70
+ import type { FrameworkSlots, GetColumnWidth, PageBarSortOptions } from '@editor/type';
69
71
  import { getEditorConfig } from '@editor/utils/config';
70
72
  import {
71
73
  DEFAULT_LEFT_COLUMN_WIDTH,
72
74
  LEFT_COLUMN_WIDTH_STORAGE_KEY,
75
+ MIN_CENTER_COLUMN_WIDTH,
76
+ MIN_LEFT_COLUMN_WIDTH,
77
+ MIN_RIGHT_COLUMN_WIDTH,
73
78
  RIGHT_COLUMN_WIDTH_STORAGE_KEY,
74
79
  } from '@editor/utils/const';
75
80
 
@@ -90,53 +95,48 @@ defineProps<{
90
95
  }>();
91
96
 
92
97
  const codeOptions = inject('codeOptions', {});
93
- const { editorService, uiService } = inject<Services>('services') || {};
98
+ const { editorService, uiService, storageService } = useServices();
94
99
 
95
100
  const contentEl = useTemplateRef<HTMLDivElement>('content');
96
101
  const splitViewRef = useTemplateRef<InstanceType<typeof SplitView>>('splitView');
97
102
 
98
- const root = computed(() => editorService?.get('root'));
99
- const page = computed(() => editorService?.get('page'));
103
+ const root = computed(() => editorService.get('root'));
104
+ const page = computed(() => editorService.get('page'));
100
105
 
101
- const pageLength = computed(() => editorService?.get('pageLength') || 0);
102
- const showSrc = computed(() => uiService?.get('showSrc'));
106
+ const pageLength = computed(() => editorService.get('pageLength') || 0);
107
+ const showSrc = computed(() => uiService.get('showSrc'));
103
108
 
104
- const columnWidth = computed(
105
- () =>
106
- uiService?.get('columnWidth') || {
107
- left: 0,
108
- center: 0,
109
- right: 0,
110
- },
111
- );
109
+ const columnWidth = computed(() => uiService.get('columnWidth'));
112
110
 
113
111
  watch(pageLength, () => {
114
112
  splitViewRef.value?.updateWidth();
115
113
  });
116
114
 
117
115
  watch(
118
- () => uiService?.get('hideSlideBar'),
116
+ () => uiService.get('hideSlideBar'),
119
117
  (hideSlideBar) => {
120
- uiService?.set('columnWidth', {
118
+ uiService.set('columnWidth', {
121
119
  ...columnWidth.value,
122
120
  left: hideSlideBar
123
121
  ? 0
124
- : Number(globalThis.localStorage.getItem(LEFT_COLUMN_WIDTH_STORAGE_KEY)) || DEFAULT_LEFT_COLUMN_WIDTH,
122
+ : storageService.getItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, { protocol: Protocol.NUMBER }) ||
123
+ DEFAULT_LEFT_COLUMN_WIDTH,
125
124
  });
126
125
  },
127
126
  );
128
127
 
129
128
  const columnWidthChange = (columnW: GetColumnWidth) => {
130
- globalThis.localStorage.setItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, `${columnW.left}`);
131
- globalThis.localStorage.setItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY, `${columnW.right}`);
132
- uiService?.set('columnWidth', columnW);
129
+ storageService.setItem(LEFT_COLUMN_WIDTH_STORAGE_KEY, columnW.left, { protocol: Protocol.NUMBER });
130
+ storageService.setItem(RIGHT_COLUMN_WIDTH_STORAGE_KEY, columnW.right, { protocol: Protocol.NUMBER });
131
+
132
+ uiService.set('columnWidth', columnW);
133
133
  };
134
134
 
135
- const frameworkRect = computed(() => uiService?.get('frameworkRect'));
135
+ const frameworkRect = computed(() => uiService.get('frameworkRect'));
136
136
 
137
137
  const resizerObserver = new ResizeObserver((entries) => {
138
138
  const { contentRect } = entries[0];
139
- uiService?.set('frameworkRect', {
139
+ uiService.set('frameworkRect', {
140
140
  width: contentRect.width,
141
141
  height: contentRect.height,
142
142
  left: contentRect.left,
@@ -157,7 +157,7 @@ onBeforeUnmount(() => {
157
157
  const saveCode = (value: string) => {
158
158
  try {
159
159
  const parseDSL = getEditorConfig('parseDSL');
160
- editorService?.set('root', parseDSL(value));
160
+ editorService.set('root', parseDSL(value));
161
161
  } catch (e: any) {
162
162
  console.error(e);
163
163
  }