@tmagic/editor 1.3.0-beta.6 → 1.3.0-beta.7

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 (34) hide show
  1. package/dist/style.css +57 -56
  2. package/dist/tmagic-editor.js +487 -390
  3. package/dist/tmagic-editor.js.map +1 -1
  4. package/dist/tmagic-editor.umd.cjs +505 -408
  5. package/dist/tmagic-editor.umd.cjs.map +1 -1
  6. package/package.json +10 -10
  7. package/src/Editor.vue +8 -0
  8. package/src/components/Tree.vue +66 -0
  9. package/src/components/TreeNode.vue +142 -0
  10. package/src/layouts/sidebar/Sidebar.vue +13 -0
  11. package/src/layouts/sidebar/data-source/DataSourceList.vue +4 -2
  12. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +8 -2
  13. package/src/layouts/sidebar/layer/LayerPanel.vue +40 -31
  14. package/src/layouts/sidebar/layer/use-click.ts +105 -0
  15. package/src/layouts/sidebar/layer/use-drag.ts +1 -1
  16. package/src/layouts/sidebar/layer/use-filter.ts +1 -12
  17. package/src/layouts/sidebar/layer/use-keybinding.ts +6 -2
  18. package/src/layouts/sidebar/layer/use-node-status.ts +4 -2
  19. package/src/theme/layer-panel.scss +2 -74
  20. package/src/theme/theme.scss +1 -0
  21. package/src/theme/tree.scss +72 -0
  22. package/src/type.ts +16 -1
  23. package/src/utils/tree.ts +15 -0
  24. package/types/{layouts/sidebar/layer/LayerNode.vue.d.ts → components/Tree.vue.d.ts} +19 -17
  25. package/types/components/TreeNode.vue.d.ts +47 -0
  26. package/types/layouts/sidebar/data-source/DataSourceList.vue.d.ts +2 -6
  27. package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +7 -1
  28. package/types/layouts/sidebar/layer/LayerPanel.vue.d.ts +1 -1
  29. package/types/layouts/sidebar/layer/use-click.d.ts +106 -0
  30. package/types/layouts/sidebar/layer/use-filter.d.ts +0 -1
  31. package/types/layouts/sidebar/layer/use-keybinding.d.ts +2 -1
  32. package/types/type.d.ts +20 -1
  33. package/types/utils/tree.d.ts +3 -0
  34. package/src/layouts/sidebar/layer/LayerNode.vue +0 -208
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.0-beta.6",
2
+ "version": "1.3.0-beta.7",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -47,13 +47,13 @@
47
47
  "dependencies": {
48
48
  "@babel/core": "^7.18.0",
49
49
  "@element-plus/icons-vue": "^2.0.9",
50
- "@tmagic/core": "1.3.0-beta.6",
51
- "@tmagic/design": "1.3.0-beta.6",
52
- "@tmagic/form": "1.3.0-beta.6",
53
- "@tmagic/schema": "1.3.0-beta.6",
54
- "@tmagic/stage": "1.3.0-beta.6",
55
- "@tmagic/table": "1.3.0-beta.6",
56
- "@tmagic/utils": "1.3.0-beta.6",
50
+ "@tmagic/core": "1.3.0-beta.7",
51
+ "@tmagic/design": "1.3.0-beta.7",
52
+ "@tmagic/form": "1.3.0-beta.7",
53
+ "@tmagic/schema": "1.3.0-beta.7",
54
+ "@tmagic/stage": "1.3.0-beta.7",
55
+ "@tmagic/table": "1.3.0-beta.7",
56
+ "@tmagic/utils": "1.3.0-beta.7",
57
57
  "buffer": "^6.0.3",
58
58
  "color": "^3.1.3",
59
59
  "events": "^3.3.0",
@@ -65,8 +65,8 @@
65
65
  "vue": "^3.3.4"
66
66
  },
67
67
  "peerDependencies": {
68
- "@tmagic/design": "1.3.0-beta.6",
69
- "@tmagic/form": "1.3.0-beta.6",
68
+ "@tmagic/design": "1.3.0-beta.7",
69
+ "@tmagic/form": "1.3.0-beta.7",
70
70
  "monaco-editor": "^0.41.0",
71
71
  "vue": "^3.3.4"
72
72
  },
package/src/Editor.vue CHANGED
@@ -25,6 +25,10 @@
25
25
  <slot name="layer-node-content" :data="data"></slot>
26
26
  </template>
27
27
 
28
+ <template #layer-node-tool="{ data }">
29
+ <slot name="layer-node-tool" :data="data"></slot>
30
+ </template>
31
+
28
32
  <template #component-list-panel-header>
29
33
  <slot name="component-list-panel-header"></slot>
30
34
  </template>
@@ -40,6 +44,10 @@
40
44
  <template #code-block-panel-tool="{ id, data }">
41
45
  <slot name="code-block-panel-tool" :id="id" :data="data"></slot>
42
46
  </template>
47
+
48
+ <template #data-source-panel-tool="{ data }">
49
+ <slot name="data-source-panel-tool" :data="data"></slot>
50
+ </template>
43
51
  </Sidebar>
44
52
  </slot>
45
53
  </template>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <div class="m-editor-tree" @dragover="handleDragOver">
3
+ <template v-if="data?.length">
4
+ <TreeNode v-for="item in data" :key="item.id" :data="item" :indent="indent" :node-status-map="nodeStatusMap">
5
+ <template #tree-node-content="{ data: nodeData }">
6
+ <slot name="tree-node-content" :data="nodeData"> </slot>
7
+ </template>
8
+
9
+ <template #tree-node-tool="{ data: nodeData }">
10
+ <slot name="tree-node-tool" :data="nodeData"> </slot>
11
+ </template>
12
+ </TreeNode>
13
+ </template>
14
+ <div v-else>
15
+ <p>{{ emptyText }}</p>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import { provide } from 'vue';
22
+
23
+ import type { Id } from '@tmagic/schema';
24
+
25
+ import type { LayerNodeStatus, TreeNodeData } from '@editor/type';
26
+
27
+ import TreeNode from './TreeNode.vue';
28
+
29
+ defineSlots<{
30
+ 'tree-node-content'(props: { data: TreeNodeData }): any;
31
+ 'tree-node-tool'(props: { data: TreeNodeData }): any;
32
+ }>();
33
+
34
+ defineOptions({
35
+ name: 'MEditorTree',
36
+ });
37
+
38
+ const emit = defineEmits<{
39
+ 'node-dragover': [event: DragEvent];
40
+ 'node-dragstart': [event: DragEvent, data: TreeNodeData];
41
+ 'node-dragleave': [event: DragEvent, data: TreeNodeData];
42
+ 'node-dragend': [event: DragEvent, data: TreeNodeData];
43
+ 'node-contextmenu': [event: MouseEvent, data: TreeNodeData];
44
+ 'node-mouseenter': [event: MouseEvent, data: TreeNodeData];
45
+ 'node-click': [event: MouseEvent, data: TreeNodeData];
46
+ }>();
47
+
48
+ provide('treeEmit', emit);
49
+
50
+ withDefaults(
51
+ defineProps<{
52
+ data: TreeNodeData[];
53
+ nodeStatusMap: Map<Id, LayerNodeStatus>;
54
+ indent?: number;
55
+ emptyText?: string;
56
+ }>(),
57
+ {
58
+ indent: 0,
59
+ emptyText: '暂无数据',
60
+ },
61
+ );
62
+
63
+ const handleDragOver = (event: DragEvent) => {
64
+ emit('node-dragover', event);
65
+ };
66
+ </script>
@@ -0,0 +1,142 @@
1
+ <template>
2
+ <div
3
+ v-show="visible"
4
+ class="m-editor-tree-node"
5
+ :draggable="draggable"
6
+ :data-node-id="data.id"
7
+ :data-is-container="Array.isArray(data.items)"
8
+ @dragstart="handleDragStart"
9
+ @dragleave="handleDragLeave"
10
+ @dragend="handleDragEnd"
11
+ >
12
+ <div
13
+ class="tree-node"
14
+ :class="{ selected, expanded }"
15
+ :style="`padding-left: ${indent}px`"
16
+ @contextmenu="nodeContentmenuHandler"
17
+ @mouseenter="mouseenterHandler"
18
+ >
19
+ <MIcon
20
+ class="expand-icon"
21
+ :style="hasChilren ? '' : 'color: transparent; cursor: default'"
22
+ :icon="expanded ? ArrowDown : ArrowRight"
23
+ @click="expandHandler"
24
+ ></MIcon>
25
+
26
+ <div class="tree-node-content" @click="nodeClickHandler">
27
+ <slot name="tree-node-content" :data="data">
28
+ <div class="tree-node-label">{{ `${data.name} (${data.id})` }}</div>
29
+ <div class="tree-node-tool">
30
+ <slot name="tree-node-tool" :data="data"></slot>
31
+ </div>
32
+ </slot>
33
+ </div>
34
+ </div>
35
+
36
+ <div v-if="hasChilren && expanded" class="m-editor-tree-node-children">
37
+ <TreeNode
38
+ v-for="item in data.items"
39
+ :key="item.id"
40
+ :data="item"
41
+ :node-status-map="nodeStatusMap"
42
+ :indent="indent + 11"
43
+ >
44
+ <template #tree-node-content="{ data: nodeData }">
45
+ <slot name="tree-node-content" :data="nodeData"> </slot>
46
+ </template>
47
+ <template #tree-node-tool="{ data: nodeData }">
48
+ <slot name="tree-node-tool" :data="nodeData"> </slot>
49
+ </template>
50
+ </TreeNode>
51
+ </div>
52
+ </div>
53
+ </template>
54
+
55
+ <script setup lang="ts">
56
+ import { computed, inject } from 'vue';
57
+ import { ArrowDown, ArrowRight } from '@element-plus/icons-vue';
58
+
59
+ import type { Id } from '@tmagic/schema';
60
+
61
+ import MIcon from '@editor/components/Icon.vue';
62
+ import type { LayerNodeStatus, TreeNodeData } from '@editor/type';
63
+ import { updateStatus } from '@editor/utils/tree';
64
+
65
+ defineSlots<{
66
+ 'tree-node-tool'(props: { data: TreeNodeData }): any;
67
+ 'tree-node-content'(props: { data: TreeNodeData }): any;
68
+ }>();
69
+
70
+ defineOptions({
71
+ name: 'MEditorTreeNode',
72
+ });
73
+
74
+ const emit = defineEmits<{
75
+ 'node-dragstart': [event: DragEvent, data: TreeNodeData];
76
+ 'node-dragleave': [event: DragEvent, data: TreeNodeData];
77
+ 'node-dragend': [event: DragEvent, data: TreeNodeData];
78
+ 'node-contextmenu': [event: MouseEvent, data: TreeNodeData];
79
+ 'node-mouseenter': [event: MouseEvent, data: TreeNodeData];
80
+ 'node-click': [event: MouseEvent, data: TreeNodeData];
81
+ }>();
82
+
83
+ const treeEmit = inject<typeof emit>('treeEmit');
84
+
85
+ const props = withDefaults(
86
+ defineProps<{
87
+ data: TreeNodeData;
88
+ nodeStatusMap: Map<Id, LayerNodeStatus>;
89
+ indent?: number;
90
+ }>(),
91
+ {
92
+ indent: 0,
93
+ },
94
+ );
95
+
96
+ const nodeStatus = computed(
97
+ () =>
98
+ props.nodeStatusMap?.get(props.data.id) || {
99
+ selected: false,
100
+ expand: false,
101
+ visible: false,
102
+ draggable: false,
103
+ },
104
+ );
105
+
106
+ const expanded = computed(() => nodeStatus.value.expand);
107
+ const selected = computed(() => nodeStatus.value.selected);
108
+ const visible = computed(() => nodeStatus.value.visible);
109
+ const draggable = computed(() => nodeStatus.value.draggable);
110
+
111
+ const hasChilren = computed(() => props.data.items && props.data.items.length > 0);
112
+
113
+ const handleDragStart = (event: DragEvent) => {
114
+ treeEmit?.('node-dragstart', event, props.data);
115
+ };
116
+
117
+ const handleDragLeave = (event: DragEvent) => {
118
+ treeEmit?.('node-dragleave', event, props.data);
119
+ };
120
+
121
+ const handleDragEnd = (event: DragEvent) => {
122
+ treeEmit?.('node-dragend', event, props.data);
123
+ };
124
+
125
+ const nodeContentmenuHandler = (event: MouseEvent) => {
126
+ treeEmit?.('node-contextmenu', event, props.data);
127
+ };
128
+
129
+ const mouseenterHandler = (event: MouseEvent) => {
130
+ treeEmit?.('node-mouseenter', event, props.data);
131
+ };
132
+
133
+ const expandHandler = () => {
134
+ updateStatus(props.nodeStatusMap, props.data.id, {
135
+ expand: !expanded.value,
136
+ });
137
+ };
138
+
139
+ const nodeClickHandler = (event: MouseEvent) => {
140
+ treeEmit?.('node-click', event, props.data);
141
+ };
142
+ </script>
@@ -64,6 +64,19 @@
64
64
  <slot v-if="config.$key === 'layer'" name="layer-node-content" :data="nodeData"></slot>
65
65
  <component v-else-if="config.slots?.layerNodeContent" :is="config.slots.layerNodeContent" :data="nodeData" />
66
66
  </template>
67
+
68
+ <template #layer-node-tool="{ data: nodeData }" v-if="config.$key === 'layer' || config.slots?.layerNodeTool">
69
+ <slot v-if="config.$key === 'layer'" name="layer-node-tool" :data="nodeData"></slot>
70
+ <component v-else-if="config.slots?.layerNodeTool" :is="config.slots.layerNodeTool" :data="nodeData" />
71
+ </template>
72
+
73
+ <template
74
+ #data-source-panel-tool="{ data }"
75
+ v-if="config.$key === 'data-source' || config.slots?.codeBlockPanelTool"
76
+ >
77
+ <slot v-if="config.$key === 'data-source'" name="data-source-panel-tool" :data="data"></slot>
78
+ <component v-else-if="config.slots?.DataSourcePanelTool" :is="config.slots.DataSourcePanelTool" />
79
+ </template>
67
80
  </component>
68
81
  </div>
69
82
  </div>
@@ -26,7 +26,7 @@
26
26
  <TMagicTooltip v-if="editable" effect="dark" content="删除" placement="bottom">
27
27
  <Icon :icon="Close" class="edit-icon" @click.stop="removeHandler(`${data.id}`)"></Icon>
28
28
  </TMagicTooltip>
29
- <slot name="data-source-panel-tool" :id="data.id" :data="data.codeBlockContent"></slot>
29
+ <slot name="data-source-panel-tool" :data="data"></slot>
30
30
  </div>
31
31
  </div>
32
32
  </div>
@@ -42,7 +42,9 @@ import { tMagicMessageBox, TMagicTooltip, TMagicTree } from '@tmagic/design';
42
42
  import { Dep, Id } from '@tmagic/schema';
43
43
 
44
44
  import Icon from '@editor/components/Icon.vue';
45
- import { DepTargetType, Services } from '@editor/type';
45
+ import { type DataSourceListSlots, DepTargetType, type Services } from '@editor/type';
46
+
47
+ defineSlots<DataSourceListSlots>();
46
48
 
47
49
  defineOptions({
48
50
  name: 'MEditorDataSourceList',
@@ -23,7 +23,11 @@
23
23
  </div>
24
24
 
25
25
  <!-- 数据源列表 -->
26
- <DataSourceList @edit="editHandler" @remove="removeHandler"></DataSourceList>
26
+ <DataSourceList @edit="editHandler" @remove="removeHandler">
27
+ <template #data-source-panel-tool="{ data }">
28
+ <slot name="data-source-panel-tool" :data="data"></slot>
29
+ </template>
30
+ </DataSourceList>
27
31
 
28
32
  <DataSourceConfigPanel
29
33
  ref="editDialog"
@@ -44,11 +48,13 @@ import type { DataSourceSchema } from '@tmagic/schema';
44
48
 
45
49
  import SearchInput from '@editor/components/SearchInput.vue';
46
50
  import ToolButton from '@editor/components/ToolButton.vue';
47
- import type { Services } from '@editor/type';
51
+ import type { DataSourceListSlots, Services } from '@editor/type';
48
52
 
49
53
  import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
50
54
  import DataSourceList from './DataSourceList.vue';
51
55
 
56
+ defineSlots<DataSourceListSlots>();
57
+
52
58
  defineOptions({
53
59
  name: 'MEditorDataSourceListPanel',
54
60
  });
@@ -1,22 +1,33 @@
1
1
  <template>
2
- <TMagicScrollbar class="magic-editor-layer-panel">
2
+ <TMagicScrollbar class="m-editor-layer-panel">
3
3
  <slot name="layer-panel-header"></slot>
4
4
 
5
5
  <SearchInput @search="filterTextChangeHandler"></SearchInput>
6
6
 
7
- <div class="magic-editor-layer-tree" ref="layerTreeContainer" tabindex="-1" @dragover="handleDragOver">
8
- <LayerNode
9
- v-if="page && root"
10
- :data="page"
11
- :filter-text="filterText"
12
- :is-ctrl-key-down="isCtrlKeyDown"
13
- @node-contextmenu="contextmenu"
14
- >
15
- <template #layer-node-content="{ data: nodeData }">
16
- <slot name="layer-node-content" :data="nodeData"> </slot>
17
- </template>
18
- </LayerNode>
19
- </div>
7
+ <Tree
8
+ v-if="page && nodeStatusMap"
9
+ tabindex="-1"
10
+ ref="tree"
11
+ :data="[page]"
12
+ :node-status-map="nodeStatusMap"
13
+ @node-dragover="handleDragOver"
14
+ @node-dragstart="handleDragStart"
15
+ @node-dragleave="handleDragLeave"
16
+ @node-dragend="handleDragEnd"
17
+ @node-contextmenu="nodeContentmenuHandler"
18
+ @node-mouseenter="mouseenterHandler"
19
+ @node-click="nodeClickHandler"
20
+ >
21
+ <template #tree-node-tool="{ data: nodeData }">
22
+ <slot name="layer-node-tool" :data="nodeData">
23
+ <LayerNodeTool :data="nodeData"></LayerNodeTool>
24
+ </slot>
25
+ </template>
26
+
27
+ <template #tree-node-content="{ data: nodeData }">
28
+ <slot name="layer-node-content" :data="nodeData"> </slot>
29
+ </template>
30
+ </Tree>
20
31
 
21
32
  <Teleport to="body">
22
33
  <LayerMenu ref="menu" :layer-content-menu="layerContentMenu" @collapse-all="collapseAllHandler"></LayerMenu>
@@ -25,15 +36,17 @@
25
36
  </template>
26
37
 
27
38
  <script setup lang="ts">
28
- import { computed, inject, provide, ref } from 'vue';
39
+ import { computed, inject, ref } from 'vue';
29
40
 
30
41
  import { TMagicScrollbar } from '@tmagic/design';
31
42
 
32
43
  import SearchInput from '@editor/components/SearchInput.vue';
33
- import type { LayerPanelSlots, MenuButton, MenuComponent, Services } from '@editor/type';
44
+ import Tree from '@editor/components/Tree.vue';
45
+ import { LayerPanelSlots, MenuButton, MenuComponent, Services } from '@editor/type';
34
46
 
35
47
  import LayerMenu from './LayerMenu.vue';
36
- import LayerNode from './LayerNode.vue';
48
+ import LayerNodeTool from './LayerNodeTool.vue';
49
+ import { useClick } from './use-click';
37
50
  import { useDrag } from './use-drag';
38
51
  import { useFilter } from './use-filter';
39
52
  import { useKeybinding } from './use-keybinding';
@@ -52,17 +65,14 @@ defineProps<{
52
65
  const services = inject<Services>('services');
53
66
  const editorService = services?.editorService;
54
67
 
55
- const layerTreeContainer = ref<HTMLDivElement>();
68
+ const tree = ref<InstanceType<typeof Tree>>();
56
69
 
57
70
  const page = computed(() => editorService?.get('page'));
58
- const root = computed(() => editorService?.get('root'));
59
71
 
60
72
  const { nodeStatusMap } = useNodeStatus(services, page);
61
- const { isCtrlKeyDown } = useKeybinding(services, layerTreeContainer);
73
+ const { isCtrlKeyDown } = useKeybinding(services, tree);
62
74
 
63
- provide('nodeStatusMap', nodeStatusMap);
64
-
65
- const { filterText, filterTextChangeHandler } = useFilter(nodeStatusMap, page);
75
+ const { filterTextChangeHandler } = useFilter(nodeStatusMap, page);
66
76
 
67
77
  const collapseAllHandler = () => {
68
78
  if (!page.value || !nodeStatusMap.value) return;
@@ -75,13 +85,12 @@ const collapseAllHandler = () => {
75
85
  }
76
86
  };
77
87
 
78
- // 右键菜单
79
- const menu = ref<InstanceType<typeof LayerMenu>>();
80
- const contextmenu = (event: MouseEvent): void => {
81
- event.preventDefault();
82
-
83
- menu.value?.show(event);
84
- };
88
+ const { handleDragStart, handleDragEnd, handleDragLeave, handleDragOver } = useDrag(services);
85
89
 
86
- const { handleDragOver } = useDrag(services);
90
+ const {
91
+ menu,
92
+ nodeClickHandler,
93
+ nodeContentmenuHandler,
94
+ highlightHandler: mouseenterHandler,
95
+ } = useClick(services, isCtrlKeyDown, nodeStatusMap);
87
96
  </script>
@@ -0,0 +1,105 @@
1
+ import { type ComputedRef, nextTick, type Ref, ref } from 'vue';
2
+ import { throttle } from 'lodash-es';
3
+
4
+ import { Id, MNode } from '@tmagic/schema';
5
+
6
+ import { LayerNodeStatus, Services, TreeNodeData, UI_SELECT_MODE_EVENT_NAME } from '@editor/type';
7
+ import { updateStatus } from '@editor/utils/tree';
8
+
9
+ import LayerMenu from './LayerMenu.vue';
10
+
11
+ export const useClick = (
12
+ services: Services | undefined,
13
+ isCtrlKeyDown: Ref<boolean>,
14
+ nodeStatusMap: ComputedRef<Map<Id, LayerNodeStatus> | undefined>,
15
+ ) => {
16
+ // 触发画布选中
17
+ const select = async (data: MNode) => {
18
+ if (!data.id) {
19
+ throw new Error('没有id');
20
+ }
21
+
22
+ if (isCtrlKeyDown.value) {
23
+ multiSelect(data);
24
+ } else {
25
+ await services?.editorService.select(data);
26
+ services?.editorService.get('stage')?.select(data.id);
27
+ }
28
+ };
29
+
30
+ const multiSelect = async (data: MNode) => {
31
+ const nodes = services?.editorService.get('nodes') || [];
32
+
33
+ const newNodes: Id[] = [];
34
+ let isCancel = false;
35
+ nodes.forEach((node) => {
36
+ if (node.id === data.id) {
37
+ isCancel = true;
38
+ return;
39
+ }
40
+
41
+ newNodes.push(node.id);
42
+ });
43
+
44
+ // 只剩一个不能取消选中
45
+ if (!isCancel || newNodes.length === 0) {
46
+ newNodes.push(data.id);
47
+ }
48
+
49
+ await services?.editorService.multiSelect(newNodes);
50
+ services?.editorService.get('stage')?.multiSelect(newNodes);
51
+ };
52
+
53
+ const throttleTime = 300;
54
+ // 鼠标在组件树移动触发高亮
55
+ const highlightHandler = throttle((event: MouseEvent, data: TreeNodeData) => {
56
+ highlight(data);
57
+ }, throttleTime);
58
+
59
+ // 触发画布高亮
60
+ const highlight = (data: TreeNodeData) => {
61
+ services?.editorService?.highlight(data);
62
+ services?.editorService?.get('stage')?.highlight(data.id);
63
+ };
64
+
65
+ const nodeClickHandler = (event: MouseEvent, data: TreeNodeData) => {
66
+ if (!nodeStatusMap?.value) return;
67
+
68
+ if (services?.uiService.get('uiSelectMode')) {
69
+ document.dispatchEvent(new CustomEvent(UI_SELECT_MODE_EVENT_NAME, { detail: data }));
70
+ return;
71
+ }
72
+
73
+ if (data.items && data.items.length > 0 && !isCtrlKeyDown.value) {
74
+ updateStatus(nodeStatusMap.value, data.id, {
75
+ expand: true,
76
+ });
77
+ }
78
+
79
+ nextTick(() => {
80
+ select(data);
81
+ });
82
+ };
83
+
84
+ // 右键菜单
85
+ const menu = ref<InstanceType<typeof LayerMenu>>();
86
+
87
+ return {
88
+ menu,
89
+
90
+ nodeClickHandler,
91
+
92
+ nodeContentmenuHandler(event: MouseEvent, data: TreeNodeData) {
93
+ event.preventDefault();
94
+
95
+ const nodes = services?.editorService.get('nodes') || [];
96
+ if (nodes.length < 2 || !nodes.includes(data)) {
97
+ nodeClickHandler(event, data);
98
+ }
99
+
100
+ menu.value?.show(event);
101
+ },
102
+
103
+ highlightHandler,
104
+ };
105
+ };
@@ -65,7 +65,7 @@ export const useDrag = (services: Services | undefined) => {
65
65
  if (!event.target) return;
66
66
 
67
67
  const targetEl = getNodeEl(event.target as HTMLElement);
68
- if (!targetEl) return;
68
+ if (!targetEl?.draggable) return;
69
69
 
70
70
  const labelEl = targetEl.children[0];
71
71
  if (!labelEl) return;
@@ -1,21 +1,10 @@
1
1
  import { type ComputedRef, ref } from 'vue';
2
2
 
3
3
  import { Id, MNode, MPage } from '@tmagic/schema';
4
- import { getKeys } from '@tmagic/utils';
5
4
 
6
5
  import { LayerNodeStatus } from '@editor/type';
7
6
  import { traverseNode } from '@editor/utils';
8
-
9
- export const updateStatus = (nodeStatusMap: Map<Id, LayerNodeStatus>, id: Id, status: Partial<LayerNodeStatus>) => {
10
- const nodeStatus = nodeStatusMap.get(id);
11
-
12
- if (!nodeStatus) return;
13
- getKeys(status).forEach((key) => {
14
- if (nodeStatus[key] !== undefined && status[key] !== undefined) {
15
- nodeStatus[key] = Boolean(status[key]);
16
- }
17
- });
18
- };
7
+ import { updateStatus } from '@editor/utils/tree';
19
8
 
20
9
  export const useFilter = (
21
10
  nodeStatusMap: ComputedRef<Map<Id, LayerNodeStatus> | undefined>,
@@ -1,9 +1,13 @@
1
1
  import { type Ref, ref, watchEffect } from 'vue';
2
2
 
3
+ import Tree from '@editor/components/Tree.vue';
3
4
  import type { Services } from '@editor/type';
4
5
  import { KeyBindingContainerKey } from '@editor/utils/keybinding-config';
5
6
 
6
- export const useKeybinding = (services: Services | undefined, contianer: Ref<HTMLDivElement | undefined>) => {
7
+ export const useKeybinding = (
8
+ services: Services | undefined,
9
+ contianer: Ref<InstanceType<typeof Tree> | undefined>,
10
+ ) => {
7
11
  const keybindingService = services?.keybindingService;
8
12
 
9
13
  // 是否多选
@@ -37,7 +41,7 @@ export const useKeybinding = (services: Services | undefined, contianer: Ref<HTM
37
41
  watchEffect(() => {
38
42
  if (contianer.value) {
39
43
  globalThis.addEventListener('blur', windowBlurHandler);
40
- keybindingService?.registeEl(KeyBindingContainerKey.LAYER_PANEL, contianer.value);
44
+ keybindingService?.registeEl(KeyBindingContainerKey.LAYER_PANEL, contianer.value.$el);
41
45
  } else {
42
46
  globalThis.removeEventListener('blur', windowBlurHandler);
43
47
  keybindingService?.unregisteEl(KeyBindingContainerKey.LAYER_PANEL);
@@ -5,8 +5,7 @@ import { getNodePath } from '@tmagic/utils';
5
5
 
6
6
  import { LayerNodeStatus, Services } from '@editor/type';
7
7
  import { traverseNode } from '@editor/utils';
8
-
9
- import { updateStatus } from './use-filter';
8
+ import { updateStatus } from '@editor/utils/tree';
10
9
 
11
10
  const createPageNodeStatus = (services: Services | undefined, pageId: Id) => {
12
11
  const map = new Map<Id, LayerNodeStatus>();
@@ -15,6 +14,7 @@ const createPageNodeStatus = (services: Services | undefined, pageId: Id) => {
15
14
  visible: true,
16
15
  expand: true,
17
16
  selected: true,
17
+ draggable: false,
18
18
  });
19
19
 
20
20
  services?.editorService.getNodeById(pageId)?.items.forEach((node: MNode) =>
@@ -23,6 +23,7 @@ const createPageNodeStatus = (services: Services | undefined, pageId: Id) => {
23
23
  visible: true,
24
24
  expand: false,
25
25
  selected: false,
26
+ draggable: true,
26
27
  });
27
28
  }),
28
29
  );
@@ -87,6 +88,7 @@ export const useNodeStatus = (services: Services | undefined, page: ComputedRef<
87
88
  visible: true,
88
89
  expand: Array.isArray(node.items),
89
90
  selected: true,
91
+ draggable: true,
90
92
  });
91
93
  });
92
94
  });