@tmagic/editor 1.1.0-beta.9 → 1.1.2
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 +53 -4
- package/dist/tmagic-editor.mjs +1134 -928
- package/dist/tmagic-editor.mjs.map +1 -1
- package/dist/tmagic-editor.umd.js +1138 -929
- package/dist/tmagic-editor.umd.js.map +1 -1
- package/package.json +10 -10
- package/src/Editor.vue +28 -8
- package/src/components/ContentMenu.vue +4 -4
- package/src/components/Icon.vue +11 -23
- package/src/components/ScrollBar.vue +147 -0
- package/src/components/ScrollViewer.vue +89 -44
- package/src/components/ToolButton.vue +40 -138
- package/src/fields/UISelect.vue +2 -2
- package/src/index.ts +2 -2
- package/src/layouts/NavMenu.vue +156 -23
- package/src/layouts/PropsPanel.vue +49 -51
- package/src/layouts/sidebar/ComponentListPanel.vue +78 -90
- package/src/layouts/sidebar/LayerMenu.vue +3 -3
- package/src/layouts/sidebar/LayerPanel.vue +39 -8
- package/src/layouts/sidebar/Sidebar.vue +4 -0
- package/src/layouts/sidebar/TabPane.vue +12 -0
- package/src/layouts/workspace/PageBar.vue +2 -2
- package/src/layouts/workspace/PageBarScrollContainer.vue +13 -3
- package/src/layouts/workspace/Stage.vue +10 -92
- package/src/layouts/workspace/ViewerMenu.vue +3 -3
- package/src/layouts/workspace/Workspace.vue +133 -138
- package/src/services/componentList.ts +5 -0
- package/src/services/editor.ts +57 -20
- package/src/services/events.ts +8 -2
- package/src/services/props.ts +31 -52
- package/src/services/storage.ts +4 -0
- package/src/services/ui.ts +33 -30
- package/src/theme/component-list-panel.scss +0 -5
- package/src/theme/content-menu.scss +4 -0
- package/src/theme/icon.scss +6 -0
- package/src/theme/index.scss +1 -0
- package/src/theme/nav-menu.scss +6 -0
- package/src/type.ts +28 -10
- package/src/utils/index.ts +1 -0
- package/src/utils/operator.ts +3 -3
- package/src/utils/props.ts +0 -3
- package/src/utils/scroll-viewer.ts +90 -158
- package/src/utils/stage.ts +91 -0
- package/types/Editor.vue.d.ts +7 -7
- package/types/components/ContentMenu.vue.d.ts +8 -8
- package/types/components/Icon.vue.d.ts +62 -12
- package/types/components/ScrollBar.vue.d.ts +83 -0
- package/types/components/ScrollViewer.vue.d.ts +131 -19
- package/types/components/ToolButton.vue.d.ts +56 -59
- package/types/index.d.ts +2 -1
- package/types/layouts/NavMenu.vue.d.ts +92 -23
- package/types/layouts/PropsPanel.vue.d.ts +25 -208
- package/types/layouts/sidebar/ComponentListPanel.vue.d.ts +50 -12
- package/types/layouts/sidebar/LayerMenu.vue.d.ts +7 -7
- package/types/layouts/sidebar/LayerPanel.vue.d.ts +17 -15
- package/types/layouts/workspace/Workspace.vue.d.ts +54 -4
- package/types/services/componentList.d.ts +1 -0
- package/types/services/editor.d.ts +1 -0
- package/types/services/events.d.ts +1 -0
- package/types/services/props.d.ts +41 -9
- package/types/services/storage.d.ts +1 -0
- package/types/services/ui.d.ts +4 -1
- package/types/type.d.ts +25 -10
- package/types/utils/index.d.ts +1 -0
- package/types/utils/operator.d.ts +1 -1
- package/types/utils/props.d.ts +0 -1
- package/types/utils/scroll-viewer.d.ts +16 -18
- package/types/utils/stage.d.ts +3 -0
- package/src/utils/polyfills.ts +0 -8
- package/types/utils/polyfills.d.ts +0 -0
package/src/services/props.ts
CHANGED
|
@@ -20,12 +20,11 @@ import { reactive } from 'vue';
|
|
|
20
20
|
import { cloneDeep, mergeWith } from 'lodash-es';
|
|
21
21
|
|
|
22
22
|
import type { FormConfig } from '@tmagic/form';
|
|
23
|
-
import type {
|
|
24
|
-
import {
|
|
25
|
-
import { isPop, toLine } from '@tmagic/utils';
|
|
23
|
+
import type { MComponent, MNode } from '@tmagic/schema';
|
|
24
|
+
import { toLine } from '@tmagic/utils';
|
|
26
25
|
|
|
27
26
|
import type { PropsState } from '../type';
|
|
28
|
-
import {
|
|
27
|
+
import { fillConfig } from '../utils/props';
|
|
29
28
|
|
|
30
29
|
import BaseService from './BaseService';
|
|
31
30
|
|
|
@@ -43,6 +42,7 @@ class Props extends BaseService {
|
|
|
43
42
|
'getPropsValue',
|
|
44
43
|
'createId',
|
|
45
44
|
'setNewItemId',
|
|
45
|
+
'fillConfig',
|
|
46
46
|
'getDefaultPropsValue',
|
|
47
47
|
]);
|
|
48
48
|
}
|
|
@@ -54,13 +54,17 @@ class Props extends BaseService {
|
|
|
54
54
|
this.emit('props-configs-change');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
public async fillConfig(config: FormConfig) {
|
|
58
|
+
return fillConfig(config);
|
|
59
|
+
}
|
|
60
|
+
|
|
57
61
|
/**
|
|
58
62
|
* 为指定类型组件设置组件属性表单配置
|
|
59
63
|
* @param type 组件类型
|
|
60
64
|
* @param config 组件属性表单配置
|
|
61
65
|
*/
|
|
62
|
-
public setPropsConfig(type: string, config: FormConfig) {
|
|
63
|
-
this.state.propsConfigMap[type] = fillConfig(Array.isArray(config) ? config : [config]);
|
|
66
|
+
public async setPropsConfig(type: string, config: FormConfig) {
|
|
67
|
+
this.state.propsConfigMap[type] = await this.fillConfig(Array.isArray(config) ? config : [config]);
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
/**
|
|
@@ -73,7 +77,7 @@ class Props extends BaseService {
|
|
|
73
77
|
return await this.getPropsConfig('button');
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
return cloneDeep(this.state.propsConfigMap[type] ||
|
|
80
|
+
return cloneDeep(this.state.propsConfigMap[type] || (await this.fillConfig([])));
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
public setPropsValues(values: Record<string, MNode>) {
|
|
@@ -125,19 +129,6 @@ class Props extends BaseService {
|
|
|
125
129
|
};
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
/**
|
|
129
|
-
* 生成指定位数的GUID,无【-】格式
|
|
130
|
-
* @param digit 位数,默认值8
|
|
131
|
-
* @returns
|
|
132
|
-
*/
|
|
133
|
-
guid(digit = 8): string {
|
|
134
|
-
return 'x'.repeat(digit).replace(/[xy]/g, (c) => {
|
|
135
|
-
const r = (Math.random() * 16) | 0;
|
|
136
|
-
const v = c == 'x' ? r : (r & 0x3) | 0x8;
|
|
137
|
-
return v.toString(16);
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
132
|
public async createId(type: string | number): Promise<string> {
|
|
142
133
|
return `${type}_${this.guid()}`;
|
|
143
134
|
}
|
|
@@ -147,19 +138,12 @@ class Props extends BaseService {
|
|
|
147
138
|
* @param {Object} config 组件配置
|
|
148
139
|
*/
|
|
149
140
|
/* eslint no-param-reassign: ["error", { "props": false }] */
|
|
150
|
-
public async setNewItemId(config: MNode
|
|
151
|
-
const oldId = config.id;
|
|
152
|
-
|
|
141
|
+
public async setNewItemId(config: MNode) {
|
|
153
142
|
config.id = await this.createId(config.type || 'component');
|
|
154
143
|
|
|
155
|
-
// 只有弹窗在页面下的一级子元素才有效
|
|
156
|
-
if (isPop(config) && parent?.type === NodeType.PAGE) {
|
|
157
|
-
updatePopId(oldId, config.id, parent);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
144
|
if (config.items && Array.isArray(config.items)) {
|
|
161
145
|
for (const item of config.items) {
|
|
162
|
-
await this.setNewItemId(item
|
|
146
|
+
await this.setNewItemId(item);
|
|
163
147
|
}
|
|
164
148
|
}
|
|
165
149
|
|
|
@@ -186,31 +170,26 @@ class Props extends BaseService {
|
|
|
186
170
|
name: type,
|
|
187
171
|
};
|
|
188
172
|
}
|
|
189
|
-
}
|
|
190
173
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
*/
|
|
197
|
-
const updatePopId = (oldId: Id, popId: Id, pageConfig: MPage) => {
|
|
198
|
-
pageConfig.items?.forEach((config) => {
|
|
199
|
-
if (config.pop === oldId) {
|
|
200
|
-
config.pop = popId;
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (config.popId === oldId) {
|
|
205
|
-
config.popId = popId;
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
174
|
+
public destroy() {
|
|
175
|
+
this.state.propsConfigMap = {};
|
|
176
|
+
this.state.propsValueMap = {};
|
|
177
|
+
this.removeAllListeners();
|
|
178
|
+
}
|
|
208
179
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
180
|
+
/**
|
|
181
|
+
* 生成指定位数的GUID,无【-】格式
|
|
182
|
+
* @param digit 位数,默认值8
|
|
183
|
+
* @returns
|
|
184
|
+
*/
|
|
185
|
+
private guid(digit = 8): string {
|
|
186
|
+
return 'x'.repeat(digit).replace(/[xy]/g, (c) => {
|
|
187
|
+
const r = (Math.random() * 16) | 0;
|
|
188
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
189
|
+
return v.toString(16);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
214
193
|
|
|
215
194
|
export type PropsService = Props;
|
|
216
195
|
|
package/src/services/storage.ts
CHANGED
|
@@ -107,6 +107,10 @@ export class WebStorage extends BaseService {
|
|
|
107
107
|
storage.setItem(`${options.namespace || namespace}:${key}`, item);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
public destroy() {
|
|
111
|
+
this.removeAllListeners();
|
|
112
|
+
}
|
|
113
|
+
|
|
110
114
|
private getValueAndProtocol(value: string | null) {
|
|
111
115
|
let protocol = '';
|
|
112
116
|
|
package/src/services/ui.ts
CHANGED
|
@@ -54,6 +54,7 @@ const state = reactive<UiState>({
|
|
|
54
54
|
showGuides: true,
|
|
55
55
|
showRule: true,
|
|
56
56
|
propsPanelSize: 'small',
|
|
57
|
+
showAddPageButton: true,
|
|
57
58
|
});
|
|
58
59
|
|
|
59
60
|
class Ui extends BaseService {
|
|
@@ -64,16 +65,6 @@ class Ui extends BaseService {
|
|
|
64
65
|
center: 'auto',
|
|
65
66
|
});
|
|
66
67
|
});
|
|
67
|
-
|
|
68
|
-
const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
|
|
69
|
-
if (columnWidthCacheData) {
|
|
70
|
-
try {
|
|
71
|
-
const columnWidthCache = JSON.parse(columnWidthCacheData);
|
|
72
|
-
this.setColumnWidth(columnWidthCache);
|
|
73
|
-
} catch (e) {
|
|
74
|
-
console.error(e);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
68
|
}
|
|
78
69
|
|
|
79
70
|
public set<T = any>(name: keyof UiState, value: T) {
|
|
@@ -98,21 +89,49 @@ class Ui extends BaseService {
|
|
|
98
89
|
}
|
|
99
90
|
|
|
100
91
|
(state as any)[name] = value;
|
|
101
|
-
|
|
102
|
-
if (name === 'stageContainerRect') {
|
|
103
|
-
state.zoom = this.calcZoom();
|
|
104
|
-
}
|
|
105
92
|
}
|
|
106
93
|
|
|
107
94
|
public get<T>(name: keyof typeof state): T {
|
|
108
95
|
return (state as any)[name];
|
|
109
96
|
}
|
|
110
97
|
|
|
98
|
+
public initColumnWidth() {
|
|
99
|
+
const columnWidthCacheData = globalThis.localStorage.getItem(COLUMN_WIDTH_STORAGE_KEY);
|
|
100
|
+
if (columnWidthCacheData) {
|
|
101
|
+
try {
|
|
102
|
+
const columnWidthCache = JSON.parse(columnWidthCacheData);
|
|
103
|
+
this.setColumnWidth(columnWidthCache);
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.error(e);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
111
110
|
public zoom(zoom: number) {
|
|
112
111
|
this.set('zoom', (this.get<number>('zoom') * 100 + zoom * 100) / 100);
|
|
113
112
|
if (this.get<number>('zoom') < 0.1) this.set('zoom', 0.1);
|
|
114
113
|
}
|
|
115
114
|
|
|
115
|
+
public calcZoom() {
|
|
116
|
+
const { stageRect, stageContainerRect } = state;
|
|
117
|
+
const { height, width } = stageContainerRect;
|
|
118
|
+
if (!width || !height) return 1;
|
|
119
|
+
|
|
120
|
+
// 30为标尺的大小
|
|
121
|
+
const stageWidth = stageRect.width + 30;
|
|
122
|
+
const stageHeight = stageRect.height + 30;
|
|
123
|
+
|
|
124
|
+
if (width > stageWidth && height > stageHeight) {
|
|
125
|
+
return 1;
|
|
126
|
+
}
|
|
127
|
+
// 60/80是为了不要让画布太过去贴住四周(这样好看些)
|
|
128
|
+
return Math.min((width - 60) / stageWidth || 1, (height - 80) / stageHeight || 1);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public destroy() {
|
|
132
|
+
this.removeAllListeners();
|
|
133
|
+
}
|
|
134
|
+
|
|
116
135
|
private setColumnWidth({ left, center, right }: SetColumnWidth) {
|
|
117
136
|
const columnWidth = {
|
|
118
137
|
...toRaw(this.get<GetColumnWidth>('columnWidth')),
|
|
@@ -150,22 +169,6 @@ class Ui extends BaseService {
|
|
|
150
169
|
};
|
|
151
170
|
state.zoom = this.calcZoom();
|
|
152
171
|
}
|
|
153
|
-
|
|
154
|
-
private calcZoom() {
|
|
155
|
-
const { stageRect, stageContainerRect } = state;
|
|
156
|
-
const { height, width } = stageContainerRect;
|
|
157
|
-
if (!width || !height) return 1;
|
|
158
|
-
|
|
159
|
-
// 30为标尺的大小
|
|
160
|
-
const stageWidth = stageRect.width + 30;
|
|
161
|
-
const stageHeight = stageRect.height + 30;
|
|
162
|
-
|
|
163
|
-
if (width > stageWidth && height > stageHeight) {
|
|
164
|
-
return 1;
|
|
165
|
-
}
|
|
166
|
-
// 60/80是为了不要让画布太过去贴住四周(这样好看些)
|
|
167
|
-
return Math.min((width - 60) / stageWidth || 1, (height - 80) / stageHeight || 1);
|
|
168
|
-
}
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
export type UiService = Ui;
|
package/src/theme/index.scss
CHANGED
package/src/theme/nav-menu.scss
CHANGED
package/src/type.ts
CHANGED
|
@@ -82,16 +82,22 @@ export interface ComponentGroupState {
|
|
|
82
82
|
list: ComponentGroup[];
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
export enum ColumnLayout {
|
|
86
|
+
LEFT = 'left',
|
|
87
|
+
CENTER = 'center',
|
|
88
|
+
RIGHT = 'right',
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
export interface SetColumnWidth {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
92
|
+
[ColumnLayout.LEFT]?: number;
|
|
93
|
+
[ColumnLayout.CENTER]?: number | 'auto';
|
|
94
|
+
[ColumnLayout.RIGHT]?: number;
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
export interface GetColumnWidth {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
[ColumnLayout.LEFT]: number;
|
|
99
|
+
[ColumnLayout.CENTER]: number;
|
|
100
|
+
[ColumnLayout.RIGHT]: number;
|
|
95
101
|
}
|
|
96
102
|
|
|
97
103
|
export interface StageRect {
|
|
@@ -118,6 +124,8 @@ export interface UiState {
|
|
|
118
124
|
showRule: boolean;
|
|
119
125
|
/** 用于控制该属性配置表单内组件的尺寸 */
|
|
120
126
|
propsPanelSize: 'large' | 'default' | 'small';
|
|
127
|
+
/** 是否显示新增页面按钮 */
|
|
128
|
+
showAddPageButton: boolean;
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
export interface EditorNodeInfo {
|
|
@@ -174,6 +182,7 @@ export interface MenuButton {
|
|
|
174
182
|
/** type为button/dropdown时点击运行的方法 */
|
|
175
183
|
handler?: (data: Services, event: MouseEvent) => Promise<any> | any;
|
|
176
184
|
/** type为dropdown时,下拉的菜单列表, 或者有子菜单时 */
|
|
185
|
+
className?: string;
|
|
177
186
|
items?: MenuButton[];
|
|
178
187
|
}
|
|
179
188
|
|
|
@@ -187,6 +196,7 @@ export interface MenuComponent {
|
|
|
187
196
|
listeners?: Record<string, Function>;
|
|
188
197
|
slots?: Record<string, any>;
|
|
189
198
|
/** 是否显示,默认为true */
|
|
199
|
+
className?: string;
|
|
190
200
|
display?: boolean | ((data?: Services) => Promise<boolean> | boolean);
|
|
191
201
|
}
|
|
192
202
|
|
|
@@ -209,16 +219,17 @@ export type MenuItem =
|
|
|
209
219
|
| 'guides'
|
|
210
220
|
| 'rule'
|
|
211
221
|
| MenuButton
|
|
212
|
-
| MenuComponent
|
|
222
|
+
| MenuComponent
|
|
223
|
+
| string;
|
|
213
224
|
|
|
214
225
|
/** 工具栏 */
|
|
215
226
|
export interface MenuBarData {
|
|
216
227
|
/** 顶部工具栏左边项 */
|
|
217
|
-
|
|
228
|
+
[ColumnLayout.LEFT]?: MenuItem[];
|
|
218
229
|
/** 顶部工具栏中间项 */
|
|
219
|
-
|
|
230
|
+
[ColumnLayout.CENTER]?: MenuItem[];
|
|
220
231
|
/** 顶部工具栏右边项 */
|
|
221
|
-
|
|
232
|
+
[ColumnLayout.RIGHT]?: MenuItem[];
|
|
222
233
|
}
|
|
223
234
|
|
|
224
235
|
export interface SideComponent extends MenuComponent {
|
|
@@ -287,3 +298,10 @@ export enum Keys {
|
|
|
287
298
|
|
|
288
299
|
export const H_GUIDE_LINE_STORAGE_KEY = '$MagicStageHorizontalGuidelinesData';
|
|
289
300
|
export const V_GUIDE_LINE_STORAGE_KEY = '$MagicStageVerticalGuidelinesData';
|
|
301
|
+
|
|
302
|
+
export interface ScrollViewerEvent {
|
|
303
|
+
scrollLeft: number;
|
|
304
|
+
scrollTop: number;
|
|
305
|
+
scrollHeight: number;
|
|
306
|
+
scrollWidth: number;
|
|
307
|
+
}
|
package/src/utils/index.ts
CHANGED
package/src/utils/operator.ts
CHANGED
|
@@ -42,7 +42,7 @@ export const beforePaste = async (position: PastePosition, config: MNode[]): Pro
|
|
|
42
42
|
pastePosition.top = configItem.style?.top - referenceTop + pastePosition.top;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const pasteConfig = await propsService.setNewItemId(configItem
|
|
45
|
+
const pasteConfig = await propsService.setNewItemId(configItem);
|
|
46
46
|
|
|
47
47
|
if (pasteConfig.style) {
|
|
48
48
|
const { left, top } = pasteConfig.style;
|
|
@@ -86,11 +86,11 @@ export const getPositionInContainer = (position: PastePosition = {}, id: Id) =>
|
|
|
86
86
|
};
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
export const getAddParent = (
|
|
89
|
+
export const getAddParent = (node: MNode) => {
|
|
90
90
|
const curNode = editorService.get<MContainer>('node');
|
|
91
91
|
|
|
92
92
|
let parentNode;
|
|
93
|
-
if (
|
|
93
|
+
if (isPage(node)) {
|
|
94
94
|
parentNode = editorService.get<MApp>('root');
|
|
95
95
|
} else if (curNode.items) {
|
|
96
96
|
parentNode = curNode;
|