@tmagic/stage 1.0.0-beta.8 → 1.0.0-beta.9

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,5 +1,7 @@
1
1
  import EventEmitter$1, { EventEmitter } from 'events';
2
2
  import Moveable from 'moveable';
3
+ import MoveableHelper from 'moveable-helper';
4
+ import { throttle } from 'lodash-es';
3
5
  import Guides from '@scena/guides';
4
6
 
5
7
  const GHOST_EL_ID_PREFIX = "ghost_el_";
@@ -11,6 +13,7 @@ var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
11
13
  })(GuidesType || {});
12
14
  var ZIndex = /* @__PURE__ */ ((ZIndex2) => {
13
15
  ZIndex2["MASK"] = "99999";
16
+ ZIndex2["SELECTED_EL"] = "666";
14
17
  return ZIndex2;
15
18
  })(ZIndex || {});
16
19
  var MouseButton = /* @__PURE__ */ ((MouseButton2) => {
@@ -25,6 +28,7 @@ var Mode = /* @__PURE__ */ ((Mode2) => {
25
28
  Mode2["SORTABLE"] = "sortable";
26
29
  return Mode2;
27
30
  })(Mode || {});
31
+ const SELECTED_CLASS = "tmagic-stage-selected-area";
28
32
 
29
33
  const getOffset = (el) => {
30
34
  const { transform } = getComputedStyle(el);
@@ -145,6 +149,17 @@ const createDiv = ({ className, cssText }) => {
145
149
  el.style.cssText = cssText;
146
150
  return el;
147
151
  };
152
+ const removeSelectedClassName = (doc) => {
153
+ const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
154
+ if (oldEl) {
155
+ oldEl.classList.remove(SELECTED_CLASS);
156
+ oldEl.parentNode?.classList.remove(`${SELECTED_CLASS}-parent`);
157
+ }
158
+ };
159
+ const addSelectedClassName = (el) => {
160
+ el.classList.add(SELECTED_CLASS);
161
+ el.parentNode?.classList.add(`${SELECTED_CLASS}-parent`);
162
+ };
148
163
 
149
164
  class StageDragResize extends EventEmitter {
150
165
  core;
@@ -158,6 +173,7 @@ class StageDragResize extends EventEmitter {
158
173
  dragStatus = "end" /* END */;
159
174
  ghostEl;
160
175
  mode = Mode.ABSOLUTE;
176
+ moveableHelper;
161
177
  constructor(config) {
162
178
  super();
163
179
  this.core = config.core;
@@ -175,6 +191,11 @@ class StageDragResize extends EventEmitter {
175
191
  this.moveableOptions = await this.getOptions({
176
192
  target: this.dragEl || this.target
177
193
  });
194
+ this.moveableHelper = MoveableHelper.create({
195
+ useBeforeRender: true,
196
+ useRender: false,
197
+ createAuto: true
198
+ });
178
199
  this.initMoveable();
179
200
  if (event) {
180
201
  this.moveable?.dragStart(event);
@@ -253,27 +274,32 @@ class StageDragResize extends EventEmitter {
253
274
  bindDragEvent() {
254
275
  if (!this.moveable)
255
276
  throw new Error("moveable \u4E3A\u521D\u59CB\u5316");
256
- this.moveable.on("dragStart", () => {
277
+ let offset = {
278
+ left: 0,
279
+ top: 0
280
+ };
281
+ this.moveable.on("dragStart", (e) => {
257
282
  if (!this.target)
258
283
  throw new Error("\u672A\u9009\u4E2D\u7EC4\u4EF6");
259
284
  this.dragStatus = "start" /* START */;
285
+ this.moveableHelper?.onDragStart(e);
286
+ offset = getAbsolutePosition(this.target, { left: 0, top: 0 });
260
287
  if (this.mode === Mode.SORTABLE) {
261
288
  this.ghostEl = this.generateGhostEl(this.target);
262
289
  }
263
- }).on("drag", ({ left, top }) => {
290
+ }).on("drag", (e) => {
264
291
  if (!this.target || !this.dragEl)
265
292
  return;
266
293
  this.dragStatus = "ing" /* ING */;
267
- const offset = getAbsolutePosition(this.target, { left, top });
294
+ const { left, top } = e;
268
295
  if (this.ghostEl) {
269
296
  this.dragEl.style.top = `${top}px`;
270
- this.ghostEl.style.top = `${offset.top}px`;
297
+ this.ghostEl.style.top = `${top + offset.top}px`;
271
298
  return;
272
299
  }
273
- this.dragEl.style.left = `${left}px`;
274
- this.dragEl.style.top = `${top}px`;
275
- this.target.style.left = `${offset.left}px`;
276
- this.target.style.top = `${offset.top}px`;
300
+ this.moveableHelper?.onDrag(e);
301
+ this.target.style.left = `${left + offset.left}px`;
302
+ this.target.style.top = `${top + offset.top}px`;
277
303
  }).on("dragEnd", () => {
278
304
  if (this.dragStatus === "ing" /* ING */) {
279
305
  switch (this.mode) {
@@ -376,17 +402,26 @@ class StageDragResize extends EventEmitter {
376
402
  moveableOptions = moveableOptions(this.core);
377
403
  }
378
404
  return {
379
- scrollable: true,
380
405
  origin: true,
406
+ rootContainer: this.core.container,
381
407
  zoom: 1,
382
- dragArea: true,
408
+ dragArea: false,
383
409
  draggable: true,
384
410
  resizable: true,
385
411
  snappable: isAbsolute,
386
412
  snapGap: isAbsolute,
387
- snapDirections: { center: isAbsolute, middle: isAbsolute },
388
- elementSnapDirections: { center: isAbsolute, middle: isAbsolute },
389
- elementGuidelines: isAbsolute ? await this.getSnapElements(this.target) : [],
413
+ snapThreshold: 5,
414
+ snapDigit: 0,
415
+ throttleDrag: 0,
416
+ isDisplaySnapDigit: isAbsolute,
417
+ snapDirections: {
418
+ top: isAbsolute,
419
+ right: isAbsolute,
420
+ bottom: isAbsolute,
421
+ left: isAbsolute,
422
+ center: isAbsolute,
423
+ middle: isAbsolute
424
+ },
390
425
  horizontalGuidelines: this.horizontalGuidelines,
391
426
  verticalGuidelines: this.verticalGuidelines,
392
427
  bounds: {
@@ -457,6 +492,36 @@ const up = (deltaTop, target) => {
457
492
  };
458
493
  };
459
494
 
495
+ class StageHighlight extends EventEmitter {
496
+ core;
497
+ container;
498
+ target;
499
+ moveable;
500
+ constructor(config) {
501
+ super();
502
+ this.core = config.core;
503
+ this.container = config.container;
504
+ }
505
+ highlight(el) {
506
+ if (!el || el === this.target)
507
+ return;
508
+ this.target = el;
509
+ this.moveable?.destroy();
510
+ this.moveable = new Moveable(this.container, {
511
+ target: this.target
512
+ });
513
+ }
514
+ clearHighlight() {
515
+ if (!this.moveable)
516
+ return;
517
+ this.moveable.target = null;
518
+ this.moveable.updateTarget();
519
+ }
520
+ destroy() {
521
+ this.moveable?.destroy();
522
+ }
523
+ }
524
+
460
525
  class Rule extends EventEmitter$1 {
461
526
  hGuides;
462
527
  vGuides;
@@ -568,6 +633,7 @@ class Rule extends EventEmitter$1 {
568
633
  }
569
634
 
570
635
  const wrapperClassName = "editor-mask-wrapper";
636
+ const throttleTime = 100;
571
637
  const hideScrollbar = () => {
572
638
  const style = globalThis.document.createElement("style");
573
639
  style.innerHTML = `
@@ -615,6 +681,9 @@ class StageMask extends Rule {
615
681
  mode = Mode.ABSOLUTE;
616
682
  pageResizeObserver = null;
617
683
  wrapperResizeObserver = null;
684
+ highlightHandler = throttle((event) => {
685
+ this.emit("highlight", event);
686
+ }, throttleTime);
618
687
  constructor(config) {
619
688
  const wrapper = createWrapper();
620
689
  super(wrapper);
@@ -623,6 +692,7 @@ class StageMask extends Rule {
623
692
  this.content.addEventListener("mousedown", this.mouseDownHandler);
624
693
  this.wrapper.appendChild(this.content);
625
694
  this.content.addEventListener("wheel", this.mouseWheelHandler);
695
+ this.content.addEventListener("mousemove", this.highlightHandler);
626
696
  }
627
697
  setMode(mode) {
628
698
  this.mode = mode;
@@ -694,7 +764,7 @@ class StageMask extends Rule {
694
764
  this.width = width;
695
765
  this.content.style.width = `${width}px`;
696
766
  }
697
- mouseDownHandler = async (event) => {
767
+ mouseDownHandler = (event) => {
698
768
  event.stopImmediatePropagation();
699
769
  event.stopPropagation();
700
770
  if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
@@ -704,9 +774,12 @@ class StageMask extends Rule {
704
774
  }
705
775
  this.emit("beforeSelect", event);
706
776
  globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
777
+ this.content.removeEventListener("mousemove", this.highlightHandler);
778
+ this.emit("clearHighlight");
707
779
  };
708
780
  mouseUpHandler = () => {
709
781
  globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
782
+ this.content.addEventListener("mousemove", this.highlightHandler);
710
783
  this.emit("select");
711
784
  };
712
785
  mouseWheelHandler = (event) => {
@@ -815,16 +888,29 @@ class StageRender extends EventEmitter {
815
888
  this.iframe?.contentDocument?.body?.appendChild(el);
816
889
  }
817
890
  }
891
+ if (this.contentWindow) {
892
+ const style = this.contentWindow.document.createElement("style");
893
+ style.id = "tmagic-stage-render";
894
+ style.innerHTML = `
895
+ .${SELECTED_CLASS}, .${SELECTED_CLASS}-parent {
896
+ z-index: ${ZIndex.SELECTED_EL};
897
+ }
898
+ `;
899
+ this.contentWindow.document.head.appendChild(style);
900
+ }
818
901
  };
819
902
  }
820
903
 
821
904
  class StageCore extends EventEmitter {
822
905
  selectedDom;
906
+ highlightedDom;
823
907
  renderer;
824
908
  mask;
825
909
  dr;
910
+ highlightLayer;
826
911
  config;
827
912
  zoom = DEFAULT_ZOOM;
913
+ container;
828
914
  canSelect;
829
915
  constructor(config) {
830
916
  super();
@@ -834,6 +920,7 @@ class StageCore extends EventEmitter {
834
920
  this.renderer = new StageRender({ core: this });
835
921
  this.mask = new StageMask({ core: this });
836
922
  this.dr = new StageDragResize({ core: this, container: this.mask.content });
923
+ this.highlightLayer = new StageHighlight({ core: this, container: this.mask.content });
837
924
  this.renderer.on("runtime-ready", (runtime) => this.emit("runtime-ready", runtime));
838
925
  this.renderer.on("page-el-update", (el) => this.mask?.observe(el));
839
926
  this.mask.on("beforeSelect", (event) => {
@@ -843,6 +930,12 @@ class StageCore extends EventEmitter {
843
930
  }).on("changeGuides", (data) => {
844
931
  this.dr.setGuidelines(data.type, data.guides);
845
932
  this.emit("changeGuides", data);
933
+ }).on("highlight", async (event) => {
934
+ await this.setElementFromPoint(event);
935
+ this.highlightLayer.highlight(this.highlightedDom);
936
+ this.emit("highlight", this.highlightedDom);
937
+ }).on("clearHighlight", async () => {
938
+ this.highlightLayer.clearHighlight();
846
939
  });
847
940
  this.dr.on("update", (data) => {
848
941
  setTimeout(() => this.emit("update", data));
@@ -869,30 +962,32 @@ class StageCore extends EventEmitter {
869
962
  if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.canSelect(el, stop)) {
870
963
  if (stopped)
871
964
  break;
965
+ if (event.type === "mousemove") {
966
+ this.highlight(el);
967
+ break;
968
+ }
872
969
  this.select(el, event);
873
970
  break;
874
971
  }
875
972
  }
876
973
  }
877
974
  async select(idOrEl, event) {
878
- let el;
879
- if (typeof idOrEl === "string" || typeof idOrEl === "number") {
880
- const runtime2 = await this.renderer?.getRuntime();
881
- el = await runtime2?.select?.(`${idOrEl}`);
882
- if (!el)
883
- throw new Error(`\u4E0D\u5B58\u5728ID\u4E3A${idOrEl}\u7684\u5143\u7D20`);
884
- } else {
885
- el = idOrEl;
886
- }
975
+ const el = await this.getTargetElement(idOrEl);
887
976
  if (el === this.selectedDom)
888
977
  return;
889
- const runtime = await this.renderer?.getRuntime();
978
+ const runtime = await this.renderer.getRuntime();
890
979
  if (runtime?.beforeSelect) {
891
980
  await runtime.beforeSelect(el);
892
981
  }
893
982
  this.mask.setLayout(el);
894
983
  this.dr?.select(el, event);
895
984
  this.selectedDom = el;
985
+ if (this.renderer.contentWindow) {
986
+ removeSelectedClassName(this.renderer.contentWindow.document);
987
+ if (this.selectedDom) {
988
+ addSelectedClassName(this.selectedDom);
989
+ }
990
+ }
896
991
  }
897
992
  update(data) {
898
993
  const { config } = data;
@@ -907,6 +1002,13 @@ class StageCore extends EventEmitter {
907
1002
  }, 0);
908
1003
  });
909
1004
  }
1005
+ async highlight(idOrEl) {
1006
+ const el = await this.getTargetElement(idOrEl);
1007
+ if (el === this.highlightedDom)
1008
+ return;
1009
+ this.highlightLayer.highlight(el);
1010
+ this.highlightedDom = el;
1011
+ }
910
1012
  sortNode(data) {
911
1013
  this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
912
1014
  }
@@ -920,6 +1022,7 @@ class StageCore extends EventEmitter {
920
1022
  this.zoom = zoom;
921
1023
  }
922
1024
  mount(el) {
1025
+ this.container = el;
923
1026
  const { mask, renderer } = this;
924
1027
  renderer.mount(el);
925
1028
  mask.mount(el);
@@ -930,11 +1033,25 @@ class StageCore extends EventEmitter {
930
1033
  this.dr.clearGuides();
931
1034
  }
932
1035
  destroy() {
933
- const { mask, renderer, dr } = this;
1036
+ const { mask, renderer, dr, highlightLayer } = this;
934
1037
  renderer.destroy();
935
1038
  mask.destroy();
936
1039
  dr.destroy();
1040
+ highlightLayer.destroy();
937
1041
  this.removeAllListeners();
1042
+ this.container = void 0;
1043
+ }
1044
+ async getTargetElement(idOrEl) {
1045
+ let el;
1046
+ if (typeof idOrEl === "string" || typeof idOrEl === "number") {
1047
+ const runtime = await this.renderer?.getRuntime();
1048
+ el = await runtime?.select?.(`${idOrEl}`);
1049
+ if (!el)
1050
+ throw new Error(`\u4E0D\u5B58\u5728ID\u4E3A${idOrEl}\u7684\u5143\u7D20`);
1051
+ } else {
1052
+ el = idOrEl;
1053
+ }
1054
+ return el;
938
1055
  }
939
1056
  }
940
1057