@tmagic/editor 1.0.0-beta.9 → 1.0.0-rc.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 (117) hide show
  1. package/README.md +1 -0
  2. package/coverage/clover.xml +1560 -0
  3. package/coverage/coverage-final.json +36 -0
  4. package/coverage/lcov-report/base.css +224 -0
  5. package/coverage/lcov-report/block-navigation.js +87 -0
  6. package/coverage/lcov-report/favicon.png +0 -0
  7. package/coverage/lcov-report/index.html +206 -0
  8. package/coverage/lcov-report/prettify.css +1 -0
  9. package/coverage/lcov-report/prettify.js +2 -0
  10. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  11. package/coverage/lcov-report/sorter.js +196 -0
  12. package/coverage/lcov-report/src/Editor.vue.html +787 -0
  13. package/coverage/lcov-report/src/components/ContentMenu.vue.html +406 -0
  14. package/coverage/lcov-report/src/components/Icon.vue.html +172 -0
  15. package/coverage/lcov-report/src/components/ScrollViewer.vue.html +283 -0
  16. package/coverage/lcov-report/src/components/ToolButton.vue.html +772 -0
  17. package/coverage/lcov-report/src/components/index.html +161 -0
  18. package/coverage/lcov-report/src/index.html +131 -0
  19. package/coverage/lcov-report/src/layouts/AddPageBox.vue.html +214 -0
  20. package/coverage/lcov-report/src/layouts/Framework.vue.html +304 -0
  21. package/coverage/lcov-report/src/layouts/NavMenu.vue.html +208 -0
  22. package/coverage/lcov-report/src/layouts/PropsPanel.vue.html +319 -0
  23. package/coverage/lcov-report/src/layouts/Resizer.vue.html +268 -0
  24. package/coverage/lcov-report/src/layouts/index.html +176 -0
  25. package/coverage/lcov-report/src/layouts/sidebar/ComponentListPanel.vue.html +358 -0
  26. package/coverage/lcov-report/src/layouts/sidebar/LayerMenu.vue.html +421 -0
  27. package/coverage/lcov-report/src/layouts/sidebar/LayerPanel.vue.html +775 -0
  28. package/coverage/lcov-report/src/layouts/sidebar/Sidebar.vue.html +226 -0
  29. package/coverage/lcov-report/src/layouts/sidebar/TabPane.vue.html +289 -0
  30. package/coverage/lcov-report/src/layouts/sidebar/index.html +176 -0
  31. package/coverage/lcov-report/src/layouts/workspace/PageBar.vue.html +718 -0
  32. package/coverage/lcov-report/src/layouts/workspace/Stage.vue.html +757 -0
  33. package/coverage/lcov-report/src/layouts/workspace/ViewerMenu.vue.html +532 -0
  34. package/coverage/lcov-report/src/layouts/workspace/Workspace.vue.html +586 -0
  35. package/coverage/lcov-report/src/layouts/workspace/index.html +161 -0
  36. package/coverage/lcov-report/src/services/BaseService.ts.html +643 -0
  37. package/coverage/lcov-report/src/services/componentList.ts.html +229 -0
  38. package/coverage/lcov-report/src/services/editor.ts.html +2077 -0
  39. package/coverage/lcov-report/src/services/events.ts.html +331 -0
  40. package/coverage/lcov-report/src/services/history.ts.html +478 -0
  41. package/coverage/lcov-report/src/services/index.html +206 -0
  42. package/coverage/lcov-report/src/services/props.ts.html +415 -0
  43. package/coverage/lcov-report/src/services/ui.ts.html +580 -0
  44. package/coverage/lcov-report/src/type.ts.html +850 -0
  45. package/coverage/lcov-report/src/utils/compose.ts.html +184 -0
  46. package/coverage/lcov-report/src/utils/config.ts.html +172 -0
  47. package/coverage/lcov-report/src/utils/editor.ts.html +838 -0
  48. package/coverage/lcov-report/src/utils/index.html +221 -0
  49. package/coverage/lcov-report/src/utils/index.ts.html +151 -0
  50. package/coverage/lcov-report/src/utils/logger.ts.html +226 -0
  51. package/coverage/lcov-report/src/utils/props.ts.html +796 -0
  52. package/coverage/lcov-report/src/utils/scroll-viewer.ts.html +733 -0
  53. package/coverage/lcov-report/src/utils/undo-redo.ts.html +313 -0
  54. package/coverage/lcov.info +3708 -0
  55. package/dist/style.css +65 -33
  56. package/dist/tmagic-editor.es.js +1379 -806
  57. package/dist/tmagic-editor.es.js.map +1 -1
  58. package/dist/tmagic-editor.umd.js +1381 -808
  59. package/dist/tmagic-editor.umd.js.map +1 -1
  60. package/dist/types/src/Editor.vue.d.ts +1 -1
  61. package/dist/types/src/components/ToolButton.vue.d.ts +12 -1
  62. package/dist/types/src/fields/UISelect.vue.d.ts +4 -1
  63. package/dist/types/src/index.d.ts +1 -0
  64. package/dist/types/src/layouts/CodeEditor.vue.d.ts +13 -4
  65. package/dist/types/src/layouts/PropsPanel.vue.d.ts +2 -1
  66. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +2 -1
  67. package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +2 -3
  68. package/dist/types/src/layouts/sidebar/TabPane.vue.d.ts +14 -0
  69. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +10 -3
  70. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -7
  71. package/dist/types/src/services/BaseService.d.ts +4 -1
  72. package/dist/types/src/services/editor.d.ts +5 -2
  73. package/dist/types/src/services/history.d.ts +1 -0
  74. package/dist/types/src/services/props.d.ts +2 -2
  75. package/dist/types/src/services/ui.d.ts +2 -0
  76. package/dist/types/src/type.d.ts +15 -9
  77. package/dist/types/src/utils/editor.d.ts +4 -3
  78. package/dist/types/src/utils/polyfills.d.ts +0 -0
  79. package/package.json +36 -12
  80. package/src/components/ContentMenu.vue +107 -0
  81. package/src/components/ScrollViewer.vue +1 -1
  82. package/src/components/ToolButton.vue +69 -30
  83. package/src/fields/UISelect.vue +14 -6
  84. package/src/index.ts +2 -0
  85. package/src/layouts/CodeEditor.vue +20 -10
  86. package/src/layouts/Framework.vue +6 -6
  87. package/src/layouts/PropsPanel.vue +4 -3
  88. package/src/layouts/sidebar/ComponentListPanel.vue +25 -3
  89. package/src/layouts/sidebar/LayerMenu.vue +91 -96
  90. package/src/layouts/sidebar/LayerPanel.vue +31 -54
  91. package/src/layouts/sidebar/Sidebar.vue +13 -52
  92. package/src/layouts/sidebar/TabPane.vue +68 -0
  93. package/src/layouts/workspace/PageBar.vue +136 -13
  94. package/src/layouts/workspace/Stage.vue +50 -75
  95. package/src/layouts/workspace/ViewerMenu.vue +104 -67
  96. package/src/layouts/workspace/Workspace.vue +106 -23
  97. package/src/services/BaseService.ts +70 -22
  98. package/src/services/editor.ts +148 -39
  99. package/src/services/history.ts +7 -0
  100. package/src/services/props.ts +3 -3
  101. package/src/services/ui.ts +35 -5
  102. package/src/theme/common/var.scss +1 -0
  103. package/src/theme/component-list-panel.scss +2 -0
  104. package/src/theme/content-menu.scss +33 -26
  105. package/src/theme/layer-panel.scss +2 -1
  106. package/src/theme/nav-menu.scss +6 -2
  107. package/src/theme/page-bar.scss +35 -3
  108. package/src/theme/props-panel.scss +13 -13
  109. package/src/type.ts +16 -9
  110. package/src/utils/editor.ts +31 -6
  111. package/{vite.config.ts → src/utils/polyfills.ts} +4 -12
  112. package/src/utils/props.ts +20 -1
  113. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
  114. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +0 -979
  115. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +0 -193
  116. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +0 -18
  117. package/tsconfig.json +0 -9
@@ -14,6 +14,7 @@
14
14
  ref="tree"
15
15
  node-key="id"
16
16
  draggable
17
+ :default-expanded-keys="expandedKeys"
17
18
  :load="loadItems"
18
19
  :data="values"
19
20
  :expand-on-click-node="false"
@@ -32,8 +33,8 @@
32
33
  <div
33
34
  :id="data.id"
34
35
  class="cus-tree-node"
35
- @mousedown="toogleClickFlag"
36
- @mouseup="toogleClickFlag"
36
+ @mousedown="toggleClickFlag"
37
+ @mouseup="toggleClickFlag"
37
38
  @mouseenter="highlightHandler(data)"
38
39
  :class="{ 'cus-tree-node-hover': canHighlight && data.id === highlightNode?.id }"
39
40
  >
@@ -47,18 +48,19 @@
47
48
  </el-tree>
48
49
 
49
50
  <teleport to="body">
50
- <layer-menu :style="menuStyle"></layer-menu>
51
+ <layer-menu ref="menu"></layer-menu>
51
52
  </teleport>
52
53
  </el-scrollbar>
53
54
  </template>
54
55
 
55
56
  <script lang="ts">
56
- import { computed, defineComponent, inject, onMounted, Ref, ref, watchEffect } from 'vue';
57
+ import { computed, defineComponent, inject, Ref, ref, watchEffect } from 'vue';
57
58
  import type { ElTree } from 'element-plus';
58
59
  import { throttle } from 'lodash-es';
59
60
 
60
61
  import type { MNode, MPage } from '@tmagic/schema';
61
62
  import { NodeType } from '@tmagic/schema';
63
+ import StageCore from '@tmagic/stage';
62
64
 
63
65
  import type { EditorService } from '@editor/services/editor';
64
66
  import type { Services } from '@editor/type';
@@ -67,12 +69,13 @@ import LayerMenu from './LayerMenu.vue';
67
69
 
68
70
  const throttleTime = 150;
69
71
 
70
- const select = (data: MNode, editorService?: EditorService) => {
72
+ const select = async (data: MNode, editorService?: EditorService) => {
71
73
  if (!data.id) {
72
74
  throw new Error('没有id');
73
75
  }
74
76
 
75
- editorService?.select(data);
77
+ await editorService?.select(data);
78
+ editorService?.get<StageCore>('stage')?.select(data.id);
76
79
  };
77
80
 
78
81
  const highlight = (data: MNode, editorService?: EditorService) => {
@@ -80,6 +83,7 @@ const highlight = (data: MNode, editorService?: EditorService) => {
80
83
  throw new Error('没有id');
81
84
  }
82
85
  editorService?.highlight(data);
86
+ editorService?.get<StageCore>('stage')?.highlight(data.id);
83
87
  };
84
88
 
85
89
  const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => ({
@@ -140,6 +144,7 @@ const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorSer
140
144
 
141
145
  highlightNode,
142
146
  clickNode: node,
147
+ expandedKeys: computed(() => (node.value ? [node.value.id] : [])),
143
148
  };
144
149
  };
145
150
 
@@ -153,12 +158,10 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
153
158
  let name = '';
154
159
  if (data.name) {
155
160
  name = data.name;
156
- } else if (data.type) {
157
- name = data.type;
158
161
  } else if (data.items) {
159
162
  name = 'container';
160
163
  }
161
- return name.indexOf(value) !== -1;
164
+ return `${data.id}${name}${data.type}`.indexOf(value) !== -1;
162
165
  },
163
166
 
164
167
  filterTextChangeHandler(val: string) {
@@ -166,46 +169,6 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
166
169
  },
167
170
  });
168
171
 
169
- const useContentMenu = (editorService?: EditorService) => {
170
- const menuStyle = ref({
171
- position: 'absolute',
172
- left: '0',
173
- top: '0',
174
- display: 'none',
175
- });
176
-
177
- onMounted(() => {
178
- document.addEventListener(
179
- 'click',
180
- () => {
181
- menuStyle.value.display = 'none';
182
- },
183
- true,
184
- );
185
- });
186
-
187
- return {
188
- menuStyle,
189
-
190
- contextmenu(event: MouseEvent, data: MNode) {
191
- const bodyHeight = globalThis.document.body.clientHeight;
192
-
193
- const left = `${event.clientX + 20}px`;
194
- let top = `${event.clientY - 10}px`;
195
-
196
- if (event.clientY + 300 > bodyHeight) {
197
- top = `${bodyHeight - 300}px`;
198
- }
199
-
200
- menuStyle.value.left = left;
201
- menuStyle.value.top = top;
202
- menuStyle.value.display = '';
203
-
204
- select(data, editorService);
205
- },
206
- };
207
- };
208
-
209
172
  export default defineComponent({
210
173
  name: 'magic-editor-layer-panel',
211
174
 
@@ -214,13 +177,14 @@ export default defineComponent({
214
177
  setup() {
215
178
  const services = inject<Services>('services');
216
179
  const tree = ref<InstanceType<typeof ElTree>>();
180
+ const menu = ref<InstanceType<typeof LayerMenu>>();
217
181
  const clicked = ref(false);
218
182
  const editorService = services?.editorService;
219
183
  const highlightHandler = throttle((data: MNode) => {
220
184
  highlight(data, editorService);
221
185
  }, throttleTime);
222
186
 
223
- const toogleClickFlag = () => {
187
+ const toggleClickFlag = () => {
224
188
  clicked.value = !clicked.value;
225
189
  };
226
190
 
@@ -229,12 +193,22 @@ export default defineComponent({
229
193
  () => statusData.highlightNode.value?.id !== statusData.clickNode.value?.id && !clicked.value,
230
194
  );
231
195
 
196
+ editorService?.on('remove', () => {
197
+ setTimeout(() => {
198
+ tree.value?.getNode(editorService.get('node').id)?.updateChildren();
199
+ }, 0);
200
+ });
201
+
232
202
  return {
233
203
  tree,
204
+ menu,
234
205
  ...statusData,
235
206
  ...useDrop(tree, editorService),
236
207
  ...useFilter(tree),
237
- ...useContentMenu(editorService),
208
+
209
+ highlightHandler,
210
+ toggleClickFlag,
211
+ canHighlight,
238
212
 
239
213
  clickHandler(data: MNode): void {
240
214
  if (services?.uiService.get<boolean>('uiSelectMode')) {
@@ -244,9 +218,12 @@ export default defineComponent({
244
218
  tree.value?.setCurrentKey(data.id);
245
219
  select(data, editorService);
246
220
  },
247
- highlightHandler,
248
- toogleClickFlag,
249
- canHighlight,
221
+
222
+ async contextmenu(event: MouseEvent, data: MNode) {
223
+ event.preventDefault();
224
+ await select(data, editorService);
225
+ menu.value?.show(event);
226
+ },
250
227
  };
251
228
  },
252
229
  });
@@ -1,36 +1,26 @@
1
1
  <template>
2
- <el-tabs v-if="data.type === 'tabs'" class="m-editor-sidebar" v-model="activeTabName" type="card" tab-position="left">
3
- <el-tab-pane v-for="item in items" :key="item.text" :name="item.text">
4
- <template #label>
5
- <span>
6
- <m-icon v-if="item.icon" :icon="item.icon"></m-icon>
7
- <div v-if="item.text" class="magic-editor-tab-panel-title">{{ item.text }}</div>
8
- </span>
9
- </template>
10
-
11
- <component :is="item.component" v-bind="item.props || {}" v-on="item.listeners || {}">
12
- <template #layer-node-content="{ data, node }" v-if="item.slots?.layerNodeContent">
13
- <component :is="item.slots.layerNodeContent" :data="data" :node="node" />
14
- </template>
15
- </component>
16
- </el-tab-pane>
2
+ <el-tabs
3
+ v-if="data.type === 'tabs' && data.items.length"
4
+ class="m-editor-sidebar"
5
+ v-model="activeTabName"
6
+ type="card"
7
+ tab-position="left"
8
+ >
9
+ <tab-pane v-for="(item, index) in data.items" :key="index" :data="item"></tab-pane>
17
10
  </el-tabs>
18
11
  </template>
19
12
 
20
13
  <script lang="ts">
21
- import { computed, defineComponent, PropType, ref, watch } from 'vue';
22
- import { Coin, Files } from '@element-plus/icons';
14
+ import { defineComponent, PropType, ref, watch } from 'vue';
23
15
 
24
- import MIcon from '@editor/components/Icon.vue';
25
- import { SideBarData, SideComponent } from '@editor/type';
16
+ import { SideBarData } from '@editor/type';
26
17
 
27
- import ComponentListPanel from './ComponentListPanel.vue';
28
- import LayerPanel from './LayerPanel.vue';
18
+ import TabPane from './TabPane.vue';
29
19
 
30
20
  export default defineComponent({
31
- name: 'm-sidebar',
21
+ components: { TabPane },
32
22
 
33
- components: { MIcon },
23
+ name: 'm-sidebar',
34
24
 
35
25
  props: {
36
26
  data: {
@@ -51,35 +41,6 @@ export default defineComponent({
51
41
 
52
42
  return {
53
43
  activeTabName,
54
-
55
- items: computed<SideComponent[] | Record<string, any>[]>(() =>
56
- props.data?.items.map((item) => {
57
- if (typeof item !== 'string') {
58
- return item;
59
- }
60
-
61
- switch (item) {
62
- case 'component-list':
63
- return {
64
- type: 'component',
65
- icon: Coin,
66
- text: '组件',
67
- component: ComponentListPanel,
68
- slots: {},
69
- };
70
- case 'layer':
71
- return {
72
- type: 'component',
73
- icon: Files,
74
- text: '已选组件',
75
- component: LayerPanel,
76
- slots: {},
77
- };
78
- default:
79
- return {};
80
- }
81
- }),
82
- ),
83
44
  };
84
45
  },
85
46
  });
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <el-tab-pane v-if="config" :name="config.text">
3
+ <template #label>
4
+ <div :key="config.text">
5
+ <m-icon v-if="config.icon" :icon="config.icon"></m-icon>
6
+ <div v-if="config.text" class="magic-editor-tab-panel-title">{{ config.text }}</div>
7
+ </div>
8
+ </template>
9
+
10
+ <component :is="config.component" v-bind="config.props || {}" v-on="config?.listeners || {}">
11
+ <template #layer-node-content="{ data, node }" v-if="config.slots?.layerNodeContent">
12
+ <component :is="config.slots?.layerNodeContent" :data="data" :node="node" />
13
+ </template>
14
+ </component>
15
+ </el-tab-pane>
16
+ </template>
17
+
18
+ <script lang="ts">
19
+ import { computed, defineComponent, PropType } from 'vue';
20
+ import { Coin, Files } from '@element-plus/icons';
21
+
22
+ import MIcon from '@editor/components/Icon.vue';
23
+ import { SideComponent, SideItem } from '@editor/type';
24
+
25
+ import ComponentListPanel from './ComponentListPanel.vue';
26
+ import LayerPanel from './LayerPanel.vue';
27
+
28
+ export default defineComponent({
29
+ components: { MIcon },
30
+
31
+ props: {
32
+ data: {
33
+ type: Object as PropType<SideItem>,
34
+ },
35
+ },
36
+
37
+ setup(props) {
38
+ return {
39
+ config: computed<SideComponent | undefined>(() => {
40
+ if (typeof props.data !== 'string') {
41
+ return props.data;
42
+ }
43
+
44
+ switch (props.data) {
45
+ case 'component-list':
46
+ return {
47
+ type: 'component',
48
+ icon: Coin,
49
+ text: '组件',
50
+ component: ComponentListPanel,
51
+ slots: {},
52
+ };
53
+ case 'layer':
54
+ return {
55
+ type: 'component',
56
+ icon: Files,
57
+ text: '已选组件',
58
+ component: LayerPanel,
59
+ slots: {},
60
+ };
61
+ default:
62
+ return undefined;
63
+ }
64
+ }),
65
+ };
66
+ },
67
+ });
68
+ </script>
@@ -1,9 +1,12 @@
1
1
  <template>
2
- <div class="m-editor-page-bar">
3
- <div class="m-editor-page-bar-item" @click="addPage">
4
- <el-icon class="m-editor-page-bar-menu-add-icon"><plus></plus></el-icon>
2
+ <div class="m-editor-page-bar" ref="pageBar">
3
+ <div id="m-editor-page-bar-add-icon" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="addPage">
4
+ <el-icon><plus></plus></el-icon>
5
5
  </div>
6
- <template v-if="root">
6
+ <div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('left')">
7
+ <el-icon><arrow-left-bold></arrow-left-bold></el-icon>
8
+ </div>
9
+ <div v-if="root" class="m-editor-page-bar-items" ref="itemsContainer" :style="`width: ${itemsContainerWidth}px`">
7
10
  <div
8
11
  v-for="item in root.items"
9
12
  :key="item.key"
@@ -19,11 +22,25 @@
19
22
  </slot>
20
23
  </div>
21
24
 
22
- <el-popover placement="top" :width="160" trigger="hover">
25
+ <el-popover popper-class="page-bar-popover" placement="top" :width="160" trigger="hover">
23
26
  <div>
24
27
  <slot name="page-bar-popover" :page="item">
25
- <div class="magic-editor-content-menu-item" @click="() => copy(item)">复制</div>
26
- <div class="magic-editor-content-menu-item" @click="() => remove(item)">删除</div>
28
+ <tool-button
29
+ :data="{
30
+ type: 'button',
31
+ text: '复制',
32
+ icon: DocumentCopy,
33
+ handler: () => copy(item),
34
+ }"
35
+ ></tool-button>
36
+ <tool-button
37
+ :data="{
38
+ type: 'button',
39
+ text: '删除',
40
+ icon: Delete,
41
+ handler: () => remove(item),
42
+ }"
43
+ ></tool-button>
27
44
  </slot>
28
45
  </div>
29
46
  <template #reference>
@@ -33,29 +50,135 @@
33
50
  </template>
34
51
  </el-popover>
35
52
  </div>
36
- </template>
53
+ </div>
54
+ <div v-if="canScroll" class="m-editor-page-bar-item m-editor-page-bar-item-icon" @click="scroll('right')">
55
+ <el-icon><arrow-right-bold></arrow-right-bold></el-icon>
56
+ </div>
37
57
  </div>
38
58
  </template>
39
59
 
40
60
  <script lang="ts">
41
- import { computed, defineComponent, inject, toRaw } from 'vue';
42
- import { CaretBottom, Plus } from '@element-plus/icons';
61
+ import {
62
+ computed,
63
+ ComputedRef,
64
+ defineComponent,
65
+ inject,
66
+ markRaw,
67
+ onMounted,
68
+ onUnmounted,
69
+ ref,
70
+ toRaw,
71
+ watch,
72
+ } from 'vue';
73
+ import { ArrowLeftBold, ArrowRightBold, CaretBottom, Delete, DocumentCopy, Plus } from '@element-plus/icons';
43
74
 
44
- import type { MPage } from '@tmagic/schema';
75
+ import type { MApp, MPage } from '@tmagic/schema';
45
76
  import { NodeType } from '@tmagic/schema';
46
77
 
78
+ import ToolButton from '@editor/components/ToolButton.vue';
47
79
  import type { Services } from '@editor/type';
48
80
  import { generatePageNameByApp } from '@editor/utils/editor';
49
81
 
82
+ const useScroll = (root: ComputedRef<MApp | undefined>) => {
83
+ const pageBar = ref<HTMLDivElement>();
84
+ const itemsContainer = ref<HTMLDivElement>();
85
+
86
+ const pageBarWidth = ref(0);
87
+ const canScroll = ref(false);
88
+
89
+ const itemsContainerWidth = computed(() => pageBarWidth.value - 105);
90
+
91
+ let translateLeft = 0;
92
+ const resizeObserver = new ResizeObserver((entries) => {
93
+ for (const { contentRect } of entries) {
94
+ const { width } = contentRect;
95
+ pageBarWidth.value = width || 0;
96
+
97
+ setCanScroll();
98
+ }
99
+ });
100
+
101
+ const setCanScroll = () => {
102
+ if (itemsContainer.value) {
103
+ canScroll.value = itemsContainer.value.scrollWidth > pageBarWidth.value - 105;
104
+ }
105
+ };
106
+
107
+ const scroll = (type: 'left' | 'right' | 'start' | 'end') => {
108
+ if (!itemsContainer.value) return;
109
+
110
+ const maxScrollLeft = itemsContainer.value.scrollWidth - itemsContainerWidth.value;
111
+
112
+ if (type === 'left') {
113
+ translateLeft += 100;
114
+
115
+ if (translateLeft > 0) {
116
+ translateLeft = 0;
117
+ }
118
+ } else if (type === 'right') {
119
+ translateLeft -= 100;
120
+
121
+ if (-translateLeft > maxScrollLeft) {
122
+ translateLeft = -maxScrollLeft;
123
+ }
124
+ } else if (type === 'start') {
125
+ translateLeft = 0;
126
+ } else if (type === 'end') {
127
+ translateLeft = -maxScrollLeft;
128
+ }
129
+
130
+ itemsContainer.value.style.transform = `translate(${translateLeft}px, 0px)`;
131
+ };
132
+
133
+ onMounted(() => {
134
+ pageBar.value && resizeObserver.observe(pageBar.value);
135
+ });
136
+
137
+ onUnmounted(() => {
138
+ resizeObserver.disconnect();
139
+ });
140
+
141
+ watch(
142
+ () => root.value?.items.length,
143
+ (length = 0, preLength = 0) => {
144
+ setTimeout(() => {
145
+ setCanScroll();
146
+ if (length < preLength) {
147
+ scroll('start');
148
+ } else {
149
+ scroll('end');
150
+ }
151
+ });
152
+ },
153
+ );
154
+
155
+ return {
156
+ pageBar,
157
+ itemsContainer,
158
+ canScroll,
159
+
160
+ itemsContainerWidth,
161
+
162
+ scroll,
163
+ };
164
+ };
165
+
50
166
  export default defineComponent({
51
- components: { CaretBottom, Plus },
167
+ components: { ArrowLeftBold, ArrowRightBold, CaretBottom, Plus, ToolButton },
52
168
 
53
169
  setup() {
54
170
  const services = inject<Services>('services');
55
171
  const editorService = services?.editorService;
56
172
 
173
+ const root = computed(() => editorService?.get<MApp>('root'));
174
+
57
175
  return {
58
- root: computed(() => editorService?.get('root')),
176
+ Delete: markRaw(Delete),
177
+ DocumentCopy: markRaw(DocumentCopy),
178
+
179
+ ...useScroll(root),
180
+
181
+ root,
59
182
  page: computed(() => editorService?.get('page')),
60
183
 
61
184
  switchPage(page: MPage) {