@tmagic/stage 1.1.0-beta.4 → 1.1.0-beta.5
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 +87 -46
- package/dist/tmagic-stage.es.js.map +1 -1
- package/dist/tmagic-stage.umd.js +87 -46
- package/dist/tmagic-stage.umd.js.map +1 -1
- package/dist/types/src/StageCore.d.ts +2 -1
- package/dist/types/src/StageMask.d.ts +1 -1
- package/dist/types/src/StageMultiDragResize.d.ts +7 -0
- package/dist/types/src/StageRender.d.ts +1 -0
- package/package.json +4 -4
- package/src/StageCore.ts +15 -9
- package/src/StageHighlight.ts +1 -1
- package/src/StageMask.ts +7 -7
- package/src/StageMultiDragResize.ts +61 -15
- package/src/StageRender.ts +28 -18
- package/src/TargetCalibrate.ts +2 -1
- package/src/style.css +1 -0
|
@@ -25,7 +25,8 @@ export default class StageCore extends EventEmitter {
|
|
|
25
25
|
private canSelect;
|
|
26
26
|
constructor(config: StageCoreConfig);
|
|
27
27
|
getElementsFromPoint(event: MouseEvent): HTMLElement[];
|
|
28
|
-
getElementFromPoint(event: MouseEvent
|
|
28
|
+
getElementFromPoint(event: MouseEvent): Promise<HTMLElement | undefined>;
|
|
29
|
+
isElCanSelect(el: HTMLElement, event: MouseEvent, stop: () => boolean): Promise<Boolean>;
|
|
29
30
|
/**
|
|
30
31
|
* 选中组件
|
|
31
32
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
|
@@ -21,7 +21,7 @@ export default class StageMask extends Rule {
|
|
|
21
21
|
maxScrollTop: number;
|
|
22
22
|
maxScrollLeft: number;
|
|
23
23
|
intersectionObserver: IntersectionObserver | null;
|
|
24
|
-
|
|
24
|
+
isMultiSelectStatus: Boolean;
|
|
25
25
|
private mode;
|
|
26
26
|
private pageResizeObserver;
|
|
27
27
|
private wrapperResizeObserver;
|
|
@@ -22,6 +22,7 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
22
22
|
* @param els
|
|
23
23
|
*/
|
|
24
24
|
multiSelect(els: HTMLElement[]): void;
|
|
25
|
+
canSelect(el: HTMLElement): Boolean;
|
|
25
26
|
/**
|
|
26
27
|
* 清除多选状态
|
|
27
28
|
*/
|
|
@@ -39,4 +40,10 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
39
40
|
* @param isResize 是否进行大小缩放
|
|
40
41
|
*/
|
|
41
42
|
private update;
|
|
43
|
+
/**
|
|
44
|
+
* 获取moveable options参数
|
|
45
|
+
* @param {MoveableOptions} options
|
|
46
|
+
* @return {MoveableOptions} moveable options参数
|
|
47
|
+
*/
|
|
48
|
+
private getOptions;
|
|
42
49
|
}
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.1.0-beta.
|
|
2
|
+
"version": "1.1.0-beta.5",
|
|
3
3
|
"name": "@tmagic/stage",
|
|
4
4
|
"sideEffects": [
|
|
5
5
|
"dist/*"
|
|
@@ -27,9 +27,9 @@
|
|
|
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.5",
|
|
31
|
+
"@tmagic/schema": "1.1.0-beta.5",
|
|
32
|
+
"@tmagic/utils": "1.1.0-beta.5",
|
|
33
33
|
"events": "^3.3.0",
|
|
34
34
|
"keycon": "^1.1.2",
|
|
35
35
|
"lodash-es": "^4.17.21",
|
package/src/StageCore.ts
CHANGED
|
@@ -99,7 +99,7 @@ export default class StageCore extends EventEmitter {
|
|
|
99
99
|
this.emit('changeGuides', data);
|
|
100
100
|
})
|
|
101
101
|
.on('highlight', async (event: MouseEvent) => {
|
|
102
|
-
const el = await this.getElementFromPoint(event
|
|
102
|
+
const el = await this.getElementFromPoint(event);
|
|
103
103
|
if (!el) return;
|
|
104
104
|
await this.highlight(el);
|
|
105
105
|
if (this.highlightedDom === this.selectedDom) {
|
|
@@ -114,8 +114,6 @@ export default class StageCore extends EventEmitter {
|
|
|
114
114
|
.on('beforeMultiSelect', async (event: MouseEvent) => {
|
|
115
115
|
const el = await this.getElementFromPoint(event);
|
|
116
116
|
if (!el) return;
|
|
117
|
-
// 多选不可以选中magic-ui-page
|
|
118
|
-
if (el.className.includes(PAGE_CLASS)) return;
|
|
119
117
|
this.clearSelectStatus('select');
|
|
120
118
|
// 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
|
|
121
119
|
if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
|
|
@@ -166,26 +164,35 @@ export default class StageCore extends EventEmitter {
|
|
|
166
164
|
return doc?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
|
|
167
165
|
}
|
|
168
166
|
|
|
169
|
-
public async getElementFromPoint(event: MouseEvent
|
|
167
|
+
public async getElementFromPoint(event: MouseEvent) {
|
|
170
168
|
const els = this.getElementsFromPoint(event);
|
|
171
169
|
let stopped = false;
|
|
172
170
|
const stop = () => (stopped = true);
|
|
173
171
|
for (const el of els) {
|
|
174
|
-
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.
|
|
172
|
+
if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isElCanSelect(el, event, stop))) {
|
|
175
173
|
if (stopped) break;
|
|
176
|
-
if (event.type === type) {
|
|
177
|
-
return el;
|
|
178
|
-
}
|
|
179
174
|
return el;
|
|
180
175
|
}
|
|
181
176
|
}
|
|
182
177
|
}
|
|
183
178
|
|
|
179
|
+
public async isElCanSelect(el: HTMLElement, event: MouseEvent, stop: () => boolean): Promise<Boolean> {
|
|
180
|
+
// 执行业务方传入的判断逻辑
|
|
181
|
+
const canSelectByProp = await this.canSelect(el, event, stop);
|
|
182
|
+
if (!canSelectByProp) return false;
|
|
183
|
+
// 多选规则
|
|
184
|
+
if (this.mask.isMultiSelectStatus) {
|
|
185
|
+
return this.multiDr.canSelect(el);
|
|
186
|
+
}
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
184
190
|
/**
|
|
185
191
|
* 选中组件
|
|
186
192
|
* @param idOrEl 组件Dom节点的id属性,或者Dom节点
|
|
187
193
|
*/
|
|
188
194
|
public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
|
|
195
|
+
this.clearSelectStatus('multiSelect');
|
|
189
196
|
const el = await this.getTargetElement(idOrEl);
|
|
190
197
|
|
|
191
198
|
if (el === this.selectedDom) return;
|
|
@@ -199,7 +206,6 @@ export default class StageCore extends EventEmitter {
|
|
|
199
206
|
}
|
|
200
207
|
|
|
201
208
|
this.mask.setLayout(el);
|
|
202
|
-
this.multiDr.destroyDragElList();
|
|
203
209
|
this.dr.select(el, event);
|
|
204
210
|
|
|
205
211
|
if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
|
package/src/StageHighlight.ts
CHANGED
package/src/StageMask.ts
CHANGED
|
@@ -83,7 +83,7 @@ export default class StageMask extends Rule {
|
|
|
83
83
|
public maxScrollTop = 0;
|
|
84
84
|
public maxScrollLeft = 0;
|
|
85
85
|
public intersectionObserver: IntersectionObserver | null = null;
|
|
86
|
-
public
|
|
86
|
+
public isMultiSelectStatus: Boolean = false;
|
|
87
87
|
|
|
88
88
|
private mode: Mode = Mode.ABSOLUTE;
|
|
89
89
|
private pageResizeObserver: ResizeObserver | null = null;
|
|
@@ -110,11 +110,11 @@ export default class StageMask extends Rule {
|
|
|
110
110
|
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
|
111
111
|
KeyController.global.keydown('shift', (e) => {
|
|
112
112
|
e.inputEvent.preventDefault();
|
|
113
|
-
this.
|
|
113
|
+
this.isMultiSelectStatus = true;
|
|
114
114
|
});
|
|
115
115
|
KeyController.global.keyup('shift', (e) => {
|
|
116
116
|
e.inputEvent.preventDefault();
|
|
117
|
-
this.
|
|
117
|
+
this.isMultiSelectStatus = false;
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -308,7 +308,7 @@ export default class StageMask extends Rule {
|
|
|
308
308
|
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
|
309
309
|
|
|
310
310
|
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
|
311
|
-
if (!this.
|
|
311
|
+
if (!this.isMultiSelectStatus && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
|
312
312
|
return;
|
|
313
313
|
}
|
|
314
314
|
// 点击对象如果是边框锚点,则可能是resize
|
|
@@ -319,13 +319,13 @@ export default class StageMask extends Rule {
|
|
|
319
319
|
this.content.removeEventListener('mousemove', this.highlightHandler);
|
|
320
320
|
|
|
321
321
|
// 判断触发多选还是单选
|
|
322
|
-
if (this.
|
|
322
|
+
if (this.isMultiSelectStatus) {
|
|
323
323
|
this.emit('beforeMultiSelect', event);
|
|
324
324
|
} else {
|
|
325
325
|
this.emit('beforeSelect', event);
|
|
326
|
-
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
327
|
-
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
|
328
326
|
}
|
|
327
|
+
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
328
|
+
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
|
329
329
|
};
|
|
330
330
|
|
|
331
331
|
private mouseUpHandler = (): void => {
|
|
@@ -18,14 +18,15 @@
|
|
|
18
18
|
|
|
19
19
|
import { EventEmitter } from 'events';
|
|
20
20
|
|
|
21
|
+
import type { MoveableOptions } from 'moveable';
|
|
21
22
|
import Moveable from 'moveable';
|
|
22
23
|
import MoveableHelper from 'moveable-helper';
|
|
23
24
|
|
|
24
|
-
import { DRAG_EL_ID_PREFIX } from './const';
|
|
25
|
+
import { DRAG_EL_ID_PREFIX, PAGE_CLASS } from './const';
|
|
25
26
|
import StageCore from './StageCore';
|
|
26
27
|
import StageMask from './StageMask';
|
|
27
28
|
import { StageDragResizeConfig } from './types';
|
|
28
|
-
import { calcValueByFontsize, getTargetElStyle } from './util';
|
|
29
|
+
import { calcValueByFontsize, getMode, getTargetElStyle } from './util';
|
|
29
30
|
export default class StageMultiDragResize extends EventEmitter {
|
|
30
31
|
public core: StageCore;
|
|
31
32
|
public mask: StageMask;
|
|
@@ -70,19 +71,12 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
70
71
|
this.moveableForMulti?.destroy();
|
|
71
72
|
this.multiMoveableHelper?.clear();
|
|
72
73
|
|
|
73
|
-
this.moveableForMulti = new Moveable(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
throttleDrag: 0,
|
|
80
|
-
startDragRotate: 0,
|
|
81
|
-
throttleDragRotate: 0,
|
|
82
|
-
zoom: 1,
|
|
83
|
-
origin: true,
|
|
84
|
-
padding: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
85
|
-
});
|
|
74
|
+
this.moveableForMulti = new Moveable(
|
|
75
|
+
this.container,
|
|
76
|
+
this.getOptions({
|
|
77
|
+
target: this.dragElList,
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
86
80
|
this.multiMoveableHelper = MoveableHelper.create({
|
|
87
81
|
useBeforeRender: true,
|
|
88
82
|
useRender: false,
|
|
@@ -134,6 +128,30 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
134
128
|
});
|
|
135
129
|
}
|
|
136
130
|
|
|
131
|
+
public canSelect(el: HTMLElement): Boolean {
|
|
132
|
+
// 多选不可以选中magic-ui-page
|
|
133
|
+
if (el.className.includes(PAGE_CLASS)) {
|
|
134
|
+
this.core.highlightedDom = undefined;
|
|
135
|
+
this.core.highlightLayer.clearHighlight();
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
const currentTargetMode = getMode(el);
|
|
139
|
+
let selectedDomMode = '';
|
|
140
|
+
|
|
141
|
+
if (this.targetList.length === 0 && this.core.selectedDom) {
|
|
142
|
+
// 单选后添加到多选的情况
|
|
143
|
+
selectedDomMode = getMode(this.core.selectedDom);
|
|
144
|
+
} else if (this.targetList.length > 0) {
|
|
145
|
+
// 已加入多选列表的布局模式是一样的,取第一个判断
|
|
146
|
+
selectedDomMode = getMode(this.targetList[0]);
|
|
147
|
+
}
|
|
148
|
+
// 定位模式不同,不可混选
|
|
149
|
+
if (currentTargetMode !== selectedDomMode) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
137
155
|
/**
|
|
138
156
|
* 清除多选状态
|
|
139
157
|
*/
|
|
@@ -142,6 +160,7 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
142
160
|
this.destroyDragElList();
|
|
143
161
|
this.moveableForMulti.target = null;
|
|
144
162
|
this.moveableForMulti.updateTarget();
|
|
163
|
+
this.targetList = [];
|
|
145
164
|
}
|
|
146
165
|
|
|
147
166
|
/**
|
|
@@ -182,4 +201,31 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
182
201
|
});
|
|
183
202
|
});
|
|
184
203
|
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 获取moveable options参数
|
|
207
|
+
* @param {MoveableOptions} options
|
|
208
|
+
* @return {MoveableOptions} moveable options参数
|
|
209
|
+
*/
|
|
210
|
+
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
|
211
|
+
let { moveableOptions = {} } = this.core.config;
|
|
212
|
+
|
|
213
|
+
if (typeof moveableOptions === 'function') {
|
|
214
|
+
moveableOptions = moveableOptions(this.core);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
defaultGroupRotate: 0,
|
|
218
|
+
defaultGroupOrigin: '50% 50%',
|
|
219
|
+
draggable: true,
|
|
220
|
+
resizable: true,
|
|
221
|
+
throttleDrag: 0,
|
|
222
|
+
startDragRotate: 0,
|
|
223
|
+
throttleDragRotate: 0,
|
|
224
|
+
zoom: 1,
|
|
225
|
+
origin: true,
|
|
226
|
+
padding: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
227
|
+
...options,
|
|
228
|
+
...moveableOptions,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
185
231
|
}
|
package/src/StageRender.ts
CHANGED
|
@@ -72,20 +72,22 @@ export default class StageRender extends EventEmitter {
|
|
|
72
72
|
* @param el 将页面挂载到该Dom节点上
|
|
73
73
|
*/
|
|
74
74
|
public async mount(el: HTMLDivElement) {
|
|
75
|
-
if (this.iframe) {
|
|
76
|
-
if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
|
|
77
|
-
// 不同域,使用srcdoc发起异步请求,需要目标地址支持跨域
|
|
78
|
-
let html = await fetch(this.runtimeUrl).then((res) => res.text());
|
|
79
|
-
// 使用base, 解决相对路径或绝对路径的问题
|
|
80
|
-
const base = `${location.protocol}//${getHost(this.runtimeUrl)}`;
|
|
81
|
-
html = html.replace('<head>', `<head>\n<base href="${base}">`);
|
|
82
|
-
this.iframe.srcdoc = html;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
el.appendChild<HTMLIFrameElement>(this.iframe);
|
|
86
|
-
} else {
|
|
75
|
+
if (!this.iframe) {
|
|
87
76
|
throw Error('mount 失败');
|
|
88
77
|
}
|
|
78
|
+
|
|
79
|
+
if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
|
|
80
|
+
// 不同域,使用srcdoc发起异步请求,需要目标地址支持跨域
|
|
81
|
+
let html = await fetch(this.runtimeUrl).then((res) => res.text());
|
|
82
|
+
// 使用base, 解决相对路径或绝对路径的问题
|
|
83
|
+
const base = `${location.protocol}//${getHost(this.runtimeUrl)}`;
|
|
84
|
+
html = html.replace('<head>', `<head>\n<base href="${base}">`);
|
|
85
|
+
this.iframe.srcdoc = html;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
el.appendChild<HTMLIFrameElement>(this.iframe);
|
|
89
|
+
|
|
90
|
+
this.postTmagicRuntimeReady();
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
public getRuntime = (): Promise<Runtime> => {
|
|
@@ -111,26 +113,34 @@ export default class StageRender extends EventEmitter {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
private loadHandler = async () => {
|
|
114
|
-
this.contentWindow
|
|
116
|
+
if (!this.contentWindow?.magic) {
|
|
117
|
+
this.postTmagicRuntimeReady();
|
|
118
|
+
}
|
|
115
119
|
|
|
116
|
-
this.contentWindow
|
|
120
|
+
if (!this.contentWindow) return;
|
|
117
121
|
|
|
118
122
|
if (this.render) {
|
|
119
123
|
const el = await this.render(this.core);
|
|
120
124
|
if (el) {
|
|
121
|
-
this.
|
|
125
|
+
this.contentWindow.document?.body?.appendChild(el);
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
this.emit('onload');
|
|
126
130
|
|
|
131
|
+
injectStyle(this.contentWindow.document, style);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
private postTmagicRuntimeReady() {
|
|
135
|
+
this.contentWindow = this.iframe?.contentWindow as RuntimeWindow;
|
|
136
|
+
|
|
137
|
+
this.contentWindow.magic = this.getMagicApi();
|
|
138
|
+
|
|
127
139
|
this.contentWindow.postMessage(
|
|
128
140
|
{
|
|
129
141
|
tmagicRuntimeReady: true,
|
|
130
142
|
},
|
|
131
143
|
'*',
|
|
132
144
|
);
|
|
133
|
-
|
|
134
|
-
injectStyle(this.contentWindow.document, style);
|
|
135
|
-
};
|
|
145
|
+
}
|
|
136
146
|
}
|
package/src/TargetCalibrate.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import { EventEmitter } from 'events';
|
|
20
20
|
|
|
21
|
-
import { Mode } from './const';
|
|
21
|
+
import { Mode, ZIndex } from './const';
|
|
22
22
|
import StageCore from './StageCore';
|
|
23
23
|
import StageDragResize from './StageDragResize';
|
|
24
24
|
import StageMask from './StageMask';
|
|
@@ -57,6 +57,7 @@ export default class TargetCalibrate extends EventEmitter {
|
|
|
57
57
|
top: ${top}px;
|
|
58
58
|
width: ${el.clientWidth}px;
|
|
59
59
|
height: ${el.clientHeight}px;
|
|
60
|
+
z-index: ${ZIndex.DRAG_EL};
|
|
60
61
|
`;
|
|
61
62
|
|
|
62
63
|
this.operationEl.id = `${prefix}${el.id}`;
|