@tmagic/stage 1.1.0-beta.2 → 1.1.0-beta.3
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 +245 -48
- package/dist/tmagic-stage.es.js.map +1 -1
- package/dist/tmagic-stage.umd.js +249 -50
- package/dist/tmagic-stage.umd.js.map +1 -1
- package/dist/types/src/StageCore.d.ts +12 -2
- package/dist/types/src/StageDragResize.d.ts +6 -3
- package/dist/types/src/StageMask.d.ts +1 -0
- package/dist/types/src/StageMultiDragResize.d.ts +42 -0
- package/dist/types/src/const.d.ts +1 -0
- package/dist/types/src/types.d.ts +3 -1
- package/dist/types/src/util.d.ts +1 -0
- package/package.json +5 -4
- package/src/StageCore.ts +84 -16
- package/src/StageDragResize.ts +38 -46
- package/src/StageMask.ts +23 -6
- package/src/StageMultiDragResize.ts +185 -0
- package/src/const.ts +2 -0
- package/src/types.ts +3 -1
- package/src/util.ts +16 -1
|
@@ -4,15 +4,18 @@ import type { Id } from '@tmagic/schema';
|
|
|
4
4
|
import StageDragResize from './StageDragResize';
|
|
5
5
|
import StageHighlight from './StageHighlight';
|
|
6
6
|
import StageMask from './StageMask';
|
|
7
|
+
import StageMultiDragResize from './StageMultiDragResize';
|
|
7
8
|
import StageRender from './StageRender';
|
|
8
9
|
import { IsContainer, RemoveData, SortEventData, StageCoreConfig, UpdateData } from './types';
|
|
9
10
|
export default class StageCore extends EventEmitter {
|
|
10
11
|
container?: HTMLDivElement;
|
|
11
|
-
selectedDom:
|
|
12
|
+
selectedDom: HTMLElement | undefined;
|
|
13
|
+
selectedDomList: HTMLElement[];
|
|
12
14
|
highlightedDom: Element | undefined;
|
|
13
15
|
renderer: StageRender;
|
|
14
16
|
mask: StageMask;
|
|
15
17
|
dr: StageDragResize;
|
|
18
|
+
multiDr: StageMultiDragResize;
|
|
16
19
|
highlightLayer: StageHighlight;
|
|
17
20
|
config: StageCoreConfig;
|
|
18
21
|
zoom: number;
|
|
@@ -22,7 +25,7 @@ export default class StageCore extends EventEmitter {
|
|
|
22
25
|
private canSelect;
|
|
23
26
|
constructor(config: StageCoreConfig);
|
|
24
27
|
getElementsFromPoint(event: MouseEvent): HTMLElement[];
|
|
25
|
-
|
|
28
|
+
getElementFromPoint(event: MouseEvent, type?: String): Promise<HTMLElement | undefined>;
|
|
26
29
|
/**
|
|
27
30
|
* 选中组件
|
|
28
31
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
|
@@ -42,6 +45,11 @@ export default class StageCore extends EventEmitter {
|
|
|
42
45
|
add(data: UpdateData): Promise<void>;
|
|
43
46
|
remove(data: RemoveData): Promise<void>;
|
|
44
47
|
setZoom(zoom?: number): void;
|
|
48
|
+
/**
|
|
49
|
+
* 用于在切换选择模式时清除上一次的状态
|
|
50
|
+
* @param selectType 需要清理的选择模式 多选:multiSelect,单选:select
|
|
51
|
+
*/
|
|
52
|
+
clearSelectStatus(selectType: String): void;
|
|
45
53
|
/**
|
|
46
54
|
* 挂载Dom节点
|
|
47
55
|
* @param el 将stage挂载到该Dom节点上
|
|
@@ -51,6 +59,8 @@ export default class StageCore extends EventEmitter {
|
|
|
51
59
|
* 清空所有参考线
|
|
52
60
|
*/
|
|
53
61
|
clearGuides(): void;
|
|
62
|
+
addContainerHighlightClassName(event: MouseEvent, exclude: Element[]): Promise<void>;
|
|
63
|
+
getAddContainerHighlightClassNameTimeout(event: MouseEvent, exclude?: Element[]): NodeJS.Timeout;
|
|
54
64
|
/**
|
|
55
65
|
* 销毁实例
|
|
56
66
|
*/
|
|
@@ -3,18 +3,20 @@ import { EventEmitter } from 'events';
|
|
|
3
3
|
import Moveable from 'moveable';
|
|
4
4
|
import { GuidesType, Mode } from './const';
|
|
5
5
|
import StageCore from './StageCore';
|
|
6
|
+
import StageMask from './StageMask';
|
|
6
7
|
import type { SortEventData, StageDragResizeConfig } from './types';
|
|
7
8
|
/**
|
|
8
9
|
* 选中框
|
|
9
10
|
*/
|
|
10
11
|
export default class StageDragResize extends EventEmitter {
|
|
11
12
|
core: StageCore;
|
|
13
|
+
mask: StageMask;
|
|
12
14
|
/** 画布容器 */
|
|
13
15
|
container: HTMLElement;
|
|
14
16
|
/** 目标节点 */
|
|
15
17
|
target?: HTMLElement;
|
|
16
18
|
/** 目标节点在蒙层中的占位节点 */
|
|
17
|
-
dragEl
|
|
19
|
+
dragEl?: HTMLDivElement;
|
|
18
20
|
/** Moveable拖拽类实例 */
|
|
19
21
|
moveable?: Moveable;
|
|
20
22
|
/** 水平参考线 */
|
|
@@ -45,6 +47,8 @@ export default class StageDragResize extends EventEmitter {
|
|
|
45
47
|
updateMoveable(el?: HTMLElement | undefined): void;
|
|
46
48
|
setGuidelines(type: GuidesType, guidelines: number[]): void;
|
|
47
49
|
clearGuides(): void;
|
|
50
|
+
clearSelectStatus(): void;
|
|
51
|
+
destroyDragEl(): void;
|
|
48
52
|
/**
|
|
49
53
|
* 销毁实例
|
|
50
54
|
*/
|
|
@@ -60,9 +64,8 @@ export default class StageDragResize extends EventEmitter {
|
|
|
60
64
|
private sort;
|
|
61
65
|
private update;
|
|
62
66
|
private generateGhostEl;
|
|
67
|
+
private setGhostElChildrenId;
|
|
63
68
|
private destroyGhostEl;
|
|
64
|
-
private updateDragEl;
|
|
65
|
-
private destroyDragEl;
|
|
66
69
|
private getOptions;
|
|
67
70
|
}
|
|
68
71
|
/**
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import Moveable from 'moveable';
|
|
4
|
+
import StageCore from './StageCore';
|
|
5
|
+
import StageMask from './StageMask';
|
|
6
|
+
import { StageDragResizeConfig } from './types';
|
|
7
|
+
export default class StageMultiDragResize extends EventEmitter {
|
|
8
|
+
core: StageCore;
|
|
9
|
+
mask: StageMask;
|
|
10
|
+
/** 画布容器 */
|
|
11
|
+
container: HTMLElement;
|
|
12
|
+
/** 多选:目标节点组 */
|
|
13
|
+
targetList: HTMLElement[];
|
|
14
|
+
/** 多选:目标节点在蒙层中的占位节点组 */
|
|
15
|
+
dragElList: HTMLDivElement[];
|
|
16
|
+
/** Moveable多选拖拽类实例 */
|
|
17
|
+
moveableForMulti?: Moveable;
|
|
18
|
+
private multiMoveableHelper?;
|
|
19
|
+
constructor(config: StageDragResizeConfig);
|
|
20
|
+
/**
|
|
21
|
+
* 多选
|
|
22
|
+
* @param els
|
|
23
|
+
*/
|
|
24
|
+
multiSelect(els: HTMLElement[]): void;
|
|
25
|
+
/**
|
|
26
|
+
* 清除多选状态
|
|
27
|
+
*/
|
|
28
|
+
clearSelectStatus(): void;
|
|
29
|
+
/**
|
|
30
|
+
* 销毁实例
|
|
31
|
+
*/
|
|
32
|
+
destroy(): void;
|
|
33
|
+
/**
|
|
34
|
+
* 清除蒙层占位节点
|
|
35
|
+
*/
|
|
36
|
+
destroyDragElList(): void;
|
|
37
|
+
/**
|
|
38
|
+
* 拖拽完成后将更新的位置信息暴露给上层业务方,业务方可以接收事件进行保存
|
|
39
|
+
* @param isResize 是否进行大小缩放
|
|
40
|
+
*/
|
|
41
|
+
private update;
|
|
42
|
+
}
|
|
@@ -5,6 +5,7 @@ export declare const DRAG_EL_ID_PREFIX = "drag_el_";
|
|
|
5
5
|
/** 高亮时需要在蒙层中创建一个占位节点,该节点的id前缀 */
|
|
6
6
|
export declare const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
|
|
7
7
|
export declare const CONTAINER_HIGHLIGHT_CLASS = "tmagic-stage-container-highlight";
|
|
8
|
+
export declare const PAGE_CLASS = "magic-ui-page";
|
|
8
9
|
/** 默认放到缩小倍数 */
|
|
9
10
|
export declare const DEFAULT_ZOOM = 1;
|
|
10
11
|
/** 参考线类型 */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MoveableOptions } from 'moveable';
|
|
2
2
|
import Core from '@tmagic/core';
|
|
3
|
-
import type { Id, MApp, MNode } from '@tmagic/schema';
|
|
3
|
+
import type { Id, MApp, MContainer, MNode } from '@tmagic/schema';
|
|
4
4
|
import { GuidesType } from './const';
|
|
5
5
|
import StageCore from './StageCore';
|
|
6
6
|
import StageDragResize from './StageDragResize';
|
|
@@ -32,6 +32,7 @@ export interface StageMaskConfig {
|
|
|
32
32
|
export interface StageDragResizeConfig {
|
|
33
33
|
core: StageCore;
|
|
34
34
|
container: HTMLElement;
|
|
35
|
+
mask: StageMask;
|
|
35
36
|
}
|
|
36
37
|
export declare type Rect = {
|
|
37
38
|
width: number;
|
|
@@ -67,6 +68,7 @@ export interface SortEventData {
|
|
|
67
68
|
}
|
|
68
69
|
export interface UpdateData {
|
|
69
70
|
config: MNode;
|
|
71
|
+
parent?: MContainer;
|
|
70
72
|
root: MApp;
|
|
71
73
|
}
|
|
72
74
|
export interface RemoveData {
|
package/dist/types/src/util.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Mode } from './const';
|
|
2
2
|
import type { Offset } from './types';
|
|
3
3
|
export declare const getOffset: (el: HTMLElement) => Offset;
|
|
4
|
+
export declare const getTargetElStyle: (el: HTMLElement) => string;
|
|
4
5
|
export declare const getAbsolutePosition: (el: HTMLElement, { top, left }: Offset) => {
|
|
5
6
|
left: number;
|
|
6
7
|
top: number;
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.1.0-beta.
|
|
2
|
+
"version": "1.1.0-beta.3",
|
|
3
3
|
"name": "@tmagic/stage",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"dist/*"
|
|
@@ -27,10 +27,11 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@scena/guides": "^0.17.0",
|
|
30
|
-
"@tmagic/core": "1.1.0-beta.
|
|
31
|
-
"@tmagic/schema": "1.1.0-beta.
|
|
32
|
-
"@tmagic/utils": "1.1.0-beta.
|
|
30
|
+
"@tmagic/core": "1.1.0-beta.3",
|
|
31
|
+
"@tmagic/schema": "1.1.0-beta.3",
|
|
32
|
+
"@tmagic/utils": "1.1.0-beta.3",
|
|
33
33
|
"events": "^3.3.0",
|
|
34
|
+
"keycon": "^1.1.2",
|
|
34
35
|
"lodash-es": "^4.17.21",
|
|
35
36
|
"moveable": "^0.30.0",
|
|
36
37
|
"moveable-helper": "^0.4.0"
|
package/src/StageCore.ts
CHANGED
|
@@ -19,11 +19,13 @@
|
|
|
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 { 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,
|
|
@@ -40,12 +42,15 @@ import { addSelectedClassName, removeSelectedClassName } from './util';
|
|
|
40
42
|
|
|
41
43
|
export default class StageCore extends EventEmitter {
|
|
42
44
|
public container?: HTMLDivElement;
|
|
43
|
-
|
|
44
|
-
public selectedDom:
|
|
45
|
+
// 当前选中的节点
|
|
46
|
+
public selectedDom: HTMLElement | undefined;
|
|
47
|
+
// 多选选中的节点组
|
|
48
|
+
public selectedDomList: HTMLElement[] = [];
|
|
45
49
|
public highlightedDom: Element | undefined;
|
|
46
50
|
public renderer: StageRender;
|
|
47
51
|
public mask: StageMask;
|
|
48
52
|
public dr: StageDragResize;
|
|
53
|
+
public multiDr: StageMultiDragResize;
|
|
49
54
|
public highlightLayer: StageHighlight;
|
|
50
55
|
public config: StageCoreConfig;
|
|
51
56
|
public zoom = DEFAULT_ZOOM;
|
|
@@ -68,7 +73,8 @@ export default class StageCore extends EventEmitter {
|
|
|
68
73
|
|
|
69
74
|
this.renderer = new StageRender({ core: this });
|
|
70
75
|
this.mask = new StageMask({ core: this });
|
|
71
|
-
this.dr = new StageDragResize({ core: this, container: this.mask.content });
|
|
76
|
+
this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
|
|
77
|
+
this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
|
|
72
78
|
this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
|
|
73
79
|
|
|
74
80
|
this.renderer.on('runtime-ready', (runtime: Runtime) => {
|
|
@@ -79,8 +85,11 @@ export default class StageCore extends EventEmitter {
|
|
|
79
85
|
});
|
|
80
86
|
|
|
81
87
|
this.mask
|
|
82
|
-
.on('beforeSelect', (event: MouseEvent) => {
|
|
83
|
-
this.
|
|
88
|
+
.on('beforeSelect', async (event: MouseEvent) => {
|
|
89
|
+
this.clearSelectStatus('multiSelect');
|
|
90
|
+
const el = await this.getElementFromPoint(event);
|
|
91
|
+
if (!el) return;
|
|
92
|
+
this.select(el, event);
|
|
84
93
|
})
|
|
85
94
|
.on('select', () => {
|
|
86
95
|
this.emit('select', this.selectedDom);
|
|
@@ -90,16 +99,39 @@ export default class StageCore extends EventEmitter {
|
|
|
90
99
|
this.emit('changeGuides', data);
|
|
91
100
|
})
|
|
92
101
|
.on('highlight', async (event: MouseEvent) => {
|
|
93
|
-
await this.
|
|
102
|
+
const el = await this.getElementFromPoint(event, 'mousemove');
|
|
103
|
+
if (!el) return;
|
|
104
|
+
await this.highlight(el);
|
|
94
105
|
if (this.highlightedDom === this.selectedDom) {
|
|
95
106
|
this.highlightLayer.clearHighlight();
|
|
96
107
|
return;
|
|
97
108
|
}
|
|
98
|
-
this.highlightLayer.highlight(this.highlightedDom as HTMLElement);
|
|
99
109
|
this.emit('highlight', this.highlightedDom);
|
|
100
110
|
})
|
|
101
111
|
.on('clearHighlight', async () => {
|
|
102
112
|
this.highlightLayer.clearHighlight();
|
|
113
|
+
})
|
|
114
|
+
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
|
115
|
+
const el = await this.getElementFromPoint(event);
|
|
116
|
+
if (!el) return;
|
|
117
|
+
// 多选不可以选中magic-ui-page
|
|
118
|
+
if (el.className.includes(PAGE_CLASS)) return;
|
|
119
|
+
this.clearSelectStatus('select');
|
|
120
|
+
// 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
|
|
121
|
+
if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
|
|
122
|
+
this.selectedDomList.push(this.selectedDom as HTMLElement);
|
|
123
|
+
this.selectedDom = undefined;
|
|
124
|
+
}
|
|
125
|
+
// 判断元素是否已在多选列表
|
|
126
|
+
const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
|
|
127
|
+
if (existIndex !== -1) {
|
|
128
|
+
// 再次点击取消选中
|
|
129
|
+
this.selectedDomList.splice(existIndex, 1);
|
|
130
|
+
} else {
|
|
131
|
+
this.selectedDomList.push(el);
|
|
132
|
+
}
|
|
133
|
+
this.multiDr.multiSelect(this.selectedDomList);
|
|
134
|
+
this.emit('multiSelect', this.selectedDomList);
|
|
103
135
|
});
|
|
104
136
|
|
|
105
137
|
// 要先触发select,在触发update
|
|
@@ -110,6 +142,10 @@ export default class StageCore extends EventEmitter {
|
|
|
110
142
|
.on('sort', (data: UpdateEventData) => {
|
|
111
143
|
setTimeout(() => this.emit('sort', data));
|
|
112
144
|
});
|
|
145
|
+
|
|
146
|
+
this.multiDr.on('update', (data: UpdateEventData) => {
|
|
147
|
+
setTimeout(() => this.emit('update', data));
|
|
148
|
+
});
|
|
113
149
|
}
|
|
114
150
|
|
|
115
151
|
public getElementsFromPoint(event: MouseEvent) {
|
|
@@ -130,20 +166,17 @@ export default class StageCore extends EventEmitter {
|
|
|
130
166
|
return doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
|
|
131
167
|
}
|
|
132
168
|
|
|
133
|
-
public async
|
|
169
|
+
public async getElementFromPoint(event: MouseEvent, type?: String) {
|
|
134
170
|
const els = this.getElementsFromPoint(event);
|
|
135
|
-
|
|
136
171
|
let stopped = false;
|
|
137
172
|
const stop = () => (stopped = true);
|
|
138
173
|
for (const el of els) {
|
|
139
174
|
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.canSelect(el, event, stop))) {
|
|
140
175
|
if (stopped) break;
|
|
141
|
-
if (event.type ===
|
|
142
|
-
|
|
143
|
-
break;
|
|
176
|
+
if (event.type === type) {
|
|
177
|
+
return el;
|
|
144
178
|
}
|
|
145
|
-
|
|
146
|
-
break;
|
|
179
|
+
return el;
|
|
147
180
|
}
|
|
148
181
|
}
|
|
149
182
|
}
|
|
@@ -166,6 +199,7 @@ export default class StageCore extends EventEmitter {
|
|
|
166
199
|
}
|
|
167
200
|
|
|
168
201
|
this.mask.setLayout(el);
|
|
202
|
+
this.multiDr.destroyDragElList();
|
|
169
203
|
this.dr.select(el, event);
|
|
170
204
|
|
|
171
205
|
if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
|
|
@@ -217,7 +251,7 @@ export default class StageCore extends EventEmitter {
|
|
|
217
251
|
this.highlightLayer.clearHighlight();
|
|
218
252
|
return;
|
|
219
253
|
}
|
|
220
|
-
if (el === this.highlightedDom) return;
|
|
254
|
+
if (el === this.highlightedDom || !el) return;
|
|
221
255
|
this.highlightLayer.highlight(el);
|
|
222
256
|
this.highlightedDom = el;
|
|
223
257
|
}
|
|
@@ -238,6 +272,19 @@ export default class StageCore extends EventEmitter {
|
|
|
238
272
|
this.zoom = zoom;
|
|
239
273
|
}
|
|
240
274
|
|
|
275
|
+
/**
|
|
276
|
+
* 用于在切换选择模式时清除上一次的状态
|
|
277
|
+
* @param selectType 需要清理的选择模式 多选:multiSelect,单选:select
|
|
278
|
+
*/
|
|
279
|
+
public clearSelectStatus(selectType: String) {
|
|
280
|
+
if (selectType === 'multiSelect') {
|
|
281
|
+
this.multiDr.clearSelectStatus();
|
|
282
|
+
this.selectedDomList = [];
|
|
283
|
+
} else {
|
|
284
|
+
this.dr.clearSelectStatus();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
241
288
|
/**
|
|
242
289
|
* 挂载Dom节点
|
|
243
290
|
* @param el 将stage挂载到该Dom节点上
|
|
@@ -260,6 +307,27 @@ export default class StageCore extends EventEmitter {
|
|
|
260
307
|
this.dr.clearGuides();
|
|
261
308
|
}
|
|
262
309
|
|
|
310
|
+
public async addContainerHighlightClassName(event: MouseEvent, exclude: Element[]) {
|
|
311
|
+
const els = this.getElementsFromPoint(event);
|
|
312
|
+
const { renderer } = this;
|
|
313
|
+
const doc = renderer.contentWindow?.document;
|
|
314
|
+
|
|
315
|
+
if (!doc) return;
|
|
316
|
+
|
|
317
|
+
for (const el of els) {
|
|
318
|
+
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isContainer(el)) && !exclude.includes(el)) {
|
|
319
|
+
addClassName(el, doc, this.containerHighlightClassName);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
public getAddContainerHighlightClassNameTimeout(event: MouseEvent, exclude: Element[] = []) {
|
|
326
|
+
return globalThis.setTimeout(() => {
|
|
327
|
+
this.addContainerHighlightClassName(event, exclude);
|
|
328
|
+
}, this.containerHighlightDuration);
|
|
329
|
+
}
|
|
330
|
+
|
|
263
331
|
/**
|
|
264
332
|
* 销毁实例
|
|
265
333
|
*/
|
package/src/StageDragResize.ts
CHANGED
|
@@ -23,12 +23,13 @@ import type { MoveableOptions } from 'moveable';
|
|
|
23
23
|
import Moveable from 'moveable';
|
|
24
24
|
import MoveableHelper from 'moveable-helper';
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import { removeClassNameByClassName } from '@tmagic/utils';
|
|
27
27
|
|
|
28
28
|
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
|
29
29
|
import StageCore from './StageCore';
|
|
30
|
+
import StageMask from './StageMask';
|
|
30
31
|
import type { SortEventData, StageDragResizeConfig } from './types';
|
|
31
|
-
import { calcValueByFontsize, getAbsolutePosition, getMode, getOffset } from './util';
|
|
32
|
+
import { calcValueByFontsize, getAbsolutePosition, getMode, getOffset, getTargetElStyle } from './util';
|
|
32
33
|
|
|
33
34
|
/** 拖动状态 */
|
|
34
35
|
enum ActionStatus {
|
|
@@ -45,12 +46,13 @@ enum ActionStatus {
|
|
|
45
46
|
*/
|
|
46
47
|
export default class StageDragResize extends EventEmitter {
|
|
47
48
|
public core: StageCore;
|
|
49
|
+
public mask: StageMask;
|
|
48
50
|
/** 画布容器 */
|
|
49
51
|
public container: HTMLElement;
|
|
50
52
|
/** 目标节点 */
|
|
51
53
|
public target?: HTMLElement;
|
|
52
54
|
/** 目标节点在蒙层中的占位节点 */
|
|
53
|
-
public dragEl
|
|
55
|
+
public dragEl?: HTMLDivElement;
|
|
54
56
|
/** Moveable拖拽类实例 */
|
|
55
57
|
public moveable?: Moveable;
|
|
56
58
|
/** 水平参考线 */
|
|
@@ -74,9 +76,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
74
76
|
|
|
75
77
|
this.core = config.core;
|
|
76
78
|
this.container = config.container;
|
|
77
|
-
|
|
78
|
-
this.dragEl = globalThis.document.createElement('div');
|
|
79
|
-
this.container.append(this.dragEl);
|
|
79
|
+
this.mask = config.mask;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -147,6 +147,17 @@ export default class StageDragResize extends EventEmitter {
|
|
|
147
147
|
this.updateMoveable();
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
public clearSelectStatus(): void {
|
|
151
|
+
if (!this.moveable) return;
|
|
152
|
+
this.destroyDragEl();
|
|
153
|
+
this.moveable.target = null;
|
|
154
|
+
this.moveable.updateTarget();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public destroyDragEl(): void {
|
|
158
|
+
this.dragEl?.remove();
|
|
159
|
+
}
|
|
160
|
+
|
|
150
161
|
/**
|
|
151
162
|
* 销毁实例
|
|
152
163
|
*/
|
|
@@ -166,9 +177,15 @@ export default class StageDragResize extends EventEmitter {
|
|
|
166
177
|
this.mode = getMode(el);
|
|
167
178
|
|
|
168
179
|
this.destroyGhostEl();
|
|
180
|
+
this.destroyDragEl();
|
|
181
|
+
this.dragEl = globalThis.document.createElement('div');
|
|
182
|
+
this.container.append(this.dragEl);
|
|
183
|
+
this.dragEl.style.cssText = getTargetElStyle(el);
|
|
184
|
+
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
|
169
185
|
|
|
170
|
-
this.updateDragEl
|
|
171
|
-
|
|
186
|
+
if (typeof this.core.config.updateDragEl === 'function') {
|
|
187
|
+
this.core.config.updateDragEl(this.dragEl, el);
|
|
188
|
+
}
|
|
172
189
|
this.moveableOptions = this.getOptions({
|
|
173
190
|
target: this.dragEl,
|
|
174
191
|
});
|
|
@@ -294,20 +311,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
294
311
|
timeout = undefined;
|
|
295
312
|
}
|
|
296
313
|
|
|
297
|
-
timeout =
|
|
298
|
-
const els = this.core.getElementsFromPoint(e.inputEvent);
|
|
299
|
-
for (const el of els) {
|
|
300
|
-
if (
|
|
301
|
-
doc &&
|
|
302
|
-
!el.id.startsWith(GHOST_EL_ID_PREFIX) &&
|
|
303
|
-
el !== this.target &&
|
|
304
|
-
(await this.core.isContainer(el))
|
|
305
|
-
) {
|
|
306
|
-
addClassName(el, doc, this.core.containerHighlightClassName);
|
|
307
|
-
break;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}, this.core.containerHighlightDuration);
|
|
314
|
+
timeout = this.core.getAddContainerHighlightClassNameTimeout(e.inputEvent, [this.target]);
|
|
311
315
|
|
|
312
316
|
this.dragStatus = ActionStatus.ING;
|
|
313
317
|
|
|
@@ -467,6 +471,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
467
471
|
}
|
|
468
472
|
|
|
469
473
|
const ghostEl = el.cloneNode(true) as HTMLElement;
|
|
474
|
+
this.setGhostElChildrenId(ghostEl);
|
|
470
475
|
const { top, left } = getAbsolutePosition(el, getOffset(el));
|
|
471
476
|
ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
|
|
472
477
|
ghostEl.style.zIndex = ZIndex.GHOST_EL;
|
|
@@ -478,34 +483,21 @@ export default class StageDragResize extends EventEmitter {
|
|
|
478
483
|
return ghostEl;
|
|
479
484
|
}
|
|
480
485
|
|
|
481
|
-
private
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
private updateDragEl(el: HTMLElement) {
|
|
487
|
-
const offset = getOffset(el);
|
|
488
|
-
const { transform } = getComputedStyle(el);
|
|
489
|
-
|
|
490
|
-
this.dragEl.style.cssText = `
|
|
491
|
-
position: absolute;
|
|
492
|
-
transform: ${transform};
|
|
493
|
-
left: ${offset.left}px;
|
|
494
|
-
top: ${offset.top}px;
|
|
495
|
-
width: ${el.clientWidth}px;
|
|
496
|
-
height: ${el.clientHeight}px;
|
|
497
|
-
z-index: ${ZIndex.DRAG_EL};
|
|
498
|
-
`;
|
|
499
|
-
|
|
500
|
-
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
|
486
|
+
private setGhostElChildrenId(el: Element) {
|
|
487
|
+
for (const child of el.children) {
|
|
488
|
+
if (child.id) {
|
|
489
|
+
child.id = `${GHOST_EL_ID_PREFIX}${child.id}`;
|
|
490
|
+
}
|
|
501
491
|
|
|
502
|
-
|
|
503
|
-
|
|
492
|
+
if (child.children.length) {
|
|
493
|
+
this.setGhostElChildrenId(child);
|
|
494
|
+
}
|
|
504
495
|
}
|
|
505
496
|
}
|
|
506
497
|
|
|
507
|
-
private
|
|
508
|
-
this.
|
|
498
|
+
private destroyGhostEl(): void {
|
|
499
|
+
this.ghostEl?.remove();
|
|
500
|
+
this.ghostEl = undefined;
|
|
509
501
|
}
|
|
510
502
|
|
|
511
503
|
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
package/src/StageMask.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import KeyController from 'keycon';
|
|
19
20
|
import { throttle } from 'lodash-es';
|
|
20
21
|
|
|
21
22
|
import { createDiv, injectStyle } from '@tmagic/utils';
|
|
@@ -82,6 +83,7 @@ export default class StageMask extends Rule {
|
|
|
82
83
|
public maxScrollTop = 0;
|
|
83
84
|
public maxScrollLeft = 0;
|
|
84
85
|
public intersectionObserver: IntersectionObserver | null = null;
|
|
86
|
+
public shiftKeyDown: Boolean = false;
|
|
85
87
|
|
|
86
88
|
private mode: Mode = Mode.ABSOLUTE;
|
|
87
89
|
private pageResizeObserver: ResizeObserver | null = null;
|
|
@@ -106,6 +108,14 @@ export default class StageMask extends Rule {
|
|
|
106
108
|
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
|
107
109
|
this.content.addEventListener('mousemove', this.highlightHandler);
|
|
108
110
|
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
|
111
|
+
KeyController.global.keydown('shift', (e) => {
|
|
112
|
+
e.inputEvent.preventDefault();
|
|
113
|
+
this.shiftKeyDown = true;
|
|
114
|
+
});
|
|
115
|
+
KeyController.global.keyup('shift', (e) => {
|
|
116
|
+
e.inputEvent.preventDefault();
|
|
117
|
+
this.shiftKeyDown = false;
|
|
118
|
+
});
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
public setMode(mode: Mode) {
|
|
@@ -292,23 +302,30 @@ export default class StageMask extends Rule {
|
|
|
292
302
|
*/
|
|
293
303
|
private mouseDownHandler = (event: MouseEvent): void => {
|
|
294
304
|
this.emit('clearHighlight');
|
|
295
|
-
|
|
296
305
|
event.stopImmediatePropagation();
|
|
297
306
|
event.stopPropagation();
|
|
298
307
|
|
|
299
308
|
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
|
300
309
|
|
|
301
|
-
//
|
|
310
|
+
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
|
311
|
+
if (!this.shiftKeyDown && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
// 点击对象如果是边框锚点,则可能是resize
|
|
302
315
|
if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
|
|
303
316
|
return;
|
|
304
317
|
}
|
|
305
318
|
|
|
306
319
|
this.content.removeEventListener('mousemove', this.highlightHandler);
|
|
307
320
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
321
|
+
// 判断触发多选还是单选
|
|
322
|
+
if (this.shiftKeyDown) {
|
|
323
|
+
this.emit('beforeMultiSelect', event);
|
|
324
|
+
} else {
|
|
325
|
+
this.emit('beforeSelect', event);
|
|
326
|
+
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
327
|
+
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
|
328
|
+
}
|
|
312
329
|
};
|
|
313
330
|
|
|
314
331
|
private mouseUpHandler = (): void => {
|