@tmagic/stage 1.1.0-beta.1 → 1.1.0-beta.12

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.
@@ -1,7 +1,8 @@
1
1
  import EventEmitter$1, { EventEmitter } from 'events';
2
+ import { removeClassName, removeClassNameByClassName, createDiv, injectStyle, isSameDomain, getHost, addClassName } from '@tmagic/utils';
3
+ import KeyController from 'keycon';
2
4
  import Moveable from 'moveable';
3
5
  import MoveableHelper from 'moveable-helper';
4
- import { removeClassName, addClassName, removeClassNameByClassName, createDiv, injectStyle, isSameDomain, getHost } from '@tmagic/utils';
5
6
  import { throttle } from 'lodash-es';
6
7
  import Guides from '@scena/guides';
7
8
 
@@ -9,6 +10,7 @@ const GHOST_EL_ID_PREFIX = "ghost_el_";
9
10
  const DRAG_EL_ID_PREFIX = "drag_el_";
10
11
  const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
11
12
  const CONTAINER_HIGHLIGHT_CLASS = "tmagic-stage-container-highlight";
13
+ const PAGE_CLASS = "magic-ui-page";
12
14
  const DEFAULT_ZOOM = 1;
13
15
  var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
14
16
  GuidesType2["HORIZONTAL"] = "horizontal";
@@ -36,6 +38,18 @@ var Mode = /* @__PURE__ */ ((Mode2) => {
36
38
  })(Mode || {});
37
39
  const SELECTED_CLASS = "tmagic-stage-selected-area";
38
40
 
41
+ var ContainerHighlightType = /* @__PURE__ */ ((ContainerHighlightType2) => {
42
+ ContainerHighlightType2["DEFAULT"] = "default";
43
+ ContainerHighlightType2["ALT"] = "alt";
44
+ return ContainerHighlightType2;
45
+ })(ContainerHighlightType || {});
46
+ var StageDragStatus = /* @__PURE__ */ ((StageDragStatus2) => {
47
+ StageDragStatus2["START"] = "start";
48
+ StageDragStatus2["ING"] = "ing";
49
+ StageDragStatus2["END"] = "end";
50
+ return StageDragStatus2;
51
+ })(StageDragStatus || {});
52
+
39
53
  const getParents = (el, relative) => {
40
54
  let cur = el.parentElement;
41
55
  const parents = [];
@@ -61,6 +75,19 @@ const getOffset = (el) => {
61
75
  top
62
76
  };
63
77
  };
78
+ const getTargetElStyle = (el) => {
79
+ const offset = getOffset(el);
80
+ const { transform } = getComputedStyle(el);
81
+ return `
82
+ position: absolute;
83
+ transform: ${transform};
84
+ left: ${offset.left}px;
85
+ top: ${offset.top}px;
86
+ width: ${el.clientWidth}px;
87
+ height: ${el.clientHeight}px;
88
+ z-index: ${ZIndex.DRAG_EL};
89
+ `;
90
+ };
64
91
  const getAbsolutePosition = (el, { top, left }) => {
65
92
  const { offsetParent } = el;
66
93
  if (offsetParent) {
@@ -141,20 +168,86 @@ const calcValueByFontsize = (doc, value) => {
141
168
  }
142
169
  return value;
143
170
  };
171
+ const down = (deltaTop, target) => {
172
+ let swapIndex = 0;
173
+ let addUpH = target.clientHeight;
174
+ const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
175
+ const index = brothers.indexOf(target);
176
+ const downEls = brothers.slice(index + 1);
177
+ for (let i = 0; i < downEls.length; i++) {
178
+ const ele = downEls[i];
179
+ if (ele.style?.position === "fixed") {
180
+ continue;
181
+ }
182
+ addUpH += ele.clientHeight / 2;
183
+ if (deltaTop <= addUpH) {
184
+ break;
185
+ }
186
+ addUpH += ele.clientHeight / 2;
187
+ swapIndex = i;
188
+ }
189
+ return {
190
+ src: target.id,
191
+ dist: downEls.length && swapIndex > -1 ? downEls[swapIndex].id : target.id
192
+ };
193
+ };
194
+ const up = (deltaTop, target) => {
195
+ const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
196
+ const index = brothers.indexOf(target);
197
+ const upEls = brothers.slice(0, index);
198
+ let addUpH = target.clientHeight;
199
+ let swapIndex = upEls.length - 1;
200
+ for (let i = upEls.length - 1; i >= 0; i--) {
201
+ const ele = upEls[i];
202
+ if (!ele)
203
+ continue;
204
+ if (ele.style.position === "fixed")
205
+ continue;
206
+ addUpH += ele.clientHeight / 2;
207
+ if (-deltaTop <= addUpH)
208
+ break;
209
+ addUpH += ele.clientHeight / 2;
210
+ swapIndex = i;
211
+ }
212
+ return {
213
+ src: target.id,
214
+ dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id
215
+ };
216
+ };
144
217
 
145
218
  class StageDragResize extends EventEmitter {
219
+ core;
220
+ mask;
221
+ container;
222
+ target;
223
+ dragEl;
224
+ moveable;
225
+ horizontalGuidelines = [];
226
+ verticalGuidelines = [];
227
+ elementGuidelines = [];
228
+ mode = Mode.ABSOLUTE;
229
+ moveableOptions = {};
230
+ dragStatus = StageDragStatus.END;
231
+ ghostEl;
232
+ moveableHelper;
233
+ isContainerHighlight = false;
146
234
  constructor(config) {
147
235
  super();
148
- this.horizontalGuidelines = [];
149
- this.verticalGuidelines = [];
150
- this.elementGuidelines = [];
151
- this.mode = Mode.ABSOLUTE;
152
- this.moveableOptions = {};
153
- this.dragStatus = "end" /* END */;
154
236
  this.core = config.core;
155
237
  this.container = config.container;
156
- this.dragEl = globalThis.document.createElement("div");
157
- this.container.append(this.dragEl);
238
+ this.mask = config.mask;
239
+ KeyController.global.keydown("alt", (e) => {
240
+ e.inputEvent.preventDefault();
241
+ this.isContainerHighlight = true;
242
+ });
243
+ KeyController.global.keyup("alt", (e) => {
244
+ e.inputEvent.preventDefault();
245
+ const doc = this.core.renderer.contentWindow?.document;
246
+ if (doc && this.canContainerHighlight()) {
247
+ removeClassNameByClassName(doc, this.core.containerHighlightClassName);
248
+ }
249
+ this.isContainerHighlight = false;
250
+ });
158
251
  }
159
252
  select(el, event) {
160
253
  const oldTarget = this.target;
@@ -205,11 +298,21 @@ class StageDragResize extends EventEmitter {
205
298
  this.moveableOptions.verticalGuidelines = [];
206
299
  this.updateMoveable();
207
300
  }
301
+ clearSelectStatus() {
302
+ if (!this.moveable)
303
+ return;
304
+ this.destroyDragEl();
305
+ this.moveable.target = null;
306
+ this.moveable.updateTarget();
307
+ }
308
+ destroyDragEl() {
309
+ this.dragEl?.remove();
310
+ }
208
311
  destroy() {
209
312
  this.moveable?.destroy();
210
313
  this.destroyGhostEl();
211
314
  this.destroyDragEl();
212
- this.dragStatus = "end" /* END */;
315
+ this.dragStatus = StageDragStatus.END;
213
316
  this.removeAllListeners();
214
317
  }
215
318
  init(el) {
@@ -218,7 +321,14 @@ class StageDragResize extends EventEmitter {
218
321
  }
219
322
  this.mode = getMode(el);
220
323
  this.destroyGhostEl();
221
- this.updateDragEl(el);
324
+ this.destroyDragEl();
325
+ this.dragEl = globalThis.document.createElement("div");
326
+ this.container.append(this.dragEl);
327
+ this.dragEl.style.cssText = getTargetElStyle(el);
328
+ this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
329
+ if (typeof this.core.config.updateDragEl === "function") {
330
+ this.core.config.updateDragEl(this.dragEl, el);
331
+ }
222
332
  this.moveableOptions = this.getOptions({
223
333
  target: this.dragEl
224
334
  });
@@ -266,7 +376,7 @@ class StageDragResize extends EventEmitter {
266
376
  this.moveable.on("resizeStart", (e) => {
267
377
  if (!this.target)
268
378
  return;
269
- this.dragStatus = "start" /* START */;
379
+ this.dragStatus = StageDragStatus.START;
270
380
  this.moveableHelper?.onResizeStart(e);
271
381
  frame.top = this.target.offsetTop;
272
382
  frame.left = this.target.offsetLeft;
@@ -275,7 +385,7 @@ class StageDragResize extends EventEmitter {
275
385
  if (!this.moveable || !this.target || !this.dragEl)
276
386
  return;
277
387
  const { beforeTranslate } = drag;
278
- this.dragStatus = "ing" /* ING */;
388
+ this.dragStatus = StageDragStatus.ING;
279
389
  this.moveableHelper?.onResize(e);
280
390
  if (this.mode === Mode.SORTABLE) {
281
391
  this.target.style.top = "0px";
@@ -286,7 +396,7 @@ class StageDragResize extends EventEmitter {
286
396
  this.target.style.width = `${width}px`;
287
397
  this.target.style.height = `${height}px`;
288
398
  }).on("resizeEnd", () => {
289
- this.dragStatus = "end" /* END */;
399
+ this.dragStatus = StageDragStatus.END;
290
400
  this.update(true);
291
401
  });
292
402
  }
@@ -303,7 +413,7 @@ class StageDragResize extends EventEmitter {
303
413
  this.moveable.on("dragStart", (e) => {
304
414
  if (!this.target)
305
415
  throw new Error("\u672A\u9009\u4E2D\u7EC4\u4EF6");
306
- this.dragStatus = "start" /* START */;
416
+ this.dragStatus = StageDragStatus.START;
307
417
  this.moveableHelper?.onDragStart(e);
308
418
  if (this.mode === Mode.SORTABLE) {
309
419
  this.ghostEl = this.generateGhostEl(this.target);
@@ -317,16 +427,10 @@ class StageDragResize extends EventEmitter {
317
427
  globalThis.clearTimeout(timeout);
318
428
  timeout = void 0;
319
429
  }
320
- timeout = globalThis.setTimeout(async () => {
321
- const els = this.core.getElementsFromPoint(e.inputEvent);
322
- for (const el of els) {
323
- if (doc && !el.id.startsWith(GHOST_EL_ID_PREFIX) && el !== this.target && await this.core.isContainer(el)) {
324
- addClassName(el, doc, this.core.containerHighlightClassName);
325
- break;
326
- }
327
- }
328
- }, this.core.containerHighlightDuration);
329
- this.dragStatus = "ing" /* ING */;
430
+ if (this.canContainerHighlight()) {
431
+ timeout = this.core.getAddContainerHighlightClassNameTimeout(e.inputEvent, [this.target]);
432
+ }
433
+ this.dragStatus = StageDragStatus.ING;
330
434
  if (this.ghostEl) {
331
435
  this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
332
436
  return;
@@ -340,10 +444,10 @@ class StageDragResize extends EventEmitter {
340
444
  timeout = void 0;
341
445
  }
342
446
  let parentEl = null;
343
- if (doc) {
447
+ if (doc && this.canContainerHighlight()) {
344
448
  parentEl = removeClassNameByClassName(doc, this.core.containerHighlightClassName);
345
449
  }
346
- if (this.dragStatus === "ing" /* ING */) {
450
+ if (this.dragStatus === StageDragStatus.ING) {
347
451
  if (parentEl) {
348
452
  this.update(false, parentEl);
349
453
  } else {
@@ -356,7 +460,7 @@ class StageDragResize extends EventEmitter {
356
460
  }
357
461
  }
358
462
  }
359
- this.dragStatus = "end" /* END */;
463
+ this.dragStatus = StageDragStatus.END;
360
464
  this.destroyGhostEl();
361
465
  });
362
466
  }
@@ -364,17 +468,17 @@ class StageDragResize extends EventEmitter {
364
468
  if (!this.moveable)
365
469
  throw new Error("moveable \u672A\u521D\u59CB\u5316");
366
470
  this.moveable.on("rotateStart", (e) => {
367
- this.dragStatus = "start" /* START */;
471
+ this.dragStatus = StageDragStatus.START;
368
472
  this.moveableHelper?.onRotateStart(e);
369
473
  }).on("rotate", (e) => {
370
474
  if (!this.target || !this.dragEl)
371
475
  return;
372
- this.dragStatus = "ing" /* ING */;
476
+ this.dragStatus = StageDragStatus.ING;
373
477
  this.moveableHelper?.onRotate(e);
374
478
  const frame = this.moveableHelper?.getFrame(e.target);
375
479
  this.target.style.transform = frame?.toCSSObject().transform || "";
376
480
  }).on("rotateEnd", (e) => {
377
- this.dragStatus = "end" /* END */;
481
+ this.dragStatus = StageDragStatus.END;
378
482
  const frame = this.moveableHelper?.getFrame(e.target);
379
483
  this.emit("update", {
380
484
  el: this.target,
@@ -388,17 +492,17 @@ class StageDragResize extends EventEmitter {
388
492
  if (!this.moveable)
389
493
  throw new Error("moveable \u672A\u521D\u59CB\u5316");
390
494
  this.moveable.on("scaleStart", (e) => {
391
- this.dragStatus = "start" /* START */;
495
+ this.dragStatus = StageDragStatus.START;
392
496
  this.moveableHelper?.onScaleStart(e);
393
497
  }).on("scale", (e) => {
394
498
  if (!this.target || !this.dragEl)
395
499
  return;
396
- this.dragStatus = "ing" /* ING */;
500
+ this.dragStatus = StageDragStatus.ING;
397
501
  this.moveableHelper?.onScale(e);
398
502
  const frame = this.moveableHelper?.getFrame(e.target);
399
503
  this.target.style.transform = frame?.toCSSObject().transform || "";
400
504
  }).on("scaleEnd", (e) => {
401
- this.dragStatus = "end" /* END */;
505
+ this.dragStatus = StageDragStatus.END;
402
506
  const frame = this.moveableHelper?.getFrame(e.target);
403
507
  this.emit("update", {
404
508
  el: this.target,
@@ -446,9 +550,13 @@ class StageDragResize extends EventEmitter {
446
550
  top = calcValueByFontsize(doc, this.dragEl.offsetTop) + parseFloat(translateY) - calcValueByFontsize(doc, parentTop);
447
551
  }
448
552
  this.emit("update", {
449
- el: this.target,
450
- parentEl,
451
- style: isResize ? { left, top, width, height } : { left, top }
553
+ data: [
554
+ {
555
+ el: this.target,
556
+ style: isResize ? { left, top, width, height } : { left, top }
557
+ }
558
+ ],
559
+ parentEl
452
560
  });
453
561
  }
454
562
  generateGhostEl(el) {
@@ -456,6 +564,7 @@ class StageDragResize extends EventEmitter {
456
564
  this.destroyGhostEl();
457
565
  }
458
566
  const ghostEl = el.cloneNode(true);
567
+ this.setGhostElChildrenId(ghostEl);
459
568
  const { top, left } = getAbsolutePosition(el, getOffset(el));
460
569
  ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
461
570
  ghostEl.style.zIndex = ZIndex.GHOST_EL;
@@ -466,30 +575,20 @@ class StageDragResize extends EventEmitter {
466
575
  el.after(ghostEl);
467
576
  return ghostEl;
468
577
  }
578
+ setGhostElChildrenId(el) {
579
+ for (const child of Array.from(el.children)) {
580
+ if (child.id) {
581
+ child.id = `${GHOST_EL_ID_PREFIX}${child.id}`;
582
+ }
583
+ if (child.children.length) {
584
+ this.setGhostElChildrenId(child);
585
+ }
586
+ }
587
+ }
469
588
  destroyGhostEl() {
470
589
  this.ghostEl?.remove();
471
590
  this.ghostEl = void 0;
472
591
  }
473
- updateDragEl(el) {
474
- const offset = getOffset(el);
475
- const { transform } = getComputedStyle(el);
476
- this.dragEl.style.cssText = `
477
- position: absolute;
478
- transform: ${transform};
479
- left: ${offset.left}px;
480
- top: ${offset.top}px;
481
- width: ${el.clientWidth}px;
482
- height: ${el.clientHeight}px;
483
- z-index: ${ZIndex.DRAG_EL};
484
- `;
485
- this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
486
- if (typeof this.core.config.updateDragEl === "function") {
487
- this.core.config.updateDragEl(this.dragEl, el);
488
- }
489
- }
490
- destroyDragEl() {
491
- this.dragEl?.remove();
492
- }
493
592
  getOptions(options = {}) {
494
593
  if (!this.target)
495
594
  return {};
@@ -540,7 +639,7 @@ class StageDragResize extends EventEmitter {
540
639
  bounds: {
541
640
  top: 0,
542
641
  left: -1,
543
- right: this.container.clientWidth,
642
+ right: this.container.clientWidth - 1,
544
643
  bottom: this.container.clientHeight,
545
644
  ...moveableOptions.bounds || {}
546
645
  },
@@ -548,55 +647,17 @@ class StageDragResize extends EventEmitter {
548
647
  ...moveableOptions
549
648
  };
550
649
  }
551
- }
552
- const down = (deltaTop, target) => {
553
- let swapIndex = 0;
554
- let addUpH = target.clientHeight;
555
- const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
556
- const index = brothers.indexOf(target);
557
- const downEls = brothers.slice(index + 1);
558
- for (let i = 0; i < downEls.length; i++) {
559
- const ele = downEls[i];
560
- if (ele.style?.position === "fixed") {
561
- continue;
562
- }
563
- addUpH += ele.clientHeight / 2;
564
- if (deltaTop <= addUpH) {
565
- break;
566
- }
567
- addUpH += ele.clientHeight / 2;
568
- swapIndex = i;
569
- }
570
- return {
571
- src: target.id,
572
- dist: downEls.length && swapIndex > -1 ? downEls[swapIndex].id : target.id
573
- };
574
- };
575
- const up = (deltaTop, target) => {
576
- const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
577
- const index = brothers.indexOf(target);
578
- const upEls = brothers.slice(0, index);
579
- let addUpH = target.clientHeight;
580
- let swapIndex = upEls.length - 1;
581
- for (let i = upEls.length - 1; i >= 0; i--) {
582
- const ele = upEls[i];
583
- if (!ele)
584
- continue;
585
- if (ele.style.position === "fixed")
586
- continue;
587
- addUpH += ele.clientHeight / 2;
588
- if (-deltaTop <= addUpH)
589
- break;
590
- addUpH += ele.clientHeight / 2;
591
- swapIndex = i;
650
+ canContainerHighlight() {
651
+ return this.core.containerHighlightType === ContainerHighlightType.DEFAULT || this.core.containerHighlightType === ContainerHighlightType.ALT && this.isContainerHighlight;
592
652
  }
593
- return {
594
- src: target.id,
595
- dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id
596
- };
597
- };
653
+ }
598
654
 
599
655
  class TargetCalibrate extends EventEmitter {
656
+ parent;
657
+ mask;
658
+ dr;
659
+ core;
660
+ operationEl;
600
661
  constructor(config) {
601
662
  super();
602
663
  this.parent = config.parent;
@@ -616,6 +677,7 @@ class TargetCalibrate extends EventEmitter {
616
677
  top: ${top}px;
617
678
  width: ${el.clientWidth}px;
618
679
  height: ${el.clientHeight}px;
680
+ z-index: ${ZIndex.DRAG_EL};
619
681
  `;
620
682
  this.operationEl.id = `${prefix}${el.id}`;
621
683
  if (typeof this.core.config.updateDragEl === "function") {
@@ -663,6 +725,11 @@ class TargetCalibrate extends EventEmitter {
663
725
  }
664
726
 
665
727
  class StageHighlight extends EventEmitter {
728
+ core;
729
+ container;
730
+ target;
731
+ moveable;
732
+ calibrationTarget;
666
733
  constructor(config) {
667
734
  super();
668
735
  this.core = config.core;
@@ -683,7 +750,7 @@ class StageHighlight extends EventEmitter {
683
750
  target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
684
751
  origin: false,
685
752
  rootContainer: this.core.container,
686
- zoom: 1
753
+ zoom: 2
687
754
  });
688
755
  }
689
756
  clearHighlight() {
@@ -700,41 +767,14 @@ class StageHighlight extends EventEmitter {
700
767
  }
701
768
 
702
769
  class Rule extends EventEmitter$1 {
770
+ hGuides;
771
+ vGuides;
772
+ horizontalGuidelines = [];
773
+ verticalGuidelines = [];
774
+ container;
775
+ containerResizeObserver;
703
776
  constructor(container) {
704
777
  super();
705
- this.horizontalGuidelines = [];
706
- this.verticalGuidelines = [];
707
- this.getGuidesStyle = (type) => ({
708
- position: "fixed",
709
- zIndex: 1,
710
- left: type === GuidesType.HORIZONTAL ? 0 : "-30px",
711
- top: type === GuidesType.HORIZONTAL ? "-30px" : 0,
712
- width: type === GuidesType.HORIZONTAL ? "100%" : "30px",
713
- height: type === GuidesType.HORIZONTAL ? "30px" : "100%"
714
- });
715
- this.createGuides = (type, defaultGuides = []) => new Guides(this.container, {
716
- type,
717
- defaultGuides,
718
- displayDragPos: true,
719
- backgroundColor: "#fff",
720
- lineColor: "#000",
721
- textColor: "#000",
722
- style: this.getGuidesStyle(type)
723
- });
724
- this.hGuidesChangeGuidesHandler = (e) => {
725
- this.horizontalGuidelines = e.guides;
726
- this.emit("changeGuides", {
727
- type: GuidesType.HORIZONTAL,
728
- guides: this.horizontalGuidelines
729
- });
730
- };
731
- this.vGuidesChangeGuidesHandler = (e) => {
732
- this.verticalGuidelines = e.guides;
733
- this.emit("changeGuides", {
734
- type: GuidesType.VERTICAL,
735
- guides: this.verticalGuidelines
736
- });
737
- };
738
778
  this.container = container;
739
779
  this.hGuides = this.createGuides(GuidesType.HORIZONTAL, this.horizontalGuidelines);
740
780
  this.vGuides = this.createGuides(GuidesType.VERTICAL, this.verticalGuidelines);
@@ -806,6 +846,37 @@ class Rule extends EventEmitter$1 {
806
846
  this.containerResizeObserver.disconnect();
807
847
  this.removeAllListeners();
808
848
  }
849
+ getGuidesStyle = (type) => ({
850
+ position: "fixed",
851
+ zIndex: 1,
852
+ left: type === GuidesType.HORIZONTAL ? 0 : "-30px",
853
+ top: type === GuidesType.HORIZONTAL ? "-30px" : 0,
854
+ width: type === GuidesType.HORIZONTAL ? "100%" : "30px",
855
+ height: type === GuidesType.HORIZONTAL ? "30px" : "100%"
856
+ });
857
+ createGuides = (type, defaultGuides = []) => new Guides(this.container, {
858
+ type,
859
+ defaultGuides,
860
+ displayDragPos: true,
861
+ backgroundColor: "#fff",
862
+ lineColor: "#000",
863
+ textColor: "#000",
864
+ style: this.getGuidesStyle(type)
865
+ });
866
+ hGuidesChangeGuidesHandler = (e) => {
867
+ this.horizontalGuidelines = e.guides;
868
+ this.emit("changeGuides", {
869
+ type: GuidesType.HORIZONTAL,
870
+ guides: this.horizontalGuidelines
871
+ });
872
+ };
873
+ vGuidesChangeGuidesHandler = (e) => {
874
+ this.verticalGuidelines = e.guides;
875
+ this.emit("changeGuides", {
876
+ type: GuidesType.VERTICAL,
877
+ guides: this.verticalGuidelines
878
+ });
879
+ };
809
880
  }
810
881
 
811
882
  const wrapperClassName = "editor-mask-wrapper";
@@ -839,66 +910,30 @@ const createWrapper = () => {
839
910
  return el;
840
911
  };
841
912
  class StageMask extends Rule {
913
+ content = createContent();
914
+ wrapper;
915
+ core;
916
+ page = null;
917
+ pageScrollParent = null;
918
+ scrollTop = 0;
919
+ scrollLeft = 0;
920
+ width = 0;
921
+ height = 0;
922
+ wrapperHeight = 0;
923
+ wrapperWidth = 0;
924
+ maxScrollTop = 0;
925
+ maxScrollLeft = 0;
926
+ intersectionObserver = null;
927
+ isMultiSelectStatus = false;
928
+ mode = Mode.ABSOLUTE;
929
+ pageResizeObserver = null;
930
+ wrapperResizeObserver = null;
931
+ highlightHandler = throttle((event) => {
932
+ this.emit("highlight", event);
933
+ }, throttleTime);
842
934
  constructor(config) {
843
935
  const wrapper = createWrapper();
844
936
  super(wrapper);
845
- this.content = createContent();
846
- this.page = null;
847
- this.pageScrollParent = null;
848
- this.scrollTop = 0;
849
- this.scrollLeft = 0;
850
- this.width = 0;
851
- this.height = 0;
852
- this.wrapperHeight = 0;
853
- this.wrapperWidth = 0;
854
- this.maxScrollTop = 0;
855
- this.maxScrollLeft = 0;
856
- this.intersectionObserver = null;
857
- this.mode = Mode.ABSOLUTE;
858
- this.pageResizeObserver = null;
859
- this.wrapperResizeObserver = null;
860
- this.highlightHandler = throttle((event) => {
861
- this.emit("highlight", event);
862
- }, throttleTime);
863
- this.mouseDownHandler = (event) => {
864
- this.emit("clearHighlight");
865
- event.stopImmediatePropagation();
866
- event.stopPropagation();
867
- if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
868
- return;
869
- if (event.target.className.indexOf("moveable-control") !== -1) {
870
- return;
871
- }
872
- this.content.removeEventListener("mousemove", this.highlightHandler);
873
- this.emit("beforeSelect", event);
874
- globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
875
- };
876
- this.mouseUpHandler = () => {
877
- globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
878
- this.content.addEventListener("mousemove", this.highlightHandler);
879
- this.emit("select");
880
- };
881
- this.mouseWheelHandler = (event) => {
882
- this.emit("clearHighlight");
883
- if (!this.page)
884
- throw new Error("page \u672A\u521D\u59CB\u5316");
885
- const { deltaY, deltaX } = event;
886
- if (this.page.clientHeight < this.wrapperHeight && deltaY)
887
- return;
888
- if (this.page.clientWidth < this.wrapperWidth && deltaX)
889
- return;
890
- if (this.maxScrollTop > 0) {
891
- this.scrollTop = this.scrollTop + deltaY;
892
- }
893
- if (this.maxScrollLeft > 0) {
894
- this.scrollLeft = this.scrollLeft + deltaX;
895
- }
896
- this.scroll();
897
- this.emit("scroll", event);
898
- };
899
- this.mouseLeaveHandler = () => {
900
- setTimeout(() => this.emit("clearHighlight"), throttleTime);
901
- };
902
937
  this.wrapper = wrapper;
903
938
  this.core = config.core;
904
939
  this.content.addEventListener("mousedown", this.mouseDownHandler);
@@ -906,6 +941,16 @@ class StageMask extends Rule {
906
941
  this.content.addEventListener("wheel", this.mouseWheelHandler);
907
942
  this.content.addEventListener("mousemove", this.highlightHandler);
908
943
  this.content.addEventListener("mouseleave", this.mouseLeaveHandler);
944
+ const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
945
+ const ctrl = isMac ? "meta" : "ctrl";
946
+ KeyController.global.keydown(ctrl, (e) => {
947
+ e.inputEvent.preventDefault();
948
+ this.isMultiSelectStatus = true;
949
+ });
950
+ KeyController.global.keyup(ctrl, (e) => {
951
+ e.inputEvent.preventDefault();
952
+ this.isMultiSelectStatus = false;
953
+ });
909
954
  }
910
955
  setMode(mode) {
911
956
  this.mode = mode;
@@ -1034,49 +1079,237 @@ class StageMask extends Rule {
1034
1079
  if (this.maxScrollLeft < this.scrollLeft)
1035
1080
  this.scrollLeft = this.maxScrollLeft;
1036
1081
  }
1082
+ mouseDownHandler = (event) => {
1083
+ this.emit("clearHighlight");
1084
+ event.stopImmediatePropagation();
1085
+ event.stopPropagation();
1086
+ if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
1087
+ return;
1088
+ if (!this.isMultiSelectStatus && event.target.className.indexOf("moveable-area") !== -1) {
1089
+ return;
1090
+ }
1091
+ if (event.target.className.indexOf("moveable-control") !== -1) {
1092
+ return;
1093
+ }
1094
+ this.content.removeEventListener("mousemove", this.highlightHandler);
1095
+ if (this.isMultiSelectStatus) {
1096
+ this.emit("beforeMultiSelect", event);
1097
+ } else {
1098
+ this.emit("beforeSelect", event);
1099
+ }
1100
+ globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
1101
+ };
1102
+ mouseUpHandler = () => {
1103
+ globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
1104
+ this.content.addEventListener("mousemove", this.highlightHandler);
1105
+ if (!this.isMultiSelectStatus) {
1106
+ this.emit("select");
1107
+ }
1108
+ };
1109
+ mouseWheelHandler = (event) => {
1110
+ this.emit("clearHighlight");
1111
+ if (!this.page)
1112
+ throw new Error("page \u672A\u521D\u59CB\u5316");
1113
+ const { deltaY, deltaX } = event;
1114
+ if (this.page.clientHeight < this.wrapperHeight && deltaY)
1115
+ return;
1116
+ if (this.page.clientWidth < this.wrapperWidth && deltaX)
1117
+ return;
1118
+ if (this.maxScrollTop > 0) {
1119
+ this.scrollTop = this.scrollTop + deltaY;
1120
+ }
1121
+ if (this.maxScrollLeft > 0) {
1122
+ this.scrollLeft = this.scrollLeft + deltaX;
1123
+ }
1124
+ this.scroll();
1125
+ this.emit("scroll", event);
1126
+ };
1127
+ mouseLeaveHandler = () => {
1128
+ setTimeout(() => this.emit("clearHighlight"), throttleTime);
1129
+ };
1037
1130
  }
1038
1131
 
1039
- var style = ".tmagic-stage-container-highlight::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n background-color: #000;\n opacity: .1;\n}\n";
1040
-
1041
- class StageRender extends EventEmitter {
1042
- constructor({ core }) {
1132
+ class StageMultiDragResize extends EventEmitter {
1133
+ core;
1134
+ mask;
1135
+ container;
1136
+ targetList = [];
1137
+ dragElList = [];
1138
+ moveableForMulti;
1139
+ dragStatus = StageDragStatus.END;
1140
+ multiMoveableHelper;
1141
+ constructor(config) {
1043
1142
  super();
1044
- this.contentWindow = null;
1045
- this.runtime = null;
1046
- this.getMagicApi = () => ({
1047
- onPageElUpdate: (el) => this.emit("page-el-update", el),
1048
- onRuntimeReady: (runtime) => {
1049
- this.runtime = runtime;
1050
- globalThis.runtime = runtime;
1051
- this.emit("runtime-ready", runtime);
1143
+ this.core = config.core;
1144
+ this.container = config.container;
1145
+ this.mask = config.mask;
1146
+ }
1147
+ multiSelect(els) {
1148
+ this.targetList = els;
1149
+ this.core.dr.destroyDragEl();
1150
+ this.destroyDragElList();
1151
+ this.dragElList = els.map((elItem) => {
1152
+ const dragElDiv = globalThis.document.createElement("div");
1153
+ this.container.append(dragElDiv);
1154
+ dragElDiv.style.cssText = getTargetElStyle(elItem);
1155
+ dragElDiv.id = `${DRAG_EL_ID_PREFIX}${elItem.id}`;
1156
+ if (typeof this.core.config.updateDragEl === "function") {
1157
+ this.core.config.updateDragEl(dragElDiv, elItem);
1052
1158
  }
1159
+ return dragElDiv;
1053
1160
  });
1054
- this.getRuntime = () => {
1055
- if (this.runtime)
1056
- return Promise.resolve(this.runtime);
1057
- return new Promise((resolve) => {
1058
- const listener = (runtime) => {
1059
- this.off("runtime-ready", listener);
1060
- resolve(runtime);
1061
- };
1062
- this.on("runtime-ready", listener);
1161
+ this.moveableForMulti?.destroy();
1162
+ this.multiMoveableHelper?.clear();
1163
+ this.moveableForMulti = new Moveable(this.container, this.getOptions({
1164
+ target: this.dragElList
1165
+ }));
1166
+ this.multiMoveableHelper = MoveableHelper.create({
1167
+ useBeforeRender: true,
1168
+ useRender: false,
1169
+ createAuto: true
1170
+ });
1171
+ const frames = [];
1172
+ this.moveableForMulti.on("dragGroupStart", (params) => {
1173
+ const { events } = params;
1174
+ this.multiMoveableHelper?.onDragGroupStart(params);
1175
+ events.forEach((ev) => {
1176
+ const matchEventTarget = this.targetList.find((targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1177
+ if (!matchEventTarget)
1178
+ return;
1179
+ frames.push({
1180
+ left: matchEventTarget.offsetLeft,
1181
+ top: matchEventTarget.offsetTop,
1182
+ id: matchEventTarget.id
1183
+ });
1063
1184
  });
1064
- };
1065
- this.loadHandler = async () => {
1066
- this.contentWindow = this.iframe?.contentWindow;
1067
- this.contentWindow.magic = this.getMagicApi();
1068
- if (this.render) {
1069
- const el = await this.render(this.core);
1070
- if (el) {
1071
- this.iframe?.contentDocument?.body?.appendChild(el);
1185
+ this.dragStatus = StageDragStatus.START;
1186
+ }).on("dragGroup", (params) => {
1187
+ const { events } = params;
1188
+ events.forEach((ev) => {
1189
+ const frameSnapShot = frames.find((frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1190
+ if (!frameSnapShot)
1191
+ return;
1192
+ const targeEl = this.targetList.find((targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1193
+ if (!targeEl)
1194
+ return;
1195
+ const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
1196
+ if (!isParentIncluded) {
1197
+ targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
1198
+ targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
1072
1199
  }
1200
+ });
1201
+ this.multiMoveableHelper?.onDragGroup(params);
1202
+ this.dragStatus = StageDragStatus.ING;
1203
+ }).on("dragGroupEnd", () => {
1204
+ this.update();
1205
+ this.dragStatus = StageDragStatus.END;
1206
+ }).on("clickGroup", (params) => {
1207
+ const { inputTarget, targets } = params;
1208
+ if (!this.mask.isMultiSelectStatus && targets.length > 1 && targets.includes(inputTarget)) {
1209
+ this.emit("select", inputTarget.id.replace(DRAG_EL_ID_PREFIX, ""));
1073
1210
  }
1074
- this.emit("onload");
1075
- this.contentWindow.postMessage({
1076
- tmagicRuntimeReady: true
1077
- }, "*");
1078
- injectStyle(this.contentWindow.document, style);
1211
+ });
1212
+ }
1213
+ canSelect(el, stop) {
1214
+ if (el.className.includes(PAGE_CLASS)) {
1215
+ this.core.highlightedDom = void 0;
1216
+ this.core.highlightLayer.clearHighlight();
1217
+ stop();
1218
+ return false;
1219
+ }
1220
+ const currentTargetMode = getMode(el);
1221
+ let selectedDomMode = "";
1222
+ if (this.core.selectedDom?.className.includes(PAGE_CLASS)) {
1223
+ return true;
1224
+ }
1225
+ if (this.targetList.length === 0 && this.core.selectedDom) {
1226
+ selectedDomMode = getMode(this.core.selectedDom);
1227
+ } else if (this.targetList.length > 0) {
1228
+ selectedDomMode = getMode(this.targetList[0]);
1229
+ }
1230
+ if (currentTargetMode !== selectedDomMode) {
1231
+ return false;
1232
+ }
1233
+ return true;
1234
+ }
1235
+ clearSelectStatus() {
1236
+ if (!this.moveableForMulti)
1237
+ return;
1238
+ this.destroyDragElList();
1239
+ this.moveableForMulti.target = null;
1240
+ this.moveableForMulti.updateTarget();
1241
+ this.targetList = [];
1242
+ }
1243
+ destroy() {
1244
+ this.moveableForMulti?.destroy();
1245
+ this.destroyDragElList();
1246
+ }
1247
+ destroyDragElList() {
1248
+ this.dragElList.forEach((dragElItem) => dragElItem?.remove());
1249
+ }
1250
+ update(isResize = false) {
1251
+ if (this.targetList.length === 0)
1252
+ return;
1253
+ const { contentWindow } = this.core.renderer;
1254
+ const doc = contentWindow?.document;
1255
+ if (!doc)
1256
+ return;
1257
+ this.emit("update", {
1258
+ data: this.targetList.map((targetItem) => {
1259
+ const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop };
1260
+ const left = calcValueByFontsize(doc, offset.left);
1261
+ const top = calcValueByFontsize(doc, offset.top);
1262
+ const width = calcValueByFontsize(doc, targetItem.clientWidth);
1263
+ const height = calcValueByFontsize(doc, targetItem.clientHeight);
1264
+ return {
1265
+ el: targetItem,
1266
+ style: isResize ? { left, top, width, height } : { left, top }
1267
+ };
1268
+ }),
1269
+ parentEl: null
1270
+ });
1271
+ }
1272
+ getOptions(options = {}) {
1273
+ let { multiMoveableOptions = {} } = this.core.config;
1274
+ if (typeof multiMoveableOptions === "function") {
1275
+ multiMoveableOptions = multiMoveableOptions(this.core);
1276
+ }
1277
+ return {
1278
+ defaultGroupRotate: 0,
1279
+ defaultGroupOrigin: "50% 50%",
1280
+ draggable: true,
1281
+ resizable: false,
1282
+ throttleDrag: 0,
1283
+ startDragRotate: 0,
1284
+ throttleDragRotate: 0,
1285
+ zoom: 1,
1286
+ origin: true,
1287
+ padding: { left: 0, top: 0, right: 0, bottom: 0 },
1288
+ snappable: true,
1289
+ bounds: {
1290
+ top: 0,
1291
+ left: -1,
1292
+ right: this.container.clientWidth - 1,
1293
+ bottom: this.container.clientHeight,
1294
+ ...multiMoveableOptions.bounds || {}
1295
+ },
1296
+ ...options,
1297
+ ...multiMoveableOptions
1079
1298
  };
1299
+ }
1300
+ }
1301
+
1302
+ const style = ".tmagic-stage-container-highlight::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n background-color: #000;\n opacity: .1;\n pointer-events: none;\n}\n";
1303
+
1304
+ class StageRender extends EventEmitter {
1305
+ contentWindow = null;
1306
+ runtime = null;
1307
+ iframe;
1308
+ runtimeUrl;
1309
+ core;
1310
+ render;
1311
+ constructor({ core }) {
1312
+ super();
1080
1313
  this.core = core;
1081
1314
  this.runtimeUrl = core.config.runtimeUrl || "";
1082
1315
  this.render = core.config.render;
@@ -1089,20 +1322,39 @@ class StageRender extends EventEmitter {
1089
1322
  `;
1090
1323
  this.iframe.addEventListener("load", this.loadHandler);
1091
1324
  }
1325
+ getMagicApi = () => ({
1326
+ onPageElUpdate: (el) => this.emit("page-el-update", el),
1327
+ onRuntimeReady: (runtime) => {
1328
+ this.runtime = runtime;
1329
+ globalThis.runtime = runtime;
1330
+ this.emit("runtime-ready", runtime);
1331
+ }
1332
+ });
1092
1333
  async mount(el) {
1093
- if (this.iframe) {
1094
- if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
1095
- let html = await fetch(this.runtimeUrl).then((res) => res.text());
1096
- const base = `${location.protocol}//${getHost(this.runtimeUrl)}`;
1097
- html = html.replace("<head>", `<head>
1098
- <base href="${base}">`);
1099
- this.iframe.srcdoc = html;
1100
- }
1101
- el.appendChild(this.iframe);
1102
- } else {
1334
+ if (!this.iframe) {
1103
1335
  throw Error("mount \u5931\u8D25");
1104
1336
  }
1105
- }
1337
+ if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
1338
+ let html = await fetch(this.runtimeUrl).then((res) => res.text());
1339
+ const base = `${location.protocol}//${getHost(this.runtimeUrl)}`;
1340
+ html = html.replace("<head>", `<head>
1341
+ <base href="${base}">`);
1342
+ this.iframe.srcdoc = html;
1343
+ }
1344
+ el.appendChild(this.iframe);
1345
+ this.postTmagicRuntimeReady();
1346
+ }
1347
+ getRuntime = () => {
1348
+ if (this.runtime)
1349
+ return Promise.resolve(this.runtime);
1350
+ return new Promise((resolve) => {
1351
+ const listener = (runtime) => {
1352
+ this.off("runtime-ready", listener);
1353
+ resolve(runtime);
1354
+ };
1355
+ this.on("runtime-ready", listener);
1356
+ });
1357
+ };
1106
1358
  destroy() {
1107
1359
  this.iframe?.removeEventListener("load", this.loadHandler);
1108
1360
  this.contentWindow = null;
@@ -1110,21 +1362,60 @@ class StageRender extends EventEmitter {
1110
1362
  this.iframe = void 0;
1111
1363
  this.removeAllListeners();
1112
1364
  }
1365
+ loadHandler = async () => {
1366
+ if (!this.contentWindow?.magic) {
1367
+ this.postTmagicRuntimeReady();
1368
+ }
1369
+ if (!this.contentWindow)
1370
+ return;
1371
+ if (this.render) {
1372
+ const el = await this.render(this.core);
1373
+ if (el) {
1374
+ this.contentWindow.document?.body?.appendChild(el);
1375
+ }
1376
+ }
1377
+ this.emit("onload");
1378
+ injectStyle(this.contentWindow.document, style);
1379
+ };
1380
+ postTmagicRuntimeReady() {
1381
+ this.contentWindow = this.iframe?.contentWindow;
1382
+ this.contentWindow.magic = this.getMagicApi();
1383
+ this.contentWindow.postMessage({
1384
+ tmagicRuntimeReady: true
1385
+ }, "*");
1386
+ }
1113
1387
  }
1114
1388
 
1115
1389
  class StageCore extends EventEmitter {
1390
+ container;
1391
+ selectedDom;
1392
+ selectedDomList = [];
1393
+ highlightedDom;
1394
+ renderer;
1395
+ mask;
1396
+ dr;
1397
+ multiDr;
1398
+ highlightLayer;
1399
+ config;
1400
+ zoom = DEFAULT_ZOOM;
1401
+ containerHighlightClassName;
1402
+ containerHighlightDuration;
1403
+ containerHighlightType;
1404
+ isContainer;
1405
+ canSelect;
1116
1406
  constructor(config) {
1117
1407
  super();
1118
- this.zoom = DEFAULT_ZOOM;
1119
1408
  this.config = config;
1120
1409
  this.setZoom(config.zoom);
1121
1410
  this.canSelect = config.canSelect || ((el) => !!el.id);
1122
1411
  this.isContainer = config.isContainer;
1123
- this.containerHighlightClassName = config.containerHighlightClassName;
1124
- this.containerHighlightDuration = config.containerHighlightDuration;
1412
+ this.containerHighlightClassName = config.containerHighlightClassName || CONTAINER_HIGHLIGHT_CLASS;
1413
+ this.containerHighlightDuration = config.containerHighlightDuration || 800;
1414
+ this.containerHighlightType = config.containerHighlightType;
1125
1415
  this.renderer = new StageRender({ core: this });
1126
1416
  this.mask = new StageMask({ core: this });
1127
- this.dr = new StageDragResize({ core: this, container: this.mask.content });
1417
+ this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
1418
+ this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
1128
1419
  this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
1129
1420
  this.renderer.on("runtime-ready", (runtime) => {
1130
1421
  this.emit("runtime-ready", runtime);
@@ -1132,29 +1423,59 @@ class StageCore extends EventEmitter {
1132
1423
  this.renderer.on("page-el-update", (el) => {
1133
1424
  this.mask?.observe(el);
1134
1425
  });
1135
- this.mask.on("beforeSelect", (event) => {
1136
- this.setElementFromPoint(event);
1426
+ this.mask.on("beforeSelect", async (event) => {
1427
+ this.clearSelectStatus("multiSelect");
1428
+ const el = await this.getElementFromPoint(event);
1429
+ if (!el)
1430
+ return;
1431
+ this.select(el, event);
1137
1432
  }).on("select", () => {
1138
1433
  this.emit("select", this.selectedDom);
1139
1434
  }).on("changeGuides", (data) => {
1140
1435
  this.dr.setGuidelines(data.type, data.guides);
1141
1436
  this.emit("changeGuides", data);
1142
1437
  }).on("highlight", async (event) => {
1143
- await this.setElementFromPoint(event);
1438
+ const el = await this.getElementFromPoint(event);
1439
+ if (!el)
1440
+ return;
1441
+ if (this.multiDr.dragStatus === StageDragStatus.ING)
1442
+ return;
1443
+ await this.highlight(el);
1144
1444
  if (this.highlightedDom === this.selectedDom) {
1145
1445
  this.highlightLayer.clearHighlight();
1146
1446
  return;
1147
1447
  }
1148
- this.highlightLayer.highlight(this.highlightedDom);
1149
1448
  this.emit("highlight", this.highlightedDom);
1150
1449
  }).on("clearHighlight", async () => {
1151
1450
  this.highlightLayer.clearHighlight();
1451
+ }).on("beforeMultiSelect", async (event) => {
1452
+ const el = await this.getElementFromPoint(event);
1453
+ if (!el)
1454
+ return;
1455
+ if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
1456
+ this.selectedDomList.push(this.selectedDom);
1457
+ this.selectedDom = void 0;
1458
+ }
1459
+ const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
1460
+ if (existIndex !== -1) {
1461
+ this.selectedDomList.splice(existIndex, 1);
1462
+ } else {
1463
+ this.selectedDomList.push(el);
1464
+ }
1465
+ this.multiSelect(this.selectedDomList);
1152
1466
  });
1153
1467
  this.dr.on("update", (data) => {
1154
1468
  setTimeout(() => this.emit("update", data));
1155
1469
  }).on("sort", (data) => {
1156
1470
  setTimeout(() => this.emit("sort", data));
1157
1471
  });
1472
+ this.multiDr.on("update", (data) => {
1473
+ setTimeout(() => this.emit("update", data));
1474
+ }).on("select", async (id) => {
1475
+ const el = await this.getTargetElement(id);
1476
+ this.select(el);
1477
+ setTimeout(() => this.emit("select", el));
1478
+ });
1158
1479
  }
1159
1480
  getElementsFromPoint(event) {
1160
1481
  const { renderer, zoom } = this;
@@ -1170,24 +1491,29 @@ class StageCore extends EventEmitter {
1170
1491
  }
1171
1492
  return doc?.elementsFromPoint(x / zoom, y / zoom);
1172
1493
  }
1173
- async setElementFromPoint(event) {
1494
+ async getElementFromPoint(event) {
1174
1495
  const els = this.getElementsFromPoint(event);
1175
1496
  let stopped = false;
1176
1497
  const stop = () => stopped = true;
1177
1498
  for (const el of els) {
1178
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.canSelect(el, event, stop)) {
1499
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isElCanSelect(el, event, stop)) {
1179
1500
  if (stopped)
1180
1501
  break;
1181
- if (event.type === "mousemove") {
1182
- this.highlight(el);
1183
- break;
1184
- }
1185
- this.select(el, event);
1186
- break;
1502
+ return el;
1187
1503
  }
1188
1504
  }
1189
1505
  }
1506
+ async isElCanSelect(el, event, stop) {
1507
+ const canSelectByProp = await this.canSelect(el, event, stop);
1508
+ if (!canSelectByProp)
1509
+ return false;
1510
+ if (this.mask.isMultiSelectStatus) {
1511
+ return this.multiDr.canSelect(el, stop);
1512
+ }
1513
+ return true;
1514
+ }
1190
1515
  async select(idOrEl, event) {
1516
+ this.clearSelectStatus("multiSelect");
1191
1517
  const el = await this.getTargetElement(idOrEl);
1192
1518
  if (el === this.selectedDom)
1193
1519
  return;
@@ -1209,6 +1535,12 @@ class StageCore extends EventEmitter {
1209
1535
  }
1210
1536
  }
1211
1537
  }
1538
+ async multiSelect(idOrElList) {
1539
+ this.clearSelectStatus("select");
1540
+ const elList = await Promise.all(idOrElList.map(async (idOrEl) => await this.getTargetElement(idOrEl)));
1541
+ this.multiDr.multiSelect(elList);
1542
+ this.emit("multiSelect", elList);
1543
+ }
1212
1544
  update(data) {
1213
1545
  const { config } = data;
1214
1546
  return this.renderer?.getRuntime().then((runtime) => {
@@ -1231,7 +1563,7 @@ class StageCore extends EventEmitter {
1231
1563
  this.highlightLayer.clearHighlight();
1232
1564
  return;
1233
1565
  }
1234
- if (el === this.highlightedDom)
1566
+ if (el === this.highlightedDom || !el)
1235
1567
  return;
1236
1568
  this.highlightLayer.highlight(el);
1237
1569
  this.highlightedDom = el;
@@ -1248,6 +1580,14 @@ class StageCore extends EventEmitter {
1248
1580
  setZoom(zoom = DEFAULT_ZOOM) {
1249
1581
  this.zoom = zoom;
1250
1582
  }
1583
+ clearSelectStatus(selectType) {
1584
+ if (selectType === "multiSelect") {
1585
+ this.multiDr.clearSelectStatus();
1586
+ this.selectedDomList = [];
1587
+ } else {
1588
+ this.dr.clearSelectStatus();
1589
+ }
1590
+ }
1251
1591
  async mount(el) {
1252
1592
  this.container = el;
1253
1593
  const { mask, renderer } = this;
@@ -1259,6 +1599,24 @@ class StageCore extends EventEmitter {
1259
1599
  this.mask.clearGuides();
1260
1600
  this.dr.clearGuides();
1261
1601
  }
1602
+ async addContainerHighlightClassName(event, exclude) {
1603
+ const els = this.getElementsFromPoint(event);
1604
+ const { renderer } = this;
1605
+ const doc = renderer.contentWindow?.document;
1606
+ if (!doc)
1607
+ return;
1608
+ for (const el of els) {
1609
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isContainer(el) && !exclude.includes(el)) {
1610
+ addClassName(el, doc, this.containerHighlightClassName);
1611
+ break;
1612
+ }
1613
+ }
1614
+ }
1615
+ getAddContainerHighlightClassNameTimeout(event, exclude = []) {
1616
+ return globalThis.setTimeout(() => {
1617
+ this.addContainerHighlightClassName(event, exclude);
1618
+ }, this.containerHighlightDuration);
1619
+ }
1262
1620
  destroy() {
1263
1621
  const { mask, renderer, dr, highlightLayer } = this;
1264
1622
  renderer.destroy();
@@ -1279,5 +1637,5 @@ class StageCore extends EventEmitter {
1279
1637
  }
1280
1638
  }
1281
1639
 
1282
- export { CONTAINER_HIGHLIGHT_CLASS, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, SELECTED_CLASS, StageDragResize, StageMask, StageRender, ZIndex, addSelectedClassName, calcValueByFontsize, StageCore as default, getAbsolutePosition, getMode, getOffset, getScrollParent, isAbsolute, isFixed, isFixedParent, isRelative, isStatic, removeSelectedClassName };
1283
- //# sourceMappingURL=tmagic-stage.es.js.map
1640
+ export { CONTAINER_HIGHLIGHT_CLASS, ContainerHighlightType, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, PAGE_CLASS, SELECTED_CLASS, StageDragResize, StageDragStatus, StageMask, StageRender, ZIndex, addSelectedClassName, calcValueByFontsize, StageCore as default, down, getAbsolutePosition, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isRelative, isStatic, removeSelectedClassName, up };
1641
+ //# sourceMappingURL=tmagic-stage.mjs.map