@tmagic/stage 1.0.0-rc.1 → 1.0.0-rc.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.
@@ -16,6 +16,8 @@ var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
16
16
  var ZIndex = /* @__PURE__ */ ((ZIndex2) => {
17
17
  ZIndex2["MASK"] = "99999";
18
18
  ZIndex2["SELECTED_EL"] = "666";
19
+ ZIndex2["GHOST_EL"] = "700";
20
+ ZIndex2["DRAG_EL"] = "9";
19
21
  return ZIndex2;
20
22
  })(ZIndex || {});
21
23
  var MouseButton = /* @__PURE__ */ ((MouseButton2) => {
@@ -31,31 +33,22 @@ var Mode = /* @__PURE__ */ ((Mode2) => {
31
33
  return Mode2;
32
34
  })(Mode || {});
33
35
  const SELECTED_CLASS = "tmagic-stage-selected-area";
36
+ const H_GUIDE_LINE_STORAGE_KEY = "$MagicStageHorizontalGuidelinesData";
37
+ const V_GUIDE_LINE_STORAGE_KEY = "$MagicStageVerticalGuidelinesData";
34
38
 
39
+ const getParents = (el, relative) => {
40
+ let cur = el.parentElement;
41
+ const parents = [];
42
+ while (cur && cur !== relative) {
43
+ parents.push(cur);
44
+ cur = cur.parentElement;
45
+ }
46
+ return parents;
47
+ };
35
48
  const getOffset = (el) => {
36
- const { transform } = getComputedStyle(el);
37
49
  const { offsetParent } = el;
38
- let left = el.offsetLeft;
39
- let top = el.offsetTop;
40
- if (transform.indexOf("matrix") > -1) {
41
- let a = 1;
42
- let b = 1;
43
- let c = 1;
44
- let d = 1;
45
- let e = 0;
46
- let f = 0;
47
- transform.replace(/matrix\((.+), (.+), (.+), (.+), (.+), (.+)\)/, ($0, $1, $2, $3, $4, $5, $6) => {
48
- a = +$1;
49
- b = +$2;
50
- c = +$3;
51
- d = +$4;
52
- e = +$5;
53
- f = +$6;
54
- return transform;
55
- });
56
- left = a * left + c * top + e;
57
- top = b * left + d * top + f;
58
- }
50
+ const left = el.offsetLeft;
51
+ const top = el.offsetTop;
59
52
  if (offsetParent) {
60
53
  const parentOffset = getOffset(offsetParent);
61
54
  return {
@@ -86,11 +79,6 @@ const isSameDomain = (targetUrl = "", source = globalThis.location.host) => {
86
79
  return true;
87
80
  return getHost(targetUrl) === source;
88
81
  };
89
- const isAbsolute = (el) => {
90
- if (!el)
91
- return false;
92
- return getComputedStyle(el).position === "absolute";
93
- };
94
82
  const isRelative = (el) => {
95
83
  if (!el)
96
84
  return false;
@@ -131,15 +119,15 @@ const getMode = (el) => {
131
119
  };
132
120
  const getScrollParent = (element, includeHidden = false) => {
133
121
  let style = getComputedStyle(element);
122
+ const excludeStaticParent = style.position === "absolute";
134
123
  const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
135
- if (isFixed(element))
124
+ if (style.position === "fixed")
136
125
  return null;
137
126
  for (let parent = element; parent.parentElement; ) {
138
127
  parent = parent.parentElement;
139
128
  style = getComputedStyle(parent);
140
- if (isAbsolute(element) && isStatic(element)) {
129
+ if (excludeStaticParent && style.position === "static")
141
130
  continue;
142
- }
143
131
  if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX))
144
132
  return parent;
145
133
  }
@@ -156,18 +144,41 @@ const removeSelectedClassName = (doc) => {
156
144
  if (oldEl) {
157
145
  oldEl.classList.remove(SELECTED_CLASS);
158
146
  oldEl.parentNode?.classList.remove(`${SELECTED_CLASS}-parent`);
147
+ doc.querySelectorAll(`.${SELECTED_CLASS}-parents`).forEach((item) => {
148
+ item.classList.remove(`${SELECTED_CLASS}-parents`);
149
+ });
159
150
  }
160
151
  };
161
- const addSelectedClassName = (el) => {
152
+ const addSelectedClassName = (el, doc) => {
162
153
  el.classList.add(SELECTED_CLASS);
163
154
  el.parentNode?.classList.add(`${SELECTED_CLASS}-parent`);
155
+ getParents(el, doc.body).forEach((item) => {
156
+ item.classList.add(`${SELECTED_CLASS}-parents`);
157
+ });
158
+ };
159
+ const getGuideLineFromCache = (type) => {
160
+ const key = {
161
+ [GuidesType.HORIZONTAL]: H_GUIDE_LINE_STORAGE_KEY,
162
+ [GuidesType.VERTICAL]: V_GUIDE_LINE_STORAGE_KEY
163
+ }[type];
164
+ if (!key)
165
+ return [];
166
+ const guideLineCacheData = globalThis.localStorage.getItem(key);
167
+ if (guideLineCacheData) {
168
+ try {
169
+ return JSON.parse(guideLineCacheData) || [];
170
+ } catch (e) {
171
+ console.error(e);
172
+ }
173
+ }
174
+ return [];
164
175
  };
165
176
 
166
177
  class StageDragResize extends EventEmitter {
167
178
  constructor(config) {
168
179
  super();
169
- this.horizontalGuidelines = [];
170
- this.verticalGuidelines = [];
180
+ this.horizontalGuidelines = getGuideLineFromCache(GuidesType.HORIZONTAL);
181
+ this.verticalGuidelines = getGuideLineFromCache(GuidesType.VERTICAL);
171
182
  this.elementGuidelines = [];
172
183
  this.mode = Mode.ABSOLUTE;
173
184
  this.moveableOptions = {};
@@ -180,8 +191,8 @@ class StageDragResize extends EventEmitter {
180
191
  select(el, event) {
181
192
  const oldTarget = this.target;
182
193
  this.target = el;
183
- this.init(el);
184
194
  if (!this.moveable || this.target !== oldTarget) {
195
+ this.init(el);
185
196
  this.moveableHelper = MoveableHelper.create({
186
197
  useBeforeRender: true,
187
198
  useRender: false,
@@ -199,7 +210,7 @@ class StageDragResize extends EventEmitter {
199
210
  if (!this.moveable)
200
211
  throw new Error("\u672A\u521D\u59CB\u5316moveable");
201
212
  if (!el)
202
- throw new Error("\u4E3A\u9009\u4E2D\u4EFB\u4F55\u8282\u70B9");
213
+ throw new Error("\u672A\u9009\u4E2D\u4EFB\u4F55\u8282\u70B9");
203
214
  this.target = el;
204
215
  this.init(el);
205
216
  Object.entries(this.moveableOptions).forEach(([key, value]) => {
@@ -242,6 +253,26 @@ class StageDragResize extends EventEmitter {
242
253
  target: this.dragEl
243
254
  });
244
255
  }
256
+ setElementGuidelines(nodes) {
257
+ this.elementGuidelines.forEach((node) => {
258
+ node.remove();
259
+ });
260
+ this.elementGuidelines = [];
261
+ if (this.mode === Mode.ABSOLUTE) {
262
+ const frame = document.createDocumentFragment();
263
+ for (const node of nodes) {
264
+ const { width, height } = node.getBoundingClientRect();
265
+ if (node === this.target)
266
+ continue;
267
+ const { left, top } = getOffset(node);
268
+ const elementGuideline = document.createElement("div");
269
+ elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
270
+ this.elementGuidelines.push(elementGuideline);
271
+ frame.append(elementGuideline);
272
+ }
273
+ this.container.append(frame);
274
+ }
275
+ }
245
276
  initMoveable() {
246
277
  this.moveable?.destroy();
247
278
  this.moveable = new Moveable(this.container, {
@@ -249,35 +280,38 @@ class StageDragResize extends EventEmitter {
249
280
  });
250
281
  this.bindResizeEvent();
251
282
  this.bindDragEvent();
283
+ this.bindRotateEvent();
284
+ this.bindScaleEvent();
252
285
  }
253
286
  bindResizeEvent() {
254
287
  if (!this.moveable)
255
- throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
288
+ throw new Error("moveable \u672A\u521D\u59CB\u5316");
289
+ const frame = {
290
+ left: 0,
291
+ top: 0
292
+ };
256
293
  this.moveable.on("resizeStart", (e) => {
257
- if (e.dragStart) {
258
- const rect = this.moveable.getRect();
259
- const offset = getAbsolutePosition(e.target, rect);
260
- e.dragStart.set([offset.left, offset.top]);
261
- }
262
- }).on("resize", ({ width, height, drag }) => {
294
+ if (!this.target)
295
+ return;
296
+ this.dragStatus = "start" /* START */;
297
+ this.moveableHelper?.onResizeStart(e);
298
+ frame.top = this.target.offsetTop;
299
+ frame.left = this.target.offsetLeft;
300
+ }).on("resize", (e) => {
301
+ const { width, height, drag } = e;
263
302
  if (!this.moveable || !this.target || !this.dragEl)
264
303
  return;
265
304
  const { beforeTranslate } = drag;
266
305
  this.dragStatus = "ing" /* ING */;
267
- this.target.style.width = `${width}px`;
268
- this.target.style.height = `${height}px`;
269
- this.dragEl.style.width = `${width}px`;
270
- this.dragEl.style.height = `${height}px`;
306
+ this.moveableHelper?.onResize(e);
271
307
  if (this.mode === Mode.SORTABLE) {
272
- this.dragEl.style.top = `${beforeTranslate[1]}px`;
273
- this.target.style.top = `0px`;
274
- return;
308
+ this.target.style.top = "0px";
309
+ } else {
310
+ this.target.style.left = `${frame.left + beforeTranslate[0]}px`;
311
+ this.target.style.top = `${frame.top + beforeTranslate[1]}px`;
275
312
  }
276
- this.dragEl.style.left = `${beforeTranslate[0]}px`;
277
- this.dragEl.style.top = `${beforeTranslate[1]}px`;
278
- const offset = getAbsolutePosition(this.target, { left: beforeTranslate[0], top: beforeTranslate[1] });
279
- this.target.style.left = `${offset.left}px`;
280
- this.target.style.top = `${offset.top}px`;
313
+ this.target.style.width = `${width}px`;
314
+ this.target.style.height = `${height}px`;
281
315
  }).on("resizeEnd", () => {
282
316
  this.dragStatus = "end" /* END */;
283
317
  this.update(true);
@@ -285,8 +319,11 @@ class StageDragResize extends EventEmitter {
285
319
  }
286
320
  bindDragEvent() {
287
321
  if (!this.moveable)
288
- throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
289
- let offset = null;
322
+ throw new Error("moveable \u672A\u521D\u59CB\u5316");
323
+ const frame = {
324
+ left: 0,
325
+ top: 0
326
+ };
290
327
  this.moveable.on("dragStart", (e) => {
291
328
  if (!this.target)
292
329
  throw new Error("\u672A\u9009\u4E2D\u7EC4\u4EF6");
@@ -295,22 +332,19 @@ class StageDragResize extends EventEmitter {
295
332
  if (this.mode === Mode.SORTABLE) {
296
333
  this.ghostEl = this.generateGhostEl(this.target);
297
334
  }
335
+ frame.top = this.target.offsetTop;
336
+ frame.left = this.target.offsetLeft;
298
337
  }).on("drag", (e) => {
299
338
  if (!this.target || !this.dragEl)
300
339
  return;
301
- if (!offset) {
302
- offset = getAbsolutePosition(this.target, { left: 0, top: 0 });
303
- }
304
340
  this.dragStatus = "ing" /* ING */;
305
- const { left, top } = e;
306
341
  if (this.ghostEl) {
307
- this.dragEl.style.top = `${top}px`;
308
- this.ghostEl.style.top = `${top + offset.top}px`;
342
+ this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
309
343
  return;
310
344
  }
311
345
  this.moveableHelper?.onDrag(e);
312
- this.target.style.left = `${left + offset.left}px`;
313
- this.target.style.top = `${top + offset.top}px`;
346
+ this.target.style.left = `${frame.left + e.beforeTranslate[0]}px`;
347
+ this.target.style.top = `${frame.top + e.beforeTranslate[1]}px`;
314
348
  }).on("dragEnd", () => {
315
349
  if (this.dragStatus === "ing" /* ING */) {
316
350
  switch (this.mode) {
@@ -321,18 +355,57 @@ class StageDragResize extends EventEmitter {
321
355
  this.update();
322
356
  }
323
357
  }
324
- offset = null;
325
358
  this.dragStatus = "end" /* END */;
326
359
  this.destroyGhostEl();
327
360
  });
328
361
  }
329
- getSnapElements(runtime, el) {
330
- const { renderer, mask } = this.core;
331
- const getSnapElements = runtime?.getSnapElements || (() => {
332
- const doc = renderer.contentWindow?.document;
333
- return doc ? Array.from(doc.querySelectorAll("[id]")) : [];
362
+ bindRotateEvent() {
363
+ if (!this.moveable)
364
+ throw new Error("moveable \u672A\u521D\u59CB\u5316");
365
+ this.moveable.on("rotateStart", (e) => {
366
+ this.dragStatus = "start" /* START */;
367
+ this.moveableHelper?.onRotateStart(e);
368
+ }).on("rotate", (e) => {
369
+ if (!this.target || !this.dragEl)
370
+ return;
371
+ this.dragStatus = "ing" /* ING */;
372
+ this.moveableHelper?.onRotate(e);
373
+ const frame = this.moveableHelper?.getFrame(e.target);
374
+ this.target.style.transform = frame?.toCSSObject().transform || "";
375
+ }).on("rotateEnd", (e) => {
376
+ this.dragStatus = "end" /* END */;
377
+ const frame = this.moveableHelper?.getFrame(e.target);
378
+ this.emit("update", {
379
+ el: this.target,
380
+ style: {
381
+ transform: frame?.get("transform")
382
+ }
383
+ });
384
+ });
385
+ }
386
+ bindScaleEvent() {
387
+ if (!this.moveable)
388
+ throw new Error("moveable \u672A\u521D\u59CB\u5316");
389
+ this.moveable.on("scaleStart", (e) => {
390
+ this.dragStatus = "start" /* START */;
391
+ this.moveableHelper?.onScaleStart(e);
392
+ }).on("scale", (e) => {
393
+ if (!this.target || !this.dragEl)
394
+ return;
395
+ this.dragStatus = "ing" /* ING */;
396
+ this.moveableHelper?.onScale(e);
397
+ const frame = this.moveableHelper?.getFrame(e.target);
398
+ this.target.style.transform = frame?.toCSSObject().transform || "";
399
+ }).on("scaleEnd", (e) => {
400
+ this.dragStatus = "end" /* END */;
401
+ const frame = this.moveableHelper?.getFrame(e.target);
402
+ this.emit("update", {
403
+ el: this.target,
404
+ style: {
405
+ transform: frame?.get("transform")
406
+ }
407
+ });
334
408
  });
335
- return getSnapElements(el).filter((element) => element !== this.target && !this.target?.contains(element) && element !== mask.page);
336
409
  }
337
410
  sort() {
338
411
  if (!this.target || !this.ghostEl)
@@ -354,12 +427,13 @@ class StageDragResize extends EventEmitter {
354
427
  }
355
428
  }
356
429
  update(isResize = false) {
357
- const rect = this.moveable.getRect();
358
- const offset = this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : getAbsolutePosition(this.target, rect);
430
+ if (!this.target)
431
+ return;
432
+ const offset = this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
359
433
  const left = this.calcValueByFontsize(offset.left);
360
434
  const top = this.calcValueByFontsize(offset.top);
361
- const width = this.calcValueByFontsize(rect.width);
362
- const height = this.calcValueByFontsize(rect.height);
435
+ const width = this.calcValueByFontsize(this.target.clientWidth);
436
+ const height = this.calcValueByFontsize(this.target.clientHeight);
363
437
  this.emit("update", {
364
438
  el: this.target,
365
439
  style: isResize ? { left, top, width, height } : { left, top }
@@ -372,7 +446,7 @@ class StageDragResize extends EventEmitter {
372
446
  const ghostEl = el.cloneNode(true);
373
447
  const { top, left } = getAbsolutePosition(el, getOffset(el));
374
448
  ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
375
- ghostEl.style.zIndex = "5";
449
+ ghostEl.style.zIndex = ZIndex.GHOST_EL;
376
450
  ghostEl.style.opacity = ".5";
377
451
  ghostEl.style.position = "absolute";
378
452
  ghostEl.style.left = `${left}px`;
@@ -385,17 +459,21 @@ class StageDragResize extends EventEmitter {
385
459
  this.ghostEl = void 0;
386
460
  }
387
461
  updateDragEl(el) {
388
- const { width, height } = el.getBoundingClientRect();
389
462
  const offset = getOffset(el);
463
+ const { transform } = getComputedStyle(el);
390
464
  this.dragEl.style.cssText = `
391
465
  position: absolute;
466
+ transform: ${transform};
392
467
  left: ${offset.left}px;
393
468
  top: ${offset.top}px;
394
- width: ${width}px;
395
- height: ${height}px;
396
- z-index: 9;
469
+ width: ${el.clientWidth}px;
470
+ height: ${el.clientHeight}px;
471
+ z-index: ${ZIndex.DRAG_EL};
397
472
  `;
398
473
  this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
474
+ if (typeof this.core.config.updateDragEl === "function") {
475
+ this.core.config.updateDragEl(this.dragEl, el);
476
+ }
399
477
  }
400
478
  destroyDragEl() {
401
479
  this.dragEl?.remove();
@@ -409,6 +487,11 @@ class StageDragResize extends EventEmitter {
409
487
  if (typeof moveableOptions === "function") {
410
488
  moveableOptions = moveableOptions(this.core);
411
489
  }
490
+ const elementGuidelines = moveableOptions.elementGuidelines || this.target.parentElement?.children || [];
491
+ this.setElementGuidelines(elementGuidelines);
492
+ if (moveableOptions.elementGuidelines) {
493
+ delete moveableOptions.elementGuidelines;
494
+ }
412
495
  return {
413
496
  origin: false,
414
497
  rootContainer: this.core.container,
@@ -416,6 +499,8 @@ class StageDragResize extends EventEmitter {
416
499
  dragArea: false,
417
500
  draggable: true,
418
501
  resizable: true,
502
+ scalable: false,
503
+ rotatable: false,
419
504
  snappable: isAbsolute || isFixed,
420
505
  snapGap: isAbsolute || isFixed,
421
506
  snapThreshold: 5,
@@ -514,49 +599,34 @@ class TargetCalibrate extends EventEmitter {
514
599
  this.parent = config.parent;
515
600
  this.mask = config.mask;
516
601
  this.dr = config.dr;
602
+ this.core = config.core;
517
603
  this.operationEl = globalThis.document.createElement("div");
518
604
  this.parent.append(this.operationEl);
519
605
  }
520
606
  update(el, prefix) {
521
- const { width, height } = el.getBoundingClientRect();
522
607
  const { left, top } = this.getOffset(el);
608
+ const { transform } = getComputedStyle(el);
523
609
  this.operationEl.style.cssText = `
524
610
  position: absolute;
611
+ transform: ${transform};
525
612
  left: ${left}px;
526
613
  top: ${top}px;
527
- width: ${width}px;
528
- height: ${height}px;
614
+ width: ${el.clientWidth}px;
615
+ height: ${el.clientHeight}px;
529
616
  `;
530
617
  this.operationEl.id = `${prefix}${el.id}`;
618
+ if (typeof this.core.config.updateDragEl === "function") {
619
+ this.core.config.updateDragEl(this.operationEl, el);
620
+ }
531
621
  return this.operationEl;
532
622
  }
533
623
  destroy() {
534
624
  this.operationEl?.remove();
535
625
  }
536
626
  getOffset(el) {
537
- const { transform } = getComputedStyle(el);
538
627
  const { offsetParent } = el;
539
- let left = el.offsetLeft;
540
- let top = el.offsetTop;
541
- if (transform.indexOf("matrix") > -1) {
542
- let a = 1;
543
- let b = 1;
544
- let c = 1;
545
- let d = 1;
546
- let e = 0;
547
- let f = 0;
548
- transform.replace(/matrix\((.+), (.+), (.+), (.+), (.+), (.+)\)/, ($0, $1, $2, $3, $4, $5, $6) => {
549
- a = +$1;
550
- b = +$2;
551
- c = +$3;
552
- d = +$4;
553
- e = +$5;
554
- f = +$6;
555
- return transform;
556
- });
557
- left = a * left + c * top + e;
558
- top = b * left + d * top + f;
559
- }
628
+ const left = el.offsetLeft;
629
+ const top = el.offsetTop;
560
630
  if (offsetParent) {
561
631
  const parentOffset = this.getOffset(offsetParent);
562
632
  return {
@@ -597,7 +667,8 @@ class StageHighlight extends EventEmitter {
597
667
  this.calibrationTarget = new TargetCalibrate({
598
668
  parent: this.core.mask.content,
599
669
  mask: this.core.mask,
600
- dr: this.core.dr
670
+ dr: this.core.dr,
671
+ core: this.core
601
672
  });
602
673
  }
603
674
  highlight(el) {
@@ -628,8 +699,8 @@ class StageHighlight extends EventEmitter {
628
699
  class Rule extends EventEmitter$1 {
629
700
  constructor(container) {
630
701
  super();
631
- this.horizontalGuidelines = [];
632
- this.verticalGuidelines = [];
702
+ this.horizontalGuidelines = getGuideLineFromCache(GuidesType.HORIZONTAL);
703
+ this.verticalGuidelines = getGuideLineFromCache(GuidesType.VERTICAL);
633
704
  this.getGuidesStyle = (type) => ({
634
705
  position: "fixed",
635
706
  zIndex: 1,
@@ -653,6 +724,7 @@ class Rule extends EventEmitter$1 {
653
724
  type: GuidesType.HORIZONTAL,
654
725
  guides: this.horizontalGuidelines
655
726
  });
727
+ globalThis.localStorage.setItem(H_GUIDE_LINE_STORAGE_KEY, JSON.stringify(e.guides));
656
728
  };
657
729
  this.vGuidesChangeGuidesHandler = (e) => {
658
730
  this.verticalGuidelines = e.guides;
@@ -660,10 +732,11 @@ class Rule extends EventEmitter$1 {
660
732
  type: GuidesType.VERTICAL,
661
733
  guides: this.verticalGuidelines
662
734
  });
735
+ globalThis.localStorage.setItem(V_GUIDE_LINE_STORAGE_KEY, JSON.stringify(e.guides));
663
736
  };
664
737
  this.container = container;
665
- this.hGuides = this.createGuides(GuidesType.HORIZONTAL);
666
- this.vGuides = this.createGuides(GuidesType.VERTICAL);
738
+ this.hGuides = this.createGuides(GuidesType.HORIZONTAL, this.horizontalGuidelines);
739
+ this.vGuides = this.createGuides(GuidesType.VERTICAL, this.verticalGuidelines);
667
740
  this.hGuides.on("changeGuides", this.hGuidesChangeGuidesHandler);
668
741
  this.vGuides.on("changeGuides", this.vGuidesChangeGuidesHandler);
669
742
  this.containerResizeObserver = new ResizeObserver(() => {
@@ -697,6 +770,8 @@ class Rule extends EventEmitter$1 {
697
770
  type: GuidesType.HORIZONTAL,
698
771
  guides: []
699
772
  });
773
+ globalThis.localStorage.setItem(V_GUIDE_LINE_STORAGE_KEY, "[]");
774
+ globalThis.localStorage.setItem(H_GUIDE_LINE_STORAGE_KEY, "[]");
700
775
  }
701
776
  showRule(show = true) {
702
777
  if (show) {
@@ -780,6 +855,7 @@ class StageMask extends Rule {
780
855
  this.wrapperWidth = 0;
781
856
  this.maxScrollTop = 0;
782
857
  this.maxScrollLeft = 0;
858
+ this.intersectionObserver = null;
783
859
  this.mode = Mode.ABSOLUTE;
784
860
  this.pageResizeObserver = null;
785
861
  this.wrapperResizeObserver = null;
@@ -819,7 +895,6 @@ class StageMask extends Rule {
819
895
  if (this.maxScrollLeft > 0) {
820
896
  this.scrollLeft = this.scrollLeft + deltaX;
821
897
  }
822
- this.fixScrollValue();
823
898
  this.scroll();
824
899
  this.emit("scroll", event);
825
900
  };
@@ -851,15 +926,33 @@ class StageMask extends Rule {
851
926
  this.page = page;
852
927
  this.pageScrollParent = getScrollParent(page) || this.core.renderer.contentWindow?.document.documentElement || null;
853
928
  this.pageResizeObserver?.disconnect();
929
+ this.wrapperResizeObserver?.disconnect();
930
+ this.intersectionObserver?.disconnect();
931
+ if (typeof IntersectionObserver !== "undefined") {
932
+ this.intersectionObserver = new IntersectionObserver((entries) => {
933
+ entries.forEach((entry) => {
934
+ const { target, intersectionRatio } = entry;
935
+ if (intersectionRatio <= 0) {
936
+ this.scrollIntoView(target);
937
+ }
938
+ this.intersectionObserver?.unobserve(target);
939
+ });
940
+ }, {
941
+ root: this.pageScrollParent,
942
+ rootMargin: "0px",
943
+ threshold: 1
944
+ });
945
+ }
854
946
  if (typeof ResizeObserver !== "undefined") {
855
947
  this.pageResizeObserver = new ResizeObserver((entries) => {
856
948
  const [entry] = entries;
857
949
  const { clientHeight, clientWidth } = entry.target;
858
950
  this.setHeight(clientHeight);
859
951
  this.setWidth(clientWidth);
860
- this.fixScrollValue();
861
952
  this.scroll();
862
- this.core.dr.updateMoveable();
953
+ if (this.core.dr.moveable) {
954
+ this.core.dr.updateMoveable();
955
+ }
863
956
  });
864
957
  this.pageResizeObserver.observe(page);
865
958
  this.wrapperResizeObserver = new ResizeObserver((entries) => {
@@ -881,6 +974,14 @@ class StageMask extends Rule {
881
974
  setLayout(el) {
882
975
  this.setMode(isFixedParent(el) ? Mode.FIXED : Mode.ABSOLUTE);
883
976
  }
977
+ scrollIntoView(el) {
978
+ el.scrollIntoView();
979
+ if (!this.pageScrollParent)
980
+ return;
981
+ this.scrollLeft = this.pageScrollParent.scrollLeft;
982
+ this.scrollTop = this.pageScrollParent.scrollTop;
983
+ this.scroll();
984
+ }
884
985
  destroy() {
885
986
  this.content?.remove();
886
987
  this.page = null;
@@ -891,6 +992,7 @@ class StageMask extends Rule {
891
992
  super.destroy();
892
993
  }
893
994
  scroll() {
995
+ this.fixScrollValue();
894
996
  let { scrollLeft, scrollTop } = this;
895
997
  if (this.pageScrollParent) {
896
998
  this.pageScrollParent.scrollTo({
@@ -919,10 +1021,10 @@ class StageMask extends Rule {
919
1021
  this.content.style.width = `${width}px`;
920
1022
  }
921
1023
  setMaxScrollLeft() {
922
- this.maxScrollLeft = this.width - this.wrapperWidth;
1024
+ this.maxScrollLeft = Math.max(this.width - this.wrapperWidth, 0);
923
1025
  }
924
1026
  setMaxScrollTop() {
925
- this.maxScrollTop = this.height - this.wrapperHeight;
1027
+ this.maxScrollTop = Math.max(this.height - this.wrapperHeight, 0);
926
1028
  }
927
1029
  fixScrollValue() {
928
1030
  if (this.scrollTop < 0)
@@ -961,23 +1063,18 @@ class StageRender extends EventEmitter {
961
1063
  });
962
1064
  };
963
1065
  this.loadHandler = async () => {
964
- this.emit("onload");
1066
+ this.contentWindow = this.iframe?.contentWindow;
1067
+ this.contentWindow.magic = this.getMagicApi();
965
1068
  if (this.render) {
966
1069
  const el = await this.render(this.core);
967
1070
  if (el) {
968
1071
  this.iframe?.contentDocument?.body?.appendChild(el);
969
1072
  }
970
1073
  }
971
- if (this.contentWindow) {
972
- const style = this.contentWindow.document.createElement("style");
973
- style.id = "tmagic-stage-render";
974
- style.innerHTML = `
975
- .${SELECTED_CLASS}, .${SELECTED_CLASS}-parent {
976
- z-index: ${ZIndex.SELECTED_EL};
977
- }
978
- `;
979
- this.contentWindow.document.head.appendChild(style);
980
- }
1074
+ this.emit("onload");
1075
+ this.contentWindow.postMessage({
1076
+ tmagicRuntimeReady: true
1077
+ }, "*");
981
1078
  };
982
1079
  this.core = core;
983
1080
  this.runtimeUrl = core.config.runtimeUrl || "";
@@ -1001,8 +1098,6 @@ class StageRender extends EventEmitter {
1001
1098
  this.iframe.srcdoc = html;
1002
1099
  }
1003
1100
  el.appendChild(this.iframe);
1004
- this.contentWindow = this.iframe?.contentWindow;
1005
- this.contentWindow.magic = this.getMagicApi();
1006
1101
  } else {
1007
1102
  throw Error("mount \u5931\u8D25");
1008
1103
  }
@@ -1096,11 +1191,14 @@ class StageCore extends EventEmitter {
1096
1191
  }
1097
1192
  this.mask.setLayout(el);
1098
1193
  this.dr.select(el, event);
1194
+ if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
1195
+ this.mask.intersectionObserver?.observe(el);
1196
+ }
1099
1197
  this.selectedDom = el;
1100
1198
  if (this.renderer.contentWindow) {
1101
1199
  removeSelectedClassName(this.renderer.contentWindow.document);
1102
1200
  if (this.selectedDom) {
1103
- addSelectedClassName(this.selectedDom);
1201
+ addSelectedClassName(this.selectedDom, this.renderer.contentWindow.document);
1104
1202
  }
1105
1203
  }
1106
1204
  }
@@ -1143,10 +1241,10 @@ class StageCore extends EventEmitter {
1143
1241
  setZoom(zoom = DEFAULT_ZOOM) {
1144
1242
  this.zoom = zoom;
1145
1243
  }
1146
- mount(el) {
1244
+ async mount(el) {
1147
1245
  this.container = el;
1148
1246
  const { mask, renderer } = this;
1149
- renderer.mount(el);
1247
+ await renderer.mount(el);
1150
1248
  mask.mount(el);
1151
1249
  this.emit("mounted");
1152
1250
  }