@tmagic/editor 1.0.0-beta.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 (98) hide show
  1. package/dist/style.css +505 -0
  2. package/dist/tmagic-editor.es.js +4233 -0
  3. package/dist/tmagic-editor.es.js.map +1 -0
  4. package/dist/tmagic-editor.umd.js +4276 -0
  5. package/dist/tmagic-editor.umd.js.map +1 -0
  6. package/dist/types/src/Editor.vue.d.ts +136 -0
  7. package/dist/types/src/components/Icon.vue.d.ts +13 -0
  8. package/dist/types/src/components/ToolButton.vue.d.ts +35 -0
  9. package/dist/types/src/fields/Code.vue.d.ts +24 -0
  10. package/dist/types/src/fields/CodeLink.vue.d.ts +54 -0
  11. package/dist/types/src/fields/UISelect.vue.d.ts +32 -0
  12. package/dist/types/src/index.d.ts +19 -0
  13. package/dist/types/src/layouts/AddPageBox.vue.d.ts +5 -0
  14. package/dist/types/src/layouts/CodeEditor.vue.d.ts +46 -0
  15. package/dist/types/src/layouts/Framework.vue.d.ts +11 -0
  16. package/dist/types/src/layouts/NavMenu.vue.d.ts +24 -0
  17. package/dist/types/src/layouts/PropsPanel.vue.d.ts +13 -0
  18. package/dist/types/src/layouts/Resizer.vue.d.ts +13 -0
  19. package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +12 -0
  20. package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +31 -0
  21. package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +973 -0
  22. package/dist/types/src/layouts/sidebar/Sidebar.vue.d.ts +27 -0
  23. package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +11 -0
  24. package/dist/types/src/layouts/workspace/Stage.vue.d.ts +153 -0
  25. package/dist/types/src/layouts/workspace/ViewerMenu.vue.d.ts +18 -0
  26. package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +37 -0
  27. package/dist/types/src/services/BaseService.d.ts +56 -0
  28. package/dist/types/src/services/editor.d.ts +122 -0
  29. package/dist/types/src/services/events.d.ts +16 -0
  30. package/dist/types/src/services/history.d.ts +51 -0
  31. package/dist/types/src/services/props.d.ts +36 -0
  32. package/dist/types/src/services/ui.d.ts +26 -0
  33. package/dist/types/src/shims-vue.d.ts +6 -0
  34. package/dist/types/src/type.d.ts +183 -0
  35. package/dist/types/src/utils/compose.d.ts +5 -0
  36. package/dist/types/src/utils/config.d.ts +4 -0
  37. package/dist/types/src/utils/editor.d.ts +45 -0
  38. package/dist/types/src/utils/index.d.ts +4 -0
  39. package/dist/types/src/utils/logger.d.ts +5 -0
  40. package/dist/types/src/utils/props.d.ts +49 -0
  41. package/dist/types/src/utils/undo-redo.d.ts +12 -0
  42. package/dist/types/src/vite-env.d.ts +1 -0
  43. package/package.json +57 -0
  44. package/src/Editor.vue +234 -0
  45. package/src/components/Icon.vue +29 -0
  46. package/src/components/ToolButton.vue +188 -0
  47. package/src/fields/Code.vue +35 -0
  48. package/src/fields/CodeLink.vue +81 -0
  49. package/src/fields/UISelect.vue +100 -0
  50. package/src/index.ts +63 -0
  51. package/src/layouts/AddPageBox.vue +41 -0
  52. package/src/layouts/CodeEditor.vue +188 -0
  53. package/src/layouts/Framework.vue +73 -0
  54. package/src/layouts/NavMenu.vue +37 -0
  55. package/src/layouts/PropsPanel.vue +81 -0
  56. package/src/layouts/Resizer.vue +61 -0
  57. package/src/layouts/sidebar/ComponentListPanel.vue +69 -0
  58. package/src/layouts/sidebar/LayerMenu.vue +117 -0
  59. package/src/layouts/sidebar/LayerPanel.vue +209 -0
  60. package/src/layouts/sidebar/Sidebar.vue +86 -0
  61. package/src/layouts/workspace/PageBar.vue +83 -0
  62. package/src/layouts/workspace/Stage.vue +221 -0
  63. package/src/layouts/workspace/ViewerMenu.vue +110 -0
  64. package/src/layouts/workspace/Workspace.vue +98 -0
  65. package/src/services/BaseService.ts +138 -0
  66. package/src/services/componentList.ts +48 -0
  67. package/src/services/editor.ts +521 -0
  68. package/src/services/events.ts +82 -0
  69. package/src/services/history.ts +124 -0
  70. package/src/services/props.ts +110 -0
  71. package/src/services/ui.ts +101 -0
  72. package/src/shims-vue.d.ts +6 -0
  73. package/src/theme/code-editor.scss +7 -0
  74. package/src/theme/common/var.scss +13 -0
  75. package/src/theme/component-list-panel.scss +102 -0
  76. package/src/theme/content-menu.scss +39 -0
  77. package/src/theme/framework.scss +72 -0
  78. package/src/theme/index.scss +13 -0
  79. package/src/theme/layer-panel.scss +68 -0
  80. package/src/theme/nav-menu.scss +69 -0
  81. package/src/theme/page-bar.scss +31 -0
  82. package/src/theme/props-panel.scss +17 -0
  83. package/src/theme/resizer.scss +51 -0
  84. package/src/theme/ruler.scss +38 -0
  85. package/src/theme/sidebar.scss +97 -0
  86. package/src/theme/stage.scss +22 -0
  87. package/src/theme/workspace.scss +5 -0
  88. package/src/type.ts +236 -0
  89. package/src/utils/compose.ts +33 -0
  90. package/src/utils/config.ts +29 -0
  91. package/src/utils/editor.ts +244 -0
  92. package/src/utils/index.ts +22 -0
  93. package/src/utils/logger.ts +47 -0
  94. package/src/utils/props.ts +218 -0
  95. package/src/utils/undo-redo.ts +76 -0
  96. package/src/vite-env.d.ts +1 -0
  97. package/tsconfig.json +9 -0
  98. package/vite.config.ts +30 -0
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <div class="m-editor">
3
+ <slot name="nav" class="m-editor-nav-menu"></slot>
4
+
5
+ <magic-code-editor v-if="showSrc" class="m-editor-content" :init-values="root" @save="saveCode"></magic-code-editor>
6
+
7
+ <div class="m-editor-content" v-else>
8
+ <div class="m-editor-framework-left" :style="`width: ${columnWidth?.left}px`">
9
+ <slot name="sidebar"></slot>
10
+ </div>
11
+
12
+ <resizer type="left"></resizer>
13
+
14
+ <template v-if="pageLength > 0">
15
+ <div class="m-editor-framework-center" :style="`width: ${columnWidth?.center}px`">
16
+ <slot name="workspace"></slot>
17
+ </div>
18
+
19
+ <resizer type="right"></resizer>
20
+
21
+ <div class="m-editor-framework-right" :style="`width: ${columnWidth?.right}px`">
22
+ <el-scrollbar>
23
+ <slot name="propsPanel"></slot>
24
+ </el-scrollbar>
25
+ </div>
26
+ </template>
27
+
28
+ <slot v-else name="empty">
29
+ <add-page-box></add-page-box>
30
+ </slot>
31
+ </div>
32
+ </div>
33
+ </template>
34
+
35
+ <script lang="ts">
36
+ import { computed, defineComponent, inject } from 'vue';
37
+
38
+ import type { MApp } from '@tmagic/schema';
39
+
40
+ import { GetColumnWidth, Services } from '@editor/type';
41
+
42
+ import AddPageBox from './AddPageBox.vue';
43
+ import Resizer from './Resizer.vue';
44
+
45
+ export default defineComponent({
46
+ components: {
47
+ AddPageBox,
48
+ Resizer,
49
+ },
50
+
51
+ setup() {
52
+ const services = inject<Services>('services');
53
+
54
+ const root = computed(() => services?.editorService.get<MApp>('root'));
55
+
56
+ return {
57
+ root,
58
+ pageLength: computed(() => root.value?.items?.length || 0),
59
+ showSrc: computed(() => services?.uiService.get<boolean>('showSrc')),
60
+ columnWidth: computed(() => services?.uiService.get<GetColumnWidth>('columnWidth')),
61
+
62
+ saveCode(value: string) {
63
+ try {
64
+ // eslint-disable-next-line no-eval
65
+ services?.editorService.set('root', eval(value));
66
+ } catch (e: any) {
67
+ console.error(e);
68
+ }
69
+ },
70
+ };
71
+ },
72
+ });
73
+ </script>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <div class="m-editor-nav-menu" :style="{ height: `${height}px` }">
3
+ <div v-for="key in keys" :class="`menu-${key}`" :key="key">
4
+ <tool-button :data="item" v-for="(item, index) in data[key]" :key="index"></tool-button>
5
+ </div>
6
+ </div>
7
+ </template>
8
+
9
+ <script lang="ts">
10
+ import { computed, defineComponent, PropType } from 'vue';
11
+
12
+ import ToolButton from '@editor/components/ToolButton.vue';
13
+ import { MenuBarData } from '@editor/type';
14
+
15
+ export default defineComponent({
16
+ name: 'nav-menu',
17
+
18
+ components: { ToolButton },
19
+
20
+ props: {
21
+ data: {
22
+ type: Object as PropType<MenuBarData>,
23
+ default: () => ({}),
24
+ },
25
+
26
+ height: {
27
+ type: Number,
28
+ },
29
+ },
30
+
31
+ setup(props) {
32
+ return {
33
+ keys: computed(() => Object.keys(props.data) as Array<keyof MenuBarData>),
34
+ };
35
+ },
36
+ });
37
+ </script>
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <m-form
3
+ class="m-editor-props-panel"
4
+ ref="configForm"
5
+ size="small"
6
+ :init-values="values"
7
+ :config="curFormConfig"
8
+ @change="submit"
9
+ ></m-form>
10
+ </template>
11
+
12
+ <script lang="ts">
13
+ import { defineComponent, getCurrentInstance, inject, onMounted, ref, watchEffect } from 'vue';
14
+ import { ElMessage } from 'element-plus';
15
+
16
+ import type { FormValue, MForm } from '@tmagic/form';
17
+ import type { MNode } from '@tmagic/schema';
18
+
19
+ import type { Services } from '@editor/type';
20
+
21
+ export default defineComponent({
22
+ name: 'm-editor-props-panel',
23
+
24
+ emits: ['mounted'],
25
+
26
+ setup(props, { emit }) {
27
+ const internalInstance = getCurrentInstance();
28
+ const values = ref<FormValue>({});
29
+ const configForm = ref<InstanceType<typeof MForm>>();
30
+ // ts类型应该是FormConfig, 但是打包时会出错,所以暂时用any
31
+ const curFormConfig = ref<any>([]);
32
+ const services = inject<Services>('services');
33
+
34
+ const init = async () => {
35
+ const node = services?.editorService.get<MNode | null>('node');
36
+
37
+ if (!node) {
38
+ curFormConfig.value = [];
39
+ return;
40
+ }
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');
48
+ curFormConfig.value = (await services?.propsService.getPropsConfig(type)) || [];
49
+ };
50
+
51
+ watchEffect(init);
52
+ services?.propsService.on('props-configs-change', init);
53
+
54
+ onMounted(() => {
55
+ emit('mounted', internalInstance);
56
+ });
57
+
58
+ return {
59
+ values,
60
+ configForm,
61
+ curFormConfig,
62
+
63
+ async submit() {
64
+ try {
65
+ const values = await configForm.value?.submitForm();
66
+ services?.editorService.update(values);
67
+ } catch (e: any) {
68
+ console.error(e);
69
+ ElMessage.closeAll();
70
+ ElMessage.error({
71
+ duration: 10000,
72
+ showClose: true,
73
+ message: e.message,
74
+ dangerouslyUseHTMLString: true,
75
+ });
76
+ }
77
+ },
78
+ };
79
+ },
80
+ });
81
+ </script>
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <span ref="target" class="m-editor-resizer">
3
+ <slot></slot>
4
+ </span>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import { defineComponent, inject, onMounted, onUnmounted, ref, toRaw } from 'vue';
9
+ import Gesto from 'gesto';
10
+
11
+ import { Services } from '@editor/type';
12
+
13
+ export default defineComponent({
14
+ name: 'm-editor-resize',
15
+
16
+ props: {
17
+ type: {
18
+ type: String,
19
+ },
20
+ },
21
+
22
+ setup(props) {
23
+ const services = inject<Services>('services');
24
+
25
+ const target = ref<HTMLSpanElement>();
26
+
27
+ let getso: Gesto;
28
+
29
+ onMounted(() => {
30
+ if (!target.value) return;
31
+ getso = new Gesto(target.value, {
32
+ container: window,
33
+ pinchOutside: true,
34
+ }).on('drag', (e) => {
35
+ if (!target.value || !services) return;
36
+
37
+ let { left, right } = {
38
+ ...toRaw(services.uiService.get('columnWidth')),
39
+ };
40
+ if (props.type === 'left') {
41
+ left += e.deltaX;
42
+ } else if (props.type === 'right') {
43
+ right -= e.deltaX;
44
+ }
45
+ services.uiService.set('columnWidth', {
46
+ left,
47
+ right,
48
+ });
49
+ });
50
+ });
51
+
52
+ onUnmounted(() => {
53
+ getso?.unset();
54
+ });
55
+
56
+ return {
57
+ target,
58
+ };
59
+ },
60
+ });
61
+ </script>
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <el-scrollbar>
3
+ <el-collapse class="ui-component-panel" :model-value="collapseValue">
4
+ <el-input
5
+ prefix-icon="el-icon-search"
6
+ placeholder="输入关键字进行过滤"
7
+ class="search-input"
8
+ size="small"
9
+ clearable
10
+ v-model="searchText"
11
+ />
12
+ <template v-for="(group, index) in list">
13
+ <el-collapse-item v-if="group.items && group.items.length" :key="index" :name="index">
14
+ <template #title><i class="el-icon-s-grid"></i>{{ group.title }}</template>
15
+ <div class="component-item" v-for="item in group.items" :key="item.type" @click="appendComponent(item)">
16
+ <m-icon :icon="item.icon"></m-icon>
17
+
18
+ <el-tooltip effect="dark" placement="bottom" :content="item.text">
19
+ <span>{{ item.text }}</span>
20
+ </el-tooltip>
21
+ </div>
22
+ </el-collapse-item>
23
+ </template>
24
+ </el-collapse>
25
+ </el-scrollbar>
26
+ </template>
27
+
28
+ <script lang="ts">
29
+ import { computed, defineComponent, inject, ref } from 'vue';
30
+
31
+ import MIcon from '@editor/components/Icon.vue';
32
+ import type { ComponentGroup, ComponentItem, Services } from '@editor/type';
33
+
34
+ export default defineComponent({
35
+ name: 'ui-component-panel',
36
+
37
+ components: { MIcon },
38
+
39
+ setup() {
40
+ const searchText = ref('');
41
+ const services = inject<Services>('services');
42
+ const list = computed(() =>
43
+ services?.componentListService.getList().map((group: ComponentGroup) => ({
44
+ ...group,
45
+ items: group.items.filter((item: ComponentItem) => item.text.includes(searchText.value)),
46
+ })),
47
+ );
48
+ const collapseValue = computed(() =>
49
+ Array(list.value?.length)
50
+ .fill(1)
51
+ .map((x, i) => i),
52
+ );
53
+
54
+ return {
55
+ searchText,
56
+ collapseValue,
57
+ list,
58
+
59
+ appendComponent({ text, type, ...config }: ComponentItem): void {
60
+ services?.editorService.add({
61
+ name: text,
62
+ type,
63
+ ...config,
64
+ });
65
+ },
66
+ };
67
+ },
68
+ });
69
+ </script>
@@ -0,0 +1,117 @@
1
+ <template>
2
+ <div v-if="node" class="magic-editor-content-menu">
3
+ <div
4
+ v-if="node.items"
5
+ class="magic-editor-content-menu-item"
6
+ @mouseenter="setSubVisiable(true)"
7
+ @mouseleave="setSubVisiable(false)"
8
+ >
9
+ 新增
10
+ </div>
11
+ <div v-if="node.type !== 'app'" class="magic-editor-content-menu-item" @click="() => copy(node)">复制</div>
12
+ <div
13
+ v-if="node.type !== 'app' && node.type !== 'page'"
14
+ class="magic-editor-content-menu-item"
15
+ @click="() => remove()"
16
+ >
17
+ 删除
18
+ </div>
19
+ <div class="subMenu" v-show="subVisible" @mouseenter="setSubVisiable(true)" @mouseleave="setSubVisiable(false)">
20
+ <el-scrollbar>
21
+ <template v-if="node.type === 'tabs'">
22
+ <div
23
+ class="magic-editor-content-menu-item"
24
+ @click="
25
+ () =>
26
+ append({
27
+ type: 'tab-pane',
28
+ })
29
+ "
30
+ >
31
+ 标签
32
+ </div>
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
+ <template v-else-if="node.items">
47
+ <div v-for="list in menu.component" :key="list.title">
48
+ <template v-for="item in list.items">
49
+ <div class="magic-editor-content-menu-item" v-if="item" :key="item.type" @click="() => append(item)">
50
+ {{ item.text }}
51
+ </div>
52
+ </template>
53
+ <div class="separation"></div>
54
+ </div>
55
+ </template>
56
+ </el-scrollbar>
57
+ </div>
58
+ </div>
59
+ </template>
60
+
61
+ <script lang="ts">
62
+ import { computed, defineComponent, inject, PropType, ref } from 'vue';
63
+
64
+ import type { ComponentGroup, Services } from '@editor/type';
65
+
66
+ export default defineComponent({
67
+ name: 'magic-editor-content-menu',
68
+
69
+ props: {
70
+ componentGroupList: {
71
+ type: Array as PropType<ComponentGroup[]>,
72
+ default: () => [],
73
+ },
74
+ },
75
+
76
+ setup(props) {
77
+ const services = inject<Services>('services');
78
+ const subVisible = ref(false);
79
+ const node = computed(() => services?.editorService.get('node'));
80
+
81
+ return {
82
+ subVisible,
83
+
84
+ node,
85
+
86
+ menu: computed(() => ({
87
+ app: [
88
+ {
89
+ type: 'page',
90
+ text: '页面',
91
+ },
92
+ ],
93
+ component: props.componentGroupList,
94
+ })),
95
+
96
+ append(config: any) {
97
+ services?.editorService.add({
98
+ name: config.text,
99
+ type: config.type,
100
+ });
101
+ },
102
+
103
+ remove() {
104
+ node.value && services?.editorService.remove(node.value);
105
+ },
106
+
107
+ copy(node: any) {
108
+ services?.editorService.copy(node);
109
+ },
110
+
111
+ setSubVisiable(v: any) {
112
+ subVisible.value = v;
113
+ },
114
+ };
115
+ },
116
+ });
117
+ </script>
@@ -0,0 +1,209 @@
1
+ <template>
2
+ <el-scrollbar class="magic-editor-layer-panel">
3
+ <el-input
4
+ class="filterInput"
5
+ size="small"
6
+ placeholder="输入关键字进行过滤"
7
+ clearable
8
+ v-model="filterText"
9
+ @change="filterTextChangeHandler"
10
+ ></el-input>
11
+
12
+ <el-tree
13
+ v-if="values.length"
14
+ ref="tree"
15
+ node-key="id"
16
+ draggable
17
+ :load="loadItems"
18
+ :data="values"
19
+ :expand-on-click-node="false"
20
+ :highlight-current="true"
21
+ :props="{
22
+ children: 'items',
23
+ }"
24
+ :filter-node-method="filterNode"
25
+ :allow-drop="allowDrop"
26
+ @node-click="clickHandler"
27
+ @node-contextmenu="contextmenu"
28
+ @node-drag-end="handleDragEnd"
29
+ empty-text="页面空荡荡的"
30
+ >
31
+ <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>
37
+ </template>
38
+ </el-tree>
39
+
40
+ <teleport to="body">
41
+ <layer-menu :style="menuStyle"></layer-menu>
42
+ </teleport>
43
+ </el-scrollbar>
44
+ </template>
45
+
46
+ <script lang="ts">
47
+ import { computed, defineComponent, inject, onMounted, Ref, ref, watchEffect } from 'vue';
48
+ import type { ElTree } from 'element-plus';
49
+
50
+ import type { MNode, MPage } from '@tmagic/schema';
51
+
52
+ import type { EditorService } from '@editor/services/editor';
53
+ import type { Services } from '@editor/type';
54
+
55
+ import LayerMenu from './LayerMenu.vue';
56
+
57
+ const select = (data: MNode, editorService?: EditorService) => {
58
+ if (!data.id) {
59
+ throw new Error('没有id');
60
+ }
61
+
62
+ editorService?.select(data);
63
+ };
64
+
65
+ const useDrop = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => ({
66
+ allowDrop: (draggingNode: any, dropNode: any, type: string): boolean => {
67
+ const { data } = dropNode || {};
68
+ const { data: ingData } = draggingNode;
69
+
70
+ const { type: ingType } = ingData;
71
+
72
+ if (ingType !== 'page' && data.type === 'page') return false;
73
+ if (ingType === 'page' && data.type !== 'page') return false;
74
+ if (!data || !data.type) return false;
75
+ if (['prev', 'next'].includes(type)) return true;
76
+ if (data.items || data.type === 'container') return true;
77
+
78
+ return false;
79
+ },
80
+
81
+ handleDragEnd() {
82
+ if (!tree.value) return;
83
+ const { data } = tree.value;
84
+ const [page] = data as [MPage];
85
+ editorService?.update(page);
86
+ },
87
+ });
88
+
89
+ const useStatus = (tree: Ref<InstanceType<typeof ElTree> | undefined>, editorService?: EditorService) => {
90
+ const page = computed(() => editorService?.get('page'));
91
+
92
+ watchEffect(() => {
93
+ if (!tree.value) return;
94
+
95
+ const node = editorService?.get('node');
96
+ node && tree.value.setCurrentKey(node.id, true);
97
+
98
+ const parent = editorService?.get('parent');
99
+ if (!parent?.id) return;
100
+
101
+ const treeNode = tree.value.getNode(parent.id);
102
+ treeNode?.updateChildren();
103
+ });
104
+
105
+ return {
106
+ values: computed(() => (page.value ? [page.value] : [])),
107
+
108
+ loadItems: (node: any, resolve: Function) => {
109
+ if (Array.isArray(node.data)) {
110
+ return resolve(node.data);
111
+ }
112
+ if (Array.isArray(node.data?.items)) {
113
+ return resolve(node.data?.items);
114
+ }
115
+ resolve([]);
116
+ },
117
+ };
118
+ };
119
+
120
+ const useFilter = (tree: Ref<InstanceType<typeof ElTree> | undefined>) => ({
121
+ filterText: ref(''),
122
+
123
+ filterNode: (value: string, data: MNode): boolean => {
124
+ if (!value) {
125
+ return true;
126
+ }
127
+ let name = '';
128
+ if (data.name) {
129
+ name = data.name;
130
+ } else if (data.type) {
131
+ name = data.type;
132
+ } else if (data.items) {
133
+ name = 'container';
134
+ }
135
+ return name.indexOf(value) !== -1;
136
+ },
137
+
138
+ filterTextChangeHandler(val: string) {
139
+ tree.value?.filter(val);
140
+ },
141
+ });
142
+
143
+ const useContentMenu = (editorService?: EditorService) => {
144
+ const menuStyle = ref({
145
+ position: 'absolute',
146
+ left: '0',
147
+ top: '0',
148
+ display: 'none',
149
+ });
150
+
151
+ onMounted(() => {
152
+ document.addEventListener(
153
+ 'click',
154
+ () => {
155
+ menuStyle.value.display = 'none';
156
+ },
157
+ true,
158
+ );
159
+ });
160
+
161
+ return {
162
+ menuStyle,
163
+
164
+ contextmenu(event: MouseEvent, data: MNode) {
165
+ const bodyHeight = globalThis.document.body.clientHeight;
166
+
167
+ const left = `${event.clientX + 20}px`;
168
+ let top = `${event.clientY - 10}px`;
169
+
170
+ if (event.clientY + 300 > bodyHeight) {
171
+ top = `${bodyHeight - 300}px`;
172
+ }
173
+
174
+ menuStyle.value.left = left;
175
+ menuStyle.value.top = top;
176
+ menuStyle.value.display = '';
177
+
178
+ select(data, editorService);
179
+ },
180
+ };
181
+ };
182
+
183
+ export default defineComponent({
184
+ name: 'magic-editor-layer-panel',
185
+
186
+ components: { LayerMenu },
187
+
188
+ setup() {
189
+ const services = inject<Services>('services');
190
+ const tree = ref<InstanceType<typeof ElTree>>();
191
+ const editorService = services?.editorService;
192
+ return {
193
+ tree,
194
+ ...useDrop(tree, editorService),
195
+ ...useStatus(tree, editorService),
196
+ ...useFilter(tree),
197
+ ...useContentMenu(editorService),
198
+
199
+ clickHandler(data: MNode): void {
200
+ if (services?.uiService.get<boolean>('uiSelectMode')) {
201
+ document.dispatchEvent(new CustomEvent('ui-select', { detail: data }));
202
+ return;
203
+ }
204
+ select(data, editorService);
205
+ },
206
+ };
207
+ },
208
+ });
209
+ </script>