@tmagic/editor 1.5.0-beta.11 → 1.5.0-beta.12
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 +15 -11
- package/dist/tmagic-editor.js +285 -281
- package/dist/tmagic-editor.umd.cjs +281 -277
- package/package.json +7 -7
- package/src/Editor.vue +1 -0
- package/src/initService.ts +94 -70
- package/src/layouts/Framework.vue +1 -0
- package/src/layouts/page-bar/AddButton.vue +29 -9
- package/src/layouts/page-bar/PageBar.vue +25 -61
- package/src/layouts/page-bar/PageBarScrollContainer.vue +45 -84
- package/src/layouts/page-bar/PageList.vue +1 -1
- package/src/layouts/page-bar/Search.vue +64 -0
- package/src/layouts/workspace/viewer/Stage.vue +11 -0
- package/src/services/dep.ts +5 -2
- package/src/services/editor.ts +20 -40
- package/src/theme/page-bar.scss +19 -12
- package/src/type.ts +2 -1
- package/src/utils/idle-task.ts +3 -2
- package/types/index.d.ts +3 -2
- package/src/layouts/page-bar/SwitchTypeButton.vue +0 -45
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="m-editor-page-bar-item m-editor-page-bar-item-icon m-editor-page-bar-search">
|
|
3
|
+
<Icon :icon="Search" @click="visible = !visible" :class="{ 'icon-active': visible }"></Icon>
|
|
4
|
+
<Teleport to=".m-editor-page-bar-tabs" v-if="visible">
|
|
5
|
+
<MForm
|
|
6
|
+
v-if="query"
|
|
7
|
+
class="m-editor-page-bar-search-panel"
|
|
8
|
+
:inline="true"
|
|
9
|
+
:config="formConfig"
|
|
10
|
+
:init-values="query"
|
|
11
|
+
@change="onFormChange"
|
|
12
|
+
></MForm>
|
|
13
|
+
</Teleport>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup lang="ts">
|
|
18
|
+
import { ref } from 'vue';
|
|
19
|
+
import { Search } from '@element-plus/icons-vue';
|
|
20
|
+
|
|
21
|
+
import { NodeType } from '@tmagic/core';
|
|
22
|
+
import { createForm, MForm } from '@tmagic/form';
|
|
23
|
+
|
|
24
|
+
import Icon from '@editor/components/Icon.vue';
|
|
25
|
+
|
|
26
|
+
interface Query {
|
|
27
|
+
pageType: NodeType[];
|
|
28
|
+
keyword: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
search: [value: Query];
|
|
33
|
+
}>();
|
|
34
|
+
|
|
35
|
+
const query = defineModel<Query>('query');
|
|
36
|
+
|
|
37
|
+
const formConfig = createForm([
|
|
38
|
+
{
|
|
39
|
+
type: 'checkbox-group',
|
|
40
|
+
name: 'pageType',
|
|
41
|
+
options: [
|
|
42
|
+
{
|
|
43
|
+
value: NodeType.PAGE,
|
|
44
|
+
text: '页面',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: NodeType.PAGE_FRAGMENT,
|
|
48
|
+
text: '页面片段',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'keyword',
|
|
54
|
+
placeholder: '请输入关键字',
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
const visible = ref(false);
|
|
59
|
+
|
|
60
|
+
const onFormChange = (values: Query) => {
|
|
61
|
+
query.value = values;
|
|
62
|
+
emit('search', values);
|
|
63
|
+
};
|
|
64
|
+
</script>
|
|
@@ -132,9 +132,20 @@ watch(zoom, (zoom) => {
|
|
|
132
132
|
stage.setZoom(zoom);
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
+
let timeoutId: NodeJS.Timeout | null = null;
|
|
135
136
|
watch(page, (page) => {
|
|
136
137
|
if (runtime && page) {
|
|
137
138
|
services?.editorService.set('stageLoading', true);
|
|
139
|
+
|
|
140
|
+
if (timeoutId) {
|
|
141
|
+
globalThis.clearTimeout(timeoutId);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
timeoutId = globalThis.setTimeout(() => {
|
|
145
|
+
services?.editorService.set('stageLoading', false);
|
|
146
|
+
timeoutId = null;
|
|
147
|
+
}, 3000);
|
|
148
|
+
|
|
138
149
|
runtime.updatePageId?.(page.id);
|
|
139
150
|
nextTick(() => {
|
|
140
151
|
stage?.select(page.id);
|
package/src/services/dep.ts
CHANGED
|
@@ -92,8 +92,11 @@ class Dep extends BaseService {
|
|
|
92
92
|
);
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
return new Promise<void>((resolve) => {
|
|
96
|
+
idleTask.once('finish', () => {
|
|
97
|
+
this.emit('collected', nodes, deep);
|
|
98
|
+
resolve();
|
|
99
|
+
});
|
|
97
100
|
});
|
|
98
101
|
}
|
|
99
102
|
|
package/src/services/editor.ts
CHANGED
|
@@ -20,10 +20,19 @@ import { reactive, toRaw } from 'vue';
|
|
|
20
20
|
import { cloneDeep, get, isObject, mergeWith, uniq } from 'lodash-es';
|
|
21
21
|
import type { Writable } from 'type-fest';
|
|
22
22
|
|
|
23
|
-
import type { Id, MApp,
|
|
23
|
+
import type { Id, MApp, MContainer, MNode, MPage, MPageFragment, TargetOptions } from '@tmagic/core';
|
|
24
24
|
import { NodeType, Target, Watcher } from '@tmagic/core';
|
|
25
25
|
import { isFixed } from '@tmagic/stage';
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
calcValueByFontsize,
|
|
28
|
+
getElById,
|
|
29
|
+
getNodeInfo,
|
|
30
|
+
getNodePath,
|
|
31
|
+
isNumber,
|
|
32
|
+
isPage,
|
|
33
|
+
isPageFragment,
|
|
34
|
+
isPop,
|
|
35
|
+
} from '@tmagic/utils';
|
|
27
36
|
|
|
28
37
|
import BaseService from '@editor/services//BaseService';
|
|
29
38
|
import propsService from '@editor/services//props';
|
|
@@ -175,36 +184,7 @@ class Editor extends BaseService {
|
|
|
175
184
|
root = toRaw(root);
|
|
176
185
|
}
|
|
177
186
|
|
|
178
|
-
|
|
179
|
-
node: null,
|
|
180
|
-
parent: null,
|
|
181
|
-
page: null,
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
if (!root) return info;
|
|
185
|
-
|
|
186
|
-
if (id === root.id) {
|
|
187
|
-
info.node = root;
|
|
188
|
-
return info;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const path = getNodePath(id, root.items);
|
|
192
|
-
|
|
193
|
-
if (!path.length) return info;
|
|
194
|
-
|
|
195
|
-
path.unshift(root);
|
|
196
|
-
|
|
197
|
-
info.node = path[path.length - 1] as MComponent;
|
|
198
|
-
info.parent = path[path.length - 2] as MContainer;
|
|
199
|
-
|
|
200
|
-
path.forEach((item) => {
|
|
201
|
-
if (isPage(item) || isPageFragment(item)) {
|
|
202
|
-
info.page = item as MPage | MPageFragment;
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
return info;
|
|
187
|
+
return getNodeInfo(id, root);
|
|
208
188
|
}
|
|
209
189
|
|
|
210
190
|
/**
|
|
@@ -494,11 +474,11 @@ class Editor extends BaseService {
|
|
|
494
474
|
if (isPage(node)) {
|
|
495
475
|
this.state.pageLength -= 1;
|
|
496
476
|
|
|
497
|
-
await selectDefault(
|
|
477
|
+
await selectDefault(rootItems);
|
|
498
478
|
} else if (isPageFragment(node)) {
|
|
499
479
|
this.state.pageFragmentLength -= 1;
|
|
500
480
|
|
|
501
|
-
await selectDefault(
|
|
481
|
+
await selectDefault(rootItems);
|
|
502
482
|
} else {
|
|
503
483
|
await this.select(parent);
|
|
504
484
|
stage?.select(parent.id);
|
|
@@ -586,11 +566,7 @@ class Editor extends BaseService {
|
|
|
586
566
|
nodes.splice(targetIndex, 1, newConfig);
|
|
587
567
|
this.set('nodes', [...nodes]);
|
|
588
568
|
|
|
589
|
-
|
|
590
|
-
config: cloneDeep(newConfig),
|
|
591
|
-
parentId: parent.id,
|
|
592
|
-
root: cloneDeep(root),
|
|
593
|
-
});
|
|
569
|
+
// update后会触发依赖收集,收集完后会掉stage.update方法
|
|
594
570
|
|
|
595
571
|
if (isPage(newConfig) || isPageFragment(newConfig)) {
|
|
596
572
|
this.set('page', newConfig as MPage | MPageFragment);
|
|
@@ -875,7 +851,11 @@ class Editor extends BaseService {
|
|
|
875
851
|
await stage.select(targetId);
|
|
876
852
|
|
|
877
853
|
const targetParent = this.getParentById(target.id);
|
|
878
|
-
await stage.update({
|
|
854
|
+
await stage.update({
|
|
855
|
+
config: cloneDeep(target),
|
|
856
|
+
parentId: targetParent?.id,
|
|
857
|
+
root: cloneDeep(root),
|
|
858
|
+
});
|
|
879
859
|
|
|
880
860
|
await this.select(newConfig);
|
|
881
861
|
stage.select(newConfig.id);
|
package/src/theme/page-bar.scss
CHANGED
|
@@ -3,19 +3,13 @@
|
|
|
3
3
|
bottom: 0;
|
|
4
4
|
left: 0;
|
|
5
5
|
width: 100%;
|
|
6
|
+
user-select: none;
|
|
7
|
+
}
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
border-radius: 3px 3px 0 0;
|
|
12
|
-
border: 1px solid $--border-color;
|
|
13
|
-
border-bottom: 1px solid transparent;
|
|
14
|
-
padding: 5px 10px;
|
|
15
|
-
|
|
16
|
-
&.active {
|
|
17
|
-
background-color: #f3f3f3;
|
|
18
|
-
}
|
|
9
|
+
.m-editor-page-bar-item-icon {
|
|
10
|
+
.icon-active {
|
|
11
|
+
font-weight: bold;
|
|
12
|
+
color: $--theme-color;
|
|
19
13
|
}
|
|
20
14
|
}
|
|
21
15
|
|
|
@@ -101,3 +95,16 @@
|
|
|
101
95
|
}
|
|
102
96
|
}
|
|
103
97
|
}
|
|
98
|
+
|
|
99
|
+
.m-editor-page-bar-search-panel {
|
|
100
|
+
position: absolute;
|
|
101
|
+
bottom: $--page-bar-height;
|
|
102
|
+
border: 1px solid $--border-color;
|
|
103
|
+
padding: 6px 10px;
|
|
104
|
+
width: 100%;
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
|
|
107
|
+
.tmagic-design-form-item {
|
|
108
|
+
margin-bottom: 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
package/src/type.ts
CHANGED
|
@@ -77,9 +77,10 @@ export interface FrameworkSlots {
|
|
|
77
77
|
'props-panel'(props: {}): any;
|
|
78
78
|
'footer'(props: {}): any;
|
|
79
79
|
'page-bar'(props: {}): any;
|
|
80
|
+
'page-bar-add-button'(props: {}): any;
|
|
80
81
|
'page-bar-title'(props: { page: MPage | MPageFragment }): any;
|
|
81
82
|
'page-bar-popover'(props: { page: MPage | MPageFragment }): any;
|
|
82
|
-
'page-list-popover'(props: { list: MPage
|
|
83
|
+
'page-list-popover'(props: { list: (MPage | MPageFragment)[] }): any;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
export interface WorkspaceSlots {
|
package/src/utils/idle-task.ts
CHANGED
|
@@ -56,13 +56,14 @@ export class IdleTask<T = any> extends EventEmitter {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
private runTaskQueue(deadline: IdleDeadline) {
|
|
59
|
-
|
|
59
|
+
// 动画会占用空闲时间,当任务一直无法执行时,看看是否有动画正在播放
|
|
60
|
+
while ((deadline.timeRemaining() > 10 || deadline.didTimeout) && this.taskList.length) {
|
|
60
61
|
const task = this.taskList.shift();
|
|
61
62
|
task!.handler(task!.data);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
if (this.taskList.length) {
|
|
65
|
-
this.taskHandle = globalThis.requestIdleCallback(this.runTaskQueue.bind(this), { timeout:
|
|
66
|
+
this.taskHandle = globalThis.requestIdleCallback(this.runTaskQueue.bind(this), { timeout: 300 });
|
|
66
67
|
} else {
|
|
67
68
|
this.taskHandle = 0;
|
|
68
69
|
|
package/types/index.d.ts
CHANGED
|
@@ -306,7 +306,7 @@ declare class Dep extends export_default {
|
|
|
306
306
|
removeTarget(id: Id, type?: string): void;
|
|
307
307
|
clearTargets(): void;
|
|
308
308
|
collect(nodes: MNode[], depExtendedData?: DepExtendedData, deep?: boolean, type?: DepTargetType): void;
|
|
309
|
-
collectIdle(nodes: MNode[], depExtendedData?: DepExtendedData, deep?: boolean, type?: DepTargetType): void
|
|
309
|
+
collectIdle(nodes: MNode[], depExtendedData?: DepExtendedData, deep?: boolean, type?: DepTargetType): Promise<void>;
|
|
310
310
|
collectNode(node: MNode, target: Target, depExtendedData?: DepExtendedData, deep?: boolean): void;
|
|
311
311
|
clear(nodes?: MNode[]): void;
|
|
312
312
|
clearByType(type: DepTargetType, nodes?: MNode[]): void;
|
|
@@ -840,6 +840,7 @@ interface FrameworkSlots {
|
|
|
840
840
|
'props-panel'(props: {}): any;
|
|
841
841
|
'footer'(props: {}): any;
|
|
842
842
|
'page-bar'(props: {}): any;
|
|
843
|
+
'page-bar-add-button'(props: {}): any;
|
|
843
844
|
'page-bar-title'(props: {
|
|
844
845
|
page: MPage | MPageFragment;
|
|
845
846
|
}): any;
|
|
@@ -847,7 +848,7 @@ interface FrameworkSlots {
|
|
|
847
848
|
page: MPage | MPageFragment;
|
|
848
849
|
}): any;
|
|
849
850
|
'page-list-popover'(props: {
|
|
850
|
-
list: MPage
|
|
851
|
+
list: (MPage | MPageFragment)[];
|
|
851
852
|
}): any;
|
|
852
853
|
}
|
|
853
854
|
interface WorkspaceSlots {
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<TMagicButton
|
|
3
|
-
v-for="item in data"
|
|
4
|
-
class="m-editor-page-bar-switch-type-button"
|
|
5
|
-
size="small"
|
|
6
|
-
:key="item.type"
|
|
7
|
-
link
|
|
8
|
-
:class="{ active: modelValue === item.type }"
|
|
9
|
-
:type="modelValue === item.type ? 'primary' : ''"
|
|
10
|
-
@click="clickHandler(item.type)"
|
|
11
|
-
>{{ item.text }}</TMagicButton
|
|
12
|
-
>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
|
-
<script setup lang="ts">
|
|
16
|
-
import { NodeType } from '@tmagic/core';
|
|
17
|
-
import { TMagicButton } from '@tmagic/design';
|
|
18
|
-
|
|
19
|
-
defineOptions({
|
|
20
|
-
name: 'MEditorPageBarSwitchTypeButton',
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
defineProps<{
|
|
24
|
-
modelValue: NodeType.PAGE | NodeType.PAGE_FRAGMENT;
|
|
25
|
-
}>();
|
|
26
|
-
|
|
27
|
-
const data: { type: NodeType.PAGE | NodeType.PAGE_FRAGMENT; text: string }[] = [
|
|
28
|
-
{
|
|
29
|
-
type: NodeType.PAGE,
|
|
30
|
-
text: '页面',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
type: NodeType.PAGE_FRAGMENT,
|
|
34
|
-
text: '页面片',
|
|
35
|
-
},
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
const emit = defineEmits<{
|
|
39
|
-
'update:modelValue': [value: NodeType.PAGE | NodeType.PAGE_FRAGMENT];
|
|
40
|
-
}>();
|
|
41
|
-
|
|
42
|
-
const clickHandler = (value: NodeType.PAGE | NodeType.PAGE_FRAGMENT) => {
|
|
43
|
-
emit('update:modelValue', value);
|
|
44
|
-
};
|
|
45
|
-
</script>
|