@tmagic/editor 1.3.6 → 1.3.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 (82) hide show
  1. package/LICENSE +5432 -0
  2. package/dist/style.css +34 -11
  3. package/dist/tmagic-editor.js +1360 -957
  4. package/dist/tmagic-editor.js.map +1 -1
  5. package/dist/tmagic-editor.umd.cjs +1382 -977
  6. package/dist/tmagic-editor.umd.cjs.map +1 -1
  7. package/package.json +17 -17
  8. package/src/Editor.vue +15 -7
  9. package/src/components/CodeBlockEditor.vue +2 -2
  10. package/src/components/ContentMenu.vue +5 -5
  11. package/src/components/ScrollBar.vue +2 -2
  12. package/src/components/ScrollViewer.vue +2 -2
  13. package/src/components/SplitView.vue +2 -2
  14. package/src/components/Tree.vue +1 -1
  15. package/src/components/TreeNode.vue +3 -3
  16. package/src/editorProps.ts +14 -4
  17. package/src/fields/PageFragmentSelect.vue +63 -0
  18. package/src/hooks/use-getso.ts +2 -2
  19. package/src/hooks/use-stage.ts +18 -1
  20. package/src/index.ts +3 -0
  21. package/src/initService.ts +15 -5
  22. package/src/layouts/AddPageBox.vue +16 -4
  23. package/src/layouts/CodeEditor.vue +2 -2
  24. package/src/layouts/Framework.vue +19 -3
  25. package/src/layouts/PropsPanel.vue +9 -7
  26. package/src/layouts/page-bar/AddButton.vue +48 -0
  27. package/src/layouts/page-bar/PageBar.vue +158 -0
  28. package/src/layouts/{workspace → page-bar}/PageBarScrollContainer.vue +61 -35
  29. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  30. package/src/layouts/sidebar/Sidebar.vue +2 -0
  31. package/src/layouts/sidebar/layer/LayerMenu.vue +39 -27
  32. package/src/layouts/sidebar/layer/LayerPanel.vue +7 -1
  33. package/src/layouts/sidebar/layer/use-click.ts +5 -3
  34. package/src/layouts/sidebar/layer/use-keybinding.ts +8 -8
  35. package/src/layouts/sidebar/layer/use-node-status.ts +3 -3
  36. package/src/layouts/workspace/Workspace.vue +6 -7
  37. package/src/layouts/workspace/viewer/NodeListMenu.vue +2 -2
  38. package/src/layouts/workspace/viewer/Stage.vue +12 -5
  39. package/src/layouts/workspace/viewer/ViewerMenu.vue +93 -80
  40. package/src/services/dataSource.ts +17 -0
  41. package/src/services/dep.ts +4 -0
  42. package/src/services/editor.ts +66 -35
  43. package/src/services/history.ts +6 -2
  44. package/src/services/keybinding.ts +48 -13
  45. package/src/theme/code-block.scss +0 -16
  46. package/src/theme/page-bar.scss +18 -1
  47. package/src/theme/page-fragment-select.scss +14 -0
  48. package/src/theme/theme.scss +1 -0
  49. package/src/theme/tree.scss +6 -0
  50. package/src/type.ts +23 -7
  51. package/src/utils/content-menu.ts +2 -2
  52. package/src/utils/editor.ts +22 -15
  53. package/src/utils/operator.ts +4 -4
  54. package/types/components/ToolButton.vue.d.ts +2 -2
  55. package/types/editorProps.d.ts +11 -2
  56. package/types/fields/PageFragmentSelect.vue.d.ts +31 -0
  57. package/types/index.d.ts +1 -0
  58. package/types/layouts/AddPageBox.vue.d.ts +14 -1
  59. package/types/layouts/Framework.vue.d.ts +14 -1
  60. package/types/layouts/PropsPanel.vue.d.ts +19 -10
  61. package/types/layouts/page-bar/AddButton.vue.d.ts +16 -0
  62. package/types/layouts/page-bar/PageBar.vue.d.ts +28 -0
  63. package/types/layouts/page-bar/PageBarScrollContainer.vue.d.ts +24 -0
  64. package/types/layouts/page-bar/SwitchTypeButton.vue.d.ts +20 -0
  65. package/types/layouts/sidebar/Sidebar.vue.d.ts +2 -0
  66. package/types/layouts/sidebar/layer/LayerMenu.vue.d.ts +22 -3
  67. package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +2 -0
  68. package/types/layouts/sidebar/layer/use-click.d.ts +25 -3
  69. package/types/layouts/sidebar/layer/use-keybinding.d.ts +1 -1
  70. package/types/layouts/workspace/Workspace.vue.d.ts +2 -0
  71. package/types/layouts/workspace/viewer/Stage.vue.d.ts +2 -0
  72. package/types/layouts/workspace/viewer/ViewerMenu.vue.d.ts +8 -0
  73. package/types/services/dataSource.d.ts +2 -0
  74. package/types/services/dep.d.ts +1 -0
  75. package/types/services/editor.d.ts +3 -2
  76. package/types/services/history.d.ts +3 -2
  77. package/types/services/keybinding.d.ts +21 -1
  78. package/types/type.d.ts +26 -12
  79. package/types/utils/editor.d.ts +9 -7
  80. package/src/layouts/workspace/PageBar.vue +0 -87
  81. package/types/layouts/workspace/PageBar.vue.d.ts +0 -15
  82. package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +0 -9
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.6",
2
+ "version": "1.3.8",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -23,11 +23,6 @@
23
23
  "./*": "./*"
24
24
  },
25
25
  "license": "Apache-2.0",
26
- "scripts": {
27
- "build": "npm run build:type && vite build",
28
- "build:type": "npm run clear:type && vue-tsc --declaration --emitDeclarationOnly --project tsconfig.build.json && tsc-alias -p tsconfig.build.json",
29
- "clear:type": "rimraf ./types"
30
- },
31
26
  "engines": {
32
27
  "node": ">=18"
33
28
  },
@@ -47,14 +42,14 @@
47
42
  "dependencies": {
48
43
  "@babel/core": "^7.18.0",
49
44
  "@element-plus/icons-vue": "^2.3.1",
50
- "@tmagic/core": "1.3.6",
51
- "@tmagic/dep": "1.3.6",
52
- "@tmagic/design": "1.3.6",
53
- "@tmagic/form": "1.3.6",
54
- "@tmagic/schema": "1.3.6",
55
- "@tmagic/stage": "1.3.6",
56
- "@tmagic/table": "1.3.6",
57
- "@tmagic/utils": "1.3.6",
45
+ "@tmagic/core": "1.3.8",
46
+ "@tmagic/dep": "1.3.8",
47
+ "@tmagic/design": "1.3.8",
48
+ "@tmagic/form": "1.3.8",
49
+ "@tmagic/schema": "1.3.8",
50
+ "@tmagic/stage": "1.3.8",
51
+ "@tmagic/table": "1.3.8",
52
+ "@tmagic/utils": "1.3.8",
58
53
  "buffer": "^6.0.3",
59
54
  "color": "^3.1.3",
60
55
  "events": "^3.3.0",
@@ -67,8 +62,8 @@
67
62
  "vue": "^3.3.8"
68
63
  },
69
64
  "peerDependencies": {
70
- "@tmagic/design": "1.3.6",
71
- "@tmagic/form": "1.3.6",
65
+ "@tmagic/design": "1.3.8",
66
+ "@tmagic/form": "1.3.8",
72
67
  "monaco-editor": "^0.41.0",
73
68
  "vue": "^3.3.8"
74
69
  },
@@ -86,5 +81,10 @@
86
81
  "typescript": "^5.0.4",
87
82
  "vite": "^5.0.7",
88
83
  "vue-tsc": "^1.8.25"
84
+ },
85
+ "scripts": {
86
+ "build": "npm run build:type && vite build",
87
+ "build:type": "npm run clear:type && vue-tsc --declaration --emitDeclarationOnly --project tsconfig.build.json && tsc-alias -p tsconfig.build.json",
88
+ "clear:type": "rimraf ./types"
89
89
  }
90
- }
90
+ }
package/src/Editor.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <Framework>
2
+ <Framework :disabled-page-fragment="disabledPageFragment">
3
3
  <template #header>
4
4
  <slot name="header"></slot>
5
5
  </template>
@@ -16,7 +16,7 @@
16
16
 
17
17
  <template #sidebar>
18
18
  <slot name="sidebar" :editorService="editorService">
19
- <Sidebar :data="sidebar" :layer-content-menu="layerContentMenu">
19
+ <Sidebar :data="sidebar" :layer-content-menu="layerContentMenu" :custom-content-menu="customContentMenu">
20
20
  <template #layer-panel-header>
21
21
  <slot name="layer-panel-header"></slot>
22
22
  </template>
@@ -58,11 +58,9 @@
58
58
 
59
59
  <template #workspace>
60
60
  <slot name="workspace" :editorService="editorService">
61
- <Workspace :stage-content-menu="stageContentMenu">
61
+ <Workspace :stage-content-menu="stageContentMenu" :custom-content-menu="customContentMenu">
62
62
  <template #stage><slot name="stage"></slot></template>
63
63
  <template #workspace-content><slot name="workspace-content" :editorService="editorService"></slot></template>
64
- <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
65
- <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
66
64
  </Workspace>
67
65
  </slot>
68
66
  </template>
@@ -72,6 +70,8 @@
72
70
  <PropsPanel
73
71
  :extend-state="extendFormState"
74
72
  @mounted="(instance: any) => $emit('props-panel-mounted', instance)"
73
+ @form-error="(e: any) => $emit('props-form-error', e)"
74
+ @submit-error="(e: any) => $emit('props-submit-error', e)"
75
75
  >
76
76
  <template #props-panel-header>
77
77
  <slot name="props-panel-header"></slot>
@@ -89,6 +89,10 @@
89
89
  <template #footer>
90
90
  <slot name="footer"></slot>
91
91
  </template>
92
+
93
+ <template #page-bar><slot name="page-bar"></slot></template>
94
+ <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
95
+ <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
92
96
  </Framework>
93
97
  </template>
94
98
 
@@ -135,6 +139,8 @@ defineOptions({
135
139
  const emit = defineEmits<{
136
140
  'props-panel-mounted': [instance: InstanceType<typeof PropsPanel>];
137
141
  'update:modelValue': [value: MApp | null];
142
+ 'props-form-error': [e: any];
143
+ 'props-submit-error': [e: any];
138
144
  }>();
139
145
 
140
146
  const props = withDefaults(defineProps<EditorProps>(), defaultEditorProps);
@@ -155,8 +161,8 @@ const services: Services = {
155
161
 
156
162
  initServiceEvents(props, emit, services);
157
163
  initServiceState(props, services);
158
- keybindingService.registe(keybindingConfig);
159
- keybindingService.registeEl('global');
164
+ keybindingService.register(keybindingConfig);
165
+ keybindingService.registerEl('global');
160
166
 
161
167
  provide('services', services);
162
168
 
@@ -176,6 +182,8 @@ provide(
176
182
  containerHighlightType: props.containerHighlightType,
177
183
  disabledDragStart: props.disabledDragStart,
178
184
  renderType: props.renderType,
185
+ guidesOptions: props.guidesOptions,
186
+ disabledMultiSelect: props.disabledMultiSelect,
179
187
  }),
180
188
  );
181
189
 
@@ -48,7 +48,7 @@
48
48
  </template>
49
49
 
50
50
  <script lang="ts" setup>
51
- import { computed, inject, onUnmounted, ref } from 'vue';
51
+ import { computed, inject, onBeforeUnmount, ref } from 'vue';
52
52
 
53
53
  import { TMagicButton, TMagicDialog, tMagicMessage, tMagicMessageBox, TMagicTag } from '@tmagic/design';
54
54
  import { ColumnConfig, FormConfig, FormState, MFormBox, MFormDrawer } from '@tmagic/form';
@@ -85,7 +85,7 @@ const windowReizehandler = () => {
85
85
 
86
86
  globalThis.addEventListener('resize', windowReizehandler);
87
87
 
88
- onUnmounted(() => {
88
+ onBeforeUnmount(() => {
89
89
  globalThis.removeEventListener('resize', windowReizehandler);
90
90
  });
91
91
 
@@ -36,7 +36,7 @@
36
36
  </template>
37
37
 
38
38
  <script lang="ts" setup>
39
- import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
39
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
40
40
 
41
41
  import { MenuButton, MenuComponent } from '@editor/type';
42
42
 
@@ -99,7 +99,7 @@ const clickHandler = () => {
99
99
  hide();
100
100
  };
101
101
 
102
- const outsideClickhideHandler = (e: MouseEvent) => {
102
+ const outsideClickHideHandler = (e: MouseEvent) => {
103
103
  if (!props.autoHide) return;
104
104
 
105
105
  const target = e.target as HTMLElement | undefined;
@@ -173,13 +173,13 @@ const mouseenterHandler = () => {
173
173
  onMounted(() => {
174
174
  if (props.isSubMenu) return;
175
175
 
176
- globalThis.addEventListener('mousedown', outsideClickhideHandler, true);
176
+ globalThis.addEventListener('mousedown', outsideClickHideHandler, true);
177
177
  });
178
178
 
179
- onUnmounted(() => {
179
+ onBeforeUnmount(() => {
180
180
  if (props.isSubMenu) return;
181
181
 
182
- globalThis.removeEventListener('mousedown', outsideClickhideHandler, true);
182
+ globalThis.removeEventListener('mousedown', outsideClickHideHandler, true);
183
183
  });
184
184
 
185
185
  defineExpose({
@@ -5,7 +5,7 @@
5
5
  </template>
6
6
 
7
7
  <script lang="ts" setup>
8
- import { computed, onMounted, onUnmounted, ref } from 'vue';
8
+ import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
9
9
  import Gesto from 'gesto';
10
10
 
11
11
  defineOptions({
@@ -53,7 +53,7 @@ onMounted(() => {
53
53
  bar.value?.addEventListener('wheel', wheelHandler, false);
54
54
  });
55
55
 
56
- onUnmounted(() => {
56
+ onBeforeUnmount(() => {
57
57
  if (gesto) gesto.off();
58
58
  bar.value?.removeEventListener('wheel', wheelHandler, false);
59
59
  });
@@ -23,7 +23,7 @@
23
23
  </template>
24
24
 
25
25
  <script lang="ts" setup>
26
- import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
26
+ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
27
27
 
28
28
  import { isNumber } from '@tmagic/utils';
29
29
 
@@ -94,7 +94,7 @@ onMounted(() => {
94
94
  });
95
95
  });
96
96
 
97
- onUnmounted(() => {
97
+ onBeforeUnmount(() => {
98
98
  scrollViewer.destroy();
99
99
  });
100
100
 
@@ -21,7 +21,7 @@
21
21
  </template>
22
22
 
23
23
  <script lang="ts" setup>
24
- import { computed, onMounted, onUnmounted, ref } from 'vue';
24
+ import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
25
25
  import { OnDrag } from 'gesto';
26
26
 
27
27
  import Resizer from './Resizer.vue';
@@ -110,7 +110,7 @@ onMounted(() => {
110
110
  }
111
111
  });
112
112
 
113
- onUnmounted(() => {
113
+ onBeforeUnmount(() => {
114
114
  resizerObserver.disconnect();
115
115
  });
116
116
 
@@ -15,7 +15,7 @@
15
15
  </template>
16
16
  </TreeNode>
17
17
  </template>
18
- <div v-else>
18
+ <div v-else class="m-editor-tree-empty">
19
19
  <p>{{ emptyText }}</p>
20
20
  </div>
21
21
  </div>
@@ -18,7 +18,7 @@
18
18
  >
19
19
  <MIcon
20
20
  class="expand-icon"
21
- :style="hasChilren ? '' : 'color: transparent; cursor: default'"
21
+ :style="hasChildren ? '' : 'color: transparent; cursor: default'"
22
22
  :icon="expanded ? ArrowDown : ArrowRight"
23
23
  @click="expandHandler"
24
24
  ></MIcon>
@@ -35,7 +35,7 @@
35
35
  </div>
36
36
  </div>
37
37
 
38
- <div v-if="hasChilren && expanded" class="m-editor-tree-node-children">
38
+ <div v-if="hasChildren && expanded" class="m-editor-tree-node-children">
39
39
  <TreeNode
40
40
  v-for="item in data.items"
41
41
  :key="item.id"
@@ -114,7 +114,7 @@ const selected = computed(() => nodeStatus.value.selected);
114
114
  const visible = computed(() => nodeStatus.value.visible);
115
115
  const draggable = computed(() => nodeStatus.value.draggable);
116
116
 
117
- const hasChilren = computed(() => props.data.items?.some((item) => props.nodeStatusMap.get(item.id)?.visible));
117
+ const hasChildren = computed(() => props.data.items?.some((item) => props.nodeStatusMap.get(item.id)?.visible));
118
118
 
119
119
  const handleDragStart = (event: DragEvent) => {
120
120
  treeEmit?.('node-dragstart', event, props.data);
@@ -1,14 +1,15 @@
1
1
  import type { EventOption } from '@tmagic/core';
2
- import { CustomTargetOptions } from '@tmagic/dep';
2
+ import type { CustomTargetOptions } from '@tmagic/dep';
3
3
  import type { FormConfig, FormState } from '@tmagic/form';
4
4
  import type { DataSourceSchema, Id, MApp, MNode } from '@tmagic/schema';
5
5
  import StageCore, {
6
6
  CONTAINER_HIGHLIGHT_CLASS_NAME,
7
7
  ContainerHighlightType,
8
- CustomizeMoveableOptionsCallbackConfig,
9
- MoveableOptions,
8
+ type CustomizeMoveableOptionsCallbackConfig,
9
+ type GuidesOptions,
10
+ type MoveableOptions,
10
11
  RenderType,
11
- UpdateDragEl,
12
+ type UpdateDragEl,
12
13
  } from '@tmagic/stage';
13
14
 
14
15
  import type {
@@ -71,6 +72,13 @@ export interface EditorProps {
71
72
  extendFormState?: (state: FormState) => Record<string, any> | Promise<Record<string, any>>;
72
73
  /** 自定义依赖收集器,复制组件时会将关联依赖一并复制 */
73
74
  collectorOptions?: CustomTargetOptions;
75
+ /** 标尺配置 */
76
+ guidesOptions?: Partial<GuidesOptions>;
77
+ /** 禁止多选 */
78
+ disabledMultiSelect?: boolean;
79
+ /** 禁用页面片 */
80
+ disabledPageFragment?: boolean;
81
+ customContentMenu?: (menus: (MenuButton | MenuComponent)[], type: string) => (MenuButton | MenuComponent)[];
74
82
  }
75
83
 
76
84
  export const defaultEditorProps = {
@@ -91,4 +99,6 @@ export const defaultEditorProps = {
91
99
  containerHighlightType: ContainerHighlightType.DEFAULT,
92
100
  codeOptions: () => ({}),
93
101
  renderType: RenderType.IFRAME,
102
+ disabledMultiSelect: false,
103
+ disabledPageFragment: false,
94
104
  };
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <div class="m-fields-page-fragment-select">
3
+ <div class="page-fragment-select-container">
4
+ <!-- 页面片下拉框 -->
5
+ <m-form-container
6
+ class="select"
7
+ :config="selectConfig"
8
+ :model="model"
9
+ :size="size"
10
+ @change="changeHandler"
11
+ ></m-form-container>
12
+ <!-- 编辑按钮 -->
13
+ <Icon v-if="model[name]" class="icon" :icon="Edit" @click="editPageFragment(model[name])"></Icon>
14
+ </div>
15
+ </div>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ import { computed, inject } from 'vue';
20
+ import { Edit } from '@element-plus/icons-vue';
21
+
22
+ import { FieldProps } from '@tmagic/form';
23
+ import { Id, NodeType } from '@tmagic/schema';
24
+
25
+ import Icon from '@editor/components/Icon.vue';
26
+ import type { PageFragmentSelectConfig, Services } from '@editor/type';
27
+
28
+ defineOptions({
29
+ name: 'MEditorPageFragmentSelect',
30
+ });
31
+
32
+ const services = inject<Services>('services');
33
+ const emit = defineEmits(['change']);
34
+
35
+ const props = withDefaults(defineProps<FieldProps<PageFragmentSelectConfig>>(), {
36
+ disabled: false,
37
+ });
38
+ const pageList = computed(() =>
39
+ services?.editorService.get('root')?.items.filter((item) => item.type === NodeType.PAGE_FRAGMENT),
40
+ );
41
+
42
+ const selectConfig = {
43
+ type: 'select',
44
+ name: props.name,
45
+ options: () => {
46
+ if (pageList.value) {
47
+ return pageList.value.map((item) => ({
48
+ text: `${item.devconfig?.tabName || item.title || item.name}(${item.id})`,
49
+ label: `${item.devconfig?.tabName || item.title || item.name}(${item.id})`,
50
+ value: item.id,
51
+ }));
52
+ }
53
+ return [];
54
+ },
55
+ };
56
+ const changeHandler = async () => {
57
+ emit('change', props.model[props.name]);
58
+ };
59
+
60
+ const editPageFragment = (id: Id) => {
61
+ services?.editorService.select(id);
62
+ };
63
+ </script>
@@ -1,4 +1,4 @@
1
- import { onMounted, onUnmounted, type Ref, ref } from 'vue';
1
+ import { onBeforeUnmount, onMounted, type Ref, ref } from 'vue';
2
2
  import Gesto, { type OnDrag } from 'gesto';
3
3
 
4
4
  export const useGetSo = (target: Ref<HTMLElement | undefined>, emit: (evt: 'change', e: OnDrag<Gesto>) => void) => {
@@ -24,7 +24,7 @@ export const useGetSo = (target: Ref<HTMLElement | undefined>, emit: (evt: 'chan
24
24
  });
25
25
  });
26
26
 
27
- onUnmounted(() => {
27
+ onBeforeUnmount(() => {
28
28
  getso?.unset();
29
29
  isDraging.value = false;
30
30
  });
@@ -1,4 +1,4 @@
1
- import { computed } from 'vue';
1
+ import { computed, watch } from 'vue';
2
2
 
3
3
  import type { MNode } from '@tmagic/schema';
4
4
  import StageCore, { GuidesType, RemoveEventData, SortEventData, UpdateEventData } from '@tmagic/stage';
@@ -44,13 +44,30 @@ export const useStage = (stageOptions: StageOptions) => {
44
44
  },
45
45
  moveableOptions: stageOptions.moveableOptions,
46
46
  updateDragEl: stageOptions.updateDragEl,
47
+ guidesOptions: stageOptions.guidesOptions,
48
+ disabledMultiSelect: stageOptions.disabledMultiSelect,
47
49
  });
48
50
 
51
+ watch(
52
+ () => editorService.get('disabledMultiSelect'),
53
+ (disabledMultiSelect) => {
54
+ if (disabledMultiSelect) {
55
+ stage.disableMultiSelect();
56
+ } else {
57
+ stage.enableMultiSelect();
58
+ }
59
+ },
60
+ );
61
+
49
62
  stage.mask.setGuides([
50
63
  getGuideLineFromCache(getGuideLineKey(H_GUIDE_LINE_STORAGE_KEY)),
51
64
  getGuideLineFromCache(getGuideLineKey(V_GUIDE_LINE_STORAGE_KEY)),
52
65
  ]);
53
66
 
67
+ stage.on('page-el-update', () => {
68
+ editorService.set('stageLoading', false);
69
+ });
70
+
54
71
  stage.on('select', (el: HTMLElement) => {
55
72
  if (`${editorService.get('node')?.id}` === el.id && editorService.get('nodes').length === 1) return;
56
73
  editorService.select(el.id);
package/src/index.ts CHANGED
@@ -30,6 +30,7 @@ import DataSourceMocks from './fields/DataSourceMocks.vue';
30
30
  import DataSourceSelect from './fields/DataSourceSelect.vue';
31
31
  import EventSelect from './fields/EventSelect.vue';
32
32
  import KeyValue from './fields/KeyValue.vue';
33
+ import PageFragmentSelect from './fields/PageFragmentSelect.vue';
33
34
  import uiSelect from './fields/UISelect.vue';
34
35
  import CodeEditor from './layouts/CodeEditor.vue';
35
36
  import { setConfig } from './utils/config';
@@ -79,6 +80,7 @@ export { default as LayoutContainer } from './components/SplitView.vue';
79
80
  export { default as SplitView } from './components/SplitView.vue';
80
81
  export { default as Resizer } from './components/Resizer.vue';
81
82
  export { default as CodeBlockEditor } from './components/CodeBlockEditor.vue';
83
+ export { default as PageFragmentSelect } from './fields/PageFragmentSelect.vue';
82
84
 
83
85
  const defaultInstallOpt: InstallOptions = {
84
86
  // eslint-disable-next-line no-eval
@@ -108,5 +110,6 @@ export default {
108
110
  app.component('m-fields-data-source-methods', DataSourceMethods);
109
111
  app.component('m-fields-data-source-method-select', DataSourceMethodSelect);
110
112
  app.component('m-fields-data-source-field-select', DataSourceFieldSelect);
113
+ app.component('m-fields-page-fragment-select', PageFragmentSelect);
111
114
  },
112
115
  };
@@ -1,4 +1,4 @@
1
- import { onUnmounted, reactive, toRaw, watch } from 'vue';
1
+ import { onBeforeUnmount, reactive, toRaw, watch } from 'vue';
2
2
  import { cloneDeep } from 'lodash-es';
3
3
 
4
4
  import type { EventOption } from '@tmagic/core';
@@ -11,7 +11,7 @@ import {
11
11
  DepTargetType,
12
12
  Target,
13
13
  } from '@tmagic/dep';
14
- import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage } from '@tmagic/schema';
14
+ import type { CodeBlockContent, DataSourceSchema, Id, MApp, MNode, MPage, MPageFragment } from '@tmagic/schema';
15
15
  import { getNodes } from '@tmagic/utils';
16
16
 
17
17
  import PropsPanel from './layouts/PropsPanel.vue';
@@ -47,6 +47,16 @@ export const initServiceState = (
47
47
  },
48
48
  );
49
49
 
50
+ watch(
51
+ () => props.disabledMultiSelect,
52
+ (disabledMultiSelect) => {
53
+ editorService.set('disabledMultiSelect', disabledMultiSelect || false);
54
+ },
55
+ {
56
+ immediate: true,
57
+ },
58
+ );
59
+
50
60
  watch(
51
61
  () => props.componentGroupList,
52
62
  (componentGroupList) => componentGroupList && componentListService.setList(componentGroupList),
@@ -165,7 +175,7 @@ export const initServiceState = (
165
175
  },
166
176
  );
167
177
 
168
- onUnmounted(() => {
178
+ onBeforeUnmount(() => {
169
179
  editorService.resetState();
170
180
  historyService.resetState();
171
181
  propsService.resetState();
@@ -340,7 +350,7 @@ export const initServiceEvents = (
340
350
  };
341
351
 
342
352
  // 由于历史记录变化是更新整个page,所以历史记录变化时,需要重新收集依赖
343
- const historyChangeHandler = (page: MPage) => {
353
+ const historyChangeHandler = (page: MPage | MPageFragment) => {
344
354
  depService.collect([page], true);
345
355
  };
346
356
 
@@ -405,7 +415,7 @@ export const initServiceEvents = (
405
415
  depService.addTarget(createRelatedCompTarget(props.collectorOptions));
406
416
  }
407
417
 
408
- onUnmounted(() => {
418
+ onBeforeUnmount(() => {
409
419
  depService.off('add-target', targetAddHandler);
410
420
  depService.off('remove-target', targetRemoveHandler);
411
421
  depService.off('dep-update', depUpdateHandler);
@@ -1,12 +1,19 @@
1
1
  <template>
2
2
  <div class="m-editor-empty-panel">
3
3
  <div class="m-editor-empty-content">
4
- <div class="m-editor-empty-button" @click="clickHandler">
4
+ <div class="m-editor-empty-button" @click="clickHandler(NodeType.PAGE)">
5
5
  <div>
6
6
  <MIcon :icon="Plus"></MIcon>
7
7
  </div>
8
8
  <p>新增页面</p>
9
9
  </div>
10
+
11
+ <div v-if="!disabledPageFragment" class="m-editor-empty-button" @click="clickHandler(NodeType.PAGE_FRAGMENT)">
12
+ <div>
13
+ <MIcon :icon="Plus"></MIcon>
14
+ </div>
15
+ <p>新增页面片</p>
16
+ </div>
10
17
  </div>
11
18
  </div>
12
19
  </template>
@@ -25,9 +32,13 @@ defineOptions({
25
32
  name: 'MEditorAddPageBox',
26
33
  });
27
34
 
35
+ defineProps<{
36
+ disabledPageFragment: boolean;
37
+ }>();
38
+
28
39
  const services = inject<Services>('services');
29
40
 
30
- const clickHandler = () => {
41
+ const clickHandler = (type: NodeType.PAGE | NodeType.PAGE_FRAGMENT) => {
31
42
  const { editorService } = services || {};
32
43
 
33
44
  if (!editorService) return;
@@ -36,8 +47,9 @@ const clickHandler = () => {
36
47
  if (!root) throw new Error('root 不能为空');
37
48
 
38
49
  editorService.add({
39
- type: NodeType.PAGE,
40
- name: generatePageNameByApp(root),
50
+ type,
51
+ name: generatePageNameByApp(root, type),
52
+ items: [],
41
53
  });
42
54
  };
43
55
  </script>
@@ -19,7 +19,7 @@
19
19
  </template>
20
20
 
21
21
  <script lang="ts" setup>
22
- import { onMounted, onUnmounted, ref, watch } from 'vue';
22
+ import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
23
23
  import { FullScreen } from '@element-plus/icons-vue';
24
24
  import { throttle } from 'lodash-es';
25
25
  import * as monaco from 'monaco-editor';
@@ -188,7 +188,7 @@ onMounted(async () => {
188
188
  init();
189
189
  });
190
190
 
191
- onUnmounted(() => {
191
+ onBeforeUnmount(() => {
192
192
  resizeObserver.disconnect();
193
193
  });
194
194
 
@@ -11,6 +11,8 @@
11
11
  </slot>
12
12
 
13
13
  <SplitView
14
+ v-loading="stageLoading"
15
+ element-loading-text="Runtime 加载中..."
14
16
  v-else
15
17
  ref="splitView"
16
18
  class="m-editor-content"
@@ -29,13 +31,20 @@
29
31
  </template>
30
32
 
31
33
  <template #center>
32
- <slot v-if="pageLength > 0" name="workspace"></slot>
34
+ <slot v-if="page" name="workspace"></slot>
33
35
  <slot v-else name="empty">
34
- <AddPageBox></AddPageBox>
36
+ <AddPageBox :disabled-page-fragment="disabledPageFragment"></AddPageBox>
37
+ </slot>
38
+
39
+ <slot name="page-bar">
40
+ <PageBar :disabled-page-fragment="disabledPageFragment">
41
+ <template #page-bar-title="{ page }"><slot name="page-bar-title" :page="page"></slot></template>
42
+ <template #page-bar-popover="{ page }"><slot name="page-bar-popover" :page="page"></slot></template>
43
+ </PageBar>
35
44
  </slot>
36
45
  </template>
37
46
 
38
- <template v-if="pageLength > 0" #right>
47
+ <template v-if="page" #right>
39
48
  <TMagicScrollbar>
40
49
  <slot name="props-panel"></slot>
41
50
  </TMagicScrollbar>
@@ -56,6 +65,7 @@ import SplitView from '@editor/components/SplitView.vue';
56
65
  import type { FrameworkSlots, GetColumnWidth, Services } from '@editor/type';
57
66
  import { getConfig } from '@editor/utils/config';
58
67
 
68
+ import PageBar from './page-bar/PageBar.vue';
59
69
  import AddPageBox from './AddPageBox.vue';
60
70
  import CodeEditor from './CodeEditor.vue';
61
71
 
@@ -65,6 +75,10 @@ defineOptions({
65
75
  name: 'MEditorFramework',
66
76
  });
67
77
 
78
+ defineProps<{
79
+ disabledPageFragment: boolean;
80
+ }>();
81
+
68
82
  const DEFAULT_LEFT_COLUMN_WIDTH = 310;
69
83
  const DEFAULT_RIGHT_COLUMN_WIDTH = 480;
70
84
 
@@ -75,8 +89,10 @@ const content = ref<HTMLDivElement>();
75
89
  const splitView = ref<InstanceType<typeof SplitView>>();
76
90
 
77
91
  const root = computed(() => editorService?.get('root'));
92
+ const page = computed(() => editorService?.get('page'));
78
93
 
79
94
  const pageLength = computed(() => editorService?.get('pageLength') || 0);
95
+ const stageLoading = computed(() => editorService?.get('stageLoading') || false);
80
96
  const showSrc = computed(() => uiService?.get('showSrc'));
81
97
 
82
98
  const LEFT_COLUMN_WIDTH_STORAGE_KEY = '$MagicEditorLeftColumnWidthData';