@tmagic/editor 1.3.0-alpha.1 → 1.3.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/style.css +46 -9
- package/dist/tmagic-editor.js +1764 -871
- package/dist/tmagic-editor.js.map +1 -1
- package/dist/tmagic-editor.umd.cjs +1780 -882
- package/dist/tmagic-editor.umd.cjs.map +1 -1
- package/package.json +19 -20
- package/src/Editor.vue +29 -3
- package/src/components/CodeDraftEditor.vue +5 -1
- package/src/components/ContentMenu.vue +30 -11
- package/src/components/FunctionEditor.vue +12 -5
- package/src/components/Icon.vue +5 -1
- package/src/components/Resizer.vue +45 -0
- package/src/components/ScrollBar.vue +5 -1
- package/src/components/ScrollViewer.vue +5 -1
- package/src/components/SearchInput.vue +4 -0
- package/src/components/{Layout.vue → SplitView.vue} +8 -4
- package/src/components/ToolButton.vue +5 -1
- package/src/editorProps.ts +5 -1
- package/src/fields/Code.vue +5 -1
- package/src/fields/CodeLink.vue +9 -3
- package/src/fields/CodeSelect.vue +8 -2
- package/src/fields/CodeSelectCol.vue +6 -2
- package/src/fields/DataSourceFields.vue +5 -1
- package/src/fields/DataSourceInput.vue +358 -0
- package/src/fields/DataSourceSelect.vue +75 -0
- package/src/fields/EventSelect.vue +9 -3
- package/src/fields/KeyValue.vue +4 -0
- package/src/fields/UISelect.vue +5 -1
- package/src/icons/AppManageIcon.vue +5 -1
- package/src/icons/CenterIcon.vue +13 -0
- package/src/icons/CodeIcon.vue +5 -1
- package/src/index.ts +12 -3
- package/src/initService.ts +73 -0
- package/src/layouts/AddPageBox.vue +5 -1
- package/src/layouts/CodeEditor.vue +34 -10
- package/src/layouts/Framework.vue +25 -25
- package/src/layouts/NavMenu.vue +5 -1
- package/src/layouts/PropsPanel.vue +14 -4
- package/src/layouts/sidebar/ComponentListPanel.vue +8 -5
- package/src/layouts/sidebar/LayerMenu.vue +13 -25
- package/src/layouts/sidebar/LayerNode.vue +40 -0
- package/src/layouts/sidebar/LayerPanel.vue +70 -27
- package/src/layouts/sidebar/Sidebar.vue +11 -7
- package/src/layouts/sidebar/code-block/CodeBlockEditor.vue +8 -4
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +5 -1
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +4 -0
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +22 -2
- package/src/layouts/workspace/Breadcrumb.vue +5 -1
- package/src/layouts/workspace/PageBar.vue +5 -1
- package/src/layouts/workspace/PageBarScrollContainer.vue +5 -1
- package/src/layouts/workspace/Stage.vue +29 -7
- package/src/layouts/workspace/ViewerMenu.vue +15 -36
- package/src/layouts/workspace/Workspace.vue +9 -134
- package/src/services/codeBlock.ts +3 -2
- package/src/services/dep.ts +4 -0
- package/src/services/keybinding.ts +185 -0
- package/src/services/storage.ts +3 -2
- package/src/theme/content-menu.scss +1 -1
- package/src/theme/data-source-input.scss +18 -0
- package/src/theme/framework.scss +0 -3
- package/src/theme/layer-panel.scss +6 -0
- package/src/theme/layout.scss +4 -0
- package/src/theme/resizer.scss +25 -10
- package/src/theme/stage.scss +4 -0
- package/src/theme/theme.scss +1 -0
- package/src/type.ts +59 -1
- package/src/utils/config.ts +1 -1
- package/src/utils/content-menu.ts +92 -0
- package/src/utils/dep.ts +7 -1
- package/src/utils/keybinding-config.ts +120 -0
- package/src/utils/props.ts +34 -0
- package/types/Editor.vue.d.ts +7 -1
- package/types/components/CodeDraftEditor.vue.d.ts +6 -3
- package/types/components/ContentMenu.vue.d.ts +10 -5
- package/types/components/FunctionEditor.vue.d.ts +74 -51
- package/types/components/Icon.vue.d.ts +2 -2
- package/types/{layouts → components}/Resizer.vue.d.ts +2 -2
- package/types/components/ScrollBar.vue.d.ts +1 -1
- package/types/components/ScrollViewer.vue.d.ts +8 -5
- package/types/components/SearchInput.vue.d.ts +1 -1
- package/types/components/{Layout.vue.d.ts → SplitView.vue.d.ts} +9 -6
- package/types/components/ToolButton.vue.d.ts +8 -5
- package/types/editorProps.d.ts +4 -1
- package/types/fields/Code.vue.d.ts +1 -1
- package/types/fields/CodeLink.vue.d.ts +9 -9
- package/types/fields/CodeSelect.vue.d.ts +10 -7
- package/types/fields/CodeSelectCol.vue.d.ts +8 -5
- package/types/fields/DataSourceFields.vue.d.ts +8 -5
- package/types/fields/DataSourceInput.vue.d.ts +54 -0
- package/types/fields/DataSourceSelect.vue.d.ts +56 -0
- package/types/fields/EventSelect.vue.d.ts +3 -3
- package/types/fields/KeyValue.vue.d.ts +8 -5
- package/types/fields/UISelect.vue.d.ts +1 -1
- package/types/icons/AppManageIcon.vue.d.ts +1 -1
- package/types/icons/CenterIcon.vue.d.ts +2 -0
- package/types/icons/CodeIcon.vue.d.ts +1 -1
- package/types/index.d.ts +6 -2
- package/types/initService.d.ts +1 -1
- package/types/layouts/AddPageBox.vue.d.ts +1 -1
- package/types/layouts/CodeEditor.vue.d.ts +16 -10
- package/types/layouts/Framework.vue.d.ts +11 -32
- package/types/layouts/NavMenu.vue.d.ts +7 -4
- package/types/layouts/PropsPanel.vue.d.ts +276 -4
- package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +4 -4
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +2 -2
- package/types/layouts/sidebar/LayerNode.vue.d.ts +16 -0
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +5 -5
- package/types/layouts/sidebar/Sidebar.vue.d.ts +18 -15
- package/types/layouts/sidebar/code-block/CodeBlockEditor.vue.d.ts +4 -4
- package/types/layouts/sidebar/code-block/CodeBlockList.vue.d.ts +7 -7
- package/types/layouts/sidebar/data-source/DataSourceConfigPanel.vue.d.ts +1 -1
- package/types/layouts/sidebar/data-source/DataSourceListPanel.vue.d.ts +3 -3
- package/types/layouts/workspace/Breadcrumb.vue.d.ts +1 -1
- package/types/layouts/workspace/PageBar.vue.d.ts +5 -5
- package/types/layouts/workspace/PageBarScrollContainer.vue.d.ts +2 -2
- package/types/layouts/workspace/Stage.vue.d.ts +2 -2
- package/types/layouts/workspace/ViewerMenu.vue.d.ts +7 -4
- package/types/layouts/workspace/Workspace.vue.d.ts +9 -9
- package/types/services/keybinding.d.ts +20 -0
- package/types/type.d.ts +56 -1
- package/types/utils/config.d.ts +1 -1
- package/types/utils/content-menu.d.ts +7 -0
- package/types/utils/keybinding-config.d.ts +3 -0
- package/src/layouts/Resizer.vue +0 -32
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
ref="tree"
|
|
11
11
|
node-key="id"
|
|
12
12
|
empty-text="页面空荡荡的"
|
|
13
|
+
tabindex="-1"
|
|
13
14
|
draggable
|
|
14
15
|
:default-expanded-keys="expandedKeys"
|
|
15
16
|
:default-checked-keys="checkedKeys"
|
|
@@ -34,9 +35,7 @@
|
|
|
34
35
|
<template #default="{ node, data }">
|
|
35
36
|
<div class="cus-tree-node" :id="data.id" @mouseenter="highlightHandler(data)">
|
|
36
37
|
<slot name="layer-node-content" :node="node" :data="data">
|
|
37
|
-
<
|
|
38
|
-
{{ `${data.name} (${data.id})` }}
|
|
39
|
-
</span>
|
|
38
|
+
<LayerNode :data="data"></LayerNode>
|
|
40
39
|
</slot>
|
|
41
40
|
</div>
|
|
42
41
|
</template>
|
|
@@ -48,9 +47,8 @@
|
|
|
48
47
|
</TMagicScrollbar>
|
|
49
48
|
</template>
|
|
50
49
|
|
|
51
|
-
<script lang="ts" setup
|
|
52
|
-
import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
53
|
-
import KeyController from 'keycon';
|
|
50
|
+
<script lang="ts" setup>
|
|
51
|
+
import { computed, inject, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
54
52
|
import { difference, throttle, union } from 'lodash-es';
|
|
55
53
|
|
|
56
54
|
import { TMagicScrollbar, TMagicTree } from '@tmagic/design';
|
|
@@ -63,6 +61,11 @@ import type { MenuButton, MenuComponent, Services } from '@editor/type';
|
|
|
63
61
|
import { Layout } from '@editor/type';
|
|
64
62
|
|
|
65
63
|
import LayerMenu from './LayerMenu.vue';
|
|
64
|
+
import LayerNode from './LayerNode.vue';
|
|
65
|
+
|
|
66
|
+
defineOptions({
|
|
67
|
+
name: 'MEditorLayerPanel',
|
|
68
|
+
});
|
|
66
69
|
|
|
67
70
|
defineProps<{
|
|
68
71
|
layerContentMenu: (MenuButton | MenuComponent)[];
|
|
@@ -71,6 +74,7 @@ defineProps<{
|
|
|
71
74
|
const throttleTime = 150;
|
|
72
75
|
const services = inject<Services>('services');
|
|
73
76
|
const editorService = services?.editorService;
|
|
77
|
+
const keybindingService = services?.keybindingService;
|
|
74
78
|
|
|
75
79
|
const tree = ref<InstanceType<typeof TMagicTree>>();
|
|
76
80
|
const menu = ref<InstanceType<typeof LayerMenu>>();
|
|
@@ -242,34 +246,69 @@ const windowBlurHandler = () => {
|
|
|
242
246
|
isCtrlKeyDown.value = false;
|
|
243
247
|
};
|
|
244
248
|
|
|
245
|
-
|
|
249
|
+
keybindingService?.registeCommand('layer-panel-not-ctrl-keydown', (e) => {
|
|
250
|
+
if (e.key !== keybindingService.ctrlKey) {
|
|
251
|
+
isCtrlKeyDown.value = false;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
keybindingService?.registeCommand('layer-panel-ctrl-keydown', () => {
|
|
256
|
+
isCtrlKeyDown.value = true;
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
keybindingService?.registeCommand('layer-panel-ctrl-keyup', () => {
|
|
260
|
+
isCtrlKeyDown.value = false;
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
keybindingService?.registeCommand('layer-panel-global-keydwon', () => {
|
|
264
|
+
if (!tree.value?.$el.contains(document.activeElement)) {
|
|
265
|
+
isCtrlKeyDown.value = false;
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
keybindingService?.registe([
|
|
270
|
+
{
|
|
271
|
+
command: 'layer-panel-not-ctrl-keydown',
|
|
272
|
+
when: [['layer-panel', 'keydown']],
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
command: 'layer-panel-ctrl-keydown',
|
|
276
|
+
keybinding: 'ctrl',
|
|
277
|
+
when: [['layer-panel', 'keydown']],
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
command: 'layer-panel-ctrl-keyup',
|
|
281
|
+
keybinding: 'ctrl',
|
|
282
|
+
when: [['layer-panel', 'keyup']],
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
command: 'layer-panel-global-keydwon',
|
|
286
|
+
keybinding: 'ctrl',
|
|
287
|
+
when: [['global', 'keydown']],
|
|
288
|
+
},
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
watch(tree, () => {
|
|
292
|
+
if (tree.value?.$el) {
|
|
293
|
+
keybindingService?.registeEl('layer-panel', tree.value.$el);
|
|
294
|
+
|
|
295
|
+
tree.value.$el.addEventListener('blur', windowBlurHandler);
|
|
296
|
+
} else {
|
|
297
|
+
keybindingService?.unregisteEl('layer-panel');
|
|
298
|
+
}
|
|
299
|
+
});
|
|
246
300
|
|
|
247
301
|
onMounted(() => {
|
|
248
302
|
editorService?.on('remove', editorServiceRemoveHandler);
|
|
249
303
|
|
|
250
|
-
keycon = new KeyController();
|
|
251
|
-
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
252
|
-
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
253
|
-
|
|
254
|
-
keycon
|
|
255
|
-
.keydown((e) => {
|
|
256
|
-
if (e.key !== ctrl) {
|
|
257
|
-
isCtrlKeyDown.value = false;
|
|
258
|
-
}
|
|
259
|
-
})
|
|
260
|
-
.keydown(ctrl, () => {
|
|
261
|
-
isCtrlKeyDown.value = true;
|
|
262
|
-
})
|
|
263
|
-
.keyup(ctrl, () => {
|
|
264
|
-
isCtrlKeyDown.value = false;
|
|
265
|
-
});
|
|
266
|
-
|
|
267
304
|
globalThis.addEventListener('blur', windowBlurHandler);
|
|
268
305
|
});
|
|
269
306
|
|
|
270
|
-
|
|
271
|
-
|
|
307
|
+
onBeforeUnmount(() => {
|
|
308
|
+
tree.value?.$el.removeEventListener('blur', windowBlurHandler);
|
|
309
|
+
});
|
|
272
310
|
|
|
311
|
+
onUnmounted(() => {
|
|
273
312
|
editorService?.off('remove', editorServiceRemoveHandler);
|
|
274
313
|
globalThis.removeEventListener('blur', windowBlurHandler);
|
|
275
314
|
});
|
|
@@ -310,7 +349,11 @@ const clickHandler = (data: MNode): void => {
|
|
|
310
349
|
// 右键菜单
|
|
311
350
|
const contextmenu = async (event: MouseEvent, data: MNode): Promise<void> => {
|
|
312
351
|
event.preventDefault();
|
|
313
|
-
|
|
352
|
+
|
|
353
|
+
if (nodes.value.length < 2) {
|
|
354
|
+
await select(data);
|
|
355
|
+
}
|
|
356
|
+
|
|
314
357
|
menu.value?.show(event);
|
|
315
358
|
};
|
|
316
359
|
</script>
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
v-if="data.type === 'tabs' && data.items.length"
|
|
4
4
|
v-model="activeTabName"
|
|
5
5
|
class="m-editor-sidebar tmagic-design-tabs"
|
|
6
|
-
v-bind="tabsComponent
|
|
7
|
-
:is="tabsComponent
|
|
6
|
+
v-bind="tabsComponent?.props({ type: 'card', tabPosition: 'left' }) || {}"
|
|
7
|
+
:is="tabsComponent?.component || 'el-tabs'"
|
|
8
8
|
>
|
|
9
9
|
<component
|
|
10
10
|
v-for="(config, index) in sideBarItems"
|
|
11
|
-
v-bind="tabPaneComponent
|
|
12
|
-
:is="tabPaneComponent
|
|
11
|
+
v-bind="tabPaneComponent?.props({ name: config.text, lazy: config.lazy }) || {}"
|
|
12
|
+
:is="tabPaneComponent?.component || 'el-tab-pane'"
|
|
13
13
|
:key="config.$key || index"
|
|
14
14
|
>
|
|
15
15
|
<template #label>
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
</component>
|
|
84
84
|
</template>
|
|
85
85
|
|
|
86
|
-
<script lang="ts" setup
|
|
86
|
+
<script lang="ts" setup>
|
|
87
87
|
import { computed, ref, watch } from 'vue';
|
|
88
88
|
import { Coin, EditPen, Goods, List } from '@element-plus/icons-vue';
|
|
89
89
|
|
|
@@ -98,6 +98,10 @@ import DataSourceListPanel from './data-source/DataSourceListPanel.vue';
|
|
|
98
98
|
import ComponentListPanel from './ComponentListPanel.vue';
|
|
99
99
|
import LayerPanel from './LayerPanel.vue';
|
|
100
100
|
|
|
101
|
+
defineOptions({
|
|
102
|
+
name: 'MEditorSidebar',
|
|
103
|
+
});
|
|
104
|
+
|
|
101
105
|
const props = withDefaults(
|
|
102
106
|
defineProps<{
|
|
103
107
|
data: SideBarData;
|
|
@@ -108,8 +112,8 @@ const props = withDefaults(
|
|
|
108
112
|
},
|
|
109
113
|
);
|
|
110
114
|
|
|
111
|
-
const tabPaneComponent = getConfig('components')
|
|
112
|
-
const tabsComponent = getConfig('components')
|
|
115
|
+
const tabPaneComponent = getConfig('components')?.tabPane;
|
|
116
|
+
const tabsComponent = getConfig('components')?.tabs;
|
|
113
117
|
|
|
114
118
|
const activeTabName = ref(props.data?.status);
|
|
115
119
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
:size="size"
|
|
11
11
|
:before-close="handleClose"
|
|
12
12
|
>
|
|
13
|
-
<
|
|
13
|
+
<SplitView v-model:left="left" :min-left="45" class="code-editor-layout">
|
|
14
14
|
<!-- 右侧区域 -->
|
|
15
15
|
<template #center>
|
|
16
16
|
<div v-if="!isEmpty(codeConfig)" class="m-editor-code-block-editor-panel">
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
></FunctionEditor>
|
|
29
29
|
</div>
|
|
30
30
|
</template>
|
|
31
|
-
</
|
|
31
|
+
</SplitView>
|
|
32
32
|
</TMagicDrawer>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
|
-
<script lang="ts" setup
|
|
35
|
+
<script lang="ts" setup>
|
|
36
36
|
import { computed, inject, reactive, ref, watchEffect } from 'vue';
|
|
37
37
|
import { cloneDeep, forIn, isEmpty } from 'lodash-es';
|
|
38
38
|
|
|
@@ -41,10 +41,14 @@ import { ColumnConfig } from '@tmagic/form';
|
|
|
41
41
|
import { CodeBlockContent } from '@tmagic/schema';
|
|
42
42
|
|
|
43
43
|
import FunctionEditor from '@editor/components/FunctionEditor.vue';
|
|
44
|
-
import
|
|
44
|
+
import SplitView from '@editor/components/SplitView.vue';
|
|
45
45
|
import type { ListState, Services } from '@editor/type';
|
|
46
46
|
import { serializeConfig } from '@editor/utils/editor';
|
|
47
47
|
|
|
48
|
+
defineOptions({
|
|
49
|
+
name: 'MEditorCodeBlockEditor',
|
|
50
|
+
});
|
|
51
|
+
|
|
48
52
|
const services = inject<Services>('services');
|
|
49
53
|
const codeOptions = inject('codeOptions', {});
|
|
50
54
|
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
</TMagicScrollbar>
|
|
56
56
|
</template>
|
|
57
57
|
|
|
58
|
-
<script setup lang="ts"
|
|
58
|
+
<script setup lang="ts">
|
|
59
59
|
import { computed, inject, ref } from 'vue';
|
|
60
60
|
import { Close, Edit, View } from '@element-plus/icons-vue';
|
|
61
61
|
|
|
@@ -71,6 +71,10 @@ import { CodeDeleteErrorType, CodeDslItem, Services } from '@editor/type';
|
|
|
71
71
|
|
|
72
72
|
import CodeBlockEditor from './CodeBlockEditor.vue';
|
|
73
73
|
|
|
74
|
+
defineOptions({
|
|
75
|
+
name: 'MEditorCodeBlockList',
|
|
76
|
+
});
|
|
77
|
+
|
|
74
78
|
const props = defineProps<{
|
|
75
79
|
customError?: (id: Id, errorType: CodeDeleteErrorType) => any;
|
|
76
80
|
paramsColConfig?: ColumnConfig;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
:expand-on-click-node="false"
|
|
16
16
|
:data="list"
|
|
17
17
|
:highlight-current="true"
|
|
18
|
+
@node-click="clickHandler"
|
|
18
19
|
>
|
|
19
20
|
<template #default="{ data }">
|
|
20
21
|
<div :id="data.id" class="list-container">
|
|
@@ -53,7 +54,7 @@ import { computed, inject, ref } from 'vue';
|
|
|
53
54
|
import { Aim, Close, Coin, Edit } from '@element-plus/icons-vue';
|
|
54
55
|
|
|
55
56
|
import { TMagicButton, tMagicMessageBox, TMagicScrollbar, TMagicTooltip, TMagicTree } from '@tmagic/design';
|
|
56
|
-
import { DataSourceSchema } from '@tmagic/schema';
|
|
57
|
+
import { DataSourceSchema, Id } from '@tmagic/schema';
|
|
57
58
|
|
|
58
59
|
import Icon from '@editor/components/Icon.vue';
|
|
59
60
|
import SearchInput from '@editor/components/SearchInput.vue';
|
|
@@ -61,8 +62,12 @@ import type { Services } from '@editor/type';
|
|
|
61
62
|
|
|
62
63
|
import DataSourceConfigPanel from './DataSourceConfigPanel.vue';
|
|
63
64
|
|
|
65
|
+
defineOptions({
|
|
66
|
+
name: 'MEditorDataSourceListPanel',
|
|
67
|
+
});
|
|
68
|
+
|
|
64
69
|
const services = inject<Partial<Services>>('services', {});
|
|
65
|
-
const { dataSourceService, depService } = inject<Services>('services') || {};
|
|
70
|
+
const { dataSourceService, depService, editorService } = inject<Services>('services') || {};
|
|
66
71
|
|
|
67
72
|
const list = computed(() =>
|
|
68
73
|
Object.values(depService?.targets['data-source'] || {}).map((target) => ({
|
|
@@ -127,4 +132,19 @@ const tree = ref<InstanceType<typeof TMagicTree>>();
|
|
|
127
132
|
const filterTextChangeHandler = (val: string) => {
|
|
128
133
|
tree.value?.filter(val);
|
|
129
134
|
};
|
|
135
|
+
|
|
136
|
+
// 选中组件
|
|
137
|
+
const selectComp = (compId: Id) => {
|
|
138
|
+
const stage = editorService?.get('stage');
|
|
139
|
+
editorService?.select(compId);
|
|
140
|
+
stage?.select(compId);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const clickHandler = (data: any, node: any) => {
|
|
144
|
+
if (data.type === 'node') {
|
|
145
|
+
selectComp(data.id);
|
|
146
|
+
} else if (data.type === 'key') {
|
|
147
|
+
selectComp(node.parent.data.id);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
130
150
|
</script>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</div>
|
|
8
8
|
</template>
|
|
9
9
|
|
|
10
|
-
<script setup lang="ts"
|
|
10
|
+
<script setup lang="ts">
|
|
11
11
|
import { computed, inject } from 'vue';
|
|
12
12
|
|
|
13
13
|
import { TMagicButton } from '@tmagic/design';
|
|
@@ -16,6 +16,10 @@ import { getNodePath } from '@tmagic/utils';
|
|
|
16
16
|
|
|
17
17
|
import type { Services } from '@editor/type';
|
|
18
18
|
|
|
19
|
+
defineOptions({
|
|
20
|
+
name: 'MEditorBreadcrumb',
|
|
21
|
+
});
|
|
22
|
+
|
|
19
23
|
const services = inject<Services>('services');
|
|
20
24
|
const editorService = services?.editorService;
|
|
21
25
|
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</PageBarScrollContainer>
|
|
47
47
|
</template>
|
|
48
48
|
|
|
49
|
-
<script lang="ts" setup
|
|
49
|
+
<script lang="ts" setup>
|
|
50
50
|
import { computed, inject } from 'vue';
|
|
51
51
|
import { CaretBottom, Delete, DocumentCopy } from '@element-plus/icons-vue';
|
|
52
52
|
|
|
@@ -58,6 +58,10 @@ import type { Services } from '@editor/type';
|
|
|
58
58
|
|
|
59
59
|
import PageBarScrollContainer from './PageBarScrollContainer.vue';
|
|
60
60
|
|
|
61
|
+
defineOptions({
|
|
62
|
+
name: 'MEditorPageBar',
|
|
63
|
+
});
|
|
64
|
+
|
|
61
65
|
const services = inject<Services>('services');
|
|
62
66
|
const editorService = services?.editorService;
|
|
63
67
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
</template>
|
|
28
28
|
|
|
29
|
-
<script setup lang="ts"
|
|
29
|
+
<script setup lang="ts">
|
|
30
30
|
import { computed, inject, nextTick, onMounted, onUnmounted, ref, toRaw, watch } from 'vue';
|
|
31
31
|
import { ArrowLeftBold, ArrowRightBold, Plus } from '@element-plus/icons-vue';
|
|
32
32
|
|
|
@@ -36,6 +36,10 @@ import Icon from '@editor/components/Icon.vue';
|
|
|
36
36
|
import type { Services } from '@editor/type';
|
|
37
37
|
import { generatePageNameByApp } from '@editor/utils/editor';
|
|
38
38
|
|
|
39
|
+
defineOptions({
|
|
40
|
+
name: 'MEditorPageBarScrollContainer',
|
|
41
|
+
});
|
|
42
|
+
|
|
39
43
|
const services = inject<Services>('services');
|
|
40
44
|
const editorService = services?.editorService;
|
|
41
45
|
const uiService = services?.uiService;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<ScrollViewer
|
|
3
3
|
class="m-editor-stage"
|
|
4
4
|
ref="stageWrap"
|
|
5
|
+
tabindex="-1"
|
|
5
6
|
:width="stageRect?.width"
|
|
6
7
|
:height="stageRect?.height"
|
|
7
8
|
:wrap-width="stageContainerRect?.width"
|
|
@@ -11,6 +12,7 @@
|
|
|
11
12
|
width: 60,
|
|
12
13
|
height: 50,
|
|
13
14
|
}"
|
|
15
|
+
@click="stageWrap?.container?.focus()"
|
|
14
16
|
>
|
|
15
17
|
<div
|
|
16
18
|
class="m-editor-stage-container"
|
|
@@ -26,7 +28,7 @@
|
|
|
26
28
|
</ScrollViewer>
|
|
27
29
|
</template>
|
|
28
30
|
|
|
29
|
-
<script lang="ts" setup
|
|
31
|
+
<script lang="ts" setup>
|
|
30
32
|
import { computed, inject, markRaw, nextTick, onMounted, onUnmounted, ref, toRaw, watch, watchEffect } from 'vue';
|
|
31
33
|
import { cloneDeep } from 'lodash-es';
|
|
32
34
|
|
|
@@ -35,10 +37,15 @@ import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stag
|
|
|
35
37
|
|
|
36
38
|
import ScrollViewer from '@editor/components/ScrollViewer.vue';
|
|
37
39
|
import { Layout, MenuButton, MenuComponent, Services, StageOptions } from '@editor/type';
|
|
40
|
+
import { getConfig } from '@editor/utils/config';
|
|
38
41
|
import { useStage } from '@editor/utils/stage';
|
|
39
42
|
|
|
40
43
|
import ViewerMenu from './ViewerMenu.vue';
|
|
41
44
|
|
|
45
|
+
defineOptions({
|
|
46
|
+
name: 'MEditorStage',
|
|
47
|
+
});
|
|
48
|
+
|
|
42
49
|
defineProps<{
|
|
43
50
|
stageContentMenu: (MenuButton | MenuComponent)[];
|
|
44
51
|
}>();
|
|
@@ -70,6 +77,10 @@ watchEffect(() => {
|
|
|
70
77
|
|
|
71
78
|
stage = useStage(stageOptions);
|
|
72
79
|
|
|
80
|
+
stage.on('select', () => {
|
|
81
|
+
stageWrap.value?.container?.focus();
|
|
82
|
+
});
|
|
83
|
+
|
|
73
84
|
services?.editorService.set('stage', markRaw(stage));
|
|
74
85
|
|
|
75
86
|
stage?.mount(stageContainer.value);
|
|
@@ -116,13 +127,17 @@ const resizeObserver = new ResizeObserver((entries) => {
|
|
|
116
127
|
});
|
|
117
128
|
|
|
118
129
|
onMounted(() => {
|
|
119
|
-
|
|
130
|
+
if (stageWrap.value?.container) {
|
|
131
|
+
resizeObserver.observe(stageWrap.value.container);
|
|
132
|
+
services?.keybindingService.registeEl('stage', stageWrap.value.container);
|
|
133
|
+
}
|
|
120
134
|
});
|
|
121
135
|
|
|
122
136
|
onUnmounted(() => {
|
|
123
137
|
stage?.destroy();
|
|
124
138
|
resizeObserver.disconnect();
|
|
125
139
|
services?.editorService.set('stage', null);
|
|
140
|
+
services?.keybindingService.unregisteEl('stage');
|
|
126
141
|
});
|
|
127
142
|
|
|
128
143
|
const contextmenuHandler = (e: MouseEvent) => {
|
|
@@ -132,9 +147,8 @@ const contextmenuHandler = (e: MouseEvent) => {
|
|
|
132
147
|
|
|
133
148
|
const dragoverHandler = (e: DragEvent) => {
|
|
134
149
|
e.preventDefault();
|
|
135
|
-
if (e.dataTransfer)
|
|
136
|
-
|
|
137
|
-
}
|
|
150
|
+
if (!e.dataTransfer) return;
|
|
151
|
+
e.dataTransfer.dropEffect = 'move';
|
|
138
152
|
};
|
|
139
153
|
|
|
140
154
|
const dropHandler = async (e: DragEvent) => {
|
|
@@ -149,8 +163,16 @@ const dropHandler = async (e: DragEvent) => {
|
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
if (e.dataTransfer && parent && stageContainer.value && stage) {
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
const parseDSL = getConfig('parseDSL');
|
|
167
|
+
|
|
168
|
+
const data = e.dataTransfer.getData('text/html');
|
|
169
|
+
|
|
170
|
+
if (!data) return;
|
|
171
|
+
|
|
172
|
+
const config = parseDSL(`(${data})`);
|
|
173
|
+
|
|
174
|
+
if (!config) return;
|
|
175
|
+
|
|
154
176
|
const layout = await services?.editorService.getLayout(parent);
|
|
155
177
|
|
|
156
178
|
const containerRect = stageContainer.value.getBoundingClientRect();
|
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
<content-menu :menu-data="menuData" ref="menu"></content-menu>
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
|
-
<script lang="ts" setup
|
|
5
|
+
<script lang="ts" setup>
|
|
6
6
|
import { computed, inject, markRaw, ref, watch } from 'vue';
|
|
7
|
-
import { Bottom,
|
|
7
|
+
import { Bottom, Top } from '@element-plus/icons-vue';
|
|
8
8
|
|
|
9
9
|
import { NodeType } from '@tmagic/schema';
|
|
10
10
|
import { isPage } from '@tmagic/utils';
|
|
11
11
|
|
|
12
12
|
import ContentMenu from '@editor/components/ContentMenu.vue';
|
|
13
|
+
import CenterIcon from '@editor/icons/CenterIcon.vue';
|
|
13
14
|
import storageService from '@editor/services/storage';
|
|
14
15
|
import { LayerOffset, Layout, MenuButton, MenuComponent, Services } from '@editor/type';
|
|
16
|
+
import { useCopyMenu, useDeleteMenu, useMoveToMenu, usePasteMenu } from '@editor/utils/content-menu';
|
|
15
17
|
import { COPY_STORAGE_KEY } from '@editor/utils/editor';
|
|
16
18
|
|
|
19
|
+
defineOptions({
|
|
20
|
+
name: 'MEditorViewerMenu',
|
|
21
|
+
});
|
|
22
|
+
|
|
17
23
|
const props = withDefaults(
|
|
18
24
|
defineProps<{ isMultiSelect?: boolean; stageContentMenu: (MenuButton | MenuComponent)[] }>(),
|
|
19
25
|
{ isMultiSelect: false },
|
|
@@ -28,42 +34,20 @@ const canCenter = ref(false);
|
|
|
28
34
|
const node = computed(() => editorService?.get('node'));
|
|
29
35
|
const nodes = computed(() => editorService?.get('nodes'));
|
|
30
36
|
const parent = computed(() => editorService?.get('parent'));
|
|
31
|
-
const stage = computed(() => editorService?.get('stage'));
|
|
32
37
|
|
|
33
38
|
const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
34
39
|
{
|
|
35
40
|
type: 'button',
|
|
36
41
|
text: '水平居中',
|
|
42
|
+
icon: markRaw(CenterIcon),
|
|
37
43
|
display: () => canCenter.value,
|
|
38
44
|
handler: () => {
|
|
39
45
|
if (!nodes.value) return;
|
|
40
46
|
editorService?.alignCenter(nodes.value);
|
|
41
47
|
},
|
|
42
48
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
text: '复制',
|
|
46
|
-
icon: markRaw(CopyDocument),
|
|
47
|
-
handler: () => {
|
|
48
|
-
nodes.value && editorService?.copy(nodes.value);
|
|
49
|
-
canPaste.value = true;
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
type: 'button',
|
|
54
|
-
text: '粘贴',
|
|
55
|
-
icon: markRaw(DocumentCopy),
|
|
56
|
-
display: () => canPaste.value,
|
|
57
|
-
handler: () => {
|
|
58
|
-
const rect = menu.value?.$el.getBoundingClientRect();
|
|
59
|
-
const parentRect = stage.value?.container?.getBoundingClientRect();
|
|
60
|
-
const initialLeft = (rect?.left || 0) - (parentRect?.left || 0);
|
|
61
|
-
const initialTop = (rect?.top || 0) - (parentRect?.top || 0);
|
|
62
|
-
|
|
63
|
-
if (!nodes.value || nodes.value.length === 0) return;
|
|
64
|
-
editorService?.paste({ left: initialLeft, top: initialTop });
|
|
65
|
-
},
|
|
66
|
-
},
|
|
49
|
+
useCopyMenu(),
|
|
50
|
+
usePasteMenu(menu),
|
|
67
51
|
{
|
|
68
52
|
type: 'divider',
|
|
69
53
|
direction: 'horizontal',
|
|
@@ -93,6 +77,7 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
|
93
77
|
{
|
|
94
78
|
type: 'button',
|
|
95
79
|
text: '置顶',
|
|
80
|
+
icon: markRaw(Top),
|
|
96
81
|
display: () => !isPage(node.value) && !props.isMultiSelect,
|
|
97
82
|
handler: () => {
|
|
98
83
|
editorService?.moveLayer(LayerOffset.TOP);
|
|
@@ -101,25 +86,19 @@ const menuData = computed<(MenuButton | MenuComponent)[]>(() => [
|
|
|
101
86
|
{
|
|
102
87
|
type: 'button',
|
|
103
88
|
text: '置底',
|
|
89
|
+
icon: markRaw(Bottom),
|
|
104
90
|
display: () => !isPage(node.value) && !props.isMultiSelect,
|
|
105
91
|
handler: () => {
|
|
106
92
|
editorService?.moveLayer(LayerOffset.BOTTOM);
|
|
107
93
|
},
|
|
108
94
|
},
|
|
95
|
+
useMoveToMenu(services),
|
|
109
96
|
{
|
|
110
97
|
type: 'divider',
|
|
111
98
|
direction: 'horizontal',
|
|
112
99
|
display: () => !isPage(node.value) && !props.isMultiSelect,
|
|
113
100
|
},
|
|
114
|
-
|
|
115
|
-
type: 'button',
|
|
116
|
-
text: '删除',
|
|
117
|
-
icon: Delete,
|
|
118
|
-
display: () => !isPage(node.value),
|
|
119
|
-
handler: () => {
|
|
120
|
-
nodes.value && editorService?.remove(nodes.value);
|
|
121
|
-
},
|
|
122
|
-
},
|
|
101
|
+
useDeleteMenu(),
|
|
123
102
|
{
|
|
124
103
|
type: 'divider',
|
|
125
104
|
direction: 'horizontal',
|