@tmagic/stage 1.0.3 → 1.1.0-beta.0

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,12 +1,14 @@
1
1
  import EventEmitter$1, { EventEmitter } from 'events';
2
2
  import Moveable from 'moveable';
3
3
  import MoveableHelper from 'moveable-helper';
4
+ import { removeClassName, addClassName, removeClassNameByClassName, createDiv, injectStyle, isSameDomain, getHost } from '@tmagic/utils';
4
5
  import { throttle } from 'lodash-es';
5
6
  import Guides from '@scena/guides';
6
7
 
7
8
  const GHOST_EL_ID_PREFIX = "ghost_el_";
8
9
  const DRAG_EL_ID_PREFIX = "drag_el_";
9
10
  const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
11
+ const CONTAINER_HIGHLIGHT_CLASS = "tmagic-stage-container-highlight";
10
12
  const DEFAULT_ZOOM = 1;
11
13
  var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
12
14
  GuidesType2["HORIZONTAL"] = "horizontal";
@@ -70,13 +72,6 @@ const getAbsolutePosition = (el, { top, left }) => {
70
72
  }
71
73
  return { left, top };
72
74
  };
73
- const getHost = (targetUrl) => targetUrl.match(/\/\/([^/]+)/)?.[1];
74
- const isSameDomain = (targetUrl = "", source = globalThis.location.host) => {
75
- const isHttpUrl = /^(http[s]?:)?\/\//.test(targetUrl);
76
- if (!isHttpUrl)
77
- return true;
78
- return getHost(targetUrl) === source;
79
- };
80
75
  const isAbsolute = (style) => style.position === "absolute";
81
76
  const isRelative = (style) => style.position === "relative";
82
77
  const isStatic = (style) => style.position === "static";
@@ -120,19 +115,14 @@ const getScrollParent = (element, includeHidden = false) => {
120
115
  }
121
116
  return null;
122
117
  };
123
- const createDiv = ({ className, cssText }) => {
124
- const el = globalThis.document.createElement("div");
125
- el.className = className;
126
- el.style.cssText = cssText;
127
- return el;
128
- };
129
118
  const removeSelectedClassName = (doc) => {
130
119
  const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
131
120
  if (oldEl) {
132
- oldEl.classList.remove(SELECTED_CLASS);
133
- oldEl.parentNode?.classList.remove(`${SELECTED_CLASS}-parent`);
121
+ removeClassName(oldEl, SELECTED_CLASS);
122
+ if (oldEl.parentNode)
123
+ removeClassName(oldEl.parentNode, `${SELECTED_CLASS}-parent`);
134
124
  doc.querySelectorAll(`.${SELECTED_CLASS}-parents`).forEach((item) => {
135
- item.classList.remove(`${SELECTED_CLASS}-parents`);
125
+ removeClassName(item, `${SELECTED_CLASS}-parents`);
136
126
  });
137
127
  }
138
128
  };
@@ -143,6 +133,14 @@ const addSelectedClassName = (el, doc) => {
143
133
  item.classList.add(`${SELECTED_CLASS}-parents`);
144
134
  });
145
135
  };
136
+ const calcValueByFontsize = (doc, value) => {
137
+ const { fontSize } = doc.documentElement.style;
138
+ if (fontSize) {
139
+ const times = globalThis.parseFloat(fontSize) / 100;
140
+ return Number((value / times).toFixed(2));
141
+ }
142
+ return value;
143
+ };
146
144
 
147
145
  class StageDragResize extends EventEmitter {
148
146
  constructor(config) {
@@ -231,19 +229,22 @@ class StageDragResize extends EventEmitter {
231
229
  });
232
230
  this.elementGuidelines = [];
233
231
  if (this.mode === Mode.ABSOLUTE) {
234
- const frame = document.createDocumentFragment();
235
- for (const node of nodes) {
236
- const { width, height } = node.getBoundingClientRect();
237
- if (node === this.target)
238
- continue;
239
- const { left, top } = getOffset(node);
240
- const elementGuideline = document.createElement("div");
241
- elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
242
- this.elementGuidelines.push(elementGuideline);
243
- frame.append(elementGuideline);
244
- }
245
- this.container.append(frame);
232
+ this.container.append(this.createGuidelineElements(nodes));
233
+ }
234
+ }
235
+ createGuidelineElements(nodes) {
236
+ const frame = globalThis.document.createDocumentFragment();
237
+ for (const node of nodes) {
238
+ const { width, height } = node.getBoundingClientRect();
239
+ if (node === this.target)
240
+ continue;
241
+ const { left, top } = getOffset(node);
242
+ const elementGuideline = globalThis.document.createElement("div");
243
+ elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
244
+ this.elementGuidelines.push(elementGuideline);
245
+ frame.append(elementGuideline);
246
246
  }
247
+ return frame;
247
248
  }
248
249
  initMoveable() {
249
250
  this.moveable?.destroy();
@@ -296,6 +297,9 @@ class StageDragResize extends EventEmitter {
296
297
  left: 0,
297
298
  top: 0
298
299
  };
300
+ let timeout;
301
+ const { contentWindow } = this.core.renderer;
302
+ const doc = contentWindow?.document;
299
303
  this.moveable.on("dragStart", (e) => {
300
304
  if (!this.target)
301
305
  throw new Error("\u672A\u9009\u4E2D\u7EC4\u4EF6");
@@ -309,6 +313,19 @@ class StageDragResize extends EventEmitter {
309
313
  }).on("drag", (e) => {
310
314
  if (!this.target || !this.dragEl)
311
315
  return;
316
+ if (timeout) {
317
+ globalThis.clearTimeout(timeout);
318
+ timeout = void 0;
319
+ }
320
+ timeout = globalThis.setTimeout(async () => {
321
+ const els = this.core.getElementsFromPoint(e.inputEvent);
322
+ for (const el of els) {
323
+ if (doc && !el.id.startsWith(GHOST_EL_ID_PREFIX) && el !== this.target && await this.core.isContainer(el)) {
324
+ addClassName(el, doc, this.core.containerHighlightClassName);
325
+ break;
326
+ }
327
+ }
328
+ }, this.core.containerHighlightDuration);
312
329
  this.dragStatus = "ing" /* ING */;
313
330
  if (this.ghostEl) {
314
331
  this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
@@ -318,13 +335,25 @@ class StageDragResize extends EventEmitter {
318
335
  this.target.style.left = `${frame.left + e.beforeTranslate[0]}px`;
319
336
  this.target.style.top = `${frame.top + e.beforeTranslate[1]}px`;
320
337
  }).on("dragEnd", () => {
338
+ if (timeout) {
339
+ globalThis.clearTimeout(timeout);
340
+ timeout = void 0;
341
+ }
342
+ let parentEl = null;
343
+ if (doc) {
344
+ parentEl = removeClassNameByClassName(doc, this.core.containerHighlightClassName);
345
+ }
321
346
  if (this.dragStatus === "ing" /* ING */) {
322
- switch (this.mode) {
323
- case Mode.SORTABLE:
324
- this.sort();
325
- break;
326
- default:
327
- this.update();
347
+ if (parentEl) {
348
+ this.update(false, parentEl);
349
+ } else {
350
+ switch (this.mode) {
351
+ case Mode.SORTABLE:
352
+ this.sort();
353
+ break;
354
+ default:
355
+ this.update();
356
+ }
328
357
  }
329
358
  }
330
359
  this.dragStatus = "end" /* END */;
@@ -398,16 +427,27 @@ class StageDragResize extends EventEmitter {
398
427
  });
399
428
  }
400
429
  }
401
- update(isResize = false) {
430
+ update(isResize = false, parentEl = null) {
402
431
  if (!this.target)
403
432
  return;
433
+ const { contentWindow } = this.core.renderer;
434
+ const doc = contentWindow?.document;
435
+ if (!doc)
436
+ return;
404
437
  const offset = this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
405
- const left = this.calcValueByFontsize(offset.left);
406
- const top = this.calcValueByFontsize(offset.top);
407
- const width = this.calcValueByFontsize(this.target.clientWidth);
408
- const height = this.calcValueByFontsize(this.target.clientHeight);
438
+ let left = calcValueByFontsize(doc, offset.left);
439
+ let top = calcValueByFontsize(doc, offset.top);
440
+ const width = calcValueByFontsize(doc, this.target.clientWidth);
441
+ const height = calcValueByFontsize(doc, this.target.clientHeight);
442
+ if (parentEl && this.mode === Mode.ABSOLUTE && this.dragEl) {
443
+ const [translateX, translateY] = this.moveableHelper?.getFrame(this.dragEl).properties.transform.translate.value;
444
+ const { left: parentLeft, top: parentTop } = getOffset(parentEl);
445
+ left = calcValueByFontsize(doc, this.dragEl.offsetLeft) + parseFloat(translateX) - calcValueByFontsize(doc, parentLeft);
446
+ top = calcValueByFontsize(doc, this.dragEl.offsetTop) + parseFloat(translateY) - calcValueByFontsize(doc, parentTop);
447
+ }
409
448
  this.emit("update", {
410
449
  el: this.target,
450
+ parentEl,
411
451
  style: isResize ? { left, top, width, height } : { left, top }
412
452
  });
413
453
  }
@@ -508,15 +548,6 @@ class StageDragResize extends EventEmitter {
508
548
  ...moveableOptions
509
549
  };
510
550
  }
511
- calcValueByFontsize(value) {
512
- const { contentWindow } = this.core.renderer;
513
- const fontSize = contentWindow?.document.documentElement.style.fontSize;
514
- if (fontSize) {
515
- const times = globalThis.parseFloat(fontSize) / 100;
516
- return (value / times).toFixed(2);
517
- }
518
- return value;
519
- }
520
551
  }
521
552
  const down = (deltaTop, target) => {
522
553
  let swapIndex = 0;
@@ -780,11 +811,7 @@ class Rule extends EventEmitter$1 {
780
811
  const wrapperClassName = "editor-mask-wrapper";
781
812
  const throttleTime = 100;
782
813
  const hideScrollbar = () => {
783
- const style = globalThis.document.createElement("style");
784
- style.innerHTML = `
785
- .${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }
786
- `;
787
- globalThis.document.head.appendChild(style);
814
+ injectStyle(globalThis.document, `.${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }`);
788
815
  };
789
816
  const createContent = () => createDiv({
790
817
  className: "editor-mask",
@@ -1009,6 +1036,8 @@ class StageMask extends Rule {
1009
1036
  }
1010
1037
  }
1011
1038
 
1039
+ var style = ".tmagic-stage-container-highlight::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n background-color: #000;\n opacity: .1;\n}\n";
1040
+
1012
1041
  class StageRender extends EventEmitter {
1013
1042
  constructor({ core }) {
1014
1043
  super();
@@ -1046,6 +1075,7 @@ class StageRender extends EventEmitter {
1046
1075
  this.contentWindow.postMessage({
1047
1076
  tmagicRuntimeReady: true
1048
1077
  }, "*");
1078
+ injectStyle(this.contentWindow.document, style);
1049
1079
  };
1050
1080
  this.core = core;
1051
1081
  this.runtimeUrl = core.config.runtimeUrl || "";
@@ -1089,6 +1119,9 @@ class StageCore extends EventEmitter {
1089
1119
  this.config = config;
1090
1120
  this.setZoom(config.zoom);
1091
1121
  this.canSelect = config.canSelect || ((el) => !!el.id);
1122
+ this.isContainer = config.isContainer;
1123
+ this.containerHighlightClassName = config.containerHighlightClassName;
1124
+ this.containerHighlightDuration = config.containerHighlightDuration;
1092
1125
  this.renderer = new StageRender({ core: this });
1093
1126
  this.mask = new StageMask({ core: this });
1094
1127
  this.dr = new StageDragResize({ core: this, container: this.mask.content });
@@ -1123,7 +1156,7 @@ class StageCore extends EventEmitter {
1123
1156
  setTimeout(() => this.emit("sort", data));
1124
1157
  });
1125
1158
  }
1126
- async setElementFromPoint(event) {
1159
+ getElementsFromPoint(event) {
1127
1160
  const { renderer, zoom } = this;
1128
1161
  const doc = renderer.contentWindow?.document;
1129
1162
  let x = event.clientX;
@@ -1135,7 +1168,10 @@ class StageCore extends EventEmitter {
1135
1168
  y = y - rect.top;
1136
1169
  }
1137
1170
  }
1138
- const els = doc?.elementsFromPoint(x / zoom, y / zoom);
1171
+ return doc?.elementsFromPoint(x / zoom, y / zoom);
1172
+ }
1173
+ async setElementFromPoint(event) {
1174
+ const els = this.getElementsFromPoint(event);
1139
1175
  let stopped = false;
1140
1176
  const stop = () => stopped = true;
1141
1177
  for (const el of els) {
@@ -1243,5 +1279,5 @@ class StageCore extends EventEmitter {
1243
1279
  }
1244
1280
  }
1245
1281
 
1246
- export { DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, SELECTED_CLASS, StageDragResize, StageMask, StageRender, ZIndex, StageCore as default };
1282
+ export { CONTAINER_HIGHLIGHT_CLASS, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, SELECTED_CLASS, StageDragResize, StageMask, StageRender, ZIndex, addSelectedClassName, calcValueByFontsize, StageCore as default, getAbsolutePosition, getMode, getOffset, getScrollParent, isAbsolute, isFixed, isFixedParent, isRelative, isStatic, removeSelectedClassName };
1247
1283
  //# sourceMappingURL=tmagic-stage.es.js.map