@tmagic/editor 1.2.0-beta.9 → 1.2.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 (103) hide show
  1. package/dist/style.css +62 -34
  2. package/dist/{tmagic-editor.mjs → tmagic-editor.js} +1641 -1266
  3. package/dist/tmagic-editor.js.map +1 -0
  4. package/dist/{tmagic-editor.umd.js → tmagic-editor.umd.cjs} +1649 -1270
  5. package/dist/tmagic-editor.umd.cjs.map +1 -0
  6. package/package.json +16 -14
  7. package/src/Editor.vue +66 -40
  8. package/src/components/CodeDraftEditor.vue +137 -0
  9. package/src/components/ContentMenu.vue +1 -1
  10. package/src/components/FunctionEditor.vue +190 -0
  11. package/src/components/Icon.vue +1 -1
  12. package/src/{layouts → components}/Layout.vue +54 -15
  13. package/src/components/ScrollBar.vue +1 -1
  14. package/src/components/ScrollViewer.vue +10 -1
  15. package/src/components/ToolButton.vue +1 -1
  16. package/src/fields/Code.vue +1 -1
  17. package/src/fields/CodeLink.vue +1 -1
  18. package/src/fields/CodeSelect.vue +102 -99
  19. package/src/fields/UISelect.vue +3 -3
  20. package/src/index.ts +2 -1
  21. package/src/layouts/AddPageBox.vue +5 -2
  22. package/src/layouts/CodeEditor.vue +2 -3
  23. package/src/layouts/Framework.vue +12 -10
  24. package/src/layouts/NavMenu.vue +11 -8
  25. package/src/layouts/PropsPanel.vue +12 -9
  26. package/src/layouts/Resizer.vue +1 -1
  27. package/src/layouts/sidebar/ComponentListPanel.vue +2 -3
  28. package/src/layouts/sidebar/LayerMenu.vue +9 -7
  29. package/src/layouts/sidebar/LayerPanel.vue +130 -178
  30. package/src/layouts/sidebar/Sidebar.vue +110 -26
  31. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +33 -118
  32. package/src/layouts/sidebar/code-block/CodeBlockList.vue +93 -126
  33. package/src/layouts/workspace/Breadcrumb.vue +6 -7
  34. package/src/layouts/workspace/PageBar.vue +3 -3
  35. package/src/layouts/workspace/PageBarScrollContainer.vue +5 -3
  36. package/src/layouts/workspace/Stage.vue +36 -18
  37. package/src/layouts/workspace/ViewerMenu.vue +16 -15
  38. package/src/layouts/workspace/Workspace.vue +9 -6
  39. package/src/services/BaseService.ts +11 -2
  40. package/src/services/codeBlock.ts +136 -146
  41. package/src/services/componentList.ts +7 -2
  42. package/src/services/editor.ts +161 -85
  43. package/src/services/events.ts +7 -2
  44. package/src/services/history.ts +8 -17
  45. package/src/services/props.ts +8 -3
  46. package/src/services/storage.ts +1 -0
  47. package/src/services/ui.ts +20 -10
  48. package/src/theme/code-block.scss +46 -23
  49. package/src/theme/component-list-panel.scss +8 -5
  50. package/src/type.ts +84 -63
  51. package/src/utils/config.ts +1 -1
  52. package/src/utils/editor.ts +17 -3
  53. package/src/utils/index.ts +2 -1
  54. package/src/utils/logger.ts +1 -1
  55. package/src/utils/operator.ts +12 -12
  56. package/src/utils/props.ts +3 -3
  57. package/src/utils/scroll-viewer.ts +18 -2
  58. package/src/utils/stage.ts +10 -9
  59. package/src/utils/undo-redo.ts +1 -1
  60. package/types/Editor.vue.d.ts +48 -28
  61. package/types/components/CodeDraftEditor.vue.d.ts +55 -0
  62. package/types/components/ContentMenu.vue.d.ts +11 -87
  63. package/types/components/FunctionEditor.vue.d.ts +60 -0
  64. package/types/components/Icon.vue.d.ts +4 -50
  65. package/types/{layouts → components}/Layout.vue.d.ts +12 -1
  66. package/types/components/ScrollBar.vue.d.ts +7 -65
  67. package/types/components/ScrollViewer.vue.d.ts +45 -1
  68. package/types/components/ToolButton.vue.d.ts +12 -78
  69. package/types/fields/Code.vue.d.ts +11 -77
  70. package/types/fields/CodeLink.vue.d.ts +12 -82
  71. package/types/fields/CodeSelect.vue.d.ts +13 -77
  72. package/types/fields/UISelect.vue.d.ts +7 -65
  73. package/types/index.d.ts +1 -0
  74. package/types/layouts/AddPageBox.vue.d.ts +1 -43
  75. package/types/layouts/CodeEditor.vue.d.ts +22 -130
  76. package/types/layouts/NavMenu.vue.d.ts +9 -69
  77. package/types/layouts/sidebar/LayerMenu.vue.d.ts +16 -48
  78. package/types/layouts/sidebar/LayerPanel.vue.d.ts +24 -7
  79. package/types/layouts/sidebar/Sidebar.vue.d.ts +10 -5
  80. package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +24 -6
  81. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +11 -5
  82. package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -43
  83. package/types/layouts/workspace/Stage.vue.d.ts +15 -43
  84. package/types/layouts/workspace/ViewerMenu.vue.d.ts +11 -66
  85. package/types/layouts/workspace/Workspace.vue.d.ts +25 -8
  86. package/types/services/BaseService.d.ts +2 -1
  87. package/types/services/codeBlock.d.ts +56 -47
  88. package/types/services/componentList.d.ts +1 -0
  89. package/types/services/editor.d.ts +10 -11
  90. package/types/services/events.d.ts +1 -0
  91. package/types/services/history.d.ts +5 -15
  92. package/types/services/props.d.ts +3 -2
  93. package/types/services/ui.d.ts +24 -24
  94. package/types/type.d.ts +70 -59
  95. package/types/utils/editor.d.ts +1 -0
  96. package/types/utils/index.d.ts +1 -0
  97. package/types/utils/operator.d.ts +1 -1
  98. package/types/utils/props.d.ts +1 -1
  99. package/types/utils/scroll-viewer.d.ts +5 -0
  100. package/dist/tmagic-editor.mjs.map +0 -1
  101. package/dist/tmagic-editor.umd.js.map +0 -1
  102. package/src/layouts/sidebar/TabPane.vue +0 -118
  103. package/types/layouts/sidebar/TabPane.vue.d.ts +0 -82
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div ref="el" class="m-editor-layout">
3
- <template v-if="typeof props.left !== 'undefined'">
3
+ <template v-if="hasLeft">
4
4
  <div class="m-editor-layout-left" :class="leftClass" :style="`width: ${left}px`">
5
5
  <slot name="left"></slot>
6
6
  </div>
@@ -11,7 +11,7 @@
11
11
  <slot name="center"></slot>
12
12
  </div>
13
13
 
14
- <template v-if="typeof props.right !== 'undefined'">
14
+ <template v-if="hasRight">
15
15
  <Resizer @change="changeRight"></Resizer>
16
16
  <div class="m-editor-layout-right" :class="rightClass" :style="`width: ${right}px`">
17
17
  <slot name="right"></slot>
@@ -20,10 +20,10 @@
20
20
  </div>
21
21
  </template>
22
22
 
23
- <script lang="ts" setup>
24
- import { onMounted, onUnmounted, ref } from 'vue';
23
+ <script lang="ts" setup name="MEditorLayout">
24
+ import { computed, onMounted, onUnmounted, ref } from 'vue';
25
25
 
26
- import Resizer from './Resizer.vue';
26
+ import Resizer from '../layouts/Resizer.vue';
27
27
 
28
28
  const emit = defineEmits(['update:left', 'change', 'update:right']);
29
29
 
@@ -33,29 +33,64 @@ const props = withDefaults(
33
33
  right?: number;
34
34
  minLeft?: number;
35
35
  minRight?: number;
36
+ minCenter?: number;
36
37
  leftClass?: string;
37
38
  rightClass?: string;
38
39
  centerClass?: string;
39
40
  }>(),
40
41
  {
41
- minLeft: 1,
42
+ minLeft: 46,
42
43
  minRight: 1,
44
+ minCenter: 5,
43
45
  },
44
46
  );
45
47
 
46
48
  const el = ref<HTMLElement>();
47
49
 
50
+ const hasLeft = computed(() => typeof props.left !== 'undefined');
51
+ const hasRight = computed(() => typeof props.right !== 'undefined');
52
+
53
+ const getCenterWidth = (clientWidth: number, left: number, right: number) => {
54
+ let center = clientWidth - left - right;
55
+ if (center < props.minCenter) {
56
+ center = props.minCenter;
57
+ if (left < right) {
58
+ right = clientWidth - left - props.minCenter;
59
+ } else {
60
+ left = clientWidth - right - props.minCenter;
61
+ }
62
+ }
63
+ return {
64
+ center,
65
+ left,
66
+ right,
67
+ };
68
+ };
69
+
48
70
  let clientWidth = 0;
49
71
  const resizerObserver = new ResizeObserver((entries) => {
50
72
  for (const { contentRect } of entries) {
51
73
  clientWidth = contentRect.width;
52
74
 
53
- center.value = clientWidth - (props.left || 0) - (props.right || 0);
75
+ let left = props.left || 0;
76
+ let right = props.right || 0;
77
+
78
+ if (left > clientWidth) {
79
+ left = clientWidth / 3;
80
+ }
81
+
82
+ if (right > clientWidth) {
83
+ right = clientWidth / 3;
84
+ }
85
+
86
+ const columnWidth = getCenterWidth(clientWidth, left, right);
87
+
88
+ center.value = columnWidth.center;
54
89
 
55
90
  emit('change', {
56
- left: props.left,
91
+ left: columnWidth.left,
57
92
  center: center.value,
58
- right: props.right,
93
+ right: columnWidth.right,
59
94
  });
60
95
  }
61
96
  });
@@ -81,12 +116,14 @@ const changeLeft = (deltaX: number) => {
81
116
  left = props.left;
82
117
  }
83
118
 
84
- center.value = clientWidth - left - (props.right || 0);
119
+ const columnWidth = getCenterWidth(clientWidth, left, props.right || 0);
120
+
121
+ center.value = columnWidth.center;
85
122
 
86
123
  emit('change', {
87
- left,
124
+ left: columnWidth.left,
88
125
  center: center.value,
89
- right: props.right,
126
+ right: columnWidth.right,
90
127
  });
91
128
  };
92
129
 
@@ -99,12 +136,14 @@ const changeRight = (deltaX: number) => {
99
136
  right = props.right;
100
137
  }
101
138
 
102
- center.value = clientWidth - (props.left || 0) - right;
139
+ const columnWidth = getCenterWidth(clientWidth, props.left || 0, right);
140
+
141
+ center.value = columnWidth.center;
103
142
 
104
143
  emit('change', {
105
- left: props.left,
144
+ left: columnWidth.left,
106
145
  center: center.value,
107
- right,
146
+ right: columnWidth.right,
108
147
  });
109
148
  };
110
149
  </script>
@@ -4,7 +4,7 @@
4
4
  </div>
5
5
  </template>
6
6
 
7
- <script lang="ts" setup>
7
+ <script lang="ts" setup name="MEditorScrollBar">
8
8
  import { computed, onMounted, onUnmounted, ref } from 'vue';
9
9
  import Gesto from 'gesto';
10
10
 
@@ -22,7 +22,7 @@
22
22
  </div>
23
23
  </template>
24
24
 
25
- <script lang="ts" setup>
25
+ <script lang="ts" setup name="MEditorScrollViewer">
26
26
  import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
27
27
 
28
28
  import { ScrollViewerEvent } from '../type';
@@ -37,6 +37,10 @@ const props = withDefaults(
37
37
  wrapWidth?: number;
38
38
  wrapHeight?: number;
39
39
  zoom?: number;
40
+ correctionScrollSize?: {
41
+ width: number;
42
+ height: number;
43
+ };
40
44
  }>(),
41
45
  {
42
46
  width: 0,
@@ -44,6 +48,10 @@ const props = withDefaults(
44
48
  wrapWidth: 0,
45
49
  wrapHeight: 0,
46
50
  zoom: 1,
51
+ correctionScrollSize: () => ({
52
+ width: 0,
53
+ height: 0,
54
+ }),
47
55
  },
48
56
  );
49
57
 
@@ -69,6 +77,7 @@ onMounted(() => {
69
77
  container: container.value,
70
78
  target: el.value,
71
79
  zoom: props.zoom,
80
+ correctionScrollSize: props.correctionScrollSize,
72
81
  });
73
82
 
74
83
  scrollViewer.on('scroll', (data: ScrollViewerEvent) => {
@@ -43,7 +43,7 @@
43
43
  </div>
44
44
  </template>
45
45
 
46
- <script lang="ts" setup>
46
+ <script lang="ts" setup name="MEditorToolButton">
47
47
  import { computed, inject } from 'vue';
48
48
  import { ArrowDown } from '@element-plus/icons-vue';
49
49
 
@@ -8,7 +8,7 @@
8
8
  ></magic-code-editor>
9
9
  </template>
10
10
 
11
- <script lang="ts" setup>
11
+ <script lang="ts" setup name="MEditorCode">
12
12
  import { computed } from 'vue';
13
13
 
14
14
  const emit = defineEmits(['change']);
@@ -2,7 +2,7 @@
2
2
  <m-fields-link :config="formConfig" :model="modelValue" name="form" @change="changeHandler"></m-fields-link>
3
3
  </template>
4
4
 
5
- <script lang="ts" setup>
5
+ <script lang="ts" setup name="MEditorCodeLink">
6
6
  import { computed, reactive, watch } from 'vue';
7
7
  import serialize from 'serialize-javascript';
8
8
 
@@ -1,131 +1,134 @@
1
1
  <template>
2
- <div class="m-fields-code-select" :key="fieldKey">
3
- <TMagicCard shadow="never">
4
- <template #header>
5
- <m-fields-select
6
- :config="selectConfig"
7
- :model="model"
8
- :prop="prop"
9
- :name="name"
10
- :size="size"
11
- @change="changeHandler"
12
- ></m-fields-select>
2
+ <div class="m-fields-code-select">
3
+ <m-form-table
4
+ :config="tableConfig"
5
+ :model="model[name]"
6
+ name="hookData"
7
+ :enableToggleMode="false"
8
+ :prop="prop"
9
+ :size="size"
10
+ @change="changeHandler"
11
+ >
12
+ <template #operateCol="{ scope }">
13
+ <Icon
14
+ v-if="scope.row.codeId"
15
+ :icon="editable ? Edit : View"
16
+ class="edit-icon"
17
+ @click="editCode(scope.row.codeId)"
18
+ ></Icon>
13
19
  </template>
14
- <div class="tool-bar">
15
- <TMagicTooltip class="tool-item" effect="dark" content="查看代码块" placement="top">
16
- <svg
17
- @click="viewHandler"
18
- preserveAspectRatio="xMidYMid meet"
19
- viewBox="0 0 24 24"
20
- width="15px"
21
- height="15px"
22
- data-v-65a7fb6c=""
23
- >
24
- <path
25
- fill="currentColor"
26
- d="m23 12l-7.071 7.071l-1.414-1.414L20.172 12l-5.657-5.657l1.414-1.414L23 12zM3.828 12l5.657 5.657l-1.414 1.414L1 12l7.071-7.071l1.414 1.414L3.828 12z"
27
- ></path>
28
- </svg>
29
- </TMagicTooltip>
30
- </div>
31
- </TMagicCard>
20
+ </m-form-table>
32
21
  </div>
33
22
  </template>
34
23
 
35
- <script lang="ts" setup>
36
- import { computed, defineEmits, defineProps, inject, ref, watchEffect } from 'vue';
37
- import { map, xor } from 'lodash-es';
24
+ <script lang="ts" setup name="MEditorCodeSelect">
25
+ import { computed, defineEmits, defineProps, inject, watch } from 'vue';
26
+ import { Edit, View } from '@element-plus/icons-vue';
27
+ import { isEmpty, map } from 'lodash-es';
38
28
 
39
- import { TMagicCard, tMagicMessage, TMagicTooltip } from '@tmagic/design';
40
- import { FormState, SelectConfig } from '@tmagic/form';
29
+ import { createValues, FormItem, FormState, TableConfig } from '@tmagic/form';
30
+ import { HookType, Id } from '@tmagic/schema';
41
31
 
42
- import type { Services } from '../type';
43
- import { CodeEditorMode, CodeSelectOp } from '../type';
32
+ import Icon from '../components/Icon.vue';
33
+ import { CodeParamStatement, HookData, Services } from '../type';
44
34
  const services = inject<Services>('services');
45
- const form = inject<FormState>('mForm');
35
+ const mForm = inject<FormState>('mForm');
46
36
  const emit = defineEmits(['change']);
47
37
 
48
38
  const props = defineProps<{
49
39
  config: {
50
- selectConfig?: SelectConfig;
40
+ tableConfig?: TableConfig;
51
41
  };
52
42
  model: any;
53
43
  prop: string;
54
44
  name: string;
55
- size: string;
45
+ size: 'mini' | 'small' | 'medium';
56
46
  }>();
47
+ const codeDsl = computed(() => services?.codeBlockService.getCodeDslSync());
57
48
 
58
- const selectConfig = computed(() => {
49
+ const tableConfig = computed<FormItem>(() => {
59
50
  const defaultConfig = {
60
- multiple: true,
61
- options: async () => {
62
- const codeDsl = await services?.codeBlockService.getCodeDsl();
63
- if (codeDsl) {
64
- return map(codeDsl, (value, key) => ({
65
- text: `${value.name}(${key})`,
66
- label: `${value.name}(${key})`,
67
- value: key,
68
- }));
69
- }
70
- return [];
71
- },
51
+ dropSort: false,
52
+ enableFullscreen: false,
53
+ border: true,
54
+ operateColWidth: 60,
55
+ items: [
56
+ {
57
+ type: 'select',
58
+ label: '代码块',
59
+ name: 'codeId',
60
+ width: '200px',
61
+ options: () => {
62
+ if (codeDsl.value) {
63
+ return map(codeDsl.value, (value, key) => ({
64
+ text: `${value.name}(${key})`,
65
+ label: `${value.name}(${key})`,
66
+ value: key,
67
+ }));
68
+ }
69
+ return [];
70
+ },
71
+ onChange: (formState: any, codeId: Id, { model }: any) => {
72
+ // 参数的items是根据函数生成的,当codeId变化后修正model的值,避免写入其他codeId的params
73
+ model.params = {};
74
+ },
75
+ },
76
+ {
77
+ name: 'params',
78
+ label: '参数',
79
+ defaultValue: {},
80
+ itemsFunction: (row: HookData) => {
81
+ const paramsConfig = getParamsConfig(row.codeId);
82
+ // 如果参数没有填值,则使用createValues补全空值
83
+ if (isEmpty(row.params) || !row.params) {
84
+ createValues(mForm, paramsConfig, {}, row.params);
85
+ }
86
+ return paramsConfig;
87
+ },
88
+ },
89
+ ],
72
90
  };
73
91
  return {
74
92
  ...defaultConfig,
75
- ...props.config.selectConfig,
93
+ ...props.config.tableConfig,
76
94
  };
77
95
  });
78
- const fieldKey = ref('');
79
- const multiple = ref(true);
80
- const lastTagSnapshot = ref<string[]>([]);
81
96
 
82
- watchEffect(async () => {
83
- if (!props.model[props.name]) return;
84
- const combineNames = await Promise.all(
85
- props.model[props.name].map(async (id: string) => {
86
- const { name = '' } = (await services?.codeBlockService.getCodeContentById(id)) || {};
87
- return name;
88
- }),
89
- );
90
- fieldKey.value = combineNames.join('-');
91
- });
97
+ const editable = computed(() => services?.codeBlockService.getEditStatus());
92
98
 
93
- const changeHandler = async (value: any) => {
94
- let codeIds = value;
95
- if (typeof value === 'string') {
96
- multiple.value = false;
97
- codeIds = value ? [value] : [];
98
- }
99
- await setCombineRelation(codeIds);
100
- emit('change', value);
101
- };
99
+ watch(
100
+ () => props.model[props.name],
101
+ (value) => {
102
+ // 兼容旧的数据结构
103
+ if (isEmpty(value)) {
104
+ // 空值或者空数组
105
+ props.model[props.name] = {
106
+ hookType: HookType.CODE,
107
+ hookData: [],
108
+ };
109
+ }
110
+ },
111
+ {
112
+ immediate: true,
113
+ },
114
+ );
102
115
 
103
- // 同步绑定关系
104
- const setCombineRelation = async (codeIds: string[]) => {
105
- // 组件id
106
- const { id = '' } = services?.editorService.get('node') || {};
116
+ const changeHandler = async () => {
117
+ emit('change', props.model[props.name]);
118
+ };
107
119
 
108
- // 兼容单选
109
- let opFlag = CodeSelectOp.CHANGE;
110
- let diffValues = codeIds;
111
- if (multiple.value) {
112
- // initValues为表单初始值,当表单内容发生变化时,initValues也会更新,可以理解为上一次表单内容的快照
113
- lastTagSnapshot.value = form?.initValues[props.name] || [];
114
- opFlag = codeIds.length < lastTagSnapshot.value.length ? CodeSelectOp.DELETE : CodeSelectOp.ADD;
115
- diffValues = xor(codeIds, lastTagSnapshot.value) as string[];
116
- }
117
- // 记录绑定关系
118
- await services?.codeBlockService.setCombineRelation(id, diffValues, opFlag, props.prop);
120
+ const getParamsConfig = (codeId: Id): CodeParamStatement[] => {
121
+ if (!codeDsl.value) return [];
122
+ const paramStatements = codeDsl.value[codeId]?.params;
123
+ if (isEmpty(paramStatements)) return [];
124
+ return paramStatements.map((paramState: CodeParamStatement) => ({
125
+ labelWidth: '100px',
126
+ text: paramState.name,
127
+ ...paramState,
128
+ }));
119
129
  };
120
130
 
121
- const viewHandler = async () => {
122
- if (props.model[props.name].length === 0) {
123
- tMagicMessage.error('请先绑定代码块');
124
- return;
125
- }
126
- // 记录当前已被绑定的代码块,为查看弹窗的展示内容
127
- await services?.codeBlockService.setCombineIds(props.model[props.name]);
128
- await services?.codeBlockService.setMode(CodeEditorMode.LIST);
129
- services?.codeBlockService.setCodeEditorContent(true, props.model[props.name][0]);
131
+ const editCode = (codeId: Id) => {
132
+ services?.codeBlockService.setCodeEditorContent(true, codeId);
130
133
  };
131
134
  </script>
@@ -12,7 +12,7 @@
12
12
  </div>
13
13
  </template>
14
14
 
15
- <script lang="ts" setup>
15
+ <script lang="ts" setup name="MEditorUISelect">
16
16
  import { computed, inject, ref } from 'vue';
17
17
  import { Close, Delete } from '@element-plus/icons-vue';
18
18
 
@@ -37,7 +37,7 @@ const uiSelectMode = ref(false);
37
37
 
38
38
  const cancelHandler = () => {
39
39
  if (!services?.uiService) return;
40
- services.uiService.set<boolean>('uiSelectMode', false);
40
+ services.uiService.set('uiSelectMode', false);
41
41
  uiSelectMode.value = false;
42
42
  globalThis.document.removeEventListener('ui-select', clickHandler as EventListener);
43
43
  };
@@ -61,7 +61,7 @@ const toName = computed(() => {
61
61
 
62
62
  const startSelect = () => {
63
63
  if (!services?.uiService) return;
64
- services.uiService.set<boolean>('uiSelectMode', true);
64
+ services.uiService.set('uiSelectMode', true);
65
65
  uiSelectMode.value = true;
66
66
  globalThis.document.addEventListener('ui-select', clickHandler as EventListener);
67
67
  };
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Tencent is pleased to support the open source community by making TMagicEditor available.
3
3
  *
4
- * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
4
+ * Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@ export { default as PropsPanel } from './layouts/PropsPanel.vue';
48
48
  export { default as ToolButton } from './components/ToolButton.vue';
49
49
  export { default as ContentMenu } from './components/ContentMenu.vue';
50
50
  export { default as Icon } from './components/Icon.vue';
51
+ export { default as LayoutContainer } from './components/Layout.vue';
51
52
 
52
53
  const defaultInstallOpt: InstallOptions = {
53
54
  // @todo, 自定义图片上传方法等编辑器依赖的外部选项
@@ -11,7 +11,7 @@
11
11
  </div>
12
12
  </template>
13
13
 
14
- <script lang="ts" setup>
14
+ <script lang="ts" setup name="MEditorAddPageBox">
15
15
  import { inject, toRaw } from 'vue';
16
16
  import { Plus } from '@element-plus/icons-vue';
17
17
 
@@ -28,9 +28,12 @@ const clickHandler = () => {
28
28
 
29
29
  if (!editorService) return;
30
30
 
31
+ const root = toRaw(editorService.get('root'));
32
+ if (!root) throw new Error('root 不能为空');
33
+
31
34
  editorService.add({
32
35
  type: NodeType.PAGE,
33
- name: generatePageNameByApp(toRaw(editorService.get('root'))),
36
+ name: generatePageNameByApp(root),
34
37
  });
35
38
  };
36
39
  </script>
@@ -2,7 +2,7 @@
2
2
  <div ref="codeEditor" class="magic-code-editor"></div>
3
3
  </template>
4
4
 
5
- <script lang="ts" setup>
5
+ <script lang="ts" setup name="MEditorCodeEditor">
6
6
  import { onMounted, onUnmounted, ref, watch } from 'vue';
7
7
  import { throttle } from 'lodash-es';
8
8
  import * as monaco from 'monaco-editor';
@@ -12,7 +12,7 @@ const props = withDefaults(
12
12
  defineProps<{
13
13
  initValues?: string | Object;
14
14
  modifiedValues?: string | Object;
15
- type?: string;
15
+ type?: 'diff';
16
16
  language?: string;
17
17
  options?: {
18
18
  [key: string]: any;
@@ -20,7 +20,6 @@ const props = withDefaults(
20
20
  autoSave?: boolean;
21
21
  }>(),
22
22
  {
23
- type: '',
24
23
  autoSave: true,
25
24
  language: 'javascript',
26
25
  options: () => ({
@@ -42,16 +42,15 @@
42
42
  </div>
43
43
  </template>
44
44
 
45
- <script lang="ts" setup>
45
+ <script lang="ts" setup name="MEditorFramework">
46
46
  import { computed, inject, ref, watch } from 'vue';
47
47
 
48
48
  import { TMagicScrollbar } from '@tmagic/design';
49
- import type { MApp } from '@tmagic/schema';
50
49
 
50
+ import Layout from '../components/Layout.vue';
51
51
  import { GetColumnWidth, Services } from '../type';
52
52
 
53
53
  import AddPageBox from './AddPageBox.vue';
54
- import Layout from './Layout.vue';
55
54
 
56
55
  const DEFAULT_LEFT_COLUMN_WIDTH = 310;
57
56
  const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
@@ -67,11 +66,11 @@ withDefaults(
67
66
 
68
67
  const { editorService, uiService } = inject<Services>('services') || {};
69
68
 
70
- const root = computed(() => editorService?.get<MApp>('root'));
71
- const nodes = computed(() => editorService?.get<Node[]>('nodes') || []);
69
+ const root = computed(() => editorService?.get('root'));
70
+ const nodes = computed(() => editorService?.get('nodes') || []);
72
71
 
73
- const pageLength = computed(() => editorService?.get<number>('pageLength') || 0);
74
- const showSrc = computed(() => uiService?.get<boolean>('showSrc'));
72
+ const pageLength = computed(() => editorService?.get('pageLength') || 0);
73
+ const showSrc = computed(() => uiService?.get('showSrc'));
75
74
 
76
75
  const LEFT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorLeftColumnWidthData';
77
76
  const RIGHT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorRightColumnWidthData';
@@ -101,7 +100,7 @@ watch(
101
100
  columnWidth.value.center = globalThis.document.body.clientWidth - left - right;
102
101
  }
103
102
 
104
- uiService?.set('columnWidth', columnWidth);
103
+ uiService?.set('columnWidth', columnWidth.value as GetColumnWidth);
105
104
  },
106
105
  {
107
106
  immediate: true,
@@ -123,8 +122,11 @@ watch(
123
122
  },
124
123
  );
125
124
 
126
- const columnWidthChange = (columnWidth: GetColumnWidth) => {
127
- uiService?.set('columnWidth', columnWidth);
125
+ const columnWidthChange = (columnW: GetColumnWidth) => {
126
+ columnWidth.value.left = columnW.left;
127
+ columnWidth.value.center = columnW.center;
128
+ columnWidth.value.right = columnW.right;
129
+ uiService?.set('columnWidth', columnW);
128
130
  };
129
131
 
130
132
  const saveCode = (value: string) => {
@@ -1,19 +1,19 @@
1
1
  <template>
2
2
  <div class="m-editor-nav-menu" :style="{ height: `${height}px` }">
3
3
  <div v-for="key in keys" :class="`menu-${key}`" :key="key" :style="`width: ${columnWidth?.[key]}px`">
4
- <tool-button :data="item" v-for="(item, index) in buttons[key]" :key="index"></tool-button>
4
+ <ToolButton :data="item" v-for="(item, index) in buttons[key]" :key="index"></ToolButton>
5
5
  </div>
6
6
  </div>
7
7
  </template>
8
8
 
9
- <script lang="ts" setup>
9
+ <script lang="ts" setup name="MEditorNavMenu">
10
10
  import { computed, inject, markRaw } 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/schema';
14
14
 
15
15
  import ToolButton from '../components/ToolButton.vue';
16
- import { ColumnLayout, GetColumnWidth, MenuBarData, MenuButton, MenuComponent, MenuItem, Services } from '../type';
16
+ import { ColumnLayout, MenuBarData, MenuButton, MenuComponent, MenuItem, Services } from '../type';
17
17
 
18
18
  const props = withDefaults(
19
19
  defineProps<{
@@ -29,12 +29,12 @@ const props = withDefaults(
29
29
  const services = inject<Services>('services');
30
30
  const uiService = services?.uiService;
31
31
 
32
- const columnWidth = computed(() => services?.uiService.get<GetColumnWidth>('columnWidth'));
32
+ const columnWidth = computed(() => services?.uiService.get('columnWidth'));
33
33
  const keys = Object.values(ColumnLayout);
34
34
 
35
- const showGuides = computed((): boolean => uiService?.get<boolean>('showGuides') ?? true);
36
- const showRule = computed((): boolean => uiService?.get<boolean>('showRule') ?? true);
37
- const zoom = computed((): number => uiService?.get<number>('zoom') ?? 1);
35
+ const showGuides = computed((): boolean => uiService?.get('showGuides') ?? true);
36
+ const showRule = computed((): boolean => uiService?.get('showRule') ?? true);
37
+ const zoom = computed((): number => uiService?.get('zoom') ?? 1);
38
38
 
39
39
  const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
40
40
  const ctrl = isMac ? 'Command' : 'Ctrl';
@@ -67,7 +67,10 @@ const getConfig = (item: MenuItem): (MenuButton | MenuComponent)[] => {
67
67
  icon: markRaw(Delete),
68
68
  tooltip: `刪除(Delete)`,
69
69
  disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
70
- handler: () => services?.editorService.remove(services?.editorService.get('node')),
70
+ handler: () => {
71
+ const node = services?.editorService.get('node');
72
+ node && services?.editorService.remove(node);
73
+ },
71
74
  });
72
75
  break;
73
76
  case 'undo':