@tmagic/editor 1.2.0-beta.1 → 1.2.0-beta.11

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 (76) hide show
  1. package/dist/style.css +14 -8
  2. package/dist/tmagic-editor.mjs +1112 -981
  3. package/dist/tmagic-editor.mjs.map +1 -1
  4. package/dist/tmagic-editor.umd.js +1124 -991
  5. package/dist/tmagic-editor.umd.js.map +1 -1
  6. package/package.json +11 -10
  7. package/src/Editor.vue +11 -13
  8. package/src/components/ContentMenu.vue +4 -4
  9. package/src/components/Icon.vue +7 -5
  10. package/src/{layouts → components}/Layout.vue +14 -4
  11. package/src/components/ScrollBar.vue +1 -1
  12. package/src/components/ScrollViewer.vue +10 -1
  13. package/src/components/ToolButton.vue +30 -15
  14. package/src/fields/Code.vue +5 -2
  15. package/src/fields/CodeLink.vue +20 -12
  16. package/src/fields/CodeSelect.vue +19 -27
  17. package/src/fields/UISelect.vue +9 -8
  18. package/src/index.ts +3 -1
  19. package/src/layouts/AddPageBox.vue +13 -20
  20. package/src/layouts/CodeEditor.vue +106 -120
  21. package/src/layouts/Framework.vue +62 -40
  22. package/src/layouts/NavMenu.vue +1 -1
  23. package/src/layouts/PropsPanel.vue +4 -9
  24. package/src/layouts/Resizer.vue +1 -1
  25. package/src/layouts/sidebar/ComponentListPanel.vue +15 -13
  26. package/src/layouts/sidebar/LayerMenu.vue +89 -92
  27. package/src/layouts/sidebar/LayerPanel.vue +273 -178
  28. package/src/layouts/sidebar/Sidebar.vue +126 -46
  29. package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +28 -24
  30. package/src/layouts/sidebar/code-block/CodeBlockList.vue +22 -22
  31. package/src/layouts/workspace/Breadcrumb.vue +32 -0
  32. package/src/layouts/workspace/PageBar.vue +12 -11
  33. package/src/layouts/workspace/PageBarScrollContainer.vue +1 -1
  34. package/src/layouts/workspace/Stage.vue +15 -7
  35. package/src/layouts/workspace/ViewerMenu.vue +8 -7
  36. package/src/layouts/workspace/Workspace.vue +10 -3
  37. package/src/services/codeBlock.ts +16 -10
  38. package/src/services/editor.ts +12 -8
  39. package/src/theme/breadcrumb.scss +6 -0
  40. package/src/theme/component-list-panel.scss +3 -7
  41. package/src/theme/index.scss +1 -15
  42. package/src/theme/layer-panel.scss +7 -2
  43. package/src/theme/theme.scss +16 -0
  44. package/src/type.ts +2 -1
  45. package/src/utils/scroll-viewer.ts +18 -2
  46. package/src/utils/stage.ts +7 -0
  47. package/types/Editor.vue.d.ts +2 -2
  48. package/types/components/ContentMenu.vue.d.ts +1 -3
  49. package/types/components/Icon.vue.d.ts +1 -3
  50. package/types/{layouts → components}/Layout.vue.d.ts +0 -0
  51. package/types/components/ScrollBar.vue.d.ts +1 -3
  52. package/types/components/ScrollViewer.vue.d.ts +45 -1
  53. package/types/components/ToolButton.vue.d.ts +1 -3
  54. package/types/fields/Code.vue.d.ts +9 -3
  55. package/types/fields/CodeLink.vue.d.ts +5 -3
  56. package/types/fields/CodeSelect.vue.d.ts +1 -3
  57. package/types/fields/UISelect.vue.d.ts +1 -3
  58. package/types/index.d.ts +2 -0
  59. package/types/layouts/AddPageBox.vue.d.ts +43 -3
  60. package/types/layouts/CodeEditor.vue.d.ts +158 -45
  61. package/types/layouts/NavMenu.vue.d.ts +1 -3
  62. package/types/layouts/sidebar/LayerMenu.vue.d.ts +31 -63
  63. package/types/layouts/sidebar/LayerPanel.vue.d.ts +38 -1074
  64. package/types/layouts/sidebar/Sidebar.vue.d.ts +119 -17
  65. package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +1 -0
  66. package/types/layouts/workspace/Breadcrumb.vue.d.ts +44 -0
  67. package/types/layouts/workspace/Stage.vue.d.ts +23 -7
  68. package/types/layouts/workspace/ViewerMenu.vue.d.ts +6 -3
  69. package/types/layouts/workspace/Workspace.vue.d.ts +23 -5
  70. package/types/services/codeBlock.d.ts +1 -1
  71. package/types/services/editor.d.ts +2 -2
  72. package/types/services/ui.d.ts +1 -1
  73. package/types/type.d.ts +2 -1
  74. package/types/utils/scroll-viewer.d.ts +5 -0
  75. package/src/layouts/sidebar/TabPane.vue +0 -126
  76. package/types/layouts/sidebar/TabPane.vue.d.ts +0 -14
@@ -1,75 +1,155 @@
1
1
  <template>
2
- <el-tabs
2
+ <TMagicTabs
3
3
  v-if="data.type === 'tabs' && data.items.length"
4
4
  class="m-editor-sidebar"
5
5
  v-model="activeTabName"
6
6
  type="card"
7
7
  tab-position="left"
8
8
  >
9
- <tab-pane v-for="(item, index) in data.items" :key="index" :data="item">
10
- <template #layer-panel-header v-if="item === 'layer'">
11
- <slot name="layer-panel-header"></slot>
9
+ <component :is="uiComponent.component" v-for="(config, index) in sideBarItems" :key="index" :name="config.text">
10
+ <template #label>
11
+ <div :key="config.text">
12
+ <MIcon v-if="config.icon" :icon="config.icon"></MIcon>
13
+ <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
14
+ </div>
12
15
  </template>
13
16
 
14
- <template #layer-node-content="{ node, data }" v-if="item === 'layer'">
15
- <slot name="layer-node-content" :data="data" :node="node"></slot>
16
- </template>
17
+ <component v-if="config" :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
18
+ <template
19
+ #component-list-panel-header
20
+ v-if="config.$key === 'component-list' || config.slots?.componentListPanelHeader"
21
+ >
22
+ <slot v-if="config.$key === 'component-list'" name="component-list-panel-header"></slot>
23
+ <component v-else-if="config.slots?.componentListPanelHeader" :is="config.slots.componentListPanelHeader" />
24
+ </template>
17
25
 
18
- <template #component-list-panel-header v-if="item === 'component-list'">
19
- <slot name="component-list-panel-header"></slot>
20
- </template>
26
+ <template
27
+ #component-list-item="{ component }"
28
+ v-if="config.$key === 'component-list' || config.slots?.componentListItem"
29
+ >
30
+ <slot v-if="config.$key === 'component-list'" name="component-list-item" :component="component"></slot>
31
+ <component
32
+ v-else-if="config.slots?.componentListItem"
33
+ :is="config.slots.componentListItem"
34
+ :component="component"
35
+ />
36
+ </template>
21
37
 
22
- <template #component-list-item="{ component }" v-if="item === 'component-list'">
23
- <slot name="component-list-item" :component="component"></slot>
24
- </template>
38
+ <template #layer-panel-header v-if="config.$key === 'layer' || config.slots?.layerPanelHeader">
39
+ <slot v-if="config.$key === 'layer'" name="layer-panel-header"></slot>
40
+ <component v-else-if="config.slots?.layerPanelHeader" :is="config.slots.layerPanelHeader" />
41
+ </template>
25
42
 
26
- <template #code-block-panel-header v-if="item === 'code-block'">
27
- <slot name="code-block-panel-header"></slot>
28
- </template>
43
+ <template #code-block-panel-header v-if="config.$key === 'code-block' || config.slots?.codeBlockPanelHeader">
44
+ <slot v-if="config.$key === 'code-block'" name="code-block-panel-header"></slot>
45
+ <component v-else-if="config.slots?.codeBlockPanelHeader" :is="config.slots.codeBlockPanelHeader" />
46
+ </template>
29
47
 
30
- <template #code-block-panel-tool="{ id }" v-if="item === 'code-block'">
31
- <slot name="code-block-panel-tool" :id="id"></slot>
32
- </template>
48
+ <template
49
+ #code-block-panel-tool="{ id, data }"
50
+ v-if="config.$key === 'code-block' || config.slots?.codeBlockPanelTool"
51
+ >
52
+ <slot v-if="config.$key === 'code-block'" name="code-block-panel-tool" :id="id" :data="data"></slot>
53
+ <component v-else-if="config.slots?.codeBlockPanelTool" :is="config.slots.codeBlockPanelTool" />
54
+ </template>
33
55
 
34
- <template #code-block-edit-panel-header="{ id }" v-if="item === 'code-block'">
35
- <slot name="code-block-edit-panel-header" :id="id"></slot>
36
- </template>
37
- </tab-pane>
38
- </el-tabs>
56
+ <template
57
+ #code-block-edit-panel-header="{ id }"
58
+ v-if="config.$key === 'code-block' || config.slots?.codeBlockEditPanelHeader"
59
+ >
60
+ <slot v-if="config.$key === 'code-block'" name="code-block-edit-panel-header" :id="id"></slot>
61
+ <component v-else-if="config.slots?.codeBlockEditPanelHeader" :is="config.slots.codeBlockEditPanelHeader" />
62
+ </template>
63
+
64
+ <template
65
+ #layer-node-content="{ data: nodeData, node }"
66
+ v-if="config.$key === 'layer' || config.slots?.layerNodeContent"
67
+ >
68
+ <slot v-if="config.$key === 'layer'" name="layer-node-content" :data="nodeData" :node="node"></slot>
69
+ <component
70
+ v-else-if="config.slots?.layerNodeContent"
71
+ :is="config.slots.layerNodeContent"
72
+ :data="nodeData"
73
+ :node="node"
74
+ />
75
+ </template>
76
+ </component>
77
+ </component>
78
+ </TMagicTabs>
39
79
  </template>
40
80
 
41
- <script lang="ts">
42
- import { defineComponent, PropType, ref, watch } from 'vue';
81
+ <script lang="ts" setup name="MEditorSidebar">
82
+ import { computed, ref, watch } from 'vue';
83
+ import { Coin, EditPen, Files } from '@element-plus/icons-vue';
84
+
85
+ import { getConfig, TMagicTabs } from '@tmagic/design';
43
86
 
87
+ import MIcon from '../../components/Icon.vue';
88
+ import type { MenuButton, MenuComponent, SideComponent, SideItem } from '../../type';
44
89
  import { SideBarData } from '../../type';
45
90
 
46
- import TabPane from './TabPane.vue';
91
+ import CodeBlockList from './code-block/CodeBlockList.vue';
92
+ import ComponentListPanel from './ComponentListPanel.vue';
93
+ import LayerPanel from './LayerPanel.vue';
47
94
 
48
- export default defineComponent({
49
- components: { TabPane },
95
+ const props = withDefaults(
96
+ defineProps<{
97
+ data?: SideBarData;
98
+ layerContentMenu: (MenuButton | MenuComponent)[];
99
+ }>(),
100
+ {
101
+ data: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer', 'code-block'] }),
102
+ },
103
+ );
104
+
105
+ const uiComponent = getConfig('components').tabPane;
50
106
 
51
- name: 'm-sidebar',
107
+ const activeTabName = ref(props.data?.status);
52
108
 
53
- props: {
54
- data: {
55
- type: Object as PropType<SideBarData>,
56
- default: () => ({ type: 'tabs', status: '组件', items: ['component-list', 'layer', 'code-block'] }),
109
+ const getItemConfig = (data: SideItem): SideComponent => {
110
+ const map: Record<string, SideComponent> = {
111
+ 'component-list': {
112
+ $key: 'component-list',
113
+ type: 'component',
114
+ icon: Coin,
115
+ text: '组件',
116
+ component: ComponentListPanel,
117
+ slots: {},
57
118
  },
58
- },
119
+ layer: {
120
+ $key: 'layer',
121
+ type: 'component',
122
+ icon: Files,
123
+ text: '已选组件',
124
+ props: {
125
+ layerContentMenu: props.layerContentMenu,
126
+ },
127
+ component: LayerPanel,
128
+ slots: {},
129
+ },
130
+ 'code-block': {
131
+ $key: 'code-block',
132
+ type: 'component',
133
+ icon: EditPen,
134
+ text: '代码编辑',
135
+ component: CodeBlockList,
136
+ slots: {},
137
+ },
138
+ };
59
139
 
60
- setup(props) {
61
- const activeTabName = ref(props.data?.status);
140
+ return typeof data === 'string' ? map[data] : data;
141
+ };
62
142
 
63
- watch(
64
- () => props.data?.status,
65
- (status) => {
66
- activeTabName.value = status || '0';
67
- },
68
- );
143
+ const sideBarItems = computed(() => props.data.items.map((item) => getItemConfig(item)));
69
144
 
70
- return {
71
- activeTabName,
72
- };
145
+ watch(
146
+ () => props.data.status,
147
+ (status) => {
148
+ activeTabName.value = status || '0';
73
149
  },
150
+ );
151
+
152
+ defineExpose({
153
+ activeTabName,
74
154
  });
75
155
  </script>
@@ -1,25 +1,24 @@
1
1
  <template>
2
- <el-dialog
2
+ <TMagicDialog
3
3
  v-model="isShowCodeBlockEditor"
4
+ class="code-editor-dialog"
4
5
  :title="currentTitle"
5
6
  :fullscreen="true"
6
7
  :before-close="saveAndClose"
7
8
  :append-to-body="true"
8
- custom-class="code-editor-dialog"
9
9
  >
10
- <layout v-model:left="left" :min-left="45" class="code-editor-layout">
10
+ <Layout v-model:left="left" :min-left="45" class="code-editor-layout">
11
11
  <!-- 左侧列表 -->
12
12
  <template #left v-if="mode === CodeEditorMode.LIST">
13
- <el-tree
13
+ <TMagicTree
14
14
  v-if="!isEmpty(state.codeList)"
15
- ref="tree"
15
+ class="side-tree"
16
16
  node-key="id"
17
17
  empty-text="暂无代码块"
18
18
  :data="state.codeList"
19
19
  :highlight-current="true"
20
- @node-click="selectHandler"
21
20
  :current-node-key="state.codeList[0].id"
22
- class="side-tree"
21
+ @node-click="selectHandler"
23
22
  >
24
23
  <template #default="{ data }">
25
24
  <div :id="data.id" class="list-container">
@@ -28,7 +27,7 @@
28
27
  </div>
29
28
  </div>
30
29
  </template>
31
- </el-tree>
30
+ </TMagicTree>
32
31
  </template>
33
32
  <!-- 右侧区域 -->
34
33
  <template #center>
@@ -41,15 +40,20 @@
41
40
  ]"
42
41
  >
43
42
  <slot name="code-block-edit-panel-header" :id="id"></slot>
44
- <el-card shadow="never">
43
+ <TMagicCard shadow="never">
45
44
  <template #header>
46
45
  <div class="code-name-wrapper">
47
46
  <div class="code-name-label">代码块名称</div>
48
- <el-input v-if="codeConfig" class="code-name-input" v-model="codeConfig.name" :disabled="!editable" />
47
+ <TMagicInput
48
+ v-if="codeConfig"
49
+ class="code-name-input"
50
+ v-model="codeConfig.name"
51
+ :disabled="!editable"
52
+ />
49
53
  </div>
50
54
  </template>
51
55
  <div class="m-editor-wrapper">
52
- <magic-code-editor
56
+ <MagicCodeEditor
53
57
  v-if="codeConfig"
54
58
  ref="codeEditor"
55
59
  class="m-editor-container"
@@ -61,32 +65,33 @@
61
65
  formatOnPaste: true,
62
66
  readOnly: !editable,
63
67
  }"
64
- ></magic-code-editor>
68
+ ></MagicCodeEditor>
65
69
  <div class="m-editor-content-bottom" v-if="editable">
66
- <el-button type="primary" class="button" @click="saveCode">保存</el-button>
67
- <el-button type="primary" class="button" @click="saveAndClose">关闭</el-button>
70
+ <TMagicButton type="primary" class="button" @click="saveCode">保存</TMagicButton>
71
+ <TMagicButton type="primary" class="button" @click="saveAndClose">关闭</TMagicButton>
68
72
  </div>
69
73
  <div class="m-editor-content-bottom" v-else>
70
- <el-button type="primary" class="button" @click="saveAndClose">关闭</el-button>
74
+ <TMagicButton type="primary" class="button" @click="saveAndClose">关闭</TMagicButton>
71
75
  </div>
72
76
  </div>
73
- </el-card>
77
+ </TMagicCard>
74
78
  </div>
75
79
  </template>
76
- </layout>
77
- </el-dialog>
80
+ </Layout>
81
+ </TMagicDialog>
78
82
  </template>
79
83
 
80
- <script lang="ts" setup>
84
+ <script lang="ts" setup name="MEditorCodeBlockEditor">
81
85
  import { computed, inject, reactive, ref, watchEffect } from 'vue';
82
- import { ElMessage } from 'element-plus';
83
86
  import { forIn, isEmpty } from 'lodash-es';
84
87
  import type * as monaco from 'monaco-editor';
85
88
 
89
+ import { TMagicButton, TMagicCard, TMagicDialog, TMagicInput, tMagicMessage, TMagicTree } from '@tmagic/design';
90
+
91
+ import Layout from '../../../components/Layout.vue';
86
92
  import type { CodeBlockContent, CodeDslList, ListState, Services } from '../../../type';
87
93
  import { CodeEditorMode } from '../../../type';
88
94
  import MagicCodeEditor from '../../CodeEditor.vue';
89
- import Layout from '../../Layout.vue';
90
95
 
91
96
  const services = inject<Services>('services');
92
97
 
@@ -122,7 +127,6 @@ watchEffect(async () => {
122
127
  state.codeList.push({
123
128
  id: key,
124
129
  name: value.name,
125
- content: value.content,
126
130
  });
127
131
  });
128
132
  currentTitle.value = state.codeList[0]?.name || '';
@@ -138,7 +142,7 @@ const saveCode = async (): Promise<boolean> => {
138
142
  /* eslint no-eval: "off" */
139
143
  codeConfig.value.content = eval(codeContent);
140
144
  } catch (e: any) {
141
- ElMessage.error(e.stack);
145
+ tMagicMessage.error(e.stack);
142
146
  return false;
143
147
  }
144
148
  // 存入dsl
@@ -146,7 +150,7 @@ const saveCode = async (): Promise<boolean> => {
146
150
  name: codeConfig.value.name,
147
151
  content: codeConfig.value.content,
148
152
  });
149
- ElMessage.success('代码保存成功');
153
+ tMagicMessage.success('代码保存成功');
150
154
  return true;
151
155
  };
152
156
 
@@ -2,22 +2,22 @@
2
2
  <div class="m-editor-code-block-list">
3
3
  <slot name="code-block-panel-header">
4
4
  <div class="code-header-wrapper">
5
- <el-input
5
+ <TMagicInput
6
6
  :class="[editable ? 'code-filter-input' : 'code-filter-input-no-btn']"
7
7
  size="small"
8
8
  placeholder="输入关键字进行过滤"
9
9
  clearable
10
10
  v-model="filterText"
11
11
  @input="filterTextChangeHandler"
12
- ></el-input>
13
- <el-button class="create-code-button" type="primary" size="small" @click="createCodeBlock" v-if="editable"
14
- >新增</el-button
12
+ ></TMagicInput>
13
+ <TMagicButton class="create-code-button" type="primary" size="small" @click="createCodeBlock" v-if="editable"
14
+ >新增</TMagicButton
15
15
  >
16
16
  </div>
17
17
  </slot>
18
18
 
19
19
  <!-- 代码块列表 -->
20
- <el-tree
20
+ <TMagicTree
21
21
  v-if="!isEmpty(state.codeList)"
22
22
  ref="tree"
23
23
  node-key="id"
@@ -33,21 +33,21 @@
33
33
  <div class="code-name">{{ data.name }}({{ data.id }})</div>
34
34
  <!-- 右侧工具栏 -->
35
35
  <div class="right-tool">
36
- <el-tooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
36
+ <TMagicTooltip effect="dark" :content="editable ? '编辑' : '查看'" placement="bottom">
37
37
  <Icon :icon="editable ? Edit : View" class="edit-icon" @click.stop="editCode(`${data.id}`)"></Icon>
38
- </el-tooltip>
39
- <el-tooltip
38
+ </TMagicTooltip>
39
+ <TMagicTooltip
40
40
  effect="dark"
41
41
  content="查看绑定关系"
42
42
  placement="bottom"
43
43
  v-if="state.bindComps[data.id] && state.bindComps[data.id].length > 0"
44
44
  >
45
45
  <Icon :icon="Link" class="edit-icon" @click.stop="toggleCombineRelation(data)"></Icon>
46
- </el-tooltip>
47
- <el-tooltip effect="dark" content="删除" placement="bottom" v-if="editable">
46
+ </TMagicTooltip>
47
+ <TMagicTooltip effect="dark" content="删除" placement="bottom" v-if="editable">
48
48
  <Icon :icon="Close" class="edit-icon" @click.stop="deleteCode(`${data.id}`)"></Icon>
49
- </el-tooltip>
50
- <slot name="code-block-panel-tool" :id="data.id"></slot>
49
+ </TMagicTooltip>
50
+ <slot name="code-block-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
51
51
  </div>
52
52
  </div>
53
53
  <!-- 展示代码块下绑定的组件 -->
@@ -62,27 +62,27 @@
62
62
  ></path>
63
63
  </svg>
64
64
  <!-- todo 功能暂时隐藏 -->
65
- <!-- <el-button
65
+ <!-- <TMagicButton
66
66
  v-for="(comp, index) in state.bindComps[data.id]"
67
67
  :key="index"
68
68
  class="code-comp"
69
69
  size="small"
70
70
  :plain="true"
71
71
  >{{ comp.name }}<Icon :icon="Close" class="comp-delete-icon" @click.stop="unbind(comp.id, data.id)"></Icon
72
- ></el-button> -->
73
- <el-button
72
+ ></TMagicButton> -->
73
+ <TMagicButton
74
74
  v-for="(comp, index) in state.bindComps[data.id]"
75
75
  :key="index"
76
76
  class="code-comp"
77
77
  size="small"
78
78
  :plain="true"
79
79
  @click.stop="selectComp(comp.id)"
80
- >{{ comp.name }}</el-button
80
+ >{{ comp.name }}</TMagicButton
81
81
  >
82
82
  </div>
83
83
  </div>
84
84
  </template>
85
- </el-tree>
85
+ </TMagicTree>
86
86
 
87
87
  <!-- 代码块编辑区 -->
88
88
  <code-block-editor>
@@ -93,12 +93,12 @@
93
93
  </div>
94
94
  </template>
95
95
 
96
- <script lang="ts" setup>
96
+ <script lang="ts" setup name="MEditorCodeBlockList">
97
97
  import { computed, inject, reactive, ref, watch } from 'vue';
98
98
  import { Close, Edit, Link, View } from '@element-plus/icons-vue';
99
- import { ElMessage } from 'element-plus';
100
99
  import { forIn, isEmpty } from 'lodash-es';
101
100
 
101
+ import { TMagicButton, TMagicInput, tMagicMessage, TMagicTooltip, TMagicTree } from '@tmagic/design';
102
102
  import { Id } from '@tmagic/schema';
103
103
  import StageCore from '@tmagic/stage';
104
104
 
@@ -148,7 +148,7 @@ const initList = async () => {
148
148
  state.codeList.push({
149
149
  id: codeId,
150
150
  name: value.name,
151
- content: value.content,
151
+ codeBlockContent: value,
152
152
  showRelation: true,
153
153
  });
154
154
  });
@@ -184,7 +184,7 @@ watch(
184
184
  const createCodeBlock = async () => {
185
185
  const { codeBlockService } = services || {};
186
186
  if (!codeBlockService) {
187
- ElMessage.error('新增代码块失败');
187
+ tMagicMessage.error('新增代码块失败');
188
188
  return;
189
189
  }
190
190
  const codeConfig: CodeBlockContent = {
@@ -214,7 +214,7 @@ const deleteCode = (key: string) => {
214
214
  if (typeof props.customError === 'function') {
215
215
  props.customError(key, existBinds ? CodeDeleteErrorType.BIND : CodeDeleteErrorType.UNDELETEABLE);
216
216
  } else {
217
- ElMessage.error('代码块删除失败');
217
+ tMagicMessage.error('代码块删除失败');
218
218
  }
219
219
  }
220
220
  };
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <div v-if="nodes.length === 1" class="m-editor-breadcrumb">
3
+ <template v-for="(item, index) in path" :key="item.id">
4
+ <TMagicButton text :disabled="item.id === node?.id" @click="select(item)">{{ item.name }}</TMagicButton
5
+ ><span v-if="index < path.length - 1">/</span>
6
+ </template>
7
+ </div>
8
+ </template>
9
+
10
+ <script setup lang="ts" name="MEditorBreadcrumb">
11
+ import { computed, inject } from 'vue';
12
+
13
+ import { TMagicButton } from '@tmagic/design';
14
+ import type { MApp, MNode } from '@tmagic/schema';
15
+ import type StageCore from '@tmagic/stage';
16
+ import { getNodePath } from '@tmagic/utils';
17
+
18
+ import type { Services } from '../../type';
19
+
20
+ const services = inject<Services>('services');
21
+ const editorService = services?.editorService;
22
+
23
+ const node = computed(() => editorService?.get<MNode>('node'));
24
+ const nodes = computed(() => editorService?.get<MNode[]>('nodes') || []);
25
+ const root = computed(() => editorService?.get<MApp>('root'));
26
+ const path = computed(() => getNodePath(node.value?.id || '', root.value?.items || []));
27
+
28
+ const select = async (node: MNode) => {
29
+ await editorService?.select(node);
30
+ editorService?.get<StageCore>('stage')?.select(node.id);
31
+ };
32
+ </script>
@@ -9,47 +9,48 @@
9
9
  >
10
10
  <div class="m-editor-page-bar-title">
11
11
  <slot name="page-bar-title" :page="item">
12
- <el-tooltip effect="dark" placement="top-start" :content="item.name">
12
+ <TMagicTooltip effect="dark" placement="top-start" :content="item.name">
13
13
  <span>{{ item.name || item.id }}</span>
14
- </el-tooltip>
14
+ </TMagicTooltip>
15
15
  </slot>
16
16
  </div>
17
17
 
18
- <el-popover popper-class="page-bar-popover" placement="top" :width="160" trigger="hover">
18
+ <TMagicPopover popper-class="page-bar-popover" placement="top" :width="160" trigger="hover">
19
19
  <div>
20
20
  <slot name="page-bar-popover" :page="item">
21
- <tool-button
21
+ <ToolButton
22
22
  :data="{
23
23
  type: 'button',
24
24
  text: '复制',
25
25
  icon: DocumentCopy,
26
26
  handler: () => copy(item),
27
27
  }"
28
- ></tool-button>
29
- <tool-button
28
+ ></ToolButton>
29
+ <ToolButton
30
30
  :data="{
31
31
  type: 'button',
32
32
  text: '删除',
33
33
  icon: Delete,
34
34
  handler: () => remove(item),
35
35
  }"
36
- ></tool-button>
36
+ ></ToolButton>
37
37
  </slot>
38
38
  </div>
39
39
  <template #reference>
40
- <el-icon class="m-editor-page-bar-menu-icon">
40
+ <TMagicIcon class="m-editor-page-bar-menu-icon">
41
41
  <CaretBottom></CaretBottom>
42
- </el-icon>
42
+ </TMagicIcon>
43
43
  </template>
44
- </el-popover>
44
+ </TMagicPopover>
45
45
  </div>
46
46
  </PageBarScrollContainer>
47
47
  </template>
48
48
 
49
- <script lang="ts" setup>
49
+ <script lang="ts" setup name="MEditorPageBar">
50
50
  import { computed, inject } from 'vue';
51
51
  import { CaretBottom, Delete, DocumentCopy } from '@element-plus/icons-vue';
52
52
 
53
+ import { TMagicIcon, TMagicPopover, TMagicTooltip } from '@tmagic/design';
53
54
  import type { MApp, MPage } from '@tmagic/schema';
54
55
 
55
56
  import ToolButton from '../../components/ToolButton.vue';
@@ -26,7 +26,7 @@
26
26
  </div>
27
27
  </template>
28
28
 
29
- <script setup lang="ts">
29
+ <script setup lang="ts" name="MEditorPageBarScrollContainer">
30
30
  import { computed, inject, nextTick, onMounted, onUnmounted, ref, toRaw, watch } from 'vue';
31
31
  import { ArrowLeftBold, ArrowRightBold, Plus } from '@element-plus/icons-vue';
32
32
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <scroll-viewer
2
+ <ScrollViewer
3
3
  class="m-editor-stage"
4
4
  ref="stageWrap"
5
5
  :width="stageRect?.width"
@@ -7,6 +7,10 @@
7
7
  :wrap-width="stageContainerRect?.width"
8
8
  :wrap-height="stageContainerRect?.height"
9
9
  :zoom="zoom"
10
+ :correction-scroll-size="{
11
+ width: 60,
12
+ height: 50,
13
+ }"
10
14
  >
11
15
  <div
12
16
  class="m-editor-stage-container"
@@ -16,13 +20,13 @@
16
20
  @drop="dropHandler"
17
21
  @dragover="dragoverHandler"
18
22
  ></div>
19
- <teleport to="body">
20
- <viewer-menu ref="menu" :is-multi-select="isMultiSelect"></viewer-menu>
21
- </teleport>
22
- </scroll-viewer>
23
+ <Teleport to="body">
24
+ <ViewerMenu ref="menu" :is-multi-select="isMultiSelect" :stage-content-menu="stageContentMenu"></ViewerMenu>
25
+ </Teleport>
26
+ </ScrollViewer>
23
27
  </template>
24
28
 
25
- <script lang="ts" setup>
29
+ <script lang="ts" setup name="MEditorStage">
26
30
  import { computed, inject, markRaw, onMounted, onUnmounted, ref, toRaw, watch, watchEffect } from 'vue';
27
31
  import { cloneDeep } from 'lodash-es';
28
32
 
@@ -30,11 +34,15 @@ import type { MApp, MContainer, MNode, MPage } from '@tmagic/schema';
30
34
  import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stage';
31
35
 
32
36
  import ScrollViewer from '../../components/ScrollViewer.vue';
33
- import { Layout, Services, StageOptions, StageRect } from '../../type';
37
+ import { Layout, MenuButton, MenuComponent, Services, StageOptions, StageRect } from '../../type';
34
38
  import { useStage } from '../../utils/stage';
35
39
 
36
40
  import ViewerMenu from './ViewerMenu.vue';
37
41
 
42
+ defineProps<{
43
+ stageContentMenu: (MenuButton | MenuComponent)[];
44
+ }>();
45
+
38
46
  let stage: StageCore | null = null;
39
47
  let runtime: Runtime | null = null;
40
48