@tmagic/editor 1.0.0-beta.1 → 1.0.0-beta.10

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 (47) hide show
  1. package/LICENSE +5432 -0
  2. package/dist/style.css +53 -24
  3. package/dist/tmagic-editor.es.js +832 -403
  4. package/dist/tmagic-editor.es.js.map +1 -1
  5. package/dist/tmagic-editor.umd.js +849 -403
  6. package/dist/tmagic-editor.umd.js.map +1 -1
  7. package/dist/types/src/Editor.vue.d.ts +5 -5
  8. package/dist/types/src/components/ScrollViewer.vue.d.ts +23 -0
  9. package/dist/types/src/layouts/CodeEditor.vue.d.ts +5 -4
  10. package/dist/types/src/layouts/NavMenu.vue.d.ts +2 -1
  11. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +10 -3
  12. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +8 -3
  13. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +77 -42
  14. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +2 -9
  15. package/dist/types/src/services/BaseService.d.ts +4 -1
  16. package/dist/types/src/services/editor.d.ts +11 -4
  17. package/dist/types/src/services/ui.d.ts +10 -3
  18. package/dist/types/src/type.d.ts +20 -6
  19. package/dist/types/src/utils/editor.d.ts +1 -2
  20. package/dist/types/src/utils/scroll-viewer.d.ts +35 -0
  21. package/package.json +15 -12
  22. package/src/Editor.vue +5 -5
  23. package/src/components/ScrollViewer.vue +66 -0
  24. package/src/components/ToolButton.vue +5 -3
  25. package/src/layouts/AddPageBox.vue +3 -1
  26. package/src/layouts/CodeEditor.vue +35 -59
  27. package/src/layouts/NavMenu.vue +7 -3
  28. package/src/layouts/PropsPanel.vue +6 -10
  29. package/src/layouts/sidebar/LayerMenu.vue +14 -39
  30. package/src/layouts/sidebar/LayerPanel.vue +63 -16
  31. package/src/layouts/workspace/PageBar.vue +113 -14
  32. package/src/layouts/workspace/Stage.vue +67 -61
  33. package/src/layouts/workspace/ViewerMenu.vue +5 -3
  34. package/src/layouts/workspace/Workspace.vue +3 -37
  35. package/src/services/BaseService.ts +70 -22
  36. package/src/services/editor.ts +98 -52
  37. package/src/services/ui.ts +42 -5
  38. package/src/theme/common/var.scss +2 -2
  39. package/src/theme/layer-panel.scss +9 -0
  40. package/src/theme/nav-menu.scss +3 -3
  41. package/src/theme/page-bar.scss +21 -2
  42. package/src/theme/props-panel.scss +8 -0
  43. package/src/theme/stage.scss +8 -7
  44. package/src/type.ts +23 -6
  45. package/src/utils/editor.ts +5 -23
  46. package/src/utils/scroll-viewer.ts +216 -0
  47. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <div class="m-editor-scroll-viewer-container" ref="container">
3
+ <div ref="el" :style="style">
4
+ <slot></slot>
5
+ </div>
6
+ </div>
7
+ </template>
8
+
9
+ <script lang="ts">
10
+ import { computed, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
11
+
12
+ import { ScrollViewer } from '@editor/utils/scroll-viewer';
13
+
14
+ export default defineComponent({
15
+ name: 'm-editor-scroll-viewer',
16
+
17
+ props: {
18
+ width: Number,
19
+ height: Number,
20
+ zoom: {
21
+ type: Number,
22
+ default: 1,
23
+ },
24
+ },
25
+
26
+ setup(props) {
27
+ const container = ref<HTMLDivElement>();
28
+ const el = ref<HTMLDivElement>();
29
+ let scrollViewer: ScrollViewer;
30
+
31
+ onMounted(() => {
32
+ if (!container.value || !el.value) return;
33
+ scrollViewer = new ScrollViewer({
34
+ container: container.value,
35
+ target: el.value,
36
+ zoom: props.zoom,
37
+ });
38
+ });
39
+
40
+ onUnmounted(() => {
41
+ scrollViewer.destroy();
42
+ });
43
+
44
+ watch(
45
+ () => props.zoom,
46
+ () => {
47
+ scrollViewer.setZoom(props.zoom);
48
+ },
49
+ );
50
+
51
+ return {
52
+ container,
53
+ el,
54
+
55
+ style: computed(
56
+ () => `
57
+ width: ${props.width}px;
58
+ height: ${props.height}px;
59
+ position: absolute;
60
+ margin-top: 30px;
61
+ `,
62
+ ),
63
+ };
64
+ },
65
+ });
66
+ </script>
@@ -4,9 +4,9 @@
4
4
  <div v-else-if="item.type === 'text'" class="menu-item-text">{{ item.text }}</div>
5
5
 
6
6
  <template v-else-if="item.type === 'zoom'">
7
- <m-icon :icon="ZoomIn" @click="zoomInHandler"></m-icon>
7
+ <el-button size="small" type="text"><m-icon :icon="ZoomIn" @click="zoomInHandler"></m-icon></el-button>
8
8
  <span class="menu-item-text" style="margin: 0 5px">{{ parseInt(`${zoom * 100}`, 10) }}%</span>
9
- <m-icon :icon="ZoomOut" @click="zoomOutHandler"></m-icon>
9
+ <el-button size="small" type="text"><m-icon :icon="ZoomOut" @click="zoomOutHandler"></m-icon></el-button>
10
10
  </template>
11
11
 
12
12
  <el-tooltip
@@ -41,6 +41,8 @@
41
41
  import { computed, defineComponent, inject, PropType } from 'vue';
42
42
  import { ArrowDown, Back, Delete, Grid, Right, ScaleToOriginal, ZoomIn, ZoomOut } from '@element-plus/icons';
43
43
 
44
+ import { NodeType } from '@tmagic/schema';
45
+
44
46
  import MIcon from '@editor/components/Icon.vue';
45
47
  import type { MenuButton, MenuComponent, MenuItem, Services } from '@editor/type';
46
48
 
@@ -87,7 +89,7 @@ export default defineComponent({
87
89
  type: 'button',
88
90
  icon: Delete,
89
91
  tooltip: '刪除',
90
- disabled: () => services?.editorService.get('node')?.type === 'page',
92
+ disabled: () => services?.editorService.get('node')?.type === NodeType.PAGE,
91
93
  handler: () => services?.editorService.remove(services?.editorService.get('node')),
92
94
  };
93
95
  case 'undo':
@@ -15,6 +15,8 @@
15
15
  import { defineComponent, inject, toRaw } from 'vue';
16
16
  import { Plus } from '@element-plus/icons';
17
17
 
18
+ import { NodeType } from '@tmagic/schema';
19
+
18
20
  import { Services } from '@editor/type';
19
21
  import { generatePageNameByApp } from '@editor/utils';
20
22
 
@@ -31,7 +33,7 @@ export default defineComponent({
31
33
  if (!editorService) return;
32
34
 
33
35
  editorService.add({
34
- type: 'page',
36
+ type: NodeType.PAGE,
35
37
  name: generatePageNameByApp(toRaw(editorService.get('root'))),
36
38
  });
37
39
  },
@@ -4,28 +4,10 @@
4
4
 
5
5
  <script lang="ts">
6
6
  import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
7
+ import * as monaco from 'monaco-editor';
7
8
  import serialize from 'serialize-javascript';
8
9
 
9
- import { asyncLoadJs } from '@tmagic/utils';
10
-
11
- const initEditor = () => {
12
- if ((globalThis as any).monaco) {
13
- Promise.resolve((globalThis as any).monaco);
14
- }
15
-
16
- return asyncLoadJs(`https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs/loader.min.js`).then(() => {
17
- (globalThis as any).require.config({
18
- paths: { vs: `https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.26.1/min/vs` },
19
- });
20
- return new Promise((resolve) => {
21
- (globalThis as any).require(['vs/editor/editor.main'], () => {
22
- resolve((globalThis as any).monaco);
23
- });
24
- });
25
- });
26
- };
27
-
28
- const toString = (v: any, language: string): string => {
10
+ const toString = (v: string | any, language: string): string => {
29
11
  let value = '';
30
12
  if (typeof v !== 'string') {
31
13
  value = serialize(v, {
@@ -64,60 +46,63 @@ export default defineComponent({
64
46
  },
65
47
  },
66
48
 
67
- emits: ['inited', 'save'],
49
+ emits: ['initd', 'save'],
68
50
 
69
51
  setup(props, { emit }) {
70
- let vsEditor: any = null;
52
+ let vsEditor: monaco.editor.IStandaloneCodeEditor | null = null;
53
+ let vsDiffEditor: monaco.editor.IStandaloneDiffEditor | null = null;
71
54
  const values = ref('');
72
55
  const loading = ref(false);
73
56
  const codeEditor = ref<HTMLDivElement>();
74
57
 
75
- const setEditorValue = (v: any, m: any) => {
58
+ const setEditorValue = (v: string | any, m: string | any) => {
76
59
  values.value = toString(v, props.language);
77
60
 
78
61
  if (props.type === 'diff') {
79
- const originalModel = (globalThis as any).monaco.editor.createModel(values.value, 'text/javascript');
80
- const modifiedModel = (globalThis as any).monaco.editor.createModel(
81
- toString(m, props.language),
82
- 'text/javascript',
83
- );
62
+ const originalModel = monaco.editor.createModel(values.value, 'text/javascript');
63
+ const modifiedModel = monaco.editor.createModel(toString(m, props.language), 'text/javascript');
84
64
 
85
- return vsEditor.setModel({
65
+ return vsDiffEditor?.setModel({
86
66
  original: originalModel,
87
67
  modified: modifiedModel,
88
68
  });
89
69
  }
90
70
 
91
- return vsEditor.setValue?.(values.value);
71
+ return vsEditor?.setValue(values.value);
92
72
  };
93
73
 
94
74
  const resizeHandler = () => {
95
75
  vsEditor?.layout();
76
+ vsDiffEditor?.layout();
96
77
  };
97
78
 
98
- const getEditorValue = () => vsEditor.getValue?.() || '';
79
+ const getEditorValue = () =>
80
+ props.type === 'diff' ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue();
99
81
 
100
82
  const init = async () => {
101
83
  if (!codeEditor.value) return;
102
84
 
103
- vsEditor = (globalThis as any).monaco.editor[props.type === 'diff' ? 'createDiffEditor' : 'create'](
104
- codeEditor.value,
105
- {
106
- value: values.value,
107
- language: props.language,
108
- tabSize: 2,
109
- theme: 'vs-dark',
110
- fontFamily: 'dm, Menlo, Monaco, "Courier New", monospace',
111
- fontSize: 15,
112
- formatOnPaste: true,
113
- },
114
- );
85
+ const options = {
86
+ value: values.value,
87
+ language: props.language,
88
+ tabSize: 2,
89
+ theme: 'vs-dark',
90
+ fontFamily: 'dm, Menlo, Monaco, "Courier New", monospace',
91
+ fontSize: 15,
92
+ formatOnPaste: true,
93
+ };
94
+
95
+ if (props.type === 'diff') {
96
+ vsDiffEditor = monaco.editor.createDiffEditor(codeEditor.value, options);
97
+ } else {
98
+ vsEditor = monaco.editor.create(codeEditor.value, options);
99
+ }
115
100
 
116
101
  setEditorValue(props.initValues, props.modifiedValues);
117
102
 
118
103
  loading.value = false;
119
104
 
120
- emit('inited', vsEditor);
105
+ emit('initd', vsEditor);
121
106
 
122
107
  codeEditor.value.addEventListener('keydown', (e) => {
123
108
  if (e.keyCode === 83 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)) {
@@ -127,7 +112,7 @@ export default defineComponent({
127
112
  });
128
113
 
129
114
  if (props.type !== 'diff') {
130
- vsEditor.onDidBlurEditorWidget(() => {
115
+ vsEditor?.onDidBlurEditorWidget(() => {
131
116
  emit('save', getEditorValue());
132
117
  });
133
118
  }
@@ -138,7 +123,7 @@ export default defineComponent({
138
123
  watch(
139
124
  () => props.initValues,
140
125
  (v, preV) => {
141
- if (vsEditor && v !== preV) {
126
+ if (v !== preV) {
142
127
  setEditorValue(props.initValues, props.modifiedValues);
143
128
  }
144
129
  },
@@ -151,17 +136,7 @@ export default defineComponent({
151
136
  onMounted(async () => {
152
137
  loading.value = true;
153
138
 
154
- await initEditor();
155
- if (!(globalThis as any).monaco) {
156
- const interval = setInterval(() => {
157
- if ((globalThis as any).monaco) {
158
- clearInterval(interval);
159
- init();
160
- }
161
- }, 300);
162
- } else {
163
- init();
164
- }
139
+ init();
165
140
  });
166
141
 
167
142
  onUnmounted(() => {
@@ -174,13 +149,14 @@ export default defineComponent({
174
149
  codeEditor,
175
150
 
176
151
  getEditor() {
177
- return vsEditor;
152
+ return vsEditor || vsDiffEditor;
178
153
  },
179
154
 
180
155
  setEditorValue,
181
156
 
182
157
  focus() {
183
- vsEditor.focus();
158
+ vsEditor?.focus();
159
+ vsDiffEditor?.focus();
184
160
  },
185
161
  };
186
162
  },
@@ -1,16 +1,16 @@
1
1
  <template>
2
2
  <div class="m-editor-nav-menu" :style="{ height: `${height}px` }">
3
- <div v-for="key in keys" :class="`menu-${key}`" :key="key">
3
+ <div v-for="key in keys" :class="`menu-${key}`" :key="key" :style="`width: ${columnWidth?.[key]}px`">
4
4
  <tool-button :data="item" v-for="(item, index) in data[key]" :key="index"></tool-button>
5
5
  </div>
6
6
  </div>
7
7
  </template>
8
8
 
9
9
  <script lang="ts">
10
- import { computed, defineComponent, PropType } from 'vue';
10
+ import { computed, defineComponent, inject, PropType } from 'vue';
11
11
 
12
12
  import ToolButton from '@editor/components/ToolButton.vue';
13
- import { MenuBarData } from '@editor/type';
13
+ import { GetColumnWidth, MenuBarData, Services } from '@editor/type';
14
14
 
15
15
  export default defineComponent({
16
16
  name: 'nav-menu',
@@ -29,8 +29,12 @@ export default defineComponent({
29
29
  },
30
30
 
31
31
  setup(props) {
32
+ const services = inject<Services>('services');
33
+
32
34
  return {
33
35
  keys: computed(() => Object.keys(props.data) as Array<keyof MenuBarData>),
36
+
37
+ columnWidth: computed(() => services?.uiService.get<GetColumnWidth>('columnWidth')),
34
38
  };
35
39
  },
36
40
  });
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <m-form
3
3
  class="m-editor-props-panel"
4
+ popper-class="m-editor-props-panel-popper"
4
5
  ref="configForm"
5
6
  size="small"
6
7
  :init-values="values"
@@ -10,7 +11,7 @@
10
11
  </template>
11
12
 
12
13
  <script lang="ts">
13
- import { defineComponent, getCurrentInstance, inject, onMounted, ref, watchEffect } from 'vue';
14
+ import { computed, defineComponent, getCurrentInstance, inject, onMounted, ref, watchEffect } from 'vue';
14
15
  import { ElMessage } from 'element-plus';
15
16
 
16
17
  import type { FormValue, MForm } from '@tmagic/form';
@@ -30,21 +31,16 @@ export default defineComponent({
30
31
  // ts类型应该是FormConfig, 但是打包时会出错,所以暂时用any
31
32
  const curFormConfig = ref<any>([]);
32
33
  const services = inject<Services>('services');
34
+ const node = computed(() => services?.editorService.get<MNode | null>('node'));
33
35
 
34
36
  const init = async () => {
35
- const node = services?.editorService.get<MNode | null>('node');
36
-
37
- if (!node) {
37
+ if (!node.value) {
38
38
  curFormConfig.value = [];
39
39
  return;
40
40
  }
41
41
 
42
- if (node.devconfig && node.style && !isNaN(+node.style.height) && !isNaN(+node.style.width)) {
43
- node.devconfig.ratio = node.style.height / node.style.width || 1;
44
- }
45
-
46
- values.value = node;
47
- const type = node.type || (node.items ? 'container' : 'text');
42
+ values.value = node.value;
43
+ const type = node.value.type || (node.value.items ? 'container' : 'text');
48
44
  curFormConfig.value = (await services?.propsService.getPropsConfig(type)) || [];
49
45
  };
50
46
 
@@ -3,8 +3,8 @@
3
3
  <div
4
4
  v-if="node.items"
5
5
  class="magic-editor-content-menu-item"
6
- @mouseenter="setSubVisiable(true)"
7
- @mouseleave="setSubVisiable(false)"
6
+ @mouseenter="setSubVisitable(true)"
7
+ @mouseleave="setSubVisitable(false)"
8
8
  >
9
9
  新增
10
10
  </div>
@@ -16,7 +16,7 @@
16
16
  >
17
17
  删除
18
18
  </div>
19
- <div class="subMenu" v-show="subVisible" @mouseenter="setSubVisiable(true)" @mouseleave="setSubVisiable(false)">
19
+ <div class="subMenu" v-show="subVisible" @mouseenter="setSubVisitable(true)" @mouseleave="setSubVisitable(false)">
20
20
  <el-scrollbar>
21
21
  <template v-if="node.type === 'tabs'">
22
22
  <div
@@ -31,20 +31,8 @@
31
31
  标签
32
32
  </div>
33
33
  </template>
34
-
35
- <template v-else-if="node.type === 'app'">
36
- <div
37
- class="magic-editor-content-menu-item"
38
- v-for="item in menu.app"
39
- :key="item.type"
40
- @click="() => append(item)"
41
- >
42
- {{ item.text }}
43
- </div>
44
- </template>
45
-
46
34
  <template v-else-if="node.items">
47
- <div v-for="list in menu.component" :key="list.title">
35
+ <div v-for="list in componentGroupList" :key="list.title">
48
36
  <template v-for="item in list.items">
49
37
  <div class="magic-editor-content-menu-item" v-if="item" :key="item.type" @click="() => append(item)">
50
38
  {{ item.text }}
@@ -59,21 +47,16 @@
59
47
  </template>
60
48
 
61
49
  <script lang="ts">
62
- import { computed, defineComponent, inject, PropType, ref } from 'vue';
50
+ import { computed, defineComponent, inject, ref } from 'vue';
51
+
52
+ import type { MNode } from '@tmagic/schema';
63
53
 
64
- import type { ComponentGroup, Services } from '@editor/type';
54
+ import type { AddMNode, Services } from '@editor/type';
65
55
 
66
56
  export default defineComponent({
67
57
  name: 'magic-editor-content-menu',
68
58
 
69
- props: {
70
- componentGroupList: {
71
- type: Array as PropType<ComponentGroup[]>,
72
- default: () => [],
73
- },
74
- },
75
-
76
- setup(props) {
59
+ setup() {
77
60
  const services = inject<Services>('services');
78
61
  const subVisible = ref(false);
79
62
  const node = computed(() => services?.editorService.get('node'));
@@ -83,17 +66,9 @@ export default defineComponent({
83
66
 
84
67
  node,
85
68
 
86
- menu: computed(() => ({
87
- app: [
88
- {
89
- type: 'page',
90
- text: '页面',
91
- },
92
- ],
93
- component: props.componentGroupList,
94
- })),
69
+ componentGroupList: computed(() => services?.componentListService.getList()),
95
70
 
96
- append(config: any) {
71
+ append(config: AddMNode) {
97
72
  services?.editorService.add({
98
73
  name: config.text,
99
74
  type: config.type,
@@ -104,11 +79,11 @@ export default defineComponent({
104
79
  node.value && services?.editorService.remove(node.value);
105
80
  },
106
81
 
107
- copy(node: any) {
108
- services?.editorService.copy(node);
82
+ copy(node?: MNode) {
83
+ node && services?.editorService.copy(node);
109
84
  },
110
85
 
111
- setSubVisiable(v: any) {
86
+ setSubVisitable(v: boolean) {
112
87
  subVisible.value = v;
113
88
  },
114
89
  };
@@ -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"
@@ -29,11 +30,20 @@
29
30
  empty-text="页面空荡荡的"
30
31
  >
31
32
  <template #default="{ node, data }">
32
- <slot name="layer-node-content" :node="node" :data="data">
33
- <span>
34
- {{ `${data.name} (${data.id})` }}
35
- </span>
36
- </slot>
33
+ <div
34
+ :id="data.id"
35
+ class="cus-tree-node"
36
+ @mousedown="toogleClickFlag"
37
+ @mouseup="toogleClickFlag"
38
+ @mouseenter="highlightHandler(data)"
39
+ :class="{ 'cus-tree-node-hover': canHighlight && data.id === highlightNode?.id }"
40
+ >
41
+ <slot name="layer-node-content" :node="node" :data="data">
42
+ <span>
43
+ {{ `${data.name} (${data.id})` }}
44
+ </span>
45
+ </slot>
46
+ </div>
37
47
  </template>
38
48
  </el-tree>
39
49
 
@@ -46,20 +56,34 @@
46
56
  <script lang="ts">
47
57
  import { computed, defineComponent, inject, onMounted, Ref, ref, watchEffect } from 'vue';
48
58
  import type { ElTree } from 'element-plus';
59
+ import { throttle } from 'lodash-es';
49
60
 
50
61
  import type { MNode, MPage } from '@tmagic/schema';
62
+ import { NodeType } from '@tmagic/schema';
63
+ import StageCore from '@tmagic/stage';
51
64
 
52
65
  import type { EditorService } from '@editor/services/editor';
53
66
  import type { Services } from '@editor/type';
54
67
 
55
68
  import LayerMenu from './LayerMenu.vue';
56
69
 
57
- const select = (data: MNode, editorService?: EditorService) => {
70
+ const throttleTime = 150;
71
+
72
+ const select = async (data: MNode, editorService?: EditorService) => {
58
73
  if (!data.id) {
59
74
  throw new Error('没有id');
60
75
  }
61
76
 
62
- editorService?.select(data);
77
+ await editorService?.select(data);
78
+ editorService?.get<StageCore>('stage')?.select(data.id);
79
+ };
80
+
81
+ const highlight = (data: MNode, editorService?: EditorService) => {
82
+ if (!data?.id) {
83
+ throw new Error('没有id');
84
+ }
85
+ editorService?.highlight(data);
86
+ editorService?.get<StageCore>('stage')?.highlight(data.id);
63
87
  };
64
88
 
65
89
  const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => ({
@@ -69,8 +93,8 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
69
93
 
70
94
  const { type: ingType } = ingData;
71
95
 
72
- if (ingType !== 'page' && data.type === 'page') return false;
73
- if (ingType === 'page' && data.type !== 'page') return false;
96
+ if (ingType !== NodeType.PAGE && data.type === NodeType.PAGE) return false;
97
+ if (ingType === NodeType.PAGE && data.type !== NodeType.PAGE) return false;
74
98
  if (!data || !data.type) return false;
75
99
  if (['prev', 'next'].includes(type)) return true;
76
100
  if (data.items || data.type === 'container') return true;
@@ -87,19 +111,22 @@ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorServi
87
111
  });
88
112
 
89
113
  const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => {
114
+ const highlightNode = ref<MNode>();
115
+ const node = ref<MNode>();
90
116
  const page = computed(() => editorService?.get('page'));
91
117
 
92
118
  watchEffect(() => {
93
119
  if (!tree.value) return;
94
-
95
- const node = editorService?.get('node');
96
- node && tree.value.setCurrentKey(node.id, true);
120
+ node.value = editorService?.get('node');
121
+ node.value && tree.value.setCurrentKey(node.value.id, true);
97
122
 
98
123
  const parent = editorService?.get('parent');
99
124
  if (!parent?.id) return;
100
125
 
101
126
  const treeNode = tree.value.getNode(parent.id);
102
127
  treeNode?.updateChildren();
128
+
129
+ highlightNode.value = editorService?.get('highlightNode');
103
130
  });
104
131
 
105
132
  return {
@@ -114,6 +141,10 @@ const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorSer
114
141
  }
115
142
  resolve([]);
116
143
  },
144
+
145
+ highlightNode,
146
+ clickNode: node,
147
+ expandedKeys: computed(() => (node.value ? [node.value.id] : [])),
117
148
  };
118
149
  };
119
150
 
@@ -127,12 +158,10 @@ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
127
158
  let name = '';
128
159
  if (data.name) {
129
160
  name = data.name;
130
- } else if (data.type) {
131
- name = data.type;
132
161
  } else if (data.items) {
133
162
  name = 'container';
134
163
  }
135
- return name.indexOf(value) !== -1;
164
+ return `${data.id}${name}${data.type}`.indexOf(value) !== -1;
136
165
  },
137
166
 
138
167
  filterTextChangeHandler(val: string) {
@@ -188,11 +217,25 @@ export default defineComponent({
188
217
  setup() {
189
218
  const services = inject<Services>('services');
190
219
  const tree = ref<InstanceType<typeof ElTree>>();
220
+ const clicked = ref(false);
191
221
  const editorService = services?.editorService;
222
+ const highlightHandler = throttle((data: MNode) => {
223
+ highlight(data, editorService);
224
+ }, throttleTime);
225
+
226
+ const toogleClickFlag = () => {
227
+ clicked.value = !clicked.value;
228
+ };
229
+
230
+ const statusData = useStatus(tree, editorService);
231
+ const canHighlight = computed(
232
+ () => statusData.highlightNode.value?.id !== statusData.clickNode.value?.id && !clicked.value,
233
+ );
234
+
192
235
  return {
193
236
  tree,
237
+ ...statusData,
194
238
  ...useDrop(tree, editorService),
195
- ...useStatus(tree, editorService),
196
239
  ...useFilter(tree),
197
240
  ...useContentMenu(editorService),
198
241
 
@@ -201,8 +244,12 @@ export default defineComponent({
201
244
  document.dispatchEvent(new CustomEvent('ui-select', { detail: data }));
202
245
  return;
203
246
  }
247
+ tree.value?.setCurrentKey(data.id);
204
248
  select(data, editorService);
205
249
  },
250
+ highlightHandler,
251
+ toogleClickFlag,
252
+ canHighlight,
206
253
  };
207
254
  },
208
255
  });