@tmagic/editor 1.3.0-alpha.9 → 1.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/style.css +77 -218
  2. package/dist/tmagic-editor.js +4143 -3302
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +5289 -4434
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +15 -15
  7. package/src/Editor.vue +4 -5
  8. package/src/components/CodeBlockEditor.vue +257 -0
  9. package/src/components/CodeParams.vue +60 -0
  10. package/src/components/ContentMenu.vue +11 -3
  11. package/src/editorProps.ts +30 -5
  12. package/src/fields/Code.vue +23 -19
  13. package/src/fields/CodeLink.vue +6 -7
  14. package/src/fields/CodeSelect.vue +12 -9
  15. package/src/fields/CodeSelectCol.vue +70 -81
  16. package/src/fields/DataSourceFieldSelect.vue +47 -0
  17. package/src/fields/DataSourceFields.vue +28 -22
  18. package/src/fields/DataSourceInput.vue +21 -58
  19. package/src/fields/DataSourceMethodSelect.vue +136 -0
  20. package/src/fields/DataSourceMethods.vue +103 -0
  21. package/src/fields/DataSourceSelect.vue +5 -12
  22. package/src/fields/EventSelect.vue +53 -19
  23. package/src/fields/KeyValue.vue +9 -11
  24. package/src/fields/UISelect.vue +54 -14
  25. package/src/hooks/index.ts +21 -0
  26. package/src/hooks/use-code-block-edit.ts +84 -0
  27. package/src/hooks/use-data-source-method.ts +100 -0
  28. package/src/{utils/stage.ts → hooks/use-stage.ts} +4 -7
  29. package/src/icons/CenterIcon.vue +13 -0
  30. package/src/icons/CodeIcon.vue +0 -2
  31. package/src/icons/FolderMinusIcon.vue +22 -0
  32. package/src/index.ts +12 -0
  33. package/src/initService.ts +69 -16
  34. package/src/layouts/CodeEditor.vue +35 -3
  35. package/src/layouts/Framework.vue +7 -3
  36. package/src/layouts/PropsPanel.vue +8 -3
  37. package/src/layouts/sidebar/ComponentListPanel.vue +4 -6
  38. package/src/layouts/sidebar/LayerMenu.vue +20 -21
  39. package/src/layouts/sidebar/LayerPanel.vue +12 -2
  40. package/src/layouts/sidebar/Sidebar.vue +22 -36
  41. package/src/layouts/sidebar/code-block/CodeBlockList.vue +81 -119
  42. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +64 -0
  43. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +27 -47
  44. package/src/layouts/sidebar/data-source/DataSourceList.vue +145 -0
  45. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +58 -85
  46. package/src/layouts/workspace/Stage.vue +3 -2
  47. package/src/layouts/workspace/ViewerMenu.vue +10 -35
  48. package/src/services/codeBlock.ts +18 -71
  49. package/src/services/dataSource.ts +16 -1
  50. package/src/services/dep.ts +22 -20
  51. package/src/services/editor.ts +46 -18
  52. package/src/services/props.ts +2 -2
  53. package/src/theme/code-block.scss +5 -117
  54. package/src/theme/code-editor.scss +27 -2
  55. package/src/theme/content-menu.scss +1 -1
  56. package/src/theme/data-source-methods.scss +13 -0
  57. package/src/theme/data-source.scss +11 -0
  58. package/src/theme/event.scss +15 -12
  59. package/src/theme/framework.scss +0 -3
  60. package/src/theme/layout.scss +4 -0
  61. package/src/theme/sidebar.scss +18 -60
  62. package/src/theme/theme.scss +1 -0
  63. package/src/type.ts +47 -7
  64. package/src/utils/content-menu.ts +92 -0
  65. package/src/utils/data-source/formConfigs/base.ts +28 -30
  66. package/src/utils/data-source/index.ts +65 -2
  67. package/src/utils/dep.ts +33 -7
  68. package/src/utils/index.ts +1 -1
  69. package/src/utils/props.ts +298 -189
  70. package/src/utils/undo-redo.ts +1 -1
  71. package/types/Editor.vue.d.ts +30 -6
  72. package/types/components/CodeBlockEditor.vue.d.ts +23 -0
  73. package/types/components/CodeParams.vue.d.ts +26 -0
  74. package/types/components/ContentMenu.vue.d.ts +2 -2
  75. package/types/components/ToolButton.vue.d.ts +3 -3
  76. package/types/editorProps.d.ts +19 -5
  77. package/types/fields/Code.vue.d.ts +24 -19
  78. package/types/fields/CodeLink.vue.d.ts +12 -21
  79. package/types/fields/CodeSelect.vue.d.ts +6 -17
  80. package/types/fields/CodeSelectCol.vue.d.ts +10 -14
  81. package/types/fields/DataSourceFieldSelect.vue.d.ts +29 -0
  82. package/types/fields/DataSourceFields.vue.d.ts +7 -18
  83. package/types/fields/DataSourceInput.vue.d.ts +10 -30
  84. package/types/fields/DataSourceMethodSelect.vue.d.ts +29 -0
  85. package/types/fields/DataSourceMethods.vue.d.ts +32 -0
  86. package/types/fields/DataSourceSelect.vue.d.ts +13 -29
  87. package/types/fields/EventSelect.vue.d.ts +2 -13
  88. package/types/fields/KeyValue.vue.d.ts +9 -24
  89. package/types/fields/UISelect.vue.d.ts +2 -11
  90. package/types/hooks/index.d.ts +3 -0
  91. package/types/{components/FunctionEditor.vue.d.ts → hooks/use-code-block-edit.d.ts} +31 -121
  92. package/types/hooks/use-data-source-method.d.ts +123 -0
  93. package/types/icons/CenterIcon.vue.d.ts +2 -0
  94. package/types/icons/FolderMinusIcon.vue.d.ts +2 -0
  95. package/types/index.d.ts +6 -0
  96. package/types/initService.d.ts +2 -2
  97. package/types/layouts/CodeEditor.vue.d.ts +7 -4
  98. package/types/layouts/PropsPanel.vue.d.ts +274 -2
  99. package/types/layouts/sidebar/Sidebar.vue.d.ts +0 -3
  100. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +4 -9
  101. package/types/layouts/sidebar/code-block/{CodeBlockEditor.vue.d.ts → CodeBlockListPanel.vue.d.ts} +9 -5
  102. package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +3 -1
  103. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +14 -0
  104. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +1 -11
  105. package/types/services/codeBlock.d.ts +6 -37
  106. package/types/services/dataSource.d.ts +7 -1
  107. package/types/services/dep.d.ts +12 -21
  108. package/types/services/editor.d.ts +1 -1
  109. package/types/services/props.d.ts +10 -115
  110. package/types/type.d.ts +42 -7
  111. package/types/utils/content-menu.d.ts +7 -0
  112. package/types/utils/data-source/formConfigs/base.d.ts +1 -2
  113. package/types/utils/data-source/index.d.ts +5 -0
  114. package/types/utils/dep.d.ts +4 -2
  115. package/types/utils/index.d.ts +1 -1
  116. package/types/utils/props.d.ts +13 -102
  117. package/src/components/CodeDraftEditor.vue +0 -148
  118. package/src/components/FunctionEditor.vue +0 -197
  119. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +0 -100
  120. package/types/components/CodeDraftEditor.vue.d.ts +0 -61
  121. /package/types/{utils/stage.d.ts → hooks/use-stage.d.ts} +0 -0
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M2 4H21V6H2V4Z" fill="black" fill-opacity="0.9" />
4
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M5 11H18V13H5V11Z" fill="black" fill-opacity="0.9" />
5
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M2 18H21V20H2V18Z" fill="black" fill-opacity="0.9" />
6
+ </svg>
7
+ </template>
8
+
9
+ <script lang="ts" setup>
10
+ defineOptions({
11
+ name: 'MEditorCenterIcon',
12
+ });
13
+ </script>
@@ -1,7 +1,5 @@
1
1
  <template>
2
- <!-- 代码icon,cdn链接:https://cloudcache.tencent-cloud.com/qcloud/ui/static/government/0d463ed5-6407-4498-8865-3d05b5e70115.svg -->
3
2
  <svg viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
4
- <!-- Generator: Sketch 60.1 (88133) - https://sketch.com -->
5
3
  <defs><rect id="path-1" x="0" y="0" width="32" height="32"></rect></defs>
6
4
  <g id="组件规范" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
7
5
  <g id="03图标" transform="translate(-561.000000, -2356.000000)">
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <svg
3
+ width="1em"
4
+ height="1em"
5
+ viewBox="0 0 16 16"
6
+ class="bi bi-folder-minus"
7
+ fill="currentColor"
8
+ xmlns="http://www.w3.org/2000/svg"
9
+ >
10
+ <path
11
+ fill-rule="evenodd"
12
+ d="M9.828 4H2.19a1 1 0 0 0-.996 1.09l.637 7a1 1 0 0 0 .995.91H9v1H2.826a2 2 0 0 1-1.991-1.819l-.637-7a1.99 1.99 0 0 1 .342-1.31L.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3h3.982a2 2 0 0 1 1.992 2.181L15.546 8H14.54l.265-2.91A1 1 0 0 0 13.81 4H9.828zm-2.95-1.707L7.587 3H2.19c-.24 0-.47.042-.684.12L1.5 2.98a1 1 0 0 1 1-.98h3.672a1 1 0 0 1 .707.293z"
13
+ />
14
+ <path fill-rule="evenodd" d="M11 11.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5z" />
15
+ </svg>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ defineOptions({
20
+ name: 'MEditorFolderMinusIcon',
21
+ });
22
+ </script>
package/src/index.ts CHANGED
@@ -22,7 +22,10 @@ import CodeLink from './fields/CodeLink.vue';
22
22
  import CodeSelect from './fields/CodeSelect.vue';
23
23
  import CodeSelectCol from './fields/CodeSelectCol.vue';
24
24
  import DataSourceFields from './fields/DataSourceFields.vue';
25
+ import DataSourceFieldSelect from './fields/DataSourceFieldSelect.vue';
25
26
  import DataSourceInput from './fields/DataSourceInput.vue';
27
+ import DataSourceMethods from './fields/DataSourceMethods.vue';
28
+ import DataSourceMethodSelect from './fields/DataSourceMethodSelect.vue';
26
29
  import DataSourceSelect from './fields/DataSourceSelect.vue';
27
30
  import EventSelect from './fields/EventSelect.vue';
28
31
  import KeyValue from './fields/KeyValue.vue';
@@ -36,6 +39,7 @@ import './theme/index.scss';
36
39
 
37
40
  export type { MoveableOptions } from '@tmagic/stage';
38
41
  export * from './type';
42
+ export * from './hooks';
39
43
  export * from './utils';
40
44
  export { default as TMagicEditor } from './Editor.vue';
41
45
  export { default as TMagicCodeEditor } from './layouts/CodeEditor.vue';
@@ -53,11 +57,15 @@ export { default as LayerPanel } from './layouts/sidebar/LayerPanel.vue';
53
57
  export { default as CodeSelect } from './fields/CodeSelect.vue';
54
58
  export { default as CodeSelectCol } from './fields/CodeSelectCol.vue';
55
59
  export { default as DataSourceFields } from './fields/DataSourceFields.vue';
60
+ export { default as DataSourceMethods } from './fields/DataSourceMethods.vue';
56
61
  export { default as DataSourceInput } from './fields/DataSourceInput.vue';
57
62
  export { default as DataSourceSelect } from './fields/DataSourceSelect.vue';
63
+ export { default as DataSourceMethodSelect } from './fields/DataSourceMethodSelect.vue';
64
+ export { default as DataSourceFieldSelect } from './fields/DataSourceFieldSelect.vue';
58
65
  export { default as EventSelect } from './fields/EventSelect.vue';
59
66
  export { default as KeyValue } from './fields/KeyValue.vue';
60
67
  export { default as CodeBlockList } from './layouts/sidebar/code-block/CodeBlockList.vue';
68
+ export { default as CodeBlockListPanel } from './layouts/sidebar/code-block/CodeBlockListPanel.vue';
61
69
  export { default as PropsPanel } from './layouts/PropsPanel.vue';
62
70
  export { default as ToolButton } from './components/ToolButton.vue';
63
71
  export { default as ContentMenu } from './components/ContentMenu.vue';
@@ -65,6 +73,7 @@ export { default as Icon } from './components/Icon.vue';
65
73
  export { default as LayoutContainer } from './components/SplitView.vue';
66
74
  export { default as SplitView } from './components/SplitView.vue';
67
75
  export { default as Resizer } from './components/Resizer.vue';
76
+ export { default as CodeBlockEditor } from './components/CodeBlockEditor.vue';
68
77
 
69
78
  const defaultInstallOpt: InstallOptions = {
70
79
  // eslint-disable-next-line no-eval
@@ -90,5 +99,8 @@ export default {
90
99
  app.component('m-fields-key-value', KeyValue);
91
100
  app.component('m-fields-data-source-input', DataSourceInput);
92
101
  app.component('m-fields-data-source-select', DataSourceSelect);
102
+ app.component('m-fields-data-source-methods', DataSourceMethods);
103
+ app.component('m-fields-data-source-method-select', DataSourceMethodSelect);
104
+ app.component('m-fields-data-source-field-select', DataSourceFieldSelect);
93
105
  },
94
106
  };
@@ -7,9 +7,14 @@ import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage } from
7
7
  import { getNodes } from '@tmagic/utils';
8
8
 
9
9
  import type { Target } from './services/dep';
10
- import { createCodeBlockTarget, createDataSourceTarget } from './utils/dep';
10
+ import {
11
+ createCodeBlockTarget,
12
+ createDataSourceCondTarget,
13
+ createDataSourceMethodTarget,
14
+ createDataSourceTarget,
15
+ } from './utils/dep';
11
16
  import editorProps from './editorProps';
12
- import type { Services } from './type';
17
+ import { DepTargetType, Services } from './type';
13
18
 
14
19
  export declare type LooseRequired<T> = {
15
20
  [P in string & keyof T]: T[P];
@@ -26,6 +31,7 @@ export const initServiceState = (
26
31
  uiService,
27
32
  codeBlockService,
28
33
  keybindingService,
34
+ dataSourceService,
29
35
  }: Services,
30
36
  ) => {
31
37
  // 初始值变化,重新设置节点信息
@@ -47,6 +53,14 @@ export const initServiceState = (
47
53
  },
48
54
  );
49
55
 
56
+ watch(
57
+ () => props.datasourceList,
58
+ (datasourceList) => dataSourceService.set('datasourceTypeList', datasourceList),
59
+ {
60
+ immediate: true,
61
+ },
62
+ );
63
+
50
64
  watch(
51
65
  () => props.propsConfigs,
52
66
  (configs) => propsService.setPropsConfigs(configs),
@@ -82,6 +96,30 @@ export const initServiceState = (
82
96
  },
83
97
  );
84
98
 
99
+ watch(
100
+ () => props.datasourceConfigs,
101
+ (configs) => {
102
+ Object.entries(configs).forEach(([key, value]) => {
103
+ dataSourceService.setFormConfig(key, value);
104
+ });
105
+ },
106
+ {
107
+ immediate: true,
108
+ },
109
+ );
110
+
111
+ watch(
112
+ () => props.datasourceValues,
113
+ (values) => {
114
+ Object.entries(values).forEach(([key, value]) => {
115
+ dataSourceService.setFormValue(key, value);
116
+ });
117
+ },
118
+ {
119
+ immediate: true,
120
+ },
121
+ );
122
+
85
123
  watch(
86
124
  () => props.defaultSelected,
87
125
  (defaultSelected) => defaultSelected && editorService.select(defaultSelected),
@@ -139,6 +177,7 @@ export const initServiceEvents = (
139
177
 
140
178
  if (app.dsl) {
141
179
  app.dsl.dataSourceDeps = root.dataSourceDeps;
180
+ app.dsl.dataSourceCondDeps = root.dataSourceCondDeps;
142
181
  app.dsl.dataSources = root.dataSources;
143
182
  }
144
183
 
@@ -159,23 +198,34 @@ export const initServiceEvents = (
159
198
  };
160
199
 
161
200
  const targetAddHandler = (target: Target) => {
162
- if (target.type !== 'data-source') return;
163
-
164
201
  const root = editorService.get('root');
165
202
  if (!root) return;
166
203
 
167
- if (!root.dataSourceDeps) {
168
- root.dataSourceDeps = {};
204
+ if (target.type === DepTargetType.DATA_SOURCE) {
205
+ if (!root.dataSourceDeps) {
206
+ root.dataSourceDeps = {};
207
+ }
208
+ root.dataSourceDeps[target.id] = target.deps;
169
209
  }
170
210
 
171
- root.dataSourceDeps[target.id] = target.deps;
211
+ if (target.type === DepTargetType.DATA_SOURCE_COND) {
212
+ if (!root.dataSourceCondDeps) {
213
+ root.dataSourceCondDeps = {};
214
+ }
215
+ root.dataSourceCondDeps[target.id] = target.deps;
216
+ }
172
217
  };
173
218
 
174
219
  const targetRemoveHandler = (id: string | number) => {
175
220
  const root = editorService.get('root');
176
- if (!root?.dataSourceDeps) return;
177
221
 
178
- delete root.dataSourceDeps[id];
222
+ if (root?.dataSourceDeps) {
223
+ delete root.dataSourceDeps[id];
224
+ }
225
+
226
+ if (root?.dataSourceCondDeps) {
227
+ delete root.dataSourceCondDeps[id];
228
+ }
179
229
  };
180
230
 
181
231
  const depUpdateHandler = (node: MNode) => {
@@ -191,6 +241,12 @@ export const initServiceEvents = (
191
241
  depService.on('dep-update', depUpdateHandler);
192
242
  depService.on('collected', collectedHandler);
193
243
 
244
+ const initDataSourceDepTarget = (ds: DataSourceSchema) => {
245
+ depService.addTarget(createDataSourceTarget(ds.id));
246
+ depService.addTarget(createDataSourceMethodTarget(ds.id));
247
+ depService.addTarget(createDataSourceCondTarget(ds.id));
248
+ };
249
+
194
250
  const rootChangeHandler = async (value: MApp, preValue?: MApp | null) => {
195
251
  const nodeId = editorService.get('node')?.id || props.defaultSelected;
196
252
  let node;
@@ -218,14 +274,14 @@ export const initServiceEvents = (
218
274
  codeBlockService.setCodeDsl(value.codeBlocks);
219
275
  dataSourceService.set('dataSources', value.dataSources);
220
276
 
221
- depService.removeTargets('code-block');
277
+ depService.removeTargets(DepTargetType.CODE_BLOCK);
222
278
 
223
279
  Object.entries(value.codeBlocks).forEach(([id, code]) => {
224
280
  depService.addTarget(createCodeBlockTarget(id, code));
225
281
  });
226
282
 
227
283
  value.dataSources.forEach((ds) => {
228
- depService.addTarget(createDataSourceTarget(ds.id, ds));
284
+ initDataSourceDepTarget(ds);
229
285
  });
230
286
 
231
287
  if (value && Array.isArray(value.items)) {
@@ -279,17 +335,14 @@ export const initServiceEvents = (
279
335
  codeBlockService.on('remove', codeBlockRemoveHandler);
280
336
 
281
337
  const dataSourceAddHandler = (config: DataSourceSchema) => {
282
- depService.addTarget(createDataSourceTarget(config.id, config));
338
+ initDataSourceDepTarget(config);
283
339
  getApp()?.dataSourceManager?.addDataSource(config);
284
340
  };
285
341
 
286
342
  const dataSourceUpdateHandler = (config: DataSourceSchema) => {
287
- if (config.title) {
288
- depService.getTarget(config.id)!.name = config.title;
289
- }
290
343
  const root = editorService.get('root');
291
344
 
292
- const targets = depService.getTargets('data-source');
345
+ const targets = depService.getTargets(DepTargetType.DATA_SOURCE);
293
346
 
294
347
  const nodes = getNodes(Object.keys(targets[config.id].deps), root?.items);
295
348
 
@@ -1,26 +1,46 @@
1
1
  <template>
2
- <div ref="codeEditor" class="magic-code-editor"></div>
2
+ <div :class="`magic-code-editor`">
3
+ <Teleport to="body" :disabled="!fullScreen">
4
+ <div
5
+ :class="`magic-code-editor-wrapper${fullScreen ? ' full-screen' : ''}`"
6
+ :style="!fullScreen && height ? `height: ${height}` : '100%'"
7
+ >
8
+ <TMagicButton
9
+ class="magic-code-editor-full-screen-icon"
10
+ circle
11
+ size="small"
12
+ :icon="FullScreen"
13
+ @click="fullScreenHandler"
14
+ ></TMagicButton>
15
+ <div ref="codeEditor" class="magic-code-editor-content"></div>
16
+ </div>
17
+ </Teleport>
18
+ </div>
3
19
  </template>
4
20
 
5
21
  <script lang="ts" setup>
6
22
  import { onMounted, onUnmounted, ref, watch } from 'vue';
23
+ import { FullScreen } from '@element-plus/icons-vue';
7
24
  import { throttle } from 'lodash-es';
8
25
  import * as monaco from 'monaco-editor';
9
26
  import serialize from 'serialize-javascript';
10
27
 
28
+ import { TMagicButton } from '@tmagic/design';
29
+
11
30
  defineOptions({
12
31
  name: 'MEditorCodeEditor',
13
32
  });
14
33
 
15
34
  const props = withDefaults(
16
35
  defineProps<{
17
- initValues?: string | Record<string | number, any> | null;
18
- modifiedValues?: string | Record<string | number, any> | null;
36
+ initValues?: any;
37
+ modifiedValues?: any;
19
38
  type?: 'diff';
20
39
  language?: string;
21
40
  options?: {
22
41
  [key: string]: any;
23
42
  };
43
+ height?: string;
24
44
  autoSave?: boolean;
25
45
  }>(),
26
46
  {
@@ -155,6 +175,17 @@ onUnmounted(() => {
155
175
  resizeObserver.disconnect();
156
176
  });
157
177
 
178
+ const fullScreen = ref(false);
179
+ const fullScreenHandler = () => {
180
+ fullScreen.value = !fullScreen.value;
181
+ setTimeout(() => {
182
+ vsEditor?.focus();
183
+ vsEditor?.layout();
184
+ vsDiffEditor?.focus();
185
+ vsDiffEditor?.layout();
186
+ });
187
+ };
188
+
158
189
  defineExpose({
159
190
  values,
160
191
 
@@ -171,6 +202,7 @@ defineExpose({
171
202
  },
172
203
 
173
204
  setEditorValue,
205
+ getEditorValue,
174
206
 
175
207
  focus() {
176
208
  vsEditor?.focus();
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="m-editor">
2
+ <div class="m-editor" ref="content">
3
3
  <slot name="header"></slot>
4
4
 
5
5
  <slot name="nav"></slot>
@@ -67,6 +67,8 @@ const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
67
67
  const codeOptions = inject('codeOptions', {});
68
68
  const { editorService, uiService } = inject<Services>('services') || {};
69
69
 
70
+ const content = ref<HTMLDivElement>();
71
+
70
72
  const root = computed(() => editorService?.get('root'));
71
73
 
72
74
  const pageLength = computed(() => editorService?.get('pageLength') || 0);
@@ -91,13 +93,15 @@ watch(
91
93
 
92
94
  columnWidth.value.left = left;
93
95
 
96
+ const container = content.value || document.body;
97
+
94
98
  if (length <= 0) {
95
99
  columnWidth.value.right = undefined;
96
- columnWidth.value.center = globalThis.document.body.clientWidth - left;
100
+ columnWidth.value.center = container.clientWidth - left;
97
101
  } else {
98
102
  const right = columnWidth.value.right || RightColumnWidthCacheData || DEFAULT_RIGHT_COLUMN_WIDTH;
99
103
  columnWidth.value.right = right;
100
- columnWidth.value.center = globalThis.document.body.clientWidth - left - right;
104
+ columnWidth.value.center = container.clientWidth - left - right;
101
105
  }
102
106
 
103
107
  uiService?.set('columnWidth', columnWidth.value as GetColumnWidth);
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="m-editor-props-panel" v-if="nodes.length === 1">
2
+ <div class="m-editor-props-panel" v-show="nodes.length === 1">
3
3
  <slot name="props-panel-header"></slot>
4
4
  <MForm
5
5
  ref="configForm"
@@ -8,6 +8,7 @@
8
8
  :size="propsPanelSize"
9
9
  :init-values="values"
10
10
  :config="curFormConfig"
11
+ :extend-state="extendState"
11
12
  @change="submit"
12
13
  ></MForm>
13
14
  </div>
@@ -17,7 +18,7 @@
17
18
  import { computed, getCurrentInstance, inject, onMounted, onUnmounted, ref, watchEffect } from 'vue';
18
19
 
19
20
  import { tMagicMessage } from '@tmagic/design';
20
- import type { FormValue } from '@tmagic/form';
21
+ import type { FormState, FormValue } from '@tmagic/form';
21
22
  import { MForm } from '@tmagic/form';
22
23
 
23
24
  import type { Services } from '@editor/type';
@@ -26,6 +27,10 @@ defineOptions({
26
27
  name: 'MEditorPropsPanel',
27
28
  });
28
29
 
30
+ defineProps<{
31
+ extendState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
32
+ }>();
33
+
29
34
  const emit = defineEmits(['mounted']);
30
35
 
31
36
  const internalInstance = getCurrentInstance();
@@ -78,5 +83,5 @@ const submit = async () => {
78
83
  }
79
84
  };
80
85
 
81
- defineExpose({ submit });
86
+ defineExpose({ configForm, submit });
82
87
  </script>
@@ -18,11 +18,9 @@
18
18
  @drag="dragHandler"
19
19
  >
20
20
  <slot name="component-list-item" :component="item">
21
- <MIcon :icon="item.icon"></MIcon>
21
+ <MIcon :title="item.text" :icon="item.icon"></MIcon>
22
22
 
23
- <TMagicTooltip effect="dark" placement="bottom" :content="item.text">
24
- <span>{{ item.text }}</span>
25
- </TMagicTooltip>
23
+ <span :title="item.text">{{ item.text }}</span>
26
24
  </slot>
27
25
  </div>
28
26
  </TMagicCollapseItem>
@@ -36,7 +34,7 @@ import { computed, inject, ref } from 'vue';
36
34
  import { Grid } from '@element-plus/icons-vue';
37
35
  import serialize from 'serialize-javascript';
38
36
 
39
- import { TMagicCollapse, TMagicCollapseItem, TMagicScrollbar, TMagicTooltip } from '@tmagic/design';
37
+ import { TMagicCollapse, TMagicCollapseItem, TMagicScrollbar } from '@tmagic/design';
40
38
  import { removeClassNameByClassName } from '@tmagic/utils';
41
39
 
42
40
  import MIcon from '@editor/components/Icon.vue';
@@ -84,7 +82,7 @@ const appendComponent = ({ text, type, data = {} }: ComponentItem): void => {
84
82
  const dragstartHandler = ({ text, type, data = {} }: ComponentItem, e: DragEvent) => {
85
83
  if (e.dataTransfer) {
86
84
  e.dataTransfer.setData(
87
- 'text/html',
85
+ 'text/json',
88
86
  serialize({
89
87
  name: text,
90
88
  type,
@@ -4,12 +4,14 @@
4
4
 
5
5
  <script lang="ts" setup>
6
6
  import { computed, inject, markRaw, ref } from 'vue';
7
- import { CopyDocument, Delete, Files, Plus } from '@element-plus/icons-vue';
7
+ import { Files, Plus } from '@element-plus/icons-vue';
8
8
 
9
- import { NodeType } from '@tmagic/schema';
9
+ import { isPage } from '@tmagic/utils';
10
10
 
11
11
  import ContentMenu from '@editor/components/ContentMenu.vue';
12
+ import FolderMinusIcon from '@editor/icons/FolderMinusIcon.vue';
12
13
  import type { ComponentGroup, MenuButton, MenuComponent, Services } from '@editor/type';
14
+ import { useCopyMenu, useDeleteMenu, useMoveToMenu, usePasteMenu } from '@editor/utils/content-menu';
13
15
 
14
16
  defineOptions({
15
17
  name: 'MEditorLayerMenu',
@@ -19,12 +21,14 @@ const props = defineProps<{
19
21
  layerContentMenu: (MenuButton | MenuComponent)[];
20
22
  }>();
21
23
 
24
+ const emit = defineEmits<{
25
+ 'collapse-all': [];
26
+ }>();
27
+
22
28
  const services = inject<Services>('services');
23
29
  const menu = ref<InstanceType<typeof ContentMenu>>();
24
30
  const node = computed(() => services?.editorService.get('node'));
25
31
  const nodes = computed(() => services?.editorService.get('nodes'));
26
- const isRoot = computed(() => node.value?.type === NodeType.ROOT);
27
- const isPage = computed(() => node.value?.type === NodeType.PAGE);
28
32
  const componentList = computed(() => services?.componentListService.getList() || []);
29
33
 
30
34
  const createMenuItems = (group: ComponentGroup): MenuButton[] =>
@@ -81,29 +85,24 @@ const getSubMenuData = computed<MenuButton[]>(() => {
81
85
  const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
82
86
  {
83
87
  type: 'button',
84
- text: '新增',
85
- icon: markRaw(Plus),
86
- display: () => node.value?.items && nodes.value?.length === 1,
87
- items: getSubMenuData.value,
88
- },
89
- {
90
- type: 'button',
91
- text: '复制',
92
- icon: markRaw(CopyDocument),
93
- display: () => !isRoot.value,
88
+ text: '全部折叠',
89
+ icon: FolderMinusIcon,
90
+ display: () => isPage(node.value),
94
91
  handler: () => {
95
- node.value && services?.editorService.copy(nodes.value || []);
92
+ emit('collapse-all');
96
93
  },
97
94
  },
98
95
  {
99
96
  type: 'button',
100
- text: '删除',
101
- icon: markRaw(Delete),
102
- display: () => !isRoot.value && !isPage.value,
103
- handler: () => {
104
- node.value && services?.editorService.remove(nodes.value || []);
105
- },
97
+ text: '新增',
98
+ icon: markRaw(Plus),
99
+ display: () => node.value?.items && nodes.value?.length === 1,
100
+ items: getSubMenuData.value,
106
101
  },
102
+ useCopyMenu(),
103
+ usePasteMenu(),
104
+ useDeleteMenu(),
105
+ useMoveToMenu(services),
107
106
  ...props.layerContentMenu,
108
107
  ]);
109
108
 
@@ -42,7 +42,7 @@
42
42
  </TMagicTree>
43
43
 
44
44
  <Teleport to="body">
45
- <LayerMenu ref="menu" :layer-content-menu="layerContentMenu"></LayerMenu>
45
+ <LayerMenu ref="menu" :layer-content-menu="layerContentMenu" @collapse-all="collapseAllHandler"></LayerMenu>
46
46
  </Teleport>
47
47
  </TMagicScrollbar>
48
48
  </template>
@@ -156,7 +156,7 @@ const handleDragEnd = async (e: any) => {
156
156
  if (!tree.value) return;
157
157
  const { data: node } = e;
158
158
  const parent = editorService?.getParentById(node.id, false) as MContainer;
159
- const layout = await editorService?.getLayout(parent);
159
+ const layout = await editorService?.getLayout(parent, node);
160
160
  node.style.position = layout;
161
161
  if (layout === Layout.RELATIVE) {
162
162
  node.style.top = 0;
@@ -356,4 +356,14 @@ const contextmenu = async (event: MouseEvent, data: MNode): Promise<void> => {
356
356
 
357
357
  menu.value?.show(event);
358
358
  };
359
+
360
+ const collapseAllHandler = () => {
361
+ const page = editorService?.get('page');
362
+ if (!tree.value || !page) return;
363
+ const rootNode = tree.value.getNode(page.id);
364
+ rootNode.childNodes.forEach((node: any) => {
365
+ node.collapse();
366
+ handleCollapse(node.data);
367
+ });
368
+ };
359
369
  </script>
@@ -1,24 +1,23 @@
1
1
  <template>
2
- <component
3
- v-if="data.type === 'tabs' && data.items.length"
4
- v-model="activeTabName"
5
- class="m-editor-sidebar tmagic-design-tabs"
6
- v-bind="tabsComponent?.props({ type: 'card', tabPosition: 'left' }) || {}"
7
- :is="tabsComponent?.component || 'el-tabs'"
8
- >
9
- <component
2
+ <div class="m-editor-sidebar" v-if="data.type === 'tabs' && data.items.length">
3
+ <div class="m-editor-sidebar-header">
4
+ <div
5
+ class="m-editor-sidebar-header-item"
6
+ v-for="(config, index) in sideBarItems"
7
+ :key="config.$key ?? index"
8
+ :class="{ 'is-active': activeTabName === config.text }"
9
+ @click="activeTabName = config.text || `${index}`"
10
+ >
11
+ <MIcon v-if="config.icon" :icon="config.icon"></MIcon>
12
+ <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
13
+ </div>
14
+ </div>
15
+ <div
16
+ class="m-editor-sidebar-content"
10
17
  v-for="(config, index) in sideBarItems"
11
- v-bind="tabPaneComponent?.props({ name: config.text, lazy: config.lazy }) || {}"
12
- :is="tabPaneComponent?.component || 'el-tab-pane'"
13
- :key="config.$key || index"
18
+ :key="config.$key ?? index"
19
+ v-show="activeTabName === config.text"
14
20
  >
15
- <template #label>
16
- <div :key="config.text">
17
- <MIcon v-if="config.icon" :icon="config.icon"></MIcon>
18
- <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
19
- </div>
20
- </template>
21
-
22
21
  <component v-if="config" :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
23
22
  <template
24
23
  #component-list-panel-header
@@ -58,14 +57,6 @@
58
57
  <component v-else-if="config.slots?.codeBlockPanelTool" :is="config.slots.codeBlockPanelTool" />
59
58
  </template>
60
59
 
61
- <template
62
- #code-block-edit-panel-header="{ id }"
63
- v-if="config.$key === 'code-block' || config.slots?.codeBlockEditPanelHeader"
64
- >
65
- <slot v-if="config.$key === 'code-block'" name="code-block-edit-panel-header" :id="id"></slot>
66
- <component v-else-if="config.slots?.codeBlockEditPanelHeader" :is="config.slots.codeBlockEditPanelHeader" />
67
- </template>
68
-
69
60
  <template
70
61
  #layer-node-content="{ data: nodeData, node }"
71
62
  v-if="config.$key === 'layer' || config.slots?.layerNodeContent"
@@ -79,21 +70,19 @@
79
70
  />
80
71
  </template>
81
72
  </component>
82
- </component>
83
- </component>
73
+ </div>
74
+ </div>
84
75
  </template>
85
76
 
86
- <script lang="ts" setup>
77
+ <script setup lang="ts">
87
78
  import { computed, ref, watch } from 'vue';
88
79
  import { Coin, EditPen, Goods, List } from '@element-plus/icons-vue';
89
80
 
90
- import { getConfig } from '@tmagic/design';
91
-
92
81
  import MIcon from '@editor/components/Icon.vue';
93
82
  import type { MenuButton, MenuComponent, SideComponent, SideItem } from '@editor/type';
94
83
  import { SideBarData } from '@editor/type';
95
84
 
96
- import CodeBlockList from './code-block/CodeBlockList.vue';
85
+ import CodeBlockListPanel from './code-block/CodeBlockListPanel.vue';
97
86
  import DataSourceListPanel from './data-source/DataSourceListPanel.vue';
98
87
  import ComponentListPanel from './ComponentListPanel.vue';
99
88
  import LayerPanel from './LayerPanel.vue';
@@ -112,9 +101,6 @@ const props = withDefaults(
112
101
  },
113
102
  );
114
103
 
115
- const tabPaneComponent = getConfig('components')?.tabPane;
116
- const tabsComponent = getConfig('components')?.tabs;
117
-
118
104
  const activeTabName = ref(props.data?.status);
119
105
 
120
106
  const getItemConfig = (data: SideItem): SideComponent => {
@@ -143,7 +129,7 @@ const getItemConfig = (data: SideItem): SideComponent => {
143
129
  type: 'component',
144
130
  icon: EditPen,
145
131
  text: '代码编辑',
146
- component: CodeBlockList,
132
+ component: CodeBlockListPanel,
147
133
  slots: {},
148
134
  },
149
135
  'data-source': {