@tmagic/stage 1.0.0-beta.8 → 1.0.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,19 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('moveable'), require('@scena/guides')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'events', 'moveable', '@scena/guides'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TMagicStage = {}, global.EventEmitter, global.Moveable, global.Guides));
5
- })(this, (function (exports, EventEmitter, Moveable, Guides) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('moveable'), require('moveable-helper'), require('lodash-es'), require('@scena/guides')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'events', 'moveable', 'moveable-helper', 'lodash-es', '@scena/guides'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TMagicStage = {}, global.EventEmitter, global.Moveable, global.MoveableHelper, global.lodashEs, global.Guides));
5
+ })(this, (function (exports, EventEmitter, Moveable, MoveableHelper, 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
+ var MoveableHelper__default = /*#__PURE__*/_interopDefaultLegacy(MoveableHelper);
11
12
  var Guides__default = /*#__PURE__*/_interopDefaultLegacy(Guides);
12
13
 
13
14
  const GHOST_EL_ID_PREFIX = "ghost_el_";
15
+ const DRAG_EL_ID_PREFIX = "drag_el_";
16
+ const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
14
17
  const DEFAULT_ZOOM = 1;
15
18
  var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
16
19
  GuidesType2["HORIZONTAL"] = "horizontal";
@@ -19,6 +22,9 @@
19
22
  })(GuidesType || {});
20
23
  var ZIndex = /* @__PURE__ */ ((ZIndex2) => {
21
24
  ZIndex2["MASK"] = "99999";
25
+ ZIndex2["SELECTED_EL"] = "666";
26
+ ZIndex2["GHOST_EL"] = "700";
27
+ ZIndex2["DRAG_EL"] = "9";
22
28
  return ZIndex2;
23
29
  })(ZIndex || {});
24
30
  var MouseButton = /* @__PURE__ */ ((MouseButton2) => {
@@ -33,31 +39,23 @@
33
39
  Mode2["SORTABLE"] = "sortable";
34
40
  return Mode2;
35
41
  })(Mode || {});
42
+ const SELECTED_CLASS = "tmagic-stage-selected-area";
43
+ const H_GUIDE_LINE_STORAGE_KEY = "$MagicStageHorizontalGuidelinesData";
44
+ const V_GUIDE_LINE_STORAGE_KEY = "$MagicStageVerticalGuidelinesData";
36
45
 
46
+ const getParents = (el, relative) => {
47
+ let cur = el.parentElement;
48
+ const parents = [];
49
+ while (cur && cur !== relative) {
50
+ parents.push(cur);
51
+ cur = cur.parentElement;
52
+ }
53
+ return parents;
54
+ };
37
55
  const getOffset = (el) => {
38
- const { transform } = getComputedStyle(el);
39
56
  const { offsetParent } = el;
40
- let left = el.offsetLeft;
41
- let top = el.offsetTop;
42
- if (transform.indexOf("matrix") > -1) {
43
- let a = 1;
44
- let b = 1;
45
- let c = 1;
46
- let d = 1;
47
- let e = 0;
48
- let f = 0;
49
- transform.replace(/matrix\((.+), (.+), (.+), (.+), (.+), (.+)\)/, ($0, $1, $2, $3, $4, $5, $6) => {
50
- a = +$1;
51
- b = +$2;
52
- c = +$3;
53
- d = +$4;
54
- e = +$5;
55
- f = +$6;
56
- return transform;
57
- });
58
- left = a * left + c * top + e;
59
- top = b * left + d * top + f;
60
- }
57
+ const left = el.offsetLeft;
58
+ const top = el.offsetTop;
61
59
  if (offsetParent) {
62
60
  const parentOffset = getOffset(offsetParent);
63
61
  return {
@@ -153,46 +151,81 @@
153
151
  el.style.cssText = cssText;
154
152
  return el;
155
153
  };
154
+ const removeSelectedClassName = (doc) => {
155
+ const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
156
+ if (oldEl) {
157
+ oldEl.classList.remove(SELECTED_CLASS);
158
+ oldEl.parentNode?.classList.remove(`${SELECTED_CLASS}-parent`);
159
+ doc.querySelectorAll(`.${SELECTED_CLASS}-parents`).forEach((item) => {
160
+ item.classList.remove(`${SELECTED_CLASS}-parents`);
161
+ });
162
+ }
163
+ };
164
+ const addSelectedClassName = (el, doc) => {
165
+ el.classList.add(SELECTED_CLASS);
166
+ el.parentNode?.classList.add(`${SELECTED_CLASS}-parent`);
167
+ getParents(el, doc.body).forEach((item) => {
168
+ item.classList.add(`${SELECTED_CLASS}-parents`);
169
+ });
170
+ };
171
+ const getGuideLineFromCache = (type) => {
172
+ const key = {
173
+ [GuidesType.HORIZONTAL]: H_GUIDE_LINE_STORAGE_KEY,
174
+ [GuidesType.VERTICAL]: V_GUIDE_LINE_STORAGE_KEY
175
+ }[type];
176
+ if (!key)
177
+ return [];
178
+ const guideLineCacheData = globalThis.localStorage.getItem(key);
179
+ if (guideLineCacheData) {
180
+ try {
181
+ return JSON.parse(guideLineCacheData) || [];
182
+ } catch (e) {
183
+ console.error(e);
184
+ }
185
+ }
186
+ return [];
187
+ };
156
188
 
157
189
  class StageDragResize extends EventEmitter.EventEmitter {
158
- core;
159
- container;
160
- target;
161
- dragEl;
162
- moveable;
163
- horizontalGuidelines = [];
164
- verticalGuidelines = [];
165
- moveableOptions = {};
166
- dragStatus = "end" /* END */;
167
- ghostEl;
168
- mode = Mode.ABSOLUTE;
169
190
  constructor(config) {
170
191
  super();
192
+ this.horizontalGuidelines = getGuideLineFromCache(GuidesType.HORIZONTAL);
193
+ this.verticalGuidelines = getGuideLineFromCache(GuidesType.VERTICAL);
194
+ this.elementGuidelines = [];
195
+ this.mode = Mode.ABSOLUTE;
196
+ this.moveableOptions = {};
197
+ this.dragStatus = "end" /* END */;
171
198
  this.core = config.core;
172
199
  this.container = config.container;
200
+ this.dragEl = globalThis.document.createElement("div");
201
+ this.container.append(this.dragEl);
173
202
  }
174
- async select(el, event) {
203
+ select(el, event) {
204
+ const oldTarget = this.target;
175
205
  this.target = el;
176
- if (/(auto|scroll)/.test(this.target.style.overflow)) {
177
- this.target.style.overflow = "hidden";
206
+ if (!this.moveable || this.target !== oldTarget) {
207
+ this.init(el);
208
+ this.moveableHelper = MoveableHelper__default["default"].create({
209
+ useBeforeRender: true,
210
+ useRender: false,
211
+ createAuto: true
212
+ });
213
+ this.initMoveable();
214
+ } else {
215
+ this.updateMoveable();
178
216
  }
179
- this.mode = getMode(el);
180
- this.destroyDragEl();
181
- this.destroyGhostEl();
182
- this.dragEl = this.generateDragEl(el);
183
- this.moveableOptions = await this.getOptions({
184
- target: this.dragEl || this.target
185
- });
186
- this.initMoveable();
187
217
  if (event) {
188
218
  this.moveable?.dragStart(event);
189
219
  }
190
220
  }
191
- async refresh() {
221
+ updateMoveable(el = this.target) {
192
222
  if (!this.moveable)
193
223
  throw new Error("\u672A\u521D\u59CB\u5316moveable");
194
- const options = await this.getOptions();
195
- Object.entries(options).forEach(([key, value]) => {
224
+ if (!el)
225
+ throw new Error("\u4E3A\u9009\u4E2D\u4EFB\u4F55\u8282\u70B9");
226
+ this.target = el;
227
+ this.init(el);
228
+ Object.entries(this.moveableOptions).forEach(([key, value]) => {
196
229
  this.moveable[key] = value;
197
230
  });
198
231
  this.moveable.updateTarget();
@@ -200,15 +233,19 @@
200
233
  setGuidelines(type, guidelines) {
201
234
  if (type === GuidesType.HORIZONTAL) {
202
235
  this.horizontalGuidelines = guidelines;
236
+ this.moveableOptions.horizontalGuidelines = guidelines;
203
237
  } else if (type === GuidesType.VERTICAL) {
204
238
  this.verticalGuidelines = guidelines;
239
+ this.moveableOptions.verticalGuidelines = guidelines;
205
240
  }
206
- this.refresh();
241
+ this.updateMoveable();
207
242
  }
208
243
  clearGuides() {
209
- this.verticalGuidelines = [];
210
244
  this.horizontalGuidelines = [];
211
- this.refresh();
245
+ this.verticalGuidelines = [];
246
+ this.moveableOptions.horizontalGuidelines = [];
247
+ this.moveableOptions.verticalGuidelines = [];
248
+ this.updateMoveable();
212
249
  }
213
250
  destroy() {
214
251
  this.moveable?.destroy();
@@ -217,6 +254,37 @@
217
254
  this.dragStatus = "end" /* END */;
218
255
  this.removeAllListeners();
219
256
  }
257
+ init(el) {
258
+ if (/(auto|scroll)/.test(el.style.overflow)) {
259
+ el.style.overflow = "hidden";
260
+ }
261
+ this.mode = getMode(el);
262
+ this.destroyGhostEl();
263
+ this.updateDragEl(el);
264
+ this.moveableOptions = this.getOptions({
265
+ target: this.dragEl
266
+ });
267
+ }
268
+ setElementGuidelines(nodes) {
269
+ this.elementGuidelines.forEach((node) => {
270
+ node.remove();
271
+ });
272
+ this.elementGuidelines = [];
273
+ if (this.mode === Mode.ABSOLUTE) {
274
+ const frame = document.createDocumentFragment();
275
+ for (const node of nodes) {
276
+ const { width, height } = node.getBoundingClientRect();
277
+ if (node === this.target)
278
+ continue;
279
+ const { left, top } = getOffset(node);
280
+ const elementGuideline = document.createElement("div");
281
+ elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
282
+ this.elementGuidelines.push(elementGuideline);
283
+ frame.append(elementGuideline);
284
+ }
285
+ this.container.append(frame);
286
+ }
287
+ }
220
288
  initMoveable() {
221
289
  this.moveable?.destroy();
222
290
  this.moveable = new Moveable__default["default"](this.container, {
@@ -224,35 +292,38 @@
224
292
  });
225
293
  this.bindResizeEvent();
226
294
  this.bindDragEvent();
295
+ this.bindRotateEvent();
296
+ this.bindScaleEvent();
227
297
  }
228
298
  bindResizeEvent() {
229
299
  if (!this.moveable)
230
300
  throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
301
+ const frame = {
302
+ left: 0,
303
+ top: 0
304
+ };
231
305
  this.moveable.on("resizeStart", (e) => {
232
- if (e.dragStart) {
233
- const rect = this.moveable.getRect();
234
- const offset = getAbsolutePosition(e.target, rect);
235
- e.dragStart.set([offset.left, offset.top]);
236
- }
237
- }).on("resize", ({ width, height, drag }) => {
306
+ if (!this.target)
307
+ return;
308
+ this.dragStatus = "start" /* START */;
309
+ this.moveableHelper?.onResizeStart(e);
310
+ frame.top = this.target.offsetTop;
311
+ frame.left = this.target.offsetLeft;
312
+ }).on("resize", (e) => {
313
+ const { width, height, drag } = e;
238
314
  if (!this.moveable || !this.target || !this.dragEl)
239
315
  return;
240
316
  const { beforeTranslate } = drag;
241
317
  this.dragStatus = "ing" /* ING */;
242
- this.target.style.width = `${width}px`;
243
- this.target.style.height = `${height}px`;
244
- this.dragEl.style.width = `${width}px`;
245
- this.dragEl.style.height = `${height}px`;
318
+ this.moveableHelper?.onResize(e);
246
319
  if (this.mode === Mode.SORTABLE) {
247
- this.dragEl.style.top = `${beforeTranslate[1]}px`;
248
- this.target.style.top = `0px`;
249
- return;
320
+ this.target.style.top = "0px";
321
+ } else {
322
+ this.target.style.left = `${frame.left + beforeTranslate[0]}px`;
323
+ this.target.style.top = `${frame.top + beforeTranslate[1]}px`;
250
324
  }
251
- this.dragEl.style.left = `${beforeTranslate[0]}px`;
252
- this.dragEl.style.top = `${beforeTranslate[1]}px`;
253
- const offset = getAbsolutePosition(this.target, { left: beforeTranslate[0], top: beforeTranslate[1] });
254
- this.target.style.left = `${offset.left}px`;
255
- this.target.style.top = `${offset.top}px`;
325
+ this.target.style.width = `${width}px`;
326
+ this.target.style.height = `${height}px`;
256
327
  }).on("resizeEnd", () => {
257
328
  this.dragStatus = "end" /* END */;
258
329
  this.update(true);
@@ -261,27 +332,31 @@
261
332
  bindDragEvent() {
262
333
  if (!this.moveable)
263
334
  throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
264
- this.moveable.on("dragStart", () => {
335
+ const frame = {
336
+ left: 0,
337
+ top: 0
338
+ };
339
+ this.moveable.on("dragStart", (e) => {
265
340
  if (!this.target)
266
341
  throw new Error("\u672A\u9009\u4E2D\u7EC4\u4EF6");
267
342
  this.dragStatus = "start" /* START */;
343
+ this.moveableHelper?.onDragStart(e);
268
344
  if (this.mode === Mode.SORTABLE) {
269
345
  this.ghostEl = this.generateGhostEl(this.target);
270
346
  }
271
- }).on("drag", ({ left, top }) => {
347
+ frame.top = this.target.offsetTop;
348
+ frame.left = this.target.offsetLeft;
349
+ }).on("drag", (e) => {
272
350
  if (!this.target || !this.dragEl)
273
351
  return;
274
352
  this.dragStatus = "ing" /* ING */;
275
- const offset = getAbsolutePosition(this.target, { left, top });
276
353
  if (this.ghostEl) {
277
- this.dragEl.style.top = `${top}px`;
278
- this.ghostEl.style.top = `${offset.top}px`;
354
+ this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
279
355
  return;
280
356
  }
281
- this.dragEl.style.left = `${left}px`;
282
- this.dragEl.style.top = `${top}px`;
283
- this.target.style.left = `${offset.left}px`;
284
- this.target.style.top = `${offset.top}px`;
357
+ this.moveableHelper?.onDrag(e);
358
+ this.target.style.left = `${frame.left + e.beforeTranslate[0]}px`;
359
+ this.target.style.top = `${frame.top + e.beforeTranslate[1]}px`;
285
360
  }).on("dragEnd", () => {
286
361
  if (this.dragStatus === "ing" /* ING */) {
287
362
  switch (this.mode) {
@@ -296,13 +371,53 @@
296
371
  this.destroyGhostEl();
297
372
  });
298
373
  }
299
- async getSnapElements(el) {
300
- const { renderer } = this.core;
301
- const getSnapElements = (await renderer.getRuntime())?.getSnapElements || (() => {
302
- const doc = renderer.contentWindow?.document;
303
- return doc ? Array.from(doc.querySelectorAll("[id]")) : [];
374
+ bindRotateEvent() {
375
+ if (!this.moveable)
376
+ throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
377
+ this.moveable.on("rotateStart", (e) => {
378
+ this.dragStatus = "start" /* START */;
379
+ this.moveableHelper?.onRotateStart(e);
380
+ }).on("rotate", (e) => {
381
+ if (!this.target || !this.dragEl)
382
+ return;
383
+ this.dragStatus = "ing" /* ING */;
384
+ this.moveableHelper?.onRotate(e);
385
+ const frame = this.moveableHelper?.getFrame(e.target);
386
+ this.target.style.transform = frame?.toCSSObject().transform || "";
387
+ }).on("rotateEnd", (e) => {
388
+ this.dragStatus = "end" /* END */;
389
+ const frame = this.moveableHelper?.getFrame(e.target);
390
+ this.emit("update", {
391
+ el: this.target,
392
+ style: {
393
+ transform: frame?.get("transform")
394
+ }
395
+ });
396
+ });
397
+ }
398
+ bindScaleEvent() {
399
+ if (!this.moveable)
400
+ throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
401
+ this.moveable.on("scaleStart", (e) => {
402
+ this.dragStatus = "start" /* START */;
403
+ this.moveableHelper?.onScaleStart(e);
404
+ }).on("scale", (e) => {
405
+ if (!this.target || !this.dragEl)
406
+ return;
407
+ this.dragStatus = "ing" /* ING */;
408
+ this.moveableHelper?.onScale(e);
409
+ const frame = this.moveableHelper?.getFrame(e.target);
410
+ this.target.style.transform = frame?.toCSSObject().transform || "";
411
+ }).on("scaleEnd", (e) => {
412
+ this.dragStatus = "end" /* END */;
413
+ const frame = this.moveableHelper?.getFrame(e.target);
414
+ this.emit("update", {
415
+ el: this.target,
416
+ style: {
417
+ transform: frame?.get("transform")
418
+ }
419
+ });
304
420
  });
305
- return getSnapElements(el).filter((element) => element !== this.target && !this.target?.contains(element));
306
421
  }
307
422
  sort() {
308
423
  if (!this.target || !this.ghostEl)
@@ -324,12 +439,13 @@
324
439
  }
325
440
  }
326
441
  update(isResize = false) {
327
- const rect = this.moveable.getRect();
328
- const offset = this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : getAbsolutePosition(this.target, rect);
442
+ if (!this.target)
443
+ return;
444
+ const offset = this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
329
445
  const left = this.calcValueByFontsize(offset.left);
330
446
  const top = this.calcValueByFontsize(offset.top);
331
- const width = this.calcValueByFontsize(rect.width);
332
- const height = this.calcValueByFontsize(rect.height);
447
+ const width = this.calcValueByFontsize(this.target.clientWidth);
448
+ const height = this.calcValueByFontsize(this.target.clientHeight);
333
449
  this.emit("update", {
334
450
  el: this.target,
335
451
  style: isResize ? { left, top, width, height } : { left, top }
@@ -341,8 +457,8 @@
341
457
  }
342
458
  const ghostEl = el.cloneNode(true);
343
459
  const { top, left } = getAbsolutePosition(el, getOffset(el));
344
- ghostEl.id = `${GHOST_EL_ID_PREFIX}${ghostEl.id}`;
345
- ghostEl.style.zIndex = "5";
460
+ ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
461
+ ghostEl.style.zIndex = ZIndex.GHOST_EL;
346
462
  ghostEl.style.opacity = ".5";
347
463
  ghostEl.style.position = "absolute";
348
464
  ghostEl.style.left = `${left}px`;
@@ -354,49 +470,73 @@
354
470
  this.ghostEl?.remove();
355
471
  this.ghostEl = void 0;
356
472
  }
357
- generateDragEl(el) {
358
- if (this.dragEl) {
359
- this.destroyDragEl();
360
- }
361
- const { width, height } = el.getBoundingClientRect();
473
+ updateDragEl(el) {
362
474
  const offset = getOffset(el);
363
- const dragEl = globalThis.document.createElement("div");
364
- dragEl.style.cssText = `
475
+ const { transform } = getComputedStyle(el);
476
+ this.dragEl.style.cssText = `
365
477
  position: absolute;
478
+ transform: ${transform};
366
479
  left: ${offset.left}px;
367
480
  top: ${offset.top}px;
368
- width: ${width}px;
369
- height: ${height}px;
481
+ width: ${el.clientWidth}px;
482
+ height: ${el.clientHeight}px;
483
+ z-index: ${ZIndex.DRAG_EL};
370
484
  `;
371
- this.container.append(dragEl);
372
- return dragEl;
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
+ }
373
489
  }
374
490
  destroyDragEl() {
375
491
  this.dragEl?.remove();
376
- this.dragEl = void 0;
377
492
  }
378
- async getOptions(options = {}) {
493
+ getOptions(options = {}) {
379
494
  if (!this.target)
380
495
  return {};
381
496
  const isAbsolute = this.mode === Mode.ABSOLUTE;
497
+ const isFixed = this.mode === Mode.FIXED;
382
498
  let { moveableOptions = {} } = this.core.config;
383
499
  if (typeof moveableOptions === "function") {
384
500
  moveableOptions = moveableOptions(this.core);
385
501
  }
502
+ const elementGuidelines = moveableOptions.elementGuidelines || this.target.parentElement?.children || [];
503
+ this.setElementGuidelines(elementGuidelines);
504
+ if (moveableOptions.elementGuidelines) {
505
+ delete moveableOptions.elementGuidelines;
506
+ }
386
507
  return {
387
- scrollable: true,
388
- origin: true,
508
+ origin: false,
509
+ rootContainer: this.core.container,
389
510
  zoom: 1,
390
- dragArea: true,
511
+ dragArea: false,
391
512
  draggable: true,
392
513
  resizable: true,
393
- snappable: isAbsolute,
394
- snapGap: isAbsolute,
395
- snapDirections: { center: isAbsolute, middle: isAbsolute },
396
- elementSnapDirections: { center: isAbsolute, middle: isAbsolute },
397
- elementGuidelines: isAbsolute ? await this.getSnapElements(this.target) : [],
514
+ scalable: false,
515
+ rotatable: false,
516
+ snappable: isAbsolute || isFixed,
517
+ snapGap: isAbsolute || isFixed,
518
+ snapThreshold: 5,
519
+ snapDigit: 0,
520
+ throttleDrag: 0,
521
+ isDisplaySnapDigit: isAbsolute,
522
+ snapDirections: {
523
+ top: isAbsolute,
524
+ right: isAbsolute,
525
+ bottom: isAbsolute,
526
+ left: isAbsolute,
527
+ center: isAbsolute,
528
+ middle: isAbsolute
529
+ },
530
+ elementSnapDirections: {
531
+ top: isAbsolute,
532
+ right: isAbsolute,
533
+ bottom: isAbsolute,
534
+ left: isAbsolute
535
+ },
536
+ isDisplayInnerSnapDigit: true,
398
537
  horizontalGuidelines: this.horizontalGuidelines,
399
538
  verticalGuidelines: this.verticalGuidelines,
539
+ elementGuidelines: this.elementGuidelines,
400
540
  bounds: {
401
541
  top: 0,
402
542
  left: 0,
@@ -465,18 +605,150 @@
465
605
  };
466
606
  };
467
607
 
608
+ class TargetCalibrate extends EventEmitter.EventEmitter {
609
+ constructor(config) {
610
+ super();
611
+ this.parent = config.parent;
612
+ this.mask = config.mask;
613
+ this.dr = config.dr;
614
+ this.core = config.core;
615
+ this.operationEl = globalThis.document.createElement("div");
616
+ this.parent.append(this.operationEl);
617
+ }
618
+ update(el, prefix) {
619
+ const { left, top } = this.getOffset(el);
620
+ const { transform } = getComputedStyle(el);
621
+ this.operationEl.style.cssText = `
622
+ position: absolute;
623
+ transform: ${transform};
624
+ left: ${left}px;
625
+ top: ${top}px;
626
+ width: ${el.clientWidth}px;
627
+ height: ${el.clientHeight}px;
628
+ `;
629
+ this.operationEl.id = `${prefix}${el.id}`;
630
+ if (typeof this.core.config.updateDragEl === "function") {
631
+ this.core.config.updateDragEl(this.operationEl, el);
632
+ }
633
+ return this.operationEl;
634
+ }
635
+ destroy() {
636
+ this.operationEl?.remove();
637
+ }
638
+ getOffset(el) {
639
+ const { offsetParent } = el;
640
+ const left = el.offsetLeft;
641
+ const top = el.offsetTop;
642
+ if (offsetParent) {
643
+ const parentOffset = this.getOffset(offsetParent);
644
+ return {
645
+ left: left + parentOffset.left,
646
+ top: top + parentOffset.top
647
+ };
648
+ }
649
+ if (this.dr.mode === Mode.FIXED) {
650
+ if (getMode(el) === Mode.FIXED) {
651
+ return {
652
+ left,
653
+ top
654
+ };
655
+ }
656
+ return {
657
+ left: left - this.mask.scrollLeft,
658
+ top: top - this.mask.scrollTop
659
+ };
660
+ }
661
+ if (getMode(el) === Mode.FIXED) {
662
+ return {
663
+ left: left + this.mask.scrollLeft,
664
+ top: top + this.mask.scrollTop
665
+ };
666
+ }
667
+ return {
668
+ left,
669
+ top
670
+ };
671
+ }
672
+ }
673
+
674
+ class StageHighlight extends EventEmitter.EventEmitter {
675
+ constructor(config) {
676
+ super();
677
+ this.core = config.core;
678
+ this.container = config.container;
679
+ this.calibrationTarget = new TargetCalibrate({
680
+ parent: this.core.mask.content,
681
+ mask: this.core.mask,
682
+ dr: this.core.dr,
683
+ core: this.core
684
+ });
685
+ }
686
+ highlight(el) {
687
+ if (!el || el === this.target)
688
+ return;
689
+ this.target = el;
690
+ this.moveable?.destroy();
691
+ this.moveable = new Moveable__default["default"](this.container, {
692
+ target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
693
+ origin: false,
694
+ rootContainer: this.core.container,
695
+ zoom: 1
696
+ });
697
+ }
698
+ clearHighlight() {
699
+ if (!this.moveable)
700
+ return;
701
+ this.target = void 0;
702
+ this.moveable.target = null;
703
+ this.moveable.updateTarget();
704
+ }
705
+ destroy() {
706
+ this.moveable?.destroy();
707
+ this.calibrationTarget.destroy();
708
+ }
709
+ }
710
+
468
711
  class Rule extends EventEmitter__default["default"] {
469
- hGuides;
470
- vGuides;
471
- horizontalGuidelines = [];
472
- verticalGuidelines = [];
473
- container;
474
- containerResizeObserver;
475
712
  constructor(container) {
476
713
  super();
714
+ this.horizontalGuidelines = getGuideLineFromCache(GuidesType.HORIZONTAL);
715
+ this.verticalGuidelines = getGuideLineFromCache(GuidesType.VERTICAL);
716
+ this.getGuidesStyle = (type) => ({
717
+ position: "fixed",
718
+ zIndex: 1,
719
+ left: type === GuidesType.HORIZONTAL ? 0 : "-30px",
720
+ top: type === GuidesType.HORIZONTAL ? "-30px" : 0,
721
+ width: type === GuidesType.HORIZONTAL ? "100%" : "30px",
722
+ height: type === GuidesType.HORIZONTAL ? "30px" : "100%"
723
+ });
724
+ this.createGuides = (type, defaultGuides = []) => new Guides__default["default"](this.container, {
725
+ type,
726
+ defaultGuides,
727
+ displayDragPos: true,
728
+ backgroundColor: "#fff",
729
+ lineColor: "#000",
730
+ textColor: "#000",
731
+ style: this.getGuidesStyle(type)
732
+ });
733
+ this.hGuidesChangeGuidesHandler = (e) => {
734
+ this.horizontalGuidelines = e.guides;
735
+ this.emit("changeGuides", {
736
+ type: GuidesType.HORIZONTAL,
737
+ guides: this.horizontalGuidelines
738
+ });
739
+ globalThis.localStorage.setItem(H_GUIDE_LINE_STORAGE_KEY, JSON.stringify(e.guides));
740
+ };
741
+ this.vGuidesChangeGuidesHandler = (e) => {
742
+ this.verticalGuidelines = e.guides;
743
+ this.emit("changeGuides", {
744
+ type: GuidesType.VERTICAL,
745
+ guides: this.verticalGuidelines
746
+ });
747
+ globalThis.localStorage.setItem(V_GUIDE_LINE_STORAGE_KEY, JSON.stringify(e.guides));
748
+ };
477
749
  this.container = container;
478
- this.hGuides = this.createGuides(GuidesType.HORIZONTAL);
479
- this.vGuides = this.createGuides(GuidesType.VERTICAL);
750
+ this.hGuides = this.createGuides(GuidesType.HORIZONTAL, this.horizontalGuidelines);
751
+ this.vGuides = this.createGuides(GuidesType.VERTICAL, this.verticalGuidelines);
480
752
  this.hGuides.on("changeGuides", this.hGuidesChangeGuidesHandler);
481
753
  this.vGuides.on("changeGuides", this.vGuidesChangeGuidesHandler);
482
754
  this.containerResizeObserver = new ResizeObserver(() => {
@@ -510,6 +782,8 @@
510
782
  type: GuidesType.HORIZONTAL,
511
783
  guides: []
512
784
  });
785
+ globalThis.localStorage.setItem(V_GUIDE_LINE_STORAGE_KEY, "[]");
786
+ globalThis.localStorage.setItem(H_GUIDE_LINE_STORAGE_KEY, "[]");
513
787
  }
514
788
  showRule(show = true) {
515
789
  if (show) {
@@ -542,40 +816,10 @@
542
816
  this.containerResizeObserver.disconnect();
543
817
  this.removeAllListeners();
544
818
  }
545
- getGuidesStyle = (type) => ({
546
- position: "fixed",
547
- zIndex: 1,
548
- left: type === GuidesType.HORIZONTAL ? 0 : "-30px",
549
- top: type === GuidesType.HORIZONTAL ? "-30px" : 0,
550
- width: type === GuidesType.HORIZONTAL ? "100%" : "30px",
551
- height: type === GuidesType.HORIZONTAL ? "30px" : "100%"
552
- });
553
- createGuides = (type, defaultGuides = []) => new Guides__default["default"](this.container, {
554
- type,
555
- defaultGuides,
556
- displayDragPos: true,
557
- backgroundColor: "#fff",
558
- lineColor: "#000",
559
- textColor: "#000",
560
- style: this.getGuidesStyle(type)
561
- });
562
- hGuidesChangeGuidesHandler = (e) => {
563
- this.horizontalGuidelines = e.guides;
564
- this.emit("changeGuides", {
565
- type: GuidesType.HORIZONTAL,
566
- guides: this.horizontalGuidelines
567
- });
568
- };
569
- vGuidesChangeGuidesHandler = (e) => {
570
- this.verticalGuidelines = e.guides;
571
- this.emit("changeGuides", {
572
- type: GuidesType.VERTICAL,
573
- guides: this.verticalGuidelines
574
- });
575
- };
576
819
  }
577
820
 
578
821
  const wrapperClassName = "editor-mask-wrapper";
822
+ const throttleTime = 100;
579
823
  const hideScrollbar = () => {
580
824
  const style = globalThis.document.createElement("style");
581
825
  style.innerHTML = `
@@ -609,28 +853,73 @@
609
853
  return el;
610
854
  };
611
855
  class StageMask extends Rule {
612
- content = createContent();
613
- wrapper;
614
- core;
615
- page = null;
616
- pageScrollParent = null;
617
- scrollTop = 0;
618
- scrollLeft = 0;
619
- width = 0;
620
- height = 0;
621
- wrapperHeight = 0;
622
- wrapperWidth = 0;
623
- mode = Mode.ABSOLUTE;
624
- pageResizeObserver = null;
625
- wrapperResizeObserver = null;
626
856
  constructor(config) {
627
857
  const wrapper = createWrapper();
628
858
  super(wrapper);
859
+ this.content = createContent();
860
+ this.page = null;
861
+ this.pageScrollParent = null;
862
+ this.scrollTop = 0;
863
+ this.scrollLeft = 0;
864
+ this.width = 0;
865
+ this.height = 0;
866
+ this.wrapperHeight = 0;
867
+ this.wrapperWidth = 0;
868
+ this.maxScrollTop = 0;
869
+ this.maxScrollLeft = 0;
870
+ this.intersectionObserver = null;
871
+ this.mode = Mode.ABSOLUTE;
872
+ this.pageResizeObserver = null;
873
+ this.wrapperResizeObserver = null;
874
+ this.highlightHandler = lodashEs.throttle((event) => {
875
+ this.emit("highlight", event);
876
+ }, throttleTime);
877
+ this.mouseDownHandler = (event) => {
878
+ this.emit("clearHighlight");
879
+ event.stopImmediatePropagation();
880
+ event.stopPropagation();
881
+ if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
882
+ return;
883
+ if (event.target.className.indexOf("moveable-control") !== -1) {
884
+ return;
885
+ }
886
+ this.content.removeEventListener("mousemove", this.highlightHandler);
887
+ this.emit("beforeSelect", event);
888
+ globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
889
+ };
890
+ this.mouseUpHandler = () => {
891
+ globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
892
+ this.content.addEventListener("mousemove", this.highlightHandler);
893
+ this.emit("select");
894
+ };
895
+ this.mouseWheelHandler = (event) => {
896
+ this.emit("clearHighlight");
897
+ if (!this.page)
898
+ throw new Error("page \u672A\u521D\u59CB\u5316");
899
+ const { deltaY, deltaX } = event;
900
+ if (this.page.clientHeight < this.wrapperHeight && deltaY)
901
+ return;
902
+ if (this.page.clientWidth < this.wrapperWidth && deltaX)
903
+ return;
904
+ if (this.maxScrollTop > 0) {
905
+ this.scrollTop = this.scrollTop + deltaY;
906
+ }
907
+ if (this.maxScrollLeft > 0) {
908
+ this.scrollLeft = this.scrollLeft + deltaX;
909
+ }
910
+ this.scroll();
911
+ this.emit("scroll", event);
912
+ };
913
+ this.mouseLeaveHandler = () => {
914
+ setTimeout(() => this.emit("clearHighlight"), throttleTime);
915
+ };
629
916
  this.wrapper = wrapper;
630
917
  this.core = config.core;
631
918
  this.content.addEventListener("mousedown", this.mouseDownHandler);
632
919
  this.wrapper.appendChild(this.content);
633
920
  this.content.addEventListener("wheel", this.mouseWheelHandler);
921
+ this.content.addEventListener("mousemove", this.highlightHandler);
922
+ this.content.addEventListener("mouseleave", this.mouseLeaveHandler);
634
923
  }
635
924
  setMode(mode) {
636
925
  this.mode = mode;
@@ -649,12 +938,33 @@
649
938
  this.page = page;
650
939
  this.pageScrollParent = getScrollParent(page) || this.core.renderer.contentWindow?.document.documentElement || null;
651
940
  this.pageResizeObserver?.disconnect();
941
+ this.wrapperResizeObserver?.disconnect();
942
+ this.intersectionObserver?.disconnect();
943
+ if (typeof IntersectionObserver !== "undefined") {
944
+ this.intersectionObserver = new IntersectionObserver((entries) => {
945
+ entries.forEach((entry) => {
946
+ const { target, intersectionRatio } = entry;
947
+ if (intersectionRatio <= 0) {
948
+ this.scrollIntoView(target);
949
+ }
950
+ this.intersectionObserver?.unobserve(target);
951
+ });
952
+ }, {
953
+ root: this.pageScrollParent,
954
+ rootMargin: "0px",
955
+ threshold: 1
956
+ });
957
+ }
652
958
  if (typeof ResizeObserver !== "undefined") {
653
959
  this.pageResizeObserver = new ResizeObserver((entries) => {
654
960
  const [entry] = entries;
655
961
  const { clientHeight, clientWidth } = entry.target;
656
962
  this.setHeight(clientHeight);
657
963
  this.setWidth(clientWidth);
964
+ this.scroll();
965
+ if (this.core.dr.moveable) {
966
+ this.core.dr.updateMoveable();
967
+ }
658
968
  });
659
969
  this.pageResizeObserver.observe(page);
660
970
  this.wrapperResizeObserver = new ResizeObserver((entries) => {
@@ -662,6 +972,8 @@
662
972
  const { clientHeight, clientWidth } = entry.target;
663
973
  this.wrapperHeight = clientHeight;
664
974
  this.wrapperWidth = clientWidth;
975
+ this.setMaxScrollLeft();
976
+ this.setMaxScrollTop();
665
977
  });
666
978
  this.wrapperResizeObserver.observe(this.wrapper);
667
979
  }
@@ -674,16 +986,32 @@
674
986
  setLayout(el) {
675
987
  this.setMode(isFixedParent(el) ? Mode.FIXED : Mode.ABSOLUTE);
676
988
  }
989
+ scrollIntoView(el) {
990
+ el.scrollIntoView();
991
+ if (!this.pageScrollParent)
992
+ return;
993
+ this.scrollLeft = this.pageScrollParent.scrollLeft;
994
+ this.scrollTop = this.pageScrollParent.scrollTop;
995
+ this.scroll();
996
+ }
677
997
  destroy() {
678
998
  this.content?.remove();
679
999
  this.page = null;
680
1000
  this.pageScrollParent = null;
681
1001
  this.pageResizeObserver?.disconnect();
682
1002
  this.wrapperResizeObserver?.disconnect();
1003
+ this.content.removeEventListener("mouseleave", this.mouseLeaveHandler);
683
1004
  super.destroy();
684
1005
  }
685
1006
  scroll() {
1007
+ this.fixScrollValue();
686
1008
  let { scrollLeft, scrollTop } = this;
1009
+ if (this.pageScrollParent) {
1010
+ this.pageScrollParent.scrollTo({
1011
+ top: scrollTop,
1012
+ left: scrollLeft
1013
+ });
1014
+ }
687
1015
  if (this.mode === Mode.FIXED) {
688
1016
  scrollLeft = 0;
689
1017
  scrollTop = 0;
@@ -696,71 +1024,65 @@
696
1024
  }
697
1025
  setHeight(height) {
698
1026
  this.height = height;
1027
+ this.setMaxScrollTop();
699
1028
  this.content.style.height = `${height}px`;
700
1029
  }
701
1030
  setWidth(width) {
702
1031
  this.width = width;
1032
+ this.setMaxScrollLeft();
703
1033
  this.content.style.width = `${width}px`;
704
1034
  }
705
- mouseDownHandler = async (event) => {
706
- event.stopImmediatePropagation();
707
- event.stopPropagation();
708
- if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
709
- return;
710
- if (event.target.className.indexOf("moveable-control") !== -1) {
711
- return;
712
- }
713
- this.emit("beforeSelect", event);
714
- globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
715
- };
716
- mouseUpHandler = () => {
717
- globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
718
- this.emit("select");
719
- };
720
- mouseWheelHandler = (event) => {
721
- if (!this.page)
722
- throw new Error("page \u672A\u521D\u59CB\u5316");
723
- const { deltaY, deltaX } = event;
724
- const { height, wrapperHeight, width, wrapperWidth } = this;
725
- const maxScrollTop = height - wrapperHeight;
726
- const maxScrollLeft = width - wrapperWidth;
727
- if (maxScrollTop > 0) {
728
- if (deltaY > 0) {
729
- this.scrollTop = this.scrollTop + Math.min(maxScrollTop - this.scrollTop, deltaY);
730
- } else {
731
- this.scrollTop = Math.max(this.scrollTop + deltaY, 0);
732
- }
733
- }
734
- if (width > wrapperWidth) {
735
- if (deltaX > 0) {
736
- this.scrollLeft = this.scrollLeft + Math.min(maxScrollLeft - this.scrollLeft, deltaX);
737
- } else {
738
- this.scrollLeft = Math.max(this.scrollLeft + deltaX, 0);
739
- }
740
- }
741
- if (this.mode !== Mode.FIXED) {
742
- this.scrollTo(this.scrollLeft, this.scrollTop);
743
- }
744
- if (this.pageScrollParent) {
745
- this.pageScrollParent.scrollTo({
746
- top: this.scrollTop,
747
- left: this.scrollLeft
748
- });
749
- }
750
- this.scroll();
751
- this.emit("scroll", event);
752
- };
1035
+ setMaxScrollLeft() {
1036
+ this.maxScrollLeft = Math.max(this.width - this.wrapperWidth, 0);
1037
+ }
1038
+ setMaxScrollTop() {
1039
+ this.maxScrollTop = Math.max(this.height - this.wrapperHeight, 0);
1040
+ }
1041
+ fixScrollValue() {
1042
+ if (this.scrollTop < 0)
1043
+ this.scrollTop = 0;
1044
+ if (this.scrollLeft < 0)
1045
+ this.scrollLeft = 0;
1046
+ if (this.maxScrollTop < this.scrollTop)
1047
+ this.scrollTop = this.maxScrollTop;
1048
+ if (this.maxScrollLeft < this.scrollLeft)
1049
+ this.scrollLeft = this.maxScrollLeft;
1050
+ }
753
1051
  }
754
1052
 
755
1053
  class StageRender extends EventEmitter.EventEmitter {
756
- contentWindow = null;
757
- runtime = null;
758
- iframe;
759
- runtimeUrl;
760
- core;
761
- render;
762
1054
  constructor({ core }) {
763
1055
  super();
1056
+ this.contentWindow = null;
1057
+ this.runtime = null;
1058
+ this.getMagicApi = () => ({
1059
+ onPageElUpdate: (el) => this.emit("page-el-update", el),
1060
+ onRuntimeReady: (runtime) => {
1061
+ this.runtime = runtime;
1062
+ globalThis.runtime = runtime;
1063
+ this.emit("runtime-ready", runtime);
1064
+ }
1065
+ });
1066
+ this.getRuntime = () => {
1067
+ if (this.runtime)
1068
+ return Promise.resolve(this.runtime);
1069
+ return new Promise((resolve) => {
1070
+ const listener = (runtime) => {
1071
+ this.off("runtime-ready", listener);
1072
+ resolve(runtime);
1073
+ };
1074
+ this.on("runtime-ready", listener);
1075
+ });
1076
+ };
1077
+ this.loadHandler = async () => {
1078
+ this.emit("onload");
1079
+ if (this.render) {
1080
+ const el = await this.render(this.core);
1081
+ if (el) {
1082
+ this.iframe?.contentDocument?.body?.appendChild(el);
1083
+ }
1084
+ }
1085
+ };
764
1086
  this.core = core;
765
1087
  this.runtimeUrl = core.config.runtimeUrl || "";
766
1088
  this.render = core.config.render;
@@ -773,14 +1095,6 @@
773
1095
  `;
774
1096
  this.iframe.addEventListener("load", this.loadHandler);
775
1097
  }
776
- getMagicApi = () => ({
777
- onPageElUpdate: (el) => this.emit("page-el-update", el),
778
- onRuntimeReady: (runtime) => {
779
- this.runtime = runtime;
780
- globalThis.runtime = runtime;
781
- this.emit("runtime-ready", runtime);
782
- }
783
- });
784
1098
  async mount(el) {
785
1099
  if (this.iframe) {
786
1100
  if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
@@ -797,17 +1111,6 @@
797
1111
  throw Error("mount \u5931\u8D25");
798
1112
  }
799
1113
  }
800
- getRuntime = () => {
801
- if (this.runtime)
802
- return Promise.resolve(this.runtime);
803
- return new Promise((resolve) => {
804
- const listener = (runtime) => {
805
- this.off("runtime-ready", listener);
806
- resolve(runtime);
807
- };
808
- this.on("runtime-ready", listener);
809
- });
810
- };
811
1114
  destroy() {
812
1115
  this.iframe?.removeEventListener("load", this.loadHandler);
813
1116
  this.contentWindow = null;
@@ -815,35 +1118,25 @@
815
1118
  this.iframe = void 0;
816
1119
  this.removeAllListeners();
817
1120
  }
818
- loadHandler = async () => {
819
- this.emit("onload");
820
- if (this.render) {
821
- const el = await this.render(this.core);
822
- if (el) {
823
- this.iframe?.contentDocument?.body?.appendChild(el);
824
- }
825
- }
826
- };
827
1121
  }
828
1122
 
829
1123
  class StageCore extends EventEmitter.EventEmitter {
830
- selectedDom;
831
- renderer;
832
- mask;
833
- dr;
834
- config;
835
- zoom = DEFAULT_ZOOM;
836
- canSelect;
837
1124
  constructor(config) {
838
1125
  super();
1126
+ this.zoom = DEFAULT_ZOOM;
839
1127
  this.config = config;
840
1128
  this.setZoom(config.zoom);
841
1129
  this.canSelect = config.canSelect || ((el) => !!el.id);
842
1130
  this.renderer = new StageRender({ core: this });
843
1131
  this.mask = new StageMask({ core: this });
844
1132
  this.dr = new StageDragResize({ core: this, container: this.mask.content });
845
- this.renderer.on("runtime-ready", (runtime) => this.emit("runtime-ready", runtime));
846
- this.renderer.on("page-el-update", (el) => this.mask?.observe(el));
1133
+ this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
1134
+ this.renderer.on("runtime-ready", (runtime) => {
1135
+ this.emit("runtime-ready", runtime);
1136
+ });
1137
+ this.renderer.on("page-el-update", (el) => {
1138
+ this.mask?.observe(el);
1139
+ });
847
1140
  this.mask.on("beforeSelect", (event) => {
848
1141
  this.setElementFromPoint(event);
849
1142
  }).on("select", () => {
@@ -851,6 +1144,16 @@
851
1144
  }).on("changeGuides", (data) => {
852
1145
  this.dr.setGuidelines(data.type, data.guides);
853
1146
  this.emit("changeGuides", data);
1147
+ }).on("highlight", async (event) => {
1148
+ await this.setElementFromPoint(event);
1149
+ if (this.highlightedDom === this.selectedDom) {
1150
+ this.highlightLayer.clearHighlight();
1151
+ return;
1152
+ }
1153
+ this.highlightLayer.highlight(this.highlightedDom);
1154
+ this.emit("highlight", this.highlightedDom);
1155
+ }).on("clearHighlight", async () => {
1156
+ this.highlightLayer.clearHighlight();
854
1157
  });
855
1158
  this.dr.on("update", (data) => {
856
1159
  setTimeout(() => this.emit("update", data));
@@ -874,60 +1177,81 @@
874
1177
  let stopped = false;
875
1178
  const stop = () => stopped = true;
876
1179
  for (const el of els) {
877
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.canSelect(el, stop)) {
1180
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.canSelect(el, event, stop)) {
878
1181
  if (stopped)
879
1182
  break;
1183
+ if (event.type === "mousemove") {
1184
+ this.highlight(el);
1185
+ break;
1186
+ }
880
1187
  this.select(el, event);
881
1188
  break;
882
1189
  }
883
1190
  }
884
1191
  }
885
1192
  async select(idOrEl, event) {
886
- let el;
887
- if (typeof idOrEl === "string" || typeof idOrEl === "number") {
888
- const runtime2 = await this.renderer?.getRuntime();
889
- el = await runtime2?.select?.(`${idOrEl}`);
890
- if (!el)
891
- throw new Error(`\u4E0D\u5B58\u5728ID\u4E3A${idOrEl}\u7684\u5143\u7D20`);
892
- } else {
893
- el = idOrEl;
894
- }
1193
+ const el = await this.getTargetElement(idOrEl);
895
1194
  if (el === this.selectedDom)
896
1195
  return;
897
- const runtime = await this.renderer?.getRuntime();
1196
+ const runtime = await this.renderer.getRuntime();
1197
+ await runtime?.select?.(el.id);
898
1198
  if (runtime?.beforeSelect) {
899
1199
  await runtime.beforeSelect(el);
900
1200
  }
901
1201
  this.mask.setLayout(el);
902
- this.dr?.select(el, event);
1202
+ this.dr.select(el, event);
1203
+ if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
1204
+ this.mask.intersectionObserver?.observe(el);
1205
+ }
903
1206
  this.selectedDom = el;
1207
+ if (this.renderer.contentWindow) {
1208
+ removeSelectedClassName(this.renderer.contentWindow.document);
1209
+ if (this.selectedDom) {
1210
+ addSelectedClassName(this.selectedDom, this.renderer.contentWindow.document);
1211
+ }
1212
+ }
904
1213
  }
905
1214
  update(data) {
906
1215
  const { config } = data;
907
- this.renderer?.getRuntime().then((runtime) => {
1216
+ return this.renderer?.getRuntime().then((runtime) => {
908
1217
  runtime?.update?.(data);
909
1218
  setTimeout(() => {
910
1219
  const el = this.renderer.contentWindow?.document.getElementById(`${config.id}`);
911
- if (el) {
1220
+ if (el && el.id === this.selectedDom?.id) {
1221
+ this.selectedDom = el;
912
1222
  this.mask.setLayout(el);
913
- this.dr?.select(el);
1223
+ this.dr.updateMoveable(el);
914
1224
  }
915
1225
  }, 0);
916
1226
  });
917
1227
  }
1228
+ async highlight(idOrEl) {
1229
+ let el;
1230
+ try {
1231
+ el = await this.getTargetElement(idOrEl);
1232
+ } catch (error) {
1233
+ this.highlightLayer.clearHighlight();
1234
+ return;
1235
+ }
1236
+ if (el === this.highlightedDom)
1237
+ return;
1238
+ this.highlightLayer.highlight(el);
1239
+ this.highlightedDom = el;
1240
+ }
918
1241
  sortNode(data) {
919
- this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
1242
+ return this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
920
1243
  }
921
1244
  add(data) {
922
- this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
1245
+ return this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
923
1246
  }
924
1247
  remove(data) {
925
- this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
1248
+ return this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
926
1249
  }
927
1250
  setZoom(zoom = DEFAULT_ZOOM) {
928
1251
  this.zoom = zoom;
929
1252
  }
930
1253
  mount(el) {
1254
+ this.container = el;
931
1255
  const { mask, renderer } = this;
932
1256
  renderer.mount(el);
933
1257
  mask.mount(el);
@@ -938,11 +1262,22 @@
938
1262
  this.dr.clearGuides();
939
1263
  }
940
1264
  destroy() {
941
- const { mask, renderer, dr } = this;
1265
+ const { mask, renderer, dr, highlightLayer } = this;
942
1266
  renderer.destroy();
943
1267
  mask.destroy();
944
1268
  dr.destroy();
1269
+ highlightLayer.destroy();
945
1270
  this.removeAllListeners();
1271
+ this.container = void 0;
1272
+ }
1273
+ async getTargetElement(idOrEl) {
1274
+ if (typeof idOrEl === "string" || typeof idOrEl === "number") {
1275
+ const el = this.renderer.contentWindow?.document.getElementById(`${idOrEl}`);
1276
+ if (!el)
1277
+ throw new Error(`\u4E0D\u5B58\u5728ID\u4E3A${idOrEl}\u7684\u5143\u7D20`);
1278
+ return el;
1279
+ }
1280
+ return idOrEl;
946
1281
  }
947
1282
  }
948
1283
 
@@ -951,8 +1286,7 @@
951
1286
  exports.StageRender = StageRender;
952
1287
  exports["default"] = StageCore;
953
1288
 
954
- Object.defineProperty(exports, '__esModule', { value: true });
955
- exports[Symbol.toStringTag] = 'Module';
1289
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
956
1290
 
957
1291
  }));
958
1292
  //# sourceMappingURL=tmagic-stage.umd.js.map