@tmagic/stage 1.1.0-beta.2 → 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.
@@ -1,20 +1,22 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('moveable'), require('moveable-helper'), require('@tmagic/utils'), require('lodash-es'), require('@scena/guides')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'events', 'moveable', 'moveable-helper', '@tmagic/utils', 'lodash-es', '@scena/guides'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TMagicStage = {}, global.EventEmitter, global.Moveable, global.MoveableHelper, global.utils, global.lodashEs, global.Guides));
5
- })(this, (function (exports, EventEmitter, Moveable, MoveableHelper, utils, lodashEs, Guides) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('@tmagic/utils'), require('moveable'), require('moveable-helper'), require('keycon'), require('lodash-es'), require('@scena/guides')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'events', '@tmagic/utils', 'moveable', 'moveable-helper', 'keycon', 'lodash-es', '@scena/guides'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TMagicStage = {}, global.EventEmitter, global.utils, global.Moveable, global.MoveableHelper, global.KeyController, global.lodashEs, global.Guides));
5
+ })(this, (function (exports, EventEmitter, utils, Moveable, MoveableHelper, KeyController, lodashEs, Guides) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
9
9
  var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
10
10
  var Moveable__default = /*#__PURE__*/_interopDefaultLegacy(Moveable);
11
11
  var MoveableHelper__default = /*#__PURE__*/_interopDefaultLegacy(MoveableHelper);
12
+ var KeyController__default = /*#__PURE__*/_interopDefaultLegacy(KeyController);
12
13
  var Guides__default = /*#__PURE__*/_interopDefaultLegacy(Guides);
13
14
 
14
15
  const GHOST_EL_ID_PREFIX = "ghost_el_";
15
16
  const DRAG_EL_ID_PREFIX = "drag_el_";
16
17
  const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
17
18
  const CONTAINER_HIGHLIGHT_CLASS = "tmagic-stage-container-highlight";
19
+ const PAGE_CLASS = "magic-ui-page";
18
20
  const DEFAULT_ZOOM = 1;
19
21
  var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
20
22
  GuidesType2["HORIZONTAL"] = "horizontal";
@@ -67,6 +69,19 @@
67
69
  top
68
70
  };
69
71
  };
72
+ const getTargetElStyle = (el) => {
73
+ const offset = getOffset(el);
74
+ const { transform } = getComputedStyle(el);
75
+ return `
76
+ position: absolute;
77
+ transform: ${transform};
78
+ left: ${offset.left}px;
79
+ top: ${offset.top}px;
80
+ width: ${el.clientWidth}px;
81
+ height: ${el.clientHeight}px;
82
+ z-index: ${ZIndex.DRAG_EL};
83
+ `;
84
+ };
70
85
  const getAbsolutePosition = (el, { top, left }) => {
71
86
  const { offsetParent } = el;
72
87
  if (offsetParent) {
@@ -147,6 +162,52 @@
147
162
  }
148
163
  return value;
149
164
  };
165
+ const down = (deltaTop, target) => {
166
+ let swapIndex = 0;
167
+ let addUpH = target.clientHeight;
168
+ const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
169
+ const index = brothers.indexOf(target);
170
+ const downEls = brothers.slice(index + 1);
171
+ for (let i = 0; i < downEls.length; i++) {
172
+ const ele = downEls[i];
173
+ if (ele.style?.position === "fixed") {
174
+ continue;
175
+ }
176
+ addUpH += ele.clientHeight / 2;
177
+ if (deltaTop <= addUpH) {
178
+ break;
179
+ }
180
+ addUpH += ele.clientHeight / 2;
181
+ swapIndex = i;
182
+ }
183
+ return {
184
+ src: target.id,
185
+ dist: downEls.length && swapIndex > -1 ? downEls[swapIndex].id : target.id
186
+ };
187
+ };
188
+ const up = (deltaTop, target) => {
189
+ const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
190
+ const index = brothers.indexOf(target);
191
+ const upEls = brothers.slice(0, index);
192
+ let addUpH = target.clientHeight;
193
+ let swapIndex = upEls.length - 1;
194
+ for (let i = upEls.length - 1; i >= 0; i--) {
195
+ const ele = upEls[i];
196
+ if (!ele)
197
+ continue;
198
+ if (ele.style.position === "fixed")
199
+ continue;
200
+ addUpH += ele.clientHeight / 2;
201
+ if (-deltaTop <= addUpH)
202
+ break;
203
+ addUpH += ele.clientHeight / 2;
204
+ swapIndex = i;
205
+ }
206
+ return {
207
+ src: target.id,
208
+ dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id
209
+ };
210
+ };
150
211
 
151
212
  class StageDragResize extends EventEmitter.EventEmitter {
152
213
  constructor(config) {
@@ -159,8 +220,7 @@
159
220
  this.dragStatus = "end" /* END */;
160
221
  this.core = config.core;
161
222
  this.container = config.container;
162
- this.dragEl = globalThis.document.createElement("div");
163
- this.container.append(this.dragEl);
223
+ this.mask = config.mask;
164
224
  }
165
225
  select(el, event) {
166
226
  const oldTarget = this.target;
@@ -211,6 +271,16 @@
211
271
  this.moveableOptions.verticalGuidelines = [];
212
272
  this.updateMoveable();
213
273
  }
274
+ clearSelectStatus() {
275
+ if (!this.moveable)
276
+ return;
277
+ this.destroyDragEl();
278
+ this.moveable.target = null;
279
+ this.moveable.updateTarget();
280
+ }
281
+ destroyDragEl() {
282
+ this.dragEl?.remove();
283
+ }
214
284
  destroy() {
215
285
  this.moveable?.destroy();
216
286
  this.destroyGhostEl();
@@ -224,7 +294,14 @@
224
294
  }
225
295
  this.mode = getMode(el);
226
296
  this.destroyGhostEl();
227
- this.updateDragEl(el);
297
+ this.destroyDragEl();
298
+ this.dragEl = globalThis.document.createElement("div");
299
+ this.container.append(this.dragEl);
300
+ this.dragEl.style.cssText = getTargetElStyle(el);
301
+ this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
302
+ if (typeof this.core.config.updateDragEl === "function") {
303
+ this.core.config.updateDragEl(this.dragEl, el);
304
+ }
228
305
  this.moveableOptions = this.getOptions({
229
306
  target: this.dragEl
230
307
  });
@@ -323,15 +400,7 @@
323
400
  globalThis.clearTimeout(timeout);
324
401
  timeout = void 0;
325
402
  }
326
- timeout = globalThis.setTimeout(async () => {
327
- const els = this.core.getElementsFromPoint(e.inputEvent);
328
- for (const el of els) {
329
- if (doc && !el.id.startsWith(GHOST_EL_ID_PREFIX) && el !== this.target && await this.core.isContainer(el)) {
330
- utils.addClassName(el, doc, this.core.containerHighlightClassName);
331
- break;
332
- }
333
- }
334
- }, this.core.containerHighlightDuration);
403
+ timeout = this.core.getAddContainerHighlightClassNameTimeout(e.inputEvent, [this.target]);
335
404
  this.dragStatus = "ing" /* ING */;
336
405
  if (this.ghostEl) {
337
406
  this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
@@ -462,6 +531,7 @@
462
531
  this.destroyGhostEl();
463
532
  }
464
533
  const ghostEl = el.cloneNode(true);
534
+ this.setGhostElChildrenId(ghostEl);
465
535
  const { top, left } = getAbsolutePosition(el, getOffset(el));
466
536
  ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
467
537
  ghostEl.style.zIndex = ZIndex.GHOST_EL;
@@ -472,30 +542,20 @@
472
542
  el.after(ghostEl);
473
543
  return ghostEl;
474
544
  }
545
+ setGhostElChildrenId(el) {
546
+ for (const child of el.children) {
547
+ if (child.id) {
548
+ child.id = `${GHOST_EL_ID_PREFIX}${child.id}`;
549
+ }
550
+ if (child.children.length) {
551
+ this.setGhostElChildrenId(child);
552
+ }
553
+ }
554
+ }
475
555
  destroyGhostEl() {
476
556
  this.ghostEl?.remove();
477
557
  this.ghostEl = void 0;
478
558
  }
479
- updateDragEl(el) {
480
- const offset = getOffset(el);
481
- const { transform } = getComputedStyle(el);
482
- this.dragEl.style.cssText = `
483
- position: absolute;
484
- transform: ${transform};
485
- left: ${offset.left}px;
486
- top: ${offset.top}px;
487
- width: ${el.clientWidth}px;
488
- height: ${el.clientHeight}px;
489
- z-index: ${ZIndex.DRAG_EL};
490
- `;
491
- this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
492
- if (typeof this.core.config.updateDragEl === "function") {
493
- this.core.config.updateDragEl(this.dragEl, el);
494
- }
495
- }
496
- destroyDragEl() {
497
- this.dragEl?.remove();
498
- }
499
559
  getOptions(options = {}) {
500
560
  if (!this.target)
501
561
  return {};
@@ -546,7 +606,7 @@
546
606
  bounds: {
547
607
  top: 0,
548
608
  left: -1,
549
- right: this.container.clientWidth,
609
+ right: this.container.clientWidth - 1,
550
610
  bottom: this.container.clientHeight,
551
611
  ...moveableOptions.bounds || {}
552
612
  },
@@ -555,52 +615,6 @@
555
615
  };
556
616
  }
557
617
  }
558
- const down = (deltaTop, target) => {
559
- let swapIndex = 0;
560
- let addUpH = target.clientHeight;
561
- const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
562
- const index = brothers.indexOf(target);
563
- const downEls = brothers.slice(index + 1);
564
- for (let i = 0; i < downEls.length; i++) {
565
- const ele = downEls[i];
566
- if (ele.style?.position === "fixed") {
567
- continue;
568
- }
569
- addUpH += ele.clientHeight / 2;
570
- if (deltaTop <= addUpH) {
571
- break;
572
- }
573
- addUpH += ele.clientHeight / 2;
574
- swapIndex = i;
575
- }
576
- return {
577
- src: target.id,
578
- dist: downEls.length && swapIndex > -1 ? downEls[swapIndex].id : target.id
579
- };
580
- };
581
- const up = (deltaTop, target) => {
582
- const brothers = Array.from(target.parentNode?.children || []).filter((node) => !node.id.startsWith(GHOST_EL_ID_PREFIX));
583
- const index = brothers.indexOf(target);
584
- const upEls = brothers.slice(0, index);
585
- let addUpH = target.clientHeight;
586
- let swapIndex = upEls.length - 1;
587
- for (let i = upEls.length - 1; i >= 0; i--) {
588
- const ele = upEls[i];
589
- if (!ele)
590
- continue;
591
- if (ele.style.position === "fixed")
592
- continue;
593
- addUpH += ele.clientHeight / 2;
594
- if (-deltaTop <= addUpH)
595
- break;
596
- addUpH += ele.clientHeight / 2;
597
- swapIndex = i;
598
- }
599
- return {
600
- src: target.id,
601
- dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id
602
- };
603
- };
604
618
 
605
619
  class TargetCalibrate extends EventEmitter.EventEmitter {
606
620
  constructor(config) {
@@ -622,6 +636,7 @@
622
636
  top: ${top}px;
623
637
  width: ${el.clientWidth}px;
624
638
  height: ${el.clientHeight}px;
639
+ z-index: ${ZIndex.DRAG_EL};
625
640
  `;
626
641
  this.operationEl.id = `${prefix}${el.id}`;
627
642
  if (typeof this.core.config.updateDragEl === "function") {
@@ -689,7 +704,7 @@
689
704
  target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
690
705
  origin: false,
691
706
  rootContainer: this.core.container,
692
- zoom: 1
707
+ zoom: 2
693
708
  });
694
709
  }
695
710
  clearHighlight() {
@@ -860,6 +875,7 @@
860
875
  this.maxScrollTop = 0;
861
876
  this.maxScrollLeft = 0;
862
877
  this.intersectionObserver = null;
878
+ this.isMultiSelectStatus = false;
863
879
  this.mode = Mode.ABSOLUTE;
864
880
  this.pageResizeObserver = null;
865
881
  this.wrapperResizeObserver = null;
@@ -872,11 +888,18 @@
872
888
  event.stopPropagation();
873
889
  if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
874
890
  return;
891
+ if (!this.isMultiSelectStatus && event.target.className.indexOf("moveable-area") !== -1) {
892
+ return;
893
+ }
875
894
  if (event.target.className.indexOf("moveable-control") !== -1) {
876
895
  return;
877
896
  }
878
897
  this.content.removeEventListener("mousemove", this.highlightHandler);
879
- this.emit("beforeSelect", event);
898
+ if (this.isMultiSelectStatus) {
899
+ this.emit("beforeMultiSelect", event);
900
+ } else {
901
+ this.emit("beforeSelect", event);
902
+ }
880
903
  globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
881
904
  };
882
905
  this.mouseUpHandler = () => {
@@ -912,6 +935,14 @@
912
935
  this.content.addEventListener("wheel", this.mouseWheelHandler);
913
936
  this.content.addEventListener("mousemove", this.highlightHandler);
914
937
  this.content.addEventListener("mouseleave", this.mouseLeaveHandler);
938
+ KeyController__default["default"].global.keydown("shift", (e) => {
939
+ e.inputEvent.preventDefault();
940
+ this.isMultiSelectStatus = true;
941
+ });
942
+ KeyController__default["default"].global.keyup("shift", (e) => {
943
+ e.inputEvent.preventDefault();
944
+ this.isMultiSelectStatus = false;
945
+ });
915
946
  }
916
947
  setMode(mode) {
917
948
  this.mode = mode;
@@ -1042,7 +1073,148 @@
1042
1073
  }
1043
1074
  }
1044
1075
 
1045
- 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";
1076
+ class StageMultiDragResize extends EventEmitter.EventEmitter {
1077
+ constructor(config) {
1078
+ super();
1079
+ this.targetList = [];
1080
+ this.dragElList = [];
1081
+ this.core = config.core;
1082
+ this.container = config.container;
1083
+ this.mask = config.mask;
1084
+ }
1085
+ multiSelect(els) {
1086
+ this.targetList = els;
1087
+ this.core.dr.destroyDragEl();
1088
+ this.destroyDragElList();
1089
+ this.dragElList = els.map((elItem) => {
1090
+ const dragElDiv = globalThis.document.createElement("div");
1091
+ this.container.append(dragElDiv);
1092
+ dragElDiv.style.cssText = getTargetElStyle(elItem);
1093
+ dragElDiv.id = `${DRAG_EL_ID_PREFIX}${elItem.id}`;
1094
+ if (typeof this.core.config.updateDragEl === "function") {
1095
+ this.core.config.updateDragEl(dragElDiv, elItem);
1096
+ }
1097
+ return dragElDiv;
1098
+ });
1099
+ this.moveableForMulti?.destroy();
1100
+ this.multiMoveableHelper?.clear();
1101
+ this.moveableForMulti = new Moveable__default["default"](this.container, this.getOptions({
1102
+ target: this.dragElList
1103
+ }));
1104
+ this.multiMoveableHelper = MoveableHelper__default["default"].create({
1105
+ useBeforeRender: true,
1106
+ useRender: false,
1107
+ createAuto: true
1108
+ });
1109
+ const frames = [];
1110
+ this.moveableForMulti.on("dragGroupStart", (params) => {
1111
+ const { events } = params;
1112
+ this.multiMoveableHelper?.onDragGroupStart(params);
1113
+ events.forEach((ev) => {
1114
+ const matchEventTarget = this.targetList.find((targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1115
+ if (!matchEventTarget)
1116
+ return;
1117
+ frames.push({
1118
+ left: matchEventTarget.offsetLeft,
1119
+ top: matchEventTarget.offsetTop,
1120
+ id: matchEventTarget.id
1121
+ });
1122
+ });
1123
+ }).on("dragGroup", (params) => {
1124
+ const { events } = params;
1125
+ events.forEach((ev) => {
1126
+ const frameSnapShot = frames.find((frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1127
+ if (!frameSnapShot)
1128
+ return;
1129
+ const targeEl = this.targetList.find((targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1130
+ if (!targeEl)
1131
+ return;
1132
+ const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
1133
+ if (!isParentIncluded) {
1134
+ targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
1135
+ targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
1136
+ }
1137
+ });
1138
+ this.multiMoveableHelper?.onDragGroup(params);
1139
+ }).on("dragGroupEnd", () => {
1140
+ this.update();
1141
+ });
1142
+ }
1143
+ canSelect(el) {
1144
+ if (el.className.includes(PAGE_CLASS)) {
1145
+ this.core.highlightedDom = void 0;
1146
+ this.core.highlightLayer.clearHighlight();
1147
+ return false;
1148
+ }
1149
+ const currentTargetMode = getMode(el);
1150
+ let selectedDomMode = "";
1151
+ if (this.targetList.length === 0 && this.core.selectedDom) {
1152
+ selectedDomMode = getMode(this.core.selectedDom);
1153
+ } else if (this.targetList.length > 0) {
1154
+ selectedDomMode = getMode(this.targetList[0]);
1155
+ }
1156
+ if (currentTargetMode !== selectedDomMode) {
1157
+ return false;
1158
+ }
1159
+ return true;
1160
+ }
1161
+ clearSelectStatus() {
1162
+ if (!this.moveableForMulti)
1163
+ return;
1164
+ this.destroyDragElList();
1165
+ this.moveableForMulti.target = null;
1166
+ this.moveableForMulti.updateTarget();
1167
+ this.targetList = [];
1168
+ }
1169
+ destroy() {
1170
+ this.moveableForMulti?.destroy();
1171
+ this.destroyDragElList();
1172
+ }
1173
+ destroyDragElList() {
1174
+ this.dragElList.forEach((dragElItem) => dragElItem?.remove());
1175
+ }
1176
+ update(isResize = false) {
1177
+ if (this.targetList.length === 0)
1178
+ return;
1179
+ const { contentWindow } = this.core.renderer;
1180
+ const doc = contentWindow?.document;
1181
+ if (!doc)
1182
+ return;
1183
+ this.targetList.forEach((targetItem) => {
1184
+ const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop };
1185
+ const left = calcValueByFontsize(doc, offset.left);
1186
+ const top = calcValueByFontsize(doc, offset.top);
1187
+ const width = calcValueByFontsize(doc, targetItem.clientWidth);
1188
+ const height = calcValueByFontsize(doc, targetItem.clientHeight);
1189
+ this.emit("update", {
1190
+ el: targetItem,
1191
+ style: isResize ? { left, top, width, height } : { left, top }
1192
+ });
1193
+ });
1194
+ }
1195
+ getOptions(options = {}) {
1196
+ let { moveableOptions = {} } = this.core.config;
1197
+ if (typeof moveableOptions === "function") {
1198
+ moveableOptions = moveableOptions(this.core);
1199
+ }
1200
+ return {
1201
+ defaultGroupRotate: 0,
1202
+ defaultGroupOrigin: "50% 50%",
1203
+ draggable: true,
1204
+ resizable: true,
1205
+ throttleDrag: 0,
1206
+ startDragRotate: 0,
1207
+ throttleDragRotate: 0,
1208
+ zoom: 1,
1209
+ origin: true,
1210
+ padding: { left: 0, top: 0, right: 0, bottom: 0 },
1211
+ ...options,
1212
+ ...moveableOptions
1213
+ };
1214
+ }
1215
+ }
1216
+
1217
+ 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 pointer-events: none;\n}\n";
1046
1218
 
1047
1219
  class StageRender extends EventEmitter.EventEmitter {
1048
1220
  constructor({ core }) {
@@ -1069,18 +1241,18 @@
1069
1241
  });
1070
1242
  };
1071
1243
  this.loadHandler = async () => {
1072
- this.contentWindow = this.iframe?.contentWindow;
1073
- this.contentWindow.magic = this.getMagicApi();
1244
+ if (!this.contentWindow?.magic) {
1245
+ this.postTmagicRuntimeReady();
1246
+ }
1247
+ if (!this.contentWindow)
1248
+ return;
1074
1249
  if (this.render) {
1075
1250
  const el = await this.render(this.core);
1076
1251
  if (el) {
1077
- this.iframe?.contentDocument?.body?.appendChild(el);
1252
+ this.contentWindow.document?.body?.appendChild(el);
1078
1253
  }
1079
1254
  }
1080
1255
  this.emit("onload");
1081
- this.contentWindow.postMessage({
1082
- tmagicRuntimeReady: true
1083
- }, "*");
1084
1256
  utils.injectStyle(this.contentWindow.document, style);
1085
1257
  };
1086
1258
  this.core = core;
@@ -1096,18 +1268,18 @@
1096
1268
  this.iframe.addEventListener("load", this.loadHandler);
1097
1269
  }
1098
1270
  async mount(el) {
1099
- if (this.iframe) {
1100
- if (!utils.isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
1101
- let html = await fetch(this.runtimeUrl).then((res) => res.text());
1102
- const base = `${location.protocol}//${utils.getHost(this.runtimeUrl)}`;
1103
- html = html.replace("<head>", `<head>
1104
- <base href="${base}">`);
1105
- this.iframe.srcdoc = html;
1106
- }
1107
- el.appendChild(this.iframe);
1108
- } else {
1271
+ if (!this.iframe) {
1109
1272
  throw Error("mount \u5931\u8D25");
1110
1273
  }
1274
+ if (!utils.isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
1275
+ let html = await fetch(this.runtimeUrl).then((res) => res.text());
1276
+ const base = `${location.protocol}//${utils.getHost(this.runtimeUrl)}`;
1277
+ html = html.replace("<head>", `<head>
1278
+ <base href="${base}">`);
1279
+ this.iframe.srcdoc = html;
1280
+ }
1281
+ el.appendChild(this.iframe);
1282
+ this.postTmagicRuntimeReady();
1111
1283
  }
1112
1284
  destroy() {
1113
1285
  this.iframe?.removeEventListener("load", this.loadHandler);
@@ -1116,11 +1288,19 @@
1116
1288
  this.iframe = void 0;
1117
1289
  this.removeAllListeners();
1118
1290
  }
1291
+ postTmagicRuntimeReady() {
1292
+ this.contentWindow = this.iframe?.contentWindow;
1293
+ this.contentWindow.magic = this.getMagicApi();
1294
+ this.contentWindow.postMessage({
1295
+ tmagicRuntimeReady: true
1296
+ }, "*");
1297
+ }
1119
1298
  }
1120
1299
 
1121
1300
  class StageCore extends EventEmitter.EventEmitter {
1122
1301
  constructor(config) {
1123
1302
  super();
1303
+ this.selectedDomList = [];
1124
1304
  this.zoom = DEFAULT_ZOOM;
1125
1305
  this.config = config;
1126
1306
  this.setZoom(config.zoom);
@@ -1130,7 +1310,8 @@
1130
1310
  this.containerHighlightDuration = config.containerHighlightDuration;
1131
1311
  this.renderer = new StageRender({ core: this });
1132
1312
  this.mask = new StageMask({ core: this });
1133
- this.dr = new StageDragResize({ core: this, container: this.mask.content });
1313
+ this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
1314
+ this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
1134
1315
  this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
1135
1316
  this.renderer.on("runtime-ready", (runtime) => {
1136
1317
  this.emit("runtime-ready", runtime);
@@ -1138,29 +1319,55 @@
1138
1319
  this.renderer.on("page-el-update", (el) => {
1139
1320
  this.mask?.observe(el);
1140
1321
  });
1141
- this.mask.on("beforeSelect", (event) => {
1142
- this.setElementFromPoint(event);
1322
+ this.mask.on("beforeSelect", async (event) => {
1323
+ this.clearSelectStatus("multiSelect");
1324
+ const el = await this.getElementFromPoint(event);
1325
+ if (!el)
1326
+ return;
1327
+ this.select(el, event);
1143
1328
  }).on("select", () => {
1144
1329
  this.emit("select", this.selectedDom);
1145
1330
  }).on("changeGuides", (data) => {
1146
1331
  this.dr.setGuidelines(data.type, data.guides);
1147
1332
  this.emit("changeGuides", data);
1148
1333
  }).on("highlight", async (event) => {
1149
- await this.setElementFromPoint(event);
1334
+ const el = await this.getElementFromPoint(event);
1335
+ if (!el)
1336
+ return;
1337
+ await this.highlight(el);
1150
1338
  if (this.highlightedDom === this.selectedDom) {
1151
1339
  this.highlightLayer.clearHighlight();
1152
1340
  return;
1153
1341
  }
1154
- this.highlightLayer.highlight(this.highlightedDom);
1155
1342
  this.emit("highlight", this.highlightedDom);
1156
1343
  }).on("clearHighlight", async () => {
1157
1344
  this.highlightLayer.clearHighlight();
1345
+ }).on("beforeMultiSelect", async (event) => {
1346
+ const el = await this.getElementFromPoint(event);
1347
+ if (!el)
1348
+ return;
1349
+ this.clearSelectStatus("select");
1350
+ if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
1351
+ this.selectedDomList.push(this.selectedDom);
1352
+ this.selectedDom = void 0;
1353
+ }
1354
+ const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
1355
+ if (existIndex !== -1) {
1356
+ this.selectedDomList.splice(existIndex, 1);
1357
+ } else {
1358
+ this.selectedDomList.push(el);
1359
+ }
1360
+ this.multiDr.multiSelect(this.selectedDomList);
1361
+ this.emit("multiSelect", this.selectedDomList);
1158
1362
  });
1159
1363
  this.dr.on("update", (data) => {
1160
1364
  setTimeout(() => this.emit("update", data));
1161
1365
  }).on("sort", (data) => {
1162
1366
  setTimeout(() => this.emit("sort", data));
1163
1367
  });
1368
+ this.multiDr.on("update", (data) => {
1369
+ setTimeout(() => this.emit("update", data));
1370
+ });
1164
1371
  }
1165
1372
  getElementsFromPoint(event) {
1166
1373
  const { renderer, zoom } = this;
@@ -1176,24 +1383,29 @@
1176
1383
  }
1177
1384
  return doc?.elementsFromPoint(x / zoom, y / zoom);
1178
1385
  }
1179
- async setElementFromPoint(event) {
1386
+ async getElementFromPoint(event) {
1180
1387
  const els = this.getElementsFromPoint(event);
1181
1388
  let stopped = false;
1182
1389
  const stop = () => stopped = true;
1183
1390
  for (const el of els) {
1184
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.canSelect(el, event, stop)) {
1391
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isElCanSelect(el, event, stop)) {
1185
1392
  if (stopped)
1186
1393
  break;
1187
- if (event.type === "mousemove") {
1188
- this.highlight(el);
1189
- break;
1190
- }
1191
- this.select(el, event);
1192
- break;
1394
+ return el;
1193
1395
  }
1194
1396
  }
1195
1397
  }
1398
+ async isElCanSelect(el, event, stop) {
1399
+ const canSelectByProp = await this.canSelect(el, event, stop);
1400
+ if (!canSelectByProp)
1401
+ return false;
1402
+ if (this.mask.isMultiSelectStatus) {
1403
+ return this.multiDr.canSelect(el);
1404
+ }
1405
+ return true;
1406
+ }
1196
1407
  async select(idOrEl, event) {
1408
+ this.clearSelectStatus("multiSelect");
1197
1409
  const el = await this.getTargetElement(idOrEl);
1198
1410
  if (el === this.selectedDom)
1199
1411
  return;
@@ -1237,7 +1449,7 @@
1237
1449
  this.highlightLayer.clearHighlight();
1238
1450
  return;
1239
1451
  }
1240
- if (el === this.highlightedDom)
1452
+ if (el === this.highlightedDom || !el)
1241
1453
  return;
1242
1454
  this.highlightLayer.highlight(el);
1243
1455
  this.highlightedDom = el;
@@ -1254,6 +1466,14 @@
1254
1466
  setZoom(zoom = DEFAULT_ZOOM) {
1255
1467
  this.zoom = zoom;
1256
1468
  }
1469
+ clearSelectStatus(selectType) {
1470
+ if (selectType === "multiSelect") {
1471
+ this.multiDr.clearSelectStatus();
1472
+ this.selectedDomList = [];
1473
+ } else {
1474
+ this.dr.clearSelectStatus();
1475
+ }
1476
+ }
1257
1477
  async mount(el) {
1258
1478
  this.container = el;
1259
1479
  const { mask, renderer } = this;
@@ -1265,6 +1485,24 @@
1265
1485
  this.mask.clearGuides();
1266
1486
  this.dr.clearGuides();
1267
1487
  }
1488
+ async addContainerHighlightClassName(event, exclude) {
1489
+ const els = this.getElementsFromPoint(event);
1490
+ const { renderer } = this;
1491
+ const doc = renderer.contentWindow?.document;
1492
+ if (!doc)
1493
+ return;
1494
+ for (const el of els) {
1495
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isContainer(el) && !exclude.includes(el)) {
1496
+ utils.addClassName(el, doc, this.containerHighlightClassName);
1497
+ break;
1498
+ }
1499
+ }
1500
+ }
1501
+ getAddContainerHighlightClassNameTimeout(event, exclude = []) {
1502
+ return globalThis.setTimeout(() => {
1503
+ this.addContainerHighlightClassName(event, exclude);
1504
+ }, this.containerHighlightDuration);
1505
+ }
1268
1506
  destroy() {
1269
1507
  const { mask, renderer, dr, highlightLayer } = this;
1270
1508
  renderer.destroy();
@@ -1293,6 +1531,7 @@
1293
1531
  exports.HIGHLIGHT_EL_ID_PREFIX = HIGHLIGHT_EL_ID_PREFIX;
1294
1532
  exports.Mode = Mode;
1295
1533
  exports.MouseButton = MouseButton;
1534
+ exports.PAGE_CLASS = PAGE_CLASS;
1296
1535
  exports.SELECTED_CLASS = SELECTED_CLASS;
1297
1536
  exports.StageDragResize = StageDragResize;
1298
1537
  exports.StageMask = StageMask;
@@ -1301,16 +1540,19 @@
1301
1540
  exports.addSelectedClassName = addSelectedClassName;
1302
1541
  exports.calcValueByFontsize = calcValueByFontsize;
1303
1542
  exports["default"] = StageCore;
1543
+ exports.down = down;
1304
1544
  exports.getAbsolutePosition = getAbsolutePosition;
1305
1545
  exports.getMode = getMode;
1306
1546
  exports.getOffset = getOffset;
1307
1547
  exports.getScrollParent = getScrollParent;
1548
+ exports.getTargetElStyle = getTargetElStyle;
1308
1549
  exports.isAbsolute = isAbsolute;
1309
1550
  exports.isFixed = isFixed;
1310
1551
  exports.isFixedParent = isFixedParent;
1311
1552
  exports.isRelative = isRelative;
1312
1553
  exports.isStatic = isStatic;
1313
1554
  exports.removeSelectedClassName = removeSelectedClassName;
1555
+ exports.up = up;
1314
1556
 
1315
1557
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
1316
1558