@tmagic/stage 1.0.6 → 1.1.0-beta.10
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/{tmagic-stage.es.js → tmagic-stage.mjs} +689 -295
- package/dist/tmagic-stage.mjs.map +1 -0
- package/dist/tmagic-stage.umd.js +722 -310
- package/dist/tmagic-stage.umd.js.map +1 -1
- package/package.json +14 -11
- package/src/StageCore.ts +126 -19
- package/src/StageDragResize.ts +155 -162
- package/src/StageHighlight.ts +1 -2
- package/src/StageMask.ts +33 -11
- package/src/StageMultiDragResize.ts +260 -0
- package/src/StageRender.ts +31 -17
- package/src/TargetCalibrate.ts +2 -2
- package/src/const.ts +4 -0
- package/src/index.ts +1 -0
- package/src/style.css +11 -0
- package/src/types.ts +40 -13
- package/src/util.ts +102 -22
- package/tsconfig.build.json +13 -0
- package/{dist/types/src → types}/Rule.d.ts +0 -0
- package/{dist/types/src → types}/StageCore.d.ts +26 -4
- package/{dist/types/src → types}/StageDragResize.d.ts +10 -19
- package/{dist/types/src → types}/StageHighlight.d.ts +0 -0
- package/{dist/types/src → types}/StageMask.d.ts +1 -0
- package/types/StageMultiDragResize.d.ts +51 -0
- package/{dist/types/src → types}/StageRender.d.ts +1 -0
- package/{dist/types/src → types}/TargetCalibrate.d.ts +0 -0
- package/{dist/types/src → types}/const.d.ts +2 -0
- package/{dist/types/src → types}/index.d.ts +1 -0
- package/types/logger.d.ts +5 -0
- package/{dist/types/src → types}/types.d.ts +38 -13
- package/{dist/types/src → types}/util.d.ts +17 -7
- package/dist/tmagic-stage.es.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.1.0-beta.10",
|
|
3
3
|
"name": "@tmagic/stage",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"dist/*"
|
|
6
6
|
],
|
|
7
7
|
"main": "dist/tmagic-stage.umd.js",
|
|
8
|
-
"module": "dist/tmagic-stage.
|
|
9
|
-
"types": "
|
|
8
|
+
"module": "dist/tmagic-stage.mjs",
|
|
9
|
+
"types": "types/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"import": "./dist/tmagic-stage.
|
|
12
|
+
"import": "./dist/tmagic-stage.mjs",
|
|
13
13
|
"require": "./dist/tmagic-stage.umd.js"
|
|
14
14
|
},
|
|
15
15
|
"./*": "./*"
|
|
16
16
|
},
|
|
17
17
|
"license": "Apache-2.0",
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "vite build"
|
|
19
|
+
"build": "npm run build:type && vite build",
|
|
20
|
+
"build:type": "npm run clear:type && tsc --declaration --emitDeclarationOnly --project tsconfig.build.json",
|
|
21
|
+
"clear:type": "rimraf ./types"
|
|
20
22
|
},
|
|
21
23
|
"engines": {
|
|
22
24
|
"node": ">=14"
|
|
@@ -27,10 +29,11 @@
|
|
|
27
29
|
},
|
|
28
30
|
"dependencies": {
|
|
29
31
|
"@scena/guides": "^0.17.0",
|
|
30
|
-
"@tmagic/core": "1.0.
|
|
31
|
-
"@tmagic/schema": "1.0.
|
|
32
|
-
"@tmagic/utils": "1.0.
|
|
32
|
+
"@tmagic/core": "1.1.0-beta.10",
|
|
33
|
+
"@tmagic/schema": "1.1.0-beta.10",
|
|
34
|
+
"@tmagic/utils": "1.1.0-beta.10",
|
|
33
35
|
"events": "^3.3.0",
|
|
36
|
+
"keycon": "^1.1.2",
|
|
34
37
|
"lodash-es": "^4.17.21",
|
|
35
38
|
"moveable": "^0.30.0",
|
|
36
39
|
"moveable-helper": "^0.4.0"
|
|
@@ -39,9 +42,9 @@
|
|
|
39
42
|
"@types/events": "^3.0.0",
|
|
40
43
|
"@types/lodash-es": "^4.17.4",
|
|
41
44
|
"@types/node": "^15.12.4",
|
|
45
|
+
"rimraf": "^3.0.2",
|
|
42
46
|
"sass": "^1.35.1",
|
|
43
|
-
"typescript": "^4.
|
|
44
|
-
"vite": "^
|
|
45
|
-
"vite-plugin-dts": "^0.9.6"
|
|
47
|
+
"typescript": "^4.7.4",
|
|
48
|
+
"vite": "^3.0.4"
|
|
46
49
|
}
|
|
47
50
|
}
|
package/src/StageCore.ts
CHANGED
|
@@ -19,35 +19,48 @@
|
|
|
19
19
|
import { EventEmitter } from 'events';
|
|
20
20
|
|
|
21
21
|
import type { Id } from '@tmagic/schema';
|
|
22
|
+
import { addClassName } from '@tmagic/utils';
|
|
22
23
|
|
|
23
|
-
import { DEFAULT_ZOOM, GHOST_EL_ID_PREFIX } from './const';
|
|
24
|
+
import { CONTAINER_HIGHLIGHT_CLASS, DEFAULT_ZOOM, GHOST_EL_ID_PREFIX, PAGE_CLASS } from './const';
|
|
24
25
|
import StageDragResize from './StageDragResize';
|
|
25
26
|
import StageHighlight from './StageHighlight';
|
|
26
27
|
import StageMask from './StageMask';
|
|
28
|
+
import StageMultiDragResize from './StageMultiDragResize';
|
|
27
29
|
import StageRender from './StageRender';
|
|
28
30
|
import {
|
|
29
31
|
CanSelect,
|
|
32
|
+
ContainerHighlightType,
|
|
30
33
|
GuidesEventData,
|
|
34
|
+
IsContainer,
|
|
31
35
|
RemoveData,
|
|
32
36
|
Runtime,
|
|
33
37
|
SortEventData,
|
|
34
38
|
StageCoreConfig,
|
|
39
|
+
StageDragStatus,
|
|
35
40
|
UpdateData,
|
|
36
41
|
UpdateEventData,
|
|
37
42
|
} from './types';
|
|
38
43
|
import { addSelectedClassName, removeSelectedClassName } from './util';
|
|
39
44
|
|
|
40
45
|
export default class StageCore extends EventEmitter {
|
|
41
|
-
public
|
|
46
|
+
public container?: HTMLDivElement;
|
|
47
|
+
// 当前选中的节点
|
|
48
|
+
public selectedDom: HTMLElement | undefined;
|
|
49
|
+
// 多选选中的节点组
|
|
50
|
+
public selectedDomList: HTMLElement[] = [];
|
|
42
51
|
public highlightedDom: Element | undefined;
|
|
43
|
-
|
|
44
52
|
public renderer: StageRender;
|
|
45
53
|
public mask: StageMask;
|
|
46
54
|
public dr: StageDragResize;
|
|
55
|
+
public multiDr: StageMultiDragResize;
|
|
47
56
|
public highlightLayer: StageHighlight;
|
|
48
57
|
public config: StageCoreConfig;
|
|
49
58
|
public zoom = DEFAULT_ZOOM;
|
|
50
|
-
public
|
|
59
|
+
public containerHighlightClassName: string;
|
|
60
|
+
public containerHighlightDuration: number;
|
|
61
|
+
public containerHighlightType?: ContainerHighlightType;
|
|
62
|
+
public isContainer: IsContainer;
|
|
63
|
+
|
|
51
64
|
private canSelect: CanSelect;
|
|
52
65
|
|
|
53
66
|
constructor(config: StageCoreConfig) {
|
|
@@ -57,10 +70,15 @@ export default class StageCore extends EventEmitter {
|
|
|
57
70
|
|
|
58
71
|
this.setZoom(config.zoom);
|
|
59
72
|
this.canSelect = config.canSelect || ((el: HTMLElement) => !!el.id);
|
|
73
|
+
this.isContainer = config.isContainer;
|
|
74
|
+
this.containerHighlightClassName = config.containerHighlightClassName || CONTAINER_HIGHLIGHT_CLASS;
|
|
75
|
+
this.containerHighlightDuration = config.containerHighlightDuration || 800;
|
|
76
|
+
this.containerHighlightType = config.containerHighlightType;
|
|
60
77
|
|
|
61
78
|
this.renderer = new StageRender({ core: this });
|
|
62
79
|
this.mask = new StageMask({ core: this });
|
|
63
|
-
this.dr = new StageDragResize({ core: this, container: this.mask.content });
|
|
80
|
+
this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
|
|
81
|
+
this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
|
|
64
82
|
this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
|
|
65
83
|
|
|
66
84
|
this.renderer.on('runtime-ready', (runtime: Runtime) => {
|
|
@@ -71,8 +89,11 @@ export default class StageCore extends EventEmitter {
|
|
|
71
89
|
});
|
|
72
90
|
|
|
73
91
|
this.mask
|
|
74
|
-
.on('beforeSelect', (event: MouseEvent) => {
|
|
75
|
-
this.
|
|
92
|
+
.on('beforeSelect', async (event: MouseEvent) => {
|
|
93
|
+
this.clearSelectStatus('multiSelect');
|
|
94
|
+
const el = await this.getElementFromPoint(event);
|
|
95
|
+
if (!el) return;
|
|
96
|
+
this.select(el, event);
|
|
76
97
|
})
|
|
77
98
|
.on('select', () => {
|
|
78
99
|
this.emit('select', this.selectedDom);
|
|
@@ -82,16 +103,37 @@ export default class StageCore extends EventEmitter {
|
|
|
82
103
|
this.emit('changeGuides', data);
|
|
83
104
|
})
|
|
84
105
|
.on('highlight', async (event: MouseEvent) => {
|
|
85
|
-
await this.
|
|
106
|
+
const el = await this.getElementFromPoint(event);
|
|
107
|
+
if (!el) return;
|
|
108
|
+
// 如果多选组件处于拖拽状态时不进行组件高亮
|
|
109
|
+
if (this.multiDr.dragStatus === StageDragStatus.ING) return;
|
|
110
|
+
await this.highlight(el);
|
|
86
111
|
if (this.highlightedDom === this.selectedDom) {
|
|
87
112
|
this.highlightLayer.clearHighlight();
|
|
88
113
|
return;
|
|
89
114
|
}
|
|
90
|
-
this.highlightLayer.highlight(this.highlightedDom as HTMLElement);
|
|
91
115
|
this.emit('highlight', this.highlightedDom);
|
|
92
116
|
})
|
|
93
117
|
.on('clearHighlight', async () => {
|
|
94
118
|
this.highlightLayer.clearHighlight();
|
|
119
|
+
})
|
|
120
|
+
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
|
121
|
+
const el = await this.getElementFromPoint(event);
|
|
122
|
+
if (!el) return;
|
|
123
|
+
// 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
|
|
124
|
+
if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
|
|
125
|
+
this.selectedDomList.push(this.selectedDom as HTMLElement);
|
|
126
|
+
this.selectedDom = undefined;
|
|
127
|
+
}
|
|
128
|
+
// 判断元素是否已在多选列表
|
|
129
|
+
const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
|
|
130
|
+
if (existIndex !== -1) {
|
|
131
|
+
// 再次点击取消选中
|
|
132
|
+
this.selectedDomList.splice(existIndex, 1);
|
|
133
|
+
} else {
|
|
134
|
+
this.selectedDomList.push(el);
|
|
135
|
+
}
|
|
136
|
+
this.multiSelect(this.selectedDomList);
|
|
95
137
|
});
|
|
96
138
|
|
|
97
139
|
// 要先触发select,在触发update
|
|
@@ -102,9 +144,19 @@ export default class StageCore extends EventEmitter {
|
|
|
102
144
|
.on('sort', (data: UpdateEventData) => {
|
|
103
145
|
setTimeout(() => this.emit('sort', data));
|
|
104
146
|
});
|
|
147
|
+
|
|
148
|
+
this.multiDr
|
|
149
|
+
.on('update', (data: UpdateEventData) => {
|
|
150
|
+
setTimeout(() => this.emit('update', data));
|
|
151
|
+
})
|
|
152
|
+
.on('select', async (id: Id) => {
|
|
153
|
+
const el = await this.getTargetElement(id);
|
|
154
|
+
this.select(el); // 选中
|
|
155
|
+
setTimeout(() => this.emit('select', el)); // set node
|
|
156
|
+
});
|
|
105
157
|
}
|
|
106
158
|
|
|
107
|
-
public
|
|
159
|
+
public getElementsFromPoint(event: MouseEvent) {
|
|
108
160
|
const { renderer, zoom } = this;
|
|
109
161
|
|
|
110
162
|
const doc = renderer.contentWindow?.document;
|
|
@@ -119,28 +171,38 @@ export default class StageCore extends EventEmitter {
|
|
|
119
171
|
}
|
|
120
172
|
}
|
|
121
173
|
|
|
122
|
-
|
|
174
|
+
return doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
|
|
175
|
+
}
|
|
123
176
|
|
|
177
|
+
public async getElementFromPoint(event: MouseEvent) {
|
|
178
|
+
const els = this.getElementsFromPoint(event);
|
|
124
179
|
let stopped = false;
|
|
125
180
|
const stop = () => (stopped = true);
|
|
126
181
|
for (const el of els) {
|
|
127
|
-
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.
|
|
182
|
+
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isElCanSelect(el, event, stop))) {
|
|
128
183
|
if (stopped) break;
|
|
129
|
-
|
|
130
|
-
this.highlight(el);
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
this.select(el, event);
|
|
134
|
-
break;
|
|
184
|
+
return el;
|
|
135
185
|
}
|
|
136
186
|
}
|
|
137
187
|
}
|
|
138
188
|
|
|
189
|
+
public async isElCanSelect(el: HTMLElement, event: MouseEvent, stop: () => boolean): Promise<Boolean> {
|
|
190
|
+
// 执行业务方传入的判断逻辑
|
|
191
|
+
const canSelectByProp = await this.canSelect(el, event, stop);
|
|
192
|
+
if (!canSelectByProp) return false;
|
|
193
|
+
// 多选规则
|
|
194
|
+
if (this.mask.isMultiSelectStatus) {
|
|
195
|
+
return this.multiDr.canSelect(el, stop);
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
|
|
139
200
|
/**
|
|
140
201
|
* 选中组件
|
|
141
202
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
|
142
203
|
*/
|
|
143
204
|
public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
|
|
205
|
+
this.clearSelectStatus('multiSelect');
|
|
144
206
|
const el = await this.getTargetElement(idOrEl);
|
|
145
207
|
|
|
146
208
|
if (el === this.selectedDom) return;
|
|
@@ -170,6 +232,17 @@ export default class StageCore extends EventEmitter {
|
|
|
170
232
|
}
|
|
171
233
|
}
|
|
172
234
|
|
|
235
|
+
/**
|
|
236
|
+
* 多选
|
|
237
|
+
* @param domList 多选节点
|
|
238
|
+
*/
|
|
239
|
+
public async multiSelect(idOrElList: HTMLElement[] | Id[]): Promise<void> {
|
|
240
|
+
this.clearSelectStatus('select');
|
|
241
|
+
const elList = await Promise.all(idOrElList.map(async (idOrEl) => await this.getTargetElement(idOrEl)));
|
|
242
|
+
this.multiDr.multiSelect(elList);
|
|
243
|
+
this.emit('multiSelect', elList);
|
|
244
|
+
}
|
|
245
|
+
|
|
173
246
|
/**
|
|
174
247
|
* 更新选中的节点
|
|
175
248
|
* @param data 更新的数据
|
|
@@ -205,7 +278,7 @@ export default class StageCore extends EventEmitter {
|
|
|
205
278
|
this.highlightLayer.clearHighlight();
|
|
206
279
|
return;
|
|
207
280
|
}
|
|
208
|
-
if (el === this.highlightedDom) return;
|
|
281
|
+
if (el === this.highlightedDom || !el) return;
|
|
209
282
|
this.highlightLayer.highlight(el);
|
|
210
283
|
this.highlightedDom = el;
|
|
211
284
|
}
|
|
@@ -226,6 +299,19 @@ export default class StageCore extends EventEmitter {
|
|
|
226
299
|
this.zoom = zoom;
|
|
227
300
|
}
|
|
228
301
|
|
|
302
|
+
/**
|
|
303
|
+
* 用于在切换选择模式时清除上一次的状态
|
|
304
|
+
* @param selectType 需要清理的选择模式 多选:multiSelect,单选:select
|
|
305
|
+
*/
|
|
306
|
+
public clearSelectStatus(selectType: String) {
|
|
307
|
+
if (selectType === 'multiSelect') {
|
|
308
|
+
this.multiDr.clearSelectStatus();
|
|
309
|
+
this.selectedDomList = [];
|
|
310
|
+
} else {
|
|
311
|
+
this.dr.clearSelectStatus();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
229
315
|
/**
|
|
230
316
|
* 挂载Dom节点
|
|
231
317
|
* @param el 将stage挂载到该Dom节点上
|
|
@@ -248,6 +334,27 @@ export default class StageCore extends EventEmitter {
|
|
|
248
334
|
this.dr.clearGuides();
|
|
249
335
|
}
|
|
250
336
|
|
|
337
|
+
public async addContainerHighlightClassName(event: MouseEvent, exclude: Element[]) {
|
|
338
|
+
const els = this.getElementsFromPoint(event);
|
|
339
|
+
const { renderer } = this;
|
|
340
|
+
const doc = renderer.contentWindow?.document;
|
|
341
|
+
|
|
342
|
+
if (!doc) return;
|
|
343
|
+
|
|
344
|
+
for (const el of els) {
|
|
345
|
+
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isContainer(el)) && !exclude.includes(el)) {
|
|
346
|
+
addClassName(el, doc, this.containerHighlightClassName);
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
public getAddContainerHighlightClassNameTimeout(event: MouseEvent, exclude: Element[] = []): NodeJS.Timeout {
|
|
353
|
+
return globalThis.setTimeout(() => {
|
|
354
|
+
this.addContainerHighlightClassName(event, exclude);
|
|
355
|
+
}, this.containerHighlightDuration);
|
|
356
|
+
}
|
|
357
|
+
|
|
251
358
|
/**
|
|
252
359
|
* 销毁实例
|
|
253
360
|
*/
|