@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/src/StageDragResize.ts
CHANGED
|
@@ -19,36 +19,32 @@
|
|
|
19
19
|
/* eslint-disable no-param-reassign */
|
|
20
20
|
import { EventEmitter } from 'events';
|
|
21
21
|
|
|
22
|
+
import KeyController from 'keycon';
|
|
22
23
|
import type { MoveableOptions } from 'moveable';
|
|
23
24
|
import Moveable from 'moveable';
|
|
24
25
|
import MoveableHelper from 'moveable-helper';
|
|
25
26
|
|
|
27
|
+
import { removeClassNameByClassName } from '@tmagic/utils';
|
|
28
|
+
|
|
26
29
|
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
|
27
30
|
import StageCore from './StageCore';
|
|
28
|
-
import
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
enum ActionStatus {
|
|
33
|
-
/** 开始拖动 */
|
|
34
|
-
START = 'start',
|
|
35
|
-
/** 拖动中 */
|
|
36
|
-
ING = 'ing',
|
|
37
|
-
/** 拖动结束 */
|
|
38
|
-
END = 'end',
|
|
39
|
-
}
|
|
31
|
+
import StageMask from './StageMask';
|
|
32
|
+
import type { StageDragResizeConfig } from './types';
|
|
33
|
+
import { ContainerHighlightType, StageDragStatus } from './types';
|
|
34
|
+
import { calcValueByFontsize, down, getAbsolutePosition, getMode, getOffset, getTargetElStyle, up } from './util';
|
|
40
35
|
|
|
41
36
|
/**
|
|
42
37
|
* 选中框
|
|
43
38
|
*/
|
|
44
39
|
export default class StageDragResize extends EventEmitter {
|
|
45
40
|
public core: StageCore;
|
|
41
|
+
public mask: StageMask;
|
|
46
42
|
/** 画布容器 */
|
|
47
43
|
public container: HTMLElement;
|
|
48
44
|
/** 目标节点 */
|
|
49
45
|
public target?: HTMLElement;
|
|
50
46
|
/** 目标节点在蒙层中的占位节点 */
|
|
51
|
-
public dragEl
|
|
47
|
+
public dragEl?: HTMLDivElement;
|
|
52
48
|
/** Moveable拖拽类实例 */
|
|
53
49
|
public moveable?: Moveable;
|
|
54
50
|
/** 水平参考线 */
|
|
@@ -62,19 +58,32 @@ export default class StageDragResize extends EventEmitter {
|
|
|
62
58
|
|
|
63
59
|
private moveableOptions: MoveableOptions = {};
|
|
64
60
|
/** 拖动状态 */
|
|
65
|
-
private dragStatus:
|
|
61
|
+
private dragStatus: StageDragStatus = StageDragStatus.END;
|
|
66
62
|
/** 流式布局下,目标节点的镜像节点 */
|
|
67
63
|
private ghostEl: HTMLElement | undefined;
|
|
68
64
|
private moveableHelper?: MoveableHelper;
|
|
65
|
+
private isContainerHighlight: Boolean = false;
|
|
69
66
|
|
|
70
67
|
constructor(config: StageDragResizeConfig) {
|
|
71
68
|
super();
|
|
72
69
|
|
|
73
70
|
this.core = config.core;
|
|
74
71
|
this.container = config.container;
|
|
72
|
+
this.mask = config.mask;
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
KeyController.global.keydown('alt', (e) => {
|
|
75
|
+
e.inputEvent.preventDefault();
|
|
76
|
+
this.isContainerHighlight = true;
|
|
77
|
+
});
|
|
78
|
+
KeyController.global.keyup('alt', (e) => {
|
|
79
|
+
e.inputEvent.preventDefault();
|
|
80
|
+
|
|
81
|
+
const doc = this.core.renderer.contentWindow?.document;
|
|
82
|
+
if (doc && this.canContainerHighlight()) {
|
|
83
|
+
removeClassNameByClassName(doc, this.core.containerHighlightClassName);
|
|
84
|
+
}
|
|
85
|
+
this.isContainerHighlight = false;
|
|
86
|
+
});
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
/**
|
|
@@ -145,6 +154,17 @@ export default class StageDragResize extends EventEmitter {
|
|
|
145
154
|
this.updateMoveable();
|
|
146
155
|
}
|
|
147
156
|
|
|
157
|
+
public clearSelectStatus(): void {
|
|
158
|
+
if (!this.moveable) return;
|
|
159
|
+
this.destroyDragEl();
|
|
160
|
+
this.moveable.target = null;
|
|
161
|
+
this.moveable.updateTarget();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public destroyDragEl(): void {
|
|
165
|
+
this.dragEl?.remove();
|
|
166
|
+
}
|
|
167
|
+
|
|
148
168
|
/**
|
|
149
169
|
* 销毁实例
|
|
150
170
|
*/
|
|
@@ -152,7 +172,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
152
172
|
this.moveable?.destroy();
|
|
153
173
|
this.destroyGhostEl();
|
|
154
174
|
this.destroyDragEl();
|
|
155
|
-
this.dragStatus =
|
|
175
|
+
this.dragStatus = StageDragStatus.END;
|
|
156
176
|
this.removeAllListeners();
|
|
157
177
|
}
|
|
158
178
|
|
|
@@ -164,9 +184,15 @@ export default class StageDragResize extends EventEmitter {
|
|
|
164
184
|
this.mode = getMode(el);
|
|
165
185
|
|
|
166
186
|
this.destroyGhostEl();
|
|
187
|
+
this.destroyDragEl();
|
|
188
|
+
this.dragEl = globalThis.document.createElement('div');
|
|
189
|
+
this.container.append(this.dragEl);
|
|
190
|
+
this.dragEl.style.cssText = getTargetElStyle(el);
|
|
191
|
+
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
|
167
192
|
|
|
168
|
-
this.updateDragEl
|
|
169
|
-
|
|
193
|
+
if (typeof this.core.config.updateDragEl === 'function') {
|
|
194
|
+
this.core.config.updateDragEl(this.dragEl, el);
|
|
195
|
+
}
|
|
170
196
|
this.moveableOptions = this.getOptions({
|
|
171
197
|
target: this.dragEl,
|
|
172
198
|
});
|
|
@@ -179,20 +205,24 @@ export default class StageDragResize extends EventEmitter {
|
|
|
179
205
|
this.elementGuidelines = [];
|
|
180
206
|
|
|
181
207
|
if (this.mode === Mode.ABSOLUTE) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const { width, height } = node.getBoundingClientRect();
|
|
186
|
-
if (node === this.target) continue;
|
|
187
|
-
const { left, top } = getOffset(node as HTMLElement);
|
|
188
|
-
const elementGuideline = document.createElement('div');
|
|
189
|
-
elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
|
|
190
|
-
this.elementGuidelines.push(elementGuideline);
|
|
191
|
-
frame.append(elementGuideline);
|
|
192
|
-
}
|
|
208
|
+
this.container.append(this.createGuidelineElements(nodes));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
193
211
|
|
|
194
|
-
|
|
212
|
+
private createGuidelineElements(nodes: HTMLElement[]) {
|
|
213
|
+
const frame = globalThis.document.createDocumentFragment();
|
|
214
|
+
|
|
215
|
+
for (const node of nodes) {
|
|
216
|
+
const { width, height } = node.getBoundingClientRect();
|
|
217
|
+
if (node === this.target) continue;
|
|
218
|
+
const { left, top } = getOffset(node as HTMLElement);
|
|
219
|
+
const elementGuideline = globalThis.document.createElement('div');
|
|
220
|
+
elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
|
|
221
|
+
this.elementGuidelines.push(elementGuideline);
|
|
222
|
+
frame.append(elementGuideline);
|
|
195
223
|
}
|
|
224
|
+
|
|
225
|
+
return frame;
|
|
196
226
|
}
|
|
197
227
|
|
|
198
228
|
private initMoveable() {
|
|
@@ -220,7 +250,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
220
250
|
.on('resizeStart', (e) => {
|
|
221
251
|
if (!this.target) return;
|
|
222
252
|
|
|
223
|
-
this.dragStatus =
|
|
253
|
+
this.dragStatus = StageDragStatus.START;
|
|
224
254
|
this.moveableHelper?.onResizeStart(e);
|
|
225
255
|
|
|
226
256
|
frame.top = this.target.offsetTop;
|
|
@@ -231,7 +261,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
231
261
|
if (!this.moveable || !this.target || !this.dragEl) return;
|
|
232
262
|
|
|
233
263
|
const { beforeTranslate } = drag;
|
|
234
|
-
this.dragStatus =
|
|
264
|
+
this.dragStatus = StageDragStatus.ING;
|
|
235
265
|
|
|
236
266
|
this.moveableHelper?.onResize(e);
|
|
237
267
|
|
|
@@ -247,7 +277,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
247
277
|
this.target.style.height = `${height}px`;
|
|
248
278
|
})
|
|
249
279
|
.on('resizeEnd', () => {
|
|
250
|
-
this.dragStatus =
|
|
280
|
+
this.dragStatus = StageDragStatus.END;
|
|
251
281
|
this.update(true);
|
|
252
282
|
});
|
|
253
283
|
}
|
|
@@ -260,11 +290,16 @@ export default class StageDragResize extends EventEmitter {
|
|
|
260
290
|
top: 0,
|
|
261
291
|
};
|
|
262
292
|
|
|
293
|
+
let timeout: NodeJS.Timeout | undefined;
|
|
294
|
+
|
|
295
|
+
const { contentWindow } = this.core.renderer;
|
|
296
|
+
const doc = contentWindow?.document;
|
|
297
|
+
|
|
263
298
|
this.moveable
|
|
264
299
|
.on('dragStart', (e) => {
|
|
265
300
|
if (!this.target) throw new Error('未选中组件');
|
|
266
301
|
|
|
267
|
-
this.dragStatus =
|
|
302
|
+
this.dragStatus = StageDragStatus.START;
|
|
268
303
|
|
|
269
304
|
this.moveableHelper?.onDragStart(e);
|
|
270
305
|
|
|
@@ -278,7 +313,16 @@ export default class StageDragResize extends EventEmitter {
|
|
|
278
313
|
.on('drag', (e) => {
|
|
279
314
|
if (!this.target || !this.dragEl) return;
|
|
280
315
|
|
|
281
|
-
|
|
316
|
+
if (timeout) {
|
|
317
|
+
globalThis.clearTimeout(timeout);
|
|
318
|
+
timeout = undefined;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (this.canContainerHighlight()) {
|
|
322
|
+
timeout = this.core.getAddContainerHighlightClassNameTimeout(e.inputEvent, [this.target]);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
this.dragStatus = StageDragStatus.ING;
|
|
282
326
|
|
|
283
327
|
// 流式布局
|
|
284
328
|
if (this.ghostEl) {
|
|
@@ -292,18 +336,33 @@ export default class StageDragResize extends EventEmitter {
|
|
|
292
336
|
this.target.style.top = `${frame.top + e.beforeTranslate[1]}px`;
|
|
293
337
|
})
|
|
294
338
|
.on('dragEnd', () => {
|
|
339
|
+
if (timeout) {
|
|
340
|
+
globalThis.clearTimeout(timeout);
|
|
341
|
+
timeout = undefined;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
let parentEl: HTMLElement | null = null;
|
|
345
|
+
|
|
346
|
+
if (doc && this.canContainerHighlight()) {
|
|
347
|
+
parentEl = removeClassNameByClassName(doc, this.core.containerHighlightClassName);
|
|
348
|
+
}
|
|
349
|
+
|
|
295
350
|
// 点击不拖动时会触发dragStart和dragEnd,但是不会有drag事件
|
|
296
|
-
if (this.dragStatus ===
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
351
|
+
if (this.dragStatus === StageDragStatus.ING) {
|
|
352
|
+
if (parentEl) {
|
|
353
|
+
this.update(false, parentEl);
|
|
354
|
+
} else {
|
|
355
|
+
switch (this.mode) {
|
|
356
|
+
case Mode.SORTABLE:
|
|
357
|
+
this.sort();
|
|
358
|
+
break;
|
|
359
|
+
default:
|
|
360
|
+
this.update();
|
|
361
|
+
}
|
|
303
362
|
}
|
|
304
363
|
}
|
|
305
364
|
|
|
306
|
-
this.dragStatus =
|
|
365
|
+
this.dragStatus = StageDragStatus.END;
|
|
307
366
|
this.destroyGhostEl();
|
|
308
367
|
});
|
|
309
368
|
}
|
|
@@ -313,18 +372,18 @@ export default class StageDragResize extends EventEmitter {
|
|
|
313
372
|
|
|
314
373
|
this.moveable
|
|
315
374
|
.on('rotateStart', (e) => {
|
|
316
|
-
this.dragStatus =
|
|
375
|
+
this.dragStatus = StageDragStatus.START;
|
|
317
376
|
this.moveableHelper?.onRotateStart(e);
|
|
318
377
|
})
|
|
319
378
|
.on('rotate', (e) => {
|
|
320
379
|
if (!this.target || !this.dragEl) return;
|
|
321
|
-
this.dragStatus =
|
|
380
|
+
this.dragStatus = StageDragStatus.ING;
|
|
322
381
|
this.moveableHelper?.onRotate(e);
|
|
323
382
|
const frame = this.moveableHelper?.getFrame(e.target);
|
|
324
383
|
this.target.style.transform = frame?.toCSSObject().transform || '';
|
|
325
384
|
})
|
|
326
385
|
.on('rotateEnd', (e) => {
|
|
327
|
-
this.dragStatus =
|
|
386
|
+
this.dragStatus = StageDragStatus.END;
|
|
328
387
|
const frame = this.moveableHelper?.getFrame(e.target);
|
|
329
388
|
this.emit('update', {
|
|
330
389
|
el: this.target,
|
|
@@ -340,18 +399,18 @@ export default class StageDragResize extends EventEmitter {
|
|
|
340
399
|
|
|
341
400
|
this.moveable
|
|
342
401
|
.on('scaleStart', (e) => {
|
|
343
|
-
this.dragStatus =
|
|
402
|
+
this.dragStatus = StageDragStatus.START;
|
|
344
403
|
this.moveableHelper?.onScaleStart(e);
|
|
345
404
|
})
|
|
346
405
|
.on('scale', (e) => {
|
|
347
406
|
if (!this.target || !this.dragEl) return;
|
|
348
|
-
this.dragStatus =
|
|
407
|
+
this.dragStatus = StageDragStatus.ING;
|
|
349
408
|
this.moveableHelper?.onScale(e);
|
|
350
409
|
const frame = this.moveableHelper?.getFrame(e.target);
|
|
351
410
|
this.target.style.transform = frame?.toCSSObject().transform || '';
|
|
352
411
|
})
|
|
353
412
|
.on('scaleEnd', (e) => {
|
|
354
|
-
this.dragStatus =
|
|
413
|
+
this.dragStatus = StageDragStatus.END;
|
|
355
414
|
const frame = this.moveableHelper?.getFrame(e.target);
|
|
356
415
|
this.emit('update', {
|
|
357
416
|
el: this.target,
|
|
@@ -381,20 +440,41 @@ export default class StageDragResize extends EventEmitter {
|
|
|
381
440
|
}
|
|
382
441
|
}
|
|
383
442
|
|
|
384
|
-
private update(isResize = false): void {
|
|
443
|
+
private update(isResize = false, parentEl: HTMLElement | null = null): void {
|
|
385
444
|
if (!this.target) return;
|
|
386
445
|
|
|
446
|
+
const { contentWindow } = this.core.renderer;
|
|
447
|
+
const doc = contentWindow?.document;
|
|
448
|
+
|
|
449
|
+
if (!doc) return;
|
|
450
|
+
|
|
387
451
|
const offset =
|
|
388
452
|
this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
|
|
389
453
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
const width =
|
|
393
|
-
const height =
|
|
454
|
+
let left = calcValueByFontsize(doc, offset.left);
|
|
455
|
+
let top = calcValueByFontsize(doc, offset.top);
|
|
456
|
+
const width = calcValueByFontsize(doc, this.target.clientWidth);
|
|
457
|
+
const height = calcValueByFontsize(doc, this.target.clientHeight);
|
|
458
|
+
|
|
459
|
+
if (parentEl && this.mode === Mode.ABSOLUTE && this.dragEl) {
|
|
460
|
+
const [translateX, translateY] = this.moveableHelper?.getFrame(this.dragEl).properties.transform.translate.value;
|
|
461
|
+
const { left: parentLeft, top: parentTop } = getOffset(parentEl);
|
|
462
|
+
left =
|
|
463
|
+
calcValueByFontsize(doc, this.dragEl.offsetLeft) +
|
|
464
|
+
parseFloat(translateX) -
|
|
465
|
+
calcValueByFontsize(doc, parentLeft);
|
|
466
|
+
top =
|
|
467
|
+
calcValueByFontsize(doc, this.dragEl.offsetTop) + parseFloat(translateY) - calcValueByFontsize(doc, parentTop);
|
|
468
|
+
}
|
|
394
469
|
|
|
395
470
|
this.emit('update', {
|
|
396
|
-
|
|
397
|
-
|
|
471
|
+
data: [
|
|
472
|
+
{
|
|
473
|
+
el: this.target,
|
|
474
|
+
style: isResize ? { left, top, width, height } : { left, top },
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
parentEl,
|
|
398
478
|
});
|
|
399
479
|
}
|
|
400
480
|
|
|
@@ -404,6 +484,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
404
484
|
}
|
|
405
485
|
|
|
406
486
|
const ghostEl = el.cloneNode(true) as HTMLElement;
|
|
487
|
+
this.setGhostElChildrenId(ghostEl);
|
|
407
488
|
const { top, left } = getAbsolutePosition(el, getOffset(el));
|
|
408
489
|
ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
|
|
409
490
|
ghostEl.style.zIndex = ZIndex.GHOST_EL;
|
|
@@ -415,34 +496,21 @@ export default class StageDragResize extends EventEmitter {
|
|
|
415
496
|
return ghostEl;
|
|
416
497
|
}
|
|
417
498
|
|
|
418
|
-
private
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
private updateDragEl(el: HTMLElement) {
|
|
424
|
-
const offset = getOffset(el);
|
|
425
|
-
const { transform } = getComputedStyle(el);
|
|
426
|
-
|
|
427
|
-
this.dragEl.style.cssText = `
|
|
428
|
-
position: absolute;
|
|
429
|
-
transform: ${transform};
|
|
430
|
-
left: ${offset.left}px;
|
|
431
|
-
top: ${offset.top}px;
|
|
432
|
-
width: ${el.clientWidth}px;
|
|
433
|
-
height: ${el.clientHeight}px;
|
|
434
|
-
z-index: ${ZIndex.DRAG_EL};
|
|
435
|
-
`;
|
|
436
|
-
|
|
437
|
-
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
|
499
|
+
private setGhostElChildrenId(el: Element) {
|
|
500
|
+
for (const child of Array.from(el.children)) {
|
|
501
|
+
if (child.id) {
|
|
502
|
+
child.id = `${GHOST_EL_ID_PREFIX}${child.id}`;
|
|
503
|
+
}
|
|
438
504
|
|
|
439
|
-
|
|
440
|
-
|
|
505
|
+
if (child.children.length) {
|
|
506
|
+
this.setGhostElChildrenId(child);
|
|
507
|
+
}
|
|
441
508
|
}
|
|
442
509
|
}
|
|
443
510
|
|
|
444
|
-
private
|
|
445
|
-
this.
|
|
511
|
+
private destroyGhostEl(): void {
|
|
512
|
+
this.ghostEl?.remove();
|
|
513
|
+
this.ghostEl = undefined;
|
|
446
514
|
}
|
|
447
515
|
|
|
448
516
|
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
|
@@ -503,7 +571,7 @@ export default class StageDragResize extends EventEmitter {
|
|
|
503
571
|
top: 0,
|
|
504
572
|
// 设置0的话无法移动到left为0,所以只能设置为-1
|
|
505
573
|
left: -1,
|
|
506
|
-
right: this.container.clientWidth,
|
|
574
|
+
right: this.container.clientWidth - 1,
|
|
507
575
|
bottom: this.container.clientHeight,
|
|
508
576
|
...(moveableOptions.bounds || {}),
|
|
509
577
|
},
|
|
@@ -512,85 +580,10 @@ export default class StageDragResize extends EventEmitter {
|
|
|
512
580
|
};
|
|
513
581
|
}
|
|
514
582
|
|
|
515
|
-
private
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
const times = globalThis.parseFloat(fontSize) / 100;
|
|
521
|
-
return (value / times).toFixed(2);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
return value;
|
|
583
|
+
private canContainerHighlight() {
|
|
584
|
+
return (
|
|
585
|
+
this.core.containerHighlightType === ContainerHighlightType.DEFAULT ||
|
|
586
|
+
(this.core.containerHighlightType === ContainerHighlightType.ALT && this.isContainerHighlight)
|
|
587
|
+
);
|
|
525
588
|
}
|
|
526
589
|
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* 下移组件位置
|
|
530
|
-
* @param {number} deltaTop 偏移量
|
|
531
|
-
* @param {Object} detail 当前选中的组件配置
|
|
532
|
-
*/
|
|
533
|
-
export const down = (deltaTop: number, target: HTMLElement | SVGElement): SortEventData | void => {
|
|
534
|
-
let swapIndex = 0;
|
|
535
|
-
let addUpH = target.clientHeight;
|
|
536
|
-
const brothers = Array.from(target.parentNode?.children || []).filter(
|
|
537
|
-
(node) => !node.id.startsWith(GHOST_EL_ID_PREFIX),
|
|
538
|
-
);
|
|
539
|
-
const index = brothers.indexOf(target);
|
|
540
|
-
// 往下移动
|
|
541
|
-
const downEls = brothers.slice(index + 1) as HTMLElement[];
|
|
542
|
-
|
|
543
|
-
for (let i = 0; i < downEls.length; i++) {
|
|
544
|
-
const ele = downEls[i];
|
|
545
|
-
// 是 fixed 不做处理
|
|
546
|
-
if (ele.style?.position === 'fixed') {
|
|
547
|
-
continue;
|
|
548
|
-
}
|
|
549
|
-
addUpH += ele.clientHeight / 2;
|
|
550
|
-
if (deltaTop <= addUpH) {
|
|
551
|
-
break;
|
|
552
|
-
}
|
|
553
|
-
addUpH += ele.clientHeight / 2;
|
|
554
|
-
swapIndex = i;
|
|
555
|
-
}
|
|
556
|
-
return {
|
|
557
|
-
src: target.id,
|
|
558
|
-
dist: downEls.length && swapIndex > -1 ? downEls[swapIndex].id : target.id,
|
|
559
|
-
};
|
|
560
|
-
};
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* 上移组件位置
|
|
564
|
-
* @param {Array} brothers 处于同一容器下的所有子组件配置
|
|
565
|
-
* @param {number} index 当前组件所处的位置
|
|
566
|
-
* @param {number} deltaTop 偏移量
|
|
567
|
-
* @param {Object} detail 当前选中的组件配置
|
|
568
|
-
*/
|
|
569
|
-
export const up = (deltaTop: number, target: HTMLElement | SVGElement): SortEventData | void => {
|
|
570
|
-
const brothers = Array.from(target.parentNode?.children || []).filter(
|
|
571
|
-
(node) => !node.id.startsWith(GHOST_EL_ID_PREFIX),
|
|
572
|
-
);
|
|
573
|
-
const index = brothers.indexOf(target);
|
|
574
|
-
// 往上移动
|
|
575
|
-
const upEls = brothers.slice(0, index) as HTMLElement[];
|
|
576
|
-
|
|
577
|
-
let addUpH = target.clientHeight;
|
|
578
|
-
let swapIndex = upEls.length - 1;
|
|
579
|
-
|
|
580
|
-
for (let i = upEls.length - 1; i >= 0; i--) {
|
|
581
|
-
const ele = upEls[i];
|
|
582
|
-
if (!ele) continue;
|
|
583
|
-
// 是 fixed 不做处理
|
|
584
|
-
if (ele.style.position === 'fixed') continue;
|
|
585
|
-
|
|
586
|
-
addUpH += ele.clientHeight / 2;
|
|
587
|
-
if (-deltaTop <= addUpH) break;
|
|
588
|
-
addUpH += ele.clientHeight / 2;
|
|
589
|
-
|
|
590
|
-
swapIndex = i;
|
|
591
|
-
}
|
|
592
|
-
return {
|
|
593
|
-
src: target.id,
|
|
594
|
-
dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id,
|
|
595
|
-
};
|
|
596
|
-
};
|
package/src/StageHighlight.ts
CHANGED
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
/* eslint-disable no-param-reassign */
|
|
20
19
|
import { EventEmitter } from 'events';
|
|
21
20
|
|
|
22
21
|
import Moveable from 'moveable';
|
|
@@ -58,7 +57,7 @@ export default class StageHighlight extends EventEmitter {
|
|
|
58
57
|
target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
|
|
59
58
|
origin: false,
|
|
60
59
|
rootContainer: this.core.container,
|
|
61
|
-
zoom:
|
|
60
|
+
zoom: 2,
|
|
62
61
|
});
|
|
63
62
|
}
|
|
64
63
|
|
package/src/StageMask.ts
CHANGED
|
@@ -16,23 +16,22 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import KeyController from 'keycon';
|
|
19
20
|
import { throttle } from 'lodash-es';
|
|
20
21
|
|
|
22
|
+
import { createDiv, injectStyle } from '@tmagic/utils';
|
|
23
|
+
|
|
21
24
|
import { Mode, MouseButton, ZIndex } from './const';
|
|
22
25
|
import Rule from './Rule';
|
|
23
26
|
import type StageCore from './StageCore';
|
|
24
27
|
import type { StageMaskConfig } from './types';
|
|
25
|
-
import {
|
|
28
|
+
import { getScrollParent, isFixedParent } from './util';
|
|
26
29
|
|
|
27
30
|
const wrapperClassName = 'editor-mask-wrapper';
|
|
28
31
|
const throttleTime = 100;
|
|
29
32
|
|
|
30
33
|
const hideScrollbar = () => {
|
|
31
|
-
|
|
32
|
-
style.innerHTML = `
|
|
33
|
-
.${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }
|
|
34
|
-
`;
|
|
35
|
-
globalThis.document.head.appendChild(style);
|
|
34
|
+
injectStyle(globalThis.document, `.${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }`);
|
|
36
35
|
};
|
|
37
36
|
|
|
38
37
|
const createContent = (): HTMLDivElement =>
|
|
@@ -84,6 +83,7 @@ export default class StageMask extends Rule {
|
|
|
84
83
|
public maxScrollTop = 0;
|
|
85
84
|
public maxScrollLeft = 0;
|
|
86
85
|
public intersectionObserver: IntersectionObserver | null = null;
|
|
86
|
+
public isMultiSelectStatus: Boolean = false;
|
|
87
87
|
|
|
88
88
|
private mode: Mode = Mode.ABSOLUTE;
|
|
89
89
|
private pageResizeObserver: ResizeObserver | null = null;
|
|
@@ -108,6 +108,19 @@ export default class StageMask extends Rule {
|
|
|
108
108
|
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
|
109
109
|
this.content.addEventListener('mousemove', this.highlightHandler);
|
|
110
110
|
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
|
111
|
+
|
|
112
|
+
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
113
|
+
|
|
114
|
+
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
115
|
+
|
|
116
|
+
KeyController.global.keydown(ctrl, (e) => {
|
|
117
|
+
e.inputEvent.preventDefault();
|
|
118
|
+
this.isMultiSelectStatus = true;
|
|
119
|
+
});
|
|
120
|
+
KeyController.global.keyup(ctrl, (e) => {
|
|
121
|
+
e.inputEvent.preventDefault();
|
|
122
|
+
this.isMultiSelectStatus = false;
|
|
123
|
+
});
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
public setMode(mode: Mode) {
|
|
@@ -294,21 +307,28 @@ export default class StageMask extends Rule {
|
|
|
294
307
|
*/
|
|
295
308
|
private mouseDownHandler = (event: MouseEvent): void => {
|
|
296
309
|
this.emit('clearHighlight');
|
|
297
|
-
|
|
298
310
|
event.stopImmediatePropagation();
|
|
299
311
|
event.stopPropagation();
|
|
300
312
|
|
|
301
313
|
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
|
302
314
|
|
|
303
|
-
//
|
|
315
|
+
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
|
316
|
+
if (!this.isMultiSelectStatus && (event.target as HTMLDivElement).className.indexOf('moveable-area') !== -1) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
// 点击对象如果是边框锚点,则可能是resize
|
|
304
320
|
if ((event.target as HTMLDivElement).className.indexOf('moveable-control') !== -1) {
|
|
305
321
|
return;
|
|
306
322
|
}
|
|
307
323
|
|
|
308
324
|
this.content.removeEventListener('mousemove', this.highlightHandler);
|
|
309
325
|
|
|
310
|
-
|
|
311
|
-
|
|
326
|
+
// 判断触发多选还是单选
|
|
327
|
+
if (this.isMultiSelectStatus) {
|
|
328
|
+
this.emit('beforeMultiSelect', event);
|
|
329
|
+
} else {
|
|
330
|
+
this.emit('beforeSelect', event);
|
|
331
|
+
}
|
|
312
332
|
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
313
333
|
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
|
314
334
|
};
|
|
@@ -316,7 +336,9 @@ export default class StageMask extends Rule {
|
|
|
316
336
|
private mouseUpHandler = (): void => {
|
|
317
337
|
globalThis.document.removeEventListener('mouseup', this.mouseUpHandler);
|
|
318
338
|
this.content.addEventListener('mousemove', this.highlightHandler);
|
|
319
|
-
this.
|
|
339
|
+
if (!this.isMultiSelectStatus) {
|
|
340
|
+
this.emit('select');
|
|
341
|
+
}
|
|
320
342
|
};
|
|
321
343
|
|
|
322
344
|
private mouseWheelHandler = (event: WheelEvent) => {
|