@tmagic/editor 1.0.0-beta.1 → 1.0.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/LICENSE +5432 -0
- package/README.md +1 -0
- package/dist/style.css +53 -24
- package/dist/tmagic-editor.es.js +901 -412
- package/dist/tmagic-editor.es.js.map +1 -1
- package/dist/tmagic-editor.umd.js +918 -412
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/dist/types/src/Editor.vue.d.ts +5 -5
- package/dist/types/src/components/ScrollViewer.vue.d.ts +23 -0
- package/dist/types/src/layouts/CodeEditor.vue.d.ts +5 -4
- package/dist/types/src/layouts/NavMenu.vue.d.ts +2 -1
- package/dist/types/src/layouts/sidebar/ComponentListPanel.vue.d.ts +1 -1
- package/dist/types/src/layouts/sidebar/LayerPanel.vue.d.ts +10 -3
- package/dist/types/src/layouts/workspace/PageBar.vue.d.ts +8 -3
- package/dist/types/src/layouts/workspace/Stage.vue.d.ts +77 -42
- package/dist/types/src/layouts/workspace/Workspace.vue.d.ts +4 -10
- package/dist/types/src/services/BaseService.d.ts +4 -1
- package/dist/types/src/services/editor.d.ts +11 -4
- package/dist/types/src/services/props.d.ts +1 -1
- package/dist/types/src/services/ui.d.ts +10 -3
- package/dist/types/src/type.d.ts +23 -7
- package/dist/types/src/utils/editor.d.ts +3 -3
- package/dist/types/src/utils/scroll-viewer.d.ts +35 -0
- package/package.json +25 -12
- package/src/Editor.vue +5 -5
- package/src/components/ScrollViewer.vue +66 -0
- package/src/components/ToolButton.vue +5 -3
- package/src/layouts/AddPageBox.vue +3 -1
- package/src/layouts/CodeEditor.vue +35 -59
- package/src/layouts/NavMenu.vue +7 -3
- package/src/layouts/PropsPanel.vue +6 -10
- package/src/layouts/sidebar/ComponentListPanel.vue +2 -2
- package/src/layouts/sidebar/LayerMenu.vue +15 -39
- package/src/layouts/sidebar/LayerPanel.vue +63 -16
- package/src/layouts/workspace/PageBar.vue +113 -14
- package/src/layouts/workspace/Stage.vue +67 -61
- package/src/layouts/workspace/ViewerMenu.vue +5 -3
- package/src/layouts/workspace/Workspace.vue +45 -34
- package/src/services/BaseService.ts +70 -22
- package/src/services/editor.ts +111 -55
- package/src/services/props.ts +2 -1
- package/src/services/ui.ts +42 -5
- package/src/theme/common/var.scss +2 -2
- package/src/theme/layer-panel.scss +9 -0
- package/src/theme/nav-menu.scss +3 -3
- package/src/theme/page-bar.scss +21 -2
- package/src/theme/props-panel.scss +8 -0
- package/src/theme/stage.scss +8 -7
- package/src/type.ts +26 -7
- package/src/utils/editor.ts +30 -27
- package/src/utils/props.ts +1 -1
- package/src/utils/scroll-viewer.ts +216 -0
- package/dist/types/src/layouts/sidebar/LayerMenu.vue.d.ts +0 -31
package/src/utils/editor.ts
CHANGED
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { random } from 'lodash-es';
|
|
20
20
|
|
|
21
|
-
import { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
22
|
-
import {
|
|
21
|
+
import type { Id, MApp, MContainer, MNode, MPage } from '@tmagic/schema';
|
|
22
|
+
import { NodeType } from '@tmagic/schema';
|
|
23
|
+
import type StageCore from '@tmagic/stage';
|
|
24
|
+
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
|
23
25
|
|
|
24
26
|
import { Layout } from '@editor/type';
|
|
25
27
|
|
|
@@ -34,7 +36,7 @@ export const generateId = (type: string | number): string => `${type}_${random(1
|
|
|
34
36
|
*/
|
|
35
37
|
export const getPageList = (app: MApp): MPage[] => {
|
|
36
38
|
if (app.items && Array.isArray(app.items)) {
|
|
37
|
-
return app.items.filter((item: MPage) => item.type ===
|
|
39
|
+
return app.items.filter((item: MPage) => item.type === NodeType.PAGE);
|
|
38
40
|
}
|
|
39
41
|
return [];
|
|
40
42
|
};
|
|
@@ -104,11 +106,11 @@ const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
|
|
|
104
106
|
export const setNewItemId = (config: MNode, parent?: MPage) => {
|
|
105
107
|
const oldId = config.id;
|
|
106
108
|
|
|
107
|
-
config.id = generateId(config.type);
|
|
109
|
+
config.id = generateId(config.type || 'component');
|
|
108
110
|
config.name = `${config.name?.replace(/_(\d+)$/, '')}_${config.id}`;
|
|
109
111
|
|
|
110
112
|
// 只有弹窗在页面下的一级子元素才有效
|
|
111
|
-
if (isPop(config) && parent?.type ===
|
|
113
|
+
if (isPop(config) && parent?.type === NodeType.PAGE) {
|
|
112
114
|
updatePopId(oldId, config.id, parent);
|
|
113
115
|
}
|
|
114
116
|
|
|
@@ -138,11 +140,29 @@ export const toRelative = (node: MNode) => {
|
|
|
138
140
|
return node;
|
|
139
141
|
};
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
const setTop2Middle = (node: MNode, parentNode: MNode, stage: StageCore) => {
|
|
144
|
+
const style = node.style || {};
|
|
145
|
+
const height = style.height || 0;
|
|
146
|
+
|
|
147
|
+
if (!stage || style.top || !parentNode.style || !isNumber(height)) return style;
|
|
148
|
+
|
|
149
|
+
const { height: parentHeight } = parentNode.style;
|
|
150
|
+
|
|
151
|
+
if (isPage(parentNode)) {
|
|
152
|
+
const { scrollTop = 0, wrapperHeight } = stage.mask;
|
|
153
|
+
style.top = (wrapperHeight - height) / 2 + scrollTop;
|
|
154
|
+
} else {
|
|
155
|
+
style.top = (parentHeight - height) / 2;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return style;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const initPosition = (node: MNode, layout: Layout, parentNode: MNode, stage: StageCore) => {
|
|
142
162
|
if (layout === Layout.ABSOLUTE) {
|
|
143
163
|
node.style = {
|
|
144
164
|
position: 'absolute',
|
|
145
|
-
...(node
|
|
165
|
+
...setTop2Middle(node, parentNode, stage),
|
|
146
166
|
};
|
|
147
167
|
return node;
|
|
148
168
|
}
|
|
@@ -199,6 +219,8 @@ export const Fixed2Other = async (node: MNode, root: MApp, getLayout: (node: MNo
|
|
|
199
219
|
const offset = {
|
|
200
220
|
left: cur?.style?.left || 0,
|
|
201
221
|
top: cur?.style?.top || 0,
|
|
222
|
+
right: '',
|
|
223
|
+
bottom: '',
|
|
202
224
|
};
|
|
203
225
|
|
|
204
226
|
path.forEach((value) => {
|
|
@@ -223,22 +245,3 @@ export const Fixed2Other = async (node: MNode, root: MApp, getLayout: (node: MNo
|
|
|
223
245
|
|
|
224
246
|
return toRelative(node);
|
|
225
247
|
};
|
|
226
|
-
|
|
227
|
-
export const defaults = (object: any, source: any) => {
|
|
228
|
-
let o = source;
|
|
229
|
-
if (Array.isArray(object)) {
|
|
230
|
-
o = object;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
Object.entries(o).forEach(([key, value]: [string, any]) => {
|
|
234
|
-
if (typeof object[key] === 'undefined') {
|
|
235
|
-
object[key] = value;
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (value && typeof value !== 'string' && Object.keys(value).length) {
|
|
240
|
-
object[key] = defaults(cloneDeep(object[key]), value);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
return object;
|
|
244
|
-
};
|
package/src/utils/props.ts
CHANGED
|
@@ -174,7 +174,7 @@ export const fillConfig = (config: FormConfig = []) => [
|
|
|
174
174
|
type: 'select',
|
|
175
175
|
options: (mForm: FormState, { model }: any) => {
|
|
176
176
|
const node = editorService.getNodeById(model.to);
|
|
177
|
-
if (!node) return [];
|
|
177
|
+
if (!node?.type) return [];
|
|
178
178
|
|
|
179
179
|
return eventsService.getMethod(node.type).map((option) => ({
|
|
180
180
|
text: option.label,
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { Keys } from '@editor/type';
|
|
2
|
+
|
|
3
|
+
interface ScrollViewerOptions {
|
|
4
|
+
container: HTMLDivElement;
|
|
5
|
+
target: HTMLDivElement;
|
|
6
|
+
zoom: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class ScrollViewer {
|
|
10
|
+
private enter = false;
|
|
11
|
+
private targetEnter = false;
|
|
12
|
+
private keydown = false;
|
|
13
|
+
private container: HTMLDivElement;
|
|
14
|
+
private target: HTMLDivElement;
|
|
15
|
+
private zoom = 1;
|
|
16
|
+
|
|
17
|
+
private scrollLeft = 0;
|
|
18
|
+
private scrollTop = 0;
|
|
19
|
+
|
|
20
|
+
private x = 0;
|
|
21
|
+
private y = 0;
|
|
22
|
+
|
|
23
|
+
private resizeObserver = new ResizeObserver((entries) => {
|
|
24
|
+
for (const { contentRect } of entries) {
|
|
25
|
+
const { width, height } = contentRect;
|
|
26
|
+
const targetRect = this.target.getBoundingClientRect();
|
|
27
|
+
const targetWidth = targetRect.width * this.zoom;
|
|
28
|
+
const targetMarginTop = Number(this.target.style.marginTop) || 0;
|
|
29
|
+
const targetHeight = (targetRect.height + targetMarginTop) * this.zoom;
|
|
30
|
+
|
|
31
|
+
if (targetWidth < width) {
|
|
32
|
+
(this.target as any)._left = 0;
|
|
33
|
+
}
|
|
34
|
+
if (targetHeight < height) {
|
|
35
|
+
(this.target as any)._top = 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.scroll();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
constructor(options: ScrollViewerOptions) {
|
|
43
|
+
this.container = options.container;
|
|
44
|
+
this.target = options.target;
|
|
45
|
+
this.zoom = options.zoom;
|
|
46
|
+
|
|
47
|
+
globalThis.addEventListener('keydown', this.keydownHandler);
|
|
48
|
+
globalThis.addEventListener('keyup', this.keyupHandler);
|
|
49
|
+
|
|
50
|
+
this.container.addEventListener('mouseenter', this.mouseEnterHandler);
|
|
51
|
+
this.container.addEventListener('mouseleave', this.mouseLeaveHandler);
|
|
52
|
+
this.target.addEventListener('mouseenter', this.targetMouseEnterHandler);
|
|
53
|
+
this.target.addEventListener('mouseleave', this.targetMouseLeaveHandler);
|
|
54
|
+
|
|
55
|
+
this.container.addEventListener('wheel', this.wheelHandler);
|
|
56
|
+
|
|
57
|
+
this.resizeObserver.observe(this.container);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public destroy() {
|
|
61
|
+
this.resizeObserver.disconnect();
|
|
62
|
+
|
|
63
|
+
this.container.removeEventListener('mouseenter', this.mouseEnterHandler);
|
|
64
|
+
this.container.removeEventListener('mouseleave', this.mouseLeaveHandler);
|
|
65
|
+
this.target.removeEventListener('mouseenter', this.targetMouseEnterHandler);
|
|
66
|
+
this.target.removeEventListener('mouseleave', this.targetMouseLeaveHandler);
|
|
67
|
+
globalThis.removeEventListener('keydown', this.keydownHandler);
|
|
68
|
+
globalThis.removeEventListener('keyup', this.keyupHandler);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public setZoom(zoom: number) {
|
|
72
|
+
this.zoom = zoom;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private scroll() {
|
|
76
|
+
const scrollLeft = (this.target as any)._left;
|
|
77
|
+
const scrollTop = (this.target as any)._top;
|
|
78
|
+
|
|
79
|
+
this.target.style.transform = `translate(${scrollLeft}px, ${scrollTop}px)`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private removeHandler() {
|
|
83
|
+
this.target.style.cursor = '';
|
|
84
|
+
this.target.removeEventListener('mousedown', this.mousedownHandler);
|
|
85
|
+
document.removeEventListener('mousemove', this.mousemoveHandler);
|
|
86
|
+
document.removeEventListener('mouseup', this.mouseupHandler);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private wheelHandler = (event: WheelEvent) => {
|
|
90
|
+
if (this.targetEnter) return;
|
|
91
|
+
|
|
92
|
+
const { deltaX, deltaY, currentTarget } = event;
|
|
93
|
+
|
|
94
|
+
if (currentTarget !== this.container) return;
|
|
95
|
+
|
|
96
|
+
this.setScrollOffset(deltaX, deltaY);
|
|
97
|
+
this.scroll();
|
|
98
|
+
this.scrollLeft = (this.target as any)._left;
|
|
99
|
+
this.scrollTop = (this.target as any)._top;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
private mouseEnterHandler = () => {
|
|
103
|
+
this.enter = true;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
private mouseLeaveHandler = () => {
|
|
107
|
+
this.enter = false;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
private targetMouseEnterHandler = () => {
|
|
111
|
+
this.targetEnter = true;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
private targetMouseLeaveHandler = () => {
|
|
115
|
+
this.targetEnter = false;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
private mousedownHandler = (event: MouseEvent) => {
|
|
119
|
+
if (!this.keydown) return;
|
|
120
|
+
|
|
121
|
+
event.stopImmediatePropagation();
|
|
122
|
+
event.stopPropagation();
|
|
123
|
+
|
|
124
|
+
this.target.style.cursor = 'grabbing';
|
|
125
|
+
|
|
126
|
+
this.x = event.clientX;
|
|
127
|
+
this.y = event.clientY;
|
|
128
|
+
|
|
129
|
+
document.addEventListener('mousemove', this.mousemoveHandler);
|
|
130
|
+
document.addEventListener('mouseup', this.mouseupHandler);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
private mouseupHandler = () => {
|
|
134
|
+
this.x = 0;
|
|
135
|
+
this.y = 0;
|
|
136
|
+
|
|
137
|
+
this.scrollLeft = (this.target as any)._left;
|
|
138
|
+
this.scrollTop = (this.target as any)._top;
|
|
139
|
+
this.removeHandler();
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
private mousemoveHandler = (event: MouseEvent) => {
|
|
143
|
+
event.stopImmediatePropagation();
|
|
144
|
+
event.stopPropagation();
|
|
145
|
+
|
|
146
|
+
const deltaX = event.clientX - this.x;
|
|
147
|
+
const deltaY = event.clientY - this.y;
|
|
148
|
+
|
|
149
|
+
this.setScrollOffset(deltaX, deltaY);
|
|
150
|
+
this.scroll();
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
private keydownHandler = (event: KeyboardEvent) => {
|
|
154
|
+
if (event.code === Keys.ESCAPE && this.enter) {
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
event.stopImmediatePropagation();
|
|
157
|
+
event.stopPropagation();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (event.code !== Keys.ESCAPE || !this.enter || this.keydown) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.keydown = true;
|
|
165
|
+
|
|
166
|
+
this.target.style.cursor = 'grab';
|
|
167
|
+
this.container.addEventListener('mousedown', this.mousedownHandler);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
private keyupHandler = (event: KeyboardEvent) => {
|
|
171
|
+
if (event.code !== Keys.ESCAPE || !this.keydown) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
event.stopImmediatePropagation();
|
|
177
|
+
event.stopPropagation();
|
|
178
|
+
|
|
179
|
+
this.keydown = false;
|
|
180
|
+
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
|
|
183
|
+
this.removeHandler();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
private setScrollOffset(deltaX: number, deltaY: number) {
|
|
187
|
+
const { width, height } = this.container.getBoundingClientRect();
|
|
188
|
+
const targetRect = this.target.getBoundingClientRect();
|
|
189
|
+
|
|
190
|
+
const targetWidth = targetRect.width * this.zoom;
|
|
191
|
+
const targetHeight = targetRect.height * this.zoom;
|
|
192
|
+
|
|
193
|
+
let y = 0;
|
|
194
|
+
|
|
195
|
+
if (targetHeight > height) {
|
|
196
|
+
if (deltaY > 0) {
|
|
197
|
+
y = this.scrollTop + Math.min(targetHeight - height - this.scrollTop, deltaY);
|
|
198
|
+
} else {
|
|
199
|
+
y = this.scrollTop + Math.max(-(targetHeight - height + this.scrollTop), deltaY);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
let x = 0;
|
|
204
|
+
|
|
205
|
+
if (targetWidth > width) {
|
|
206
|
+
if (deltaX > 0) {
|
|
207
|
+
x = this.scrollLeft + Math.min(targetWidth - width - this.scrollLeft, deltaX);
|
|
208
|
+
} else {
|
|
209
|
+
x = this.scrollLeft + Math.max(-(targetWidth - width + this.scrollLeft), deltaX);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
(this.target as any)._left = x;
|
|
214
|
+
(this.target as any)._top = y;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { MNode } from '@tmagic/schema';
|
|
2
|
-
import type { DefineComponent, Ref, ComputedRef, ComponentOptionsMixin, VNodeProps, AllowedComponentProps, ComponentCustomProps, ExtractPropTypes, PropType } from 'vue';
|
|
3
|
-
import type { ComponentGroup } from '../../type';
|
|
4
|
-
declare const _default: DefineComponent<{
|
|
5
|
-
componentGroupList: {
|
|
6
|
-
type: PropType<ComponentGroup[]>;
|
|
7
|
-
default: () => never[];
|
|
8
|
-
};
|
|
9
|
-
}, {
|
|
10
|
-
subVisible: Ref<boolean>;
|
|
11
|
-
node: ComputedRef<MNode | undefined>;
|
|
12
|
-
menu: ComputedRef<{
|
|
13
|
-
app: {
|
|
14
|
-
type: string;
|
|
15
|
-
text: string;
|
|
16
|
-
}[];
|
|
17
|
-
component: ComponentGroup[];
|
|
18
|
-
}>;
|
|
19
|
-
append(config: any): void;
|
|
20
|
-
remove(): void;
|
|
21
|
-
copy(node: any): void;
|
|
22
|
-
setSubVisiable(v: any): void;
|
|
23
|
-
}, unknown, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, Record<string, any>, string, VNodeProps & AllowedComponentProps & ComponentCustomProps, Readonly<ExtractPropTypes<{
|
|
24
|
-
componentGroupList: {
|
|
25
|
-
type: PropType<ComponentGroup[]>;
|
|
26
|
-
default: () => never[];
|
|
27
|
-
};
|
|
28
|
-
}>>, {
|
|
29
|
-
componentGroupList: ComponentGroup[];
|
|
30
|
-
}>;
|
|
31
|
-
export default _default;
|