@tmagic/stage 1.2.0-beta.2 → 1.2.0-beta.21

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.
Files changed (41) hide show
  1. package/README.md +62 -1
  2. package/dist/tmagic-stage.js +2157 -0
  3. package/dist/tmagic-stage.js.map +1 -0
  4. package/dist/{tmagic-stage.umd.js → tmagic-stage.umd.cjs} +1436 -993
  5. package/dist/tmagic-stage.umd.cjs.map +1 -0
  6. package/package.json +9 -8
  7. package/src/ActionManager.ts +534 -0
  8. package/src/DragResizeHelper.ts +338 -0
  9. package/src/MoveableOptionsManager.ts +249 -0
  10. package/src/MoveableSelectParentAble.ts +76 -0
  11. package/src/Rule.ts +13 -9
  12. package/src/StageCore.ts +220 -260
  13. package/src/StageDragResize.ts +83 -339
  14. package/src/StageHighlight.ts +17 -16
  15. package/src/StageMask.ts +88 -140
  16. package/src/StageMultiDragResize.ts +97 -198
  17. package/src/StageRender.ts +90 -15
  18. package/src/TargetShadow.ts +120 -0
  19. package/src/const.ts +1 -1
  20. package/src/types.ts +97 -19
  21. package/src/util.ts +24 -11
  22. package/types/ActionManager.d.ts +141 -0
  23. package/types/DragResizeHelper.d.ts +70 -0
  24. package/types/MoveableOptionsManager.d.ts +86 -0
  25. package/types/MoveableSelectParentAble.d.ts +8 -0
  26. package/types/Rule.d.ts +4 -3
  27. package/types/StageCore.d.ts +65 -39
  28. package/types/StageDragResize.d.ts +11 -40
  29. package/types/StageHighlight.d.ts +3 -4
  30. package/types/StageMask.d.ts +23 -22
  31. package/types/StageMultiDragResize.d.ts +8 -24
  32. package/types/StageRender.d.ts +24 -6
  33. package/types/TargetShadow.d.ts +22 -0
  34. package/types/const.d.ts +1 -1
  35. package/types/types.d.ts +85 -18
  36. package/types/util.d.ts +9 -8
  37. package/dist/tmagic-stage.mjs +0 -1715
  38. package/dist/tmagic-stage.mjs.map +0 -1
  39. package/dist/tmagic-stage.umd.js.map +0 -1
  40. package/src/TargetCalibrate.ts +0 -119
  41. package/types/TargetCalibrate.d.ts +0 -20
@@ -1,1715 +0,0 @@
1
- import EventEmitter$1, { EventEmitter } from 'events';
2
- import { removeClassName, removeClassNameByClassName, createDiv, injectStyle, isSameDomain, getHost, addClassName } from '@tmagic/utils';
3
- import KeyController from 'keycon';
4
- import Moveable from 'moveable';
5
- import MoveableHelper from 'moveable-helper';
6
- import { throttle } from 'lodash-es';
7
- import Guides from '@scena/guides';
8
-
9
- const GHOST_EL_ID_PREFIX = "ghost_el_";
10
- const DRAG_EL_ID_PREFIX = "drag_el_";
11
- const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
12
- const CONTAINER_HIGHLIGHT_CLASS = "tmagic-stage-container-highlight";
13
- const PAGE_CLASS = "magic-ui-page";
14
- const DEFAULT_ZOOM = 1;
15
- var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
16
- GuidesType2["HORIZONTAL"] = "horizontal";
17
- GuidesType2["VERTICAL"] = "vertical";
18
- return GuidesType2;
19
- })(GuidesType || {});
20
- var ZIndex = /* @__PURE__ */ ((ZIndex2) => {
21
- ZIndex2["MASK"] = "99999";
22
- ZIndex2["SELECTED_EL"] = "666";
23
- ZIndex2["GHOST_EL"] = "700";
24
- ZIndex2["DRAG_EL"] = "9";
25
- ZIndex2["HIGHLIGHT_EL"] = "8";
26
- return ZIndex2;
27
- })(ZIndex || {});
28
- var MouseButton = /* @__PURE__ */ ((MouseButton2) => {
29
- MouseButton2[MouseButton2["LEFT"] = 0] = "LEFT";
30
- MouseButton2[MouseButton2["MIDDLE"] = 1] = "MIDDLE";
31
- MouseButton2[MouseButton2["RIGHT"] = 2] = "RIGHT";
32
- return MouseButton2;
33
- })(MouseButton || {});
34
- var Mode = /* @__PURE__ */ ((Mode2) => {
35
- Mode2["ABSOLUTE"] = "absolute";
36
- Mode2["FIXED"] = "fixed";
37
- Mode2["SORTABLE"] = "sortable";
38
- return Mode2;
39
- })(Mode || {});
40
- const SELECTED_CLASS = "tmagic-stage-selected-area";
41
-
42
- var ContainerHighlightType = /* @__PURE__ */ ((ContainerHighlightType2) => {
43
- ContainerHighlightType2["DEFAULT"] = "default";
44
- ContainerHighlightType2["ALT"] = "alt";
45
- return ContainerHighlightType2;
46
- })(ContainerHighlightType || {});
47
- var StageDragStatus = /* @__PURE__ */ ((StageDragStatus2) => {
48
- StageDragStatus2["START"] = "start";
49
- StageDragStatus2["ING"] = "ing";
50
- StageDragStatus2["END"] = "end";
51
- return StageDragStatus2;
52
- })(StageDragStatus || {});
53
-
54
- const getParents = (el, relative) => {
55
- let cur = el.parentElement;
56
- const parents = [];
57
- while (cur && cur !== relative) {
58
- parents.push(cur);
59
- cur = cur.parentElement;
60
- }
61
- return parents;
62
- };
63
- const getOffset = (el) => {
64
- const { offsetParent } = el;
65
- const left = el.offsetLeft;
66
- const top = el.offsetTop;
67
- if (offsetParent) {
68
- const parentOffset = getOffset(offsetParent);
69
- return {
70
- left: left + parentOffset.left,
71
- top: top + parentOffset.top
72
- };
73
- }
74
- return {
75
- left,
76
- top
77
- };
78
- };
79
- const getTargetElStyle = (el) => {
80
- const offset = getOffset(el);
81
- const { transform } = getComputedStyle(el);
82
- return `
83
- position: absolute;
84
- transform: ${transform};
85
- left: ${offset.left}px;
86
- top: ${offset.top}px;
87
- width: ${el.clientWidth}px;
88
- height: ${el.clientHeight}px;
89
- z-index: ${ZIndex.DRAG_EL};
90
- `;
91
- };
92
- const getAbsolutePosition = (el, { top, left }) => {
93
- const { offsetParent } = el;
94
- if (offsetParent) {
95
- const parentOffset = getOffset(offsetParent);
96
- return {
97
- left: left - parentOffset.left,
98
- top: top - parentOffset.top
99
- };
100
- }
101
- return { left, top };
102
- };
103
- const isAbsolute = (style) => style.position === "absolute";
104
- const isRelative = (style) => style.position === "relative";
105
- const isStatic = (style) => style.position === "static";
106
- const isFixed = (style) => style.position === "fixed";
107
- const isFixedParent = (el) => {
108
- let fixed = false;
109
- let dom = el;
110
- while (dom) {
111
- fixed = isFixed(getComputedStyle(dom));
112
- if (fixed) {
113
- break;
114
- }
115
- const { parentElement } = dom;
116
- if (!parentElement || parentElement.tagName === "BODY") {
117
- break;
118
- }
119
- dom = parentElement;
120
- }
121
- return fixed;
122
- };
123
- const getMode = (el) => {
124
- if (isFixedParent(el))
125
- return Mode.FIXED;
126
- const style = getComputedStyle(el);
127
- if (isStatic(style) || isRelative(style))
128
- return Mode.SORTABLE;
129
- return Mode.ABSOLUTE;
130
- };
131
- const getScrollParent = (element, includeHidden = false) => {
132
- let style = getComputedStyle(element);
133
- const overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
134
- if (isFixed(style))
135
- return null;
136
- for (let parent = element; parent.parentElement; ) {
137
- parent = parent.parentElement;
138
- style = getComputedStyle(parent);
139
- if (isAbsolute(style) && isStatic(style))
140
- continue;
141
- if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX))
142
- return parent;
143
- }
144
- return null;
145
- };
146
- const removeSelectedClassName = (doc) => {
147
- const oldEl = doc.querySelector(`.${SELECTED_CLASS}`);
148
- if (oldEl) {
149
- removeClassName(oldEl, SELECTED_CLASS);
150
- if (oldEl.parentNode)
151
- removeClassName(oldEl.parentNode, `${SELECTED_CLASS}-parent`);
152
- doc.querySelectorAll(`.${SELECTED_CLASS}-parents`).forEach((item) => {
153
- removeClassName(item, `${SELECTED_CLASS}-parents`);
154
- });
155
- }
156
- };
157
- const addSelectedClassName = (el, doc) => {
158
- el.classList.add(SELECTED_CLASS);
159
- el.parentNode?.classList.add(`${SELECTED_CLASS}-parent`);
160
- getParents(el, doc.body).forEach((item) => {
161
- item.classList.add(`${SELECTED_CLASS}-parents`);
162
- });
163
- };
164
- const calcValueByFontsize = (doc, value) => {
165
- const { fontSize } = doc.documentElement.style;
166
- if (fontSize) {
167
- const times = globalThis.parseFloat(fontSize) / 100;
168
- return Number((value / times).toFixed(2));
169
- }
170
- return value;
171
- };
172
- const down = (deltaTop, target) => {
173
- let swapIndex = 0;
174
- let addUpH = target.clientHeight;
175
- const brothers = Array.from(target.parentNode?.children || []).filter(
176
- (node) => !node.id.startsWith(GHOST_EL_ID_PREFIX)
177
- );
178
- const index = brothers.indexOf(target);
179
- const downEls = brothers.slice(index + 1);
180
- for (let i = 0; i < downEls.length; i++) {
181
- const ele = downEls[i];
182
- if (ele.style?.position === "fixed") {
183
- continue;
184
- }
185
- addUpH += ele.clientHeight / 2;
186
- if (deltaTop <= addUpH) {
187
- break;
188
- }
189
- addUpH += ele.clientHeight / 2;
190
- swapIndex = i;
191
- }
192
- return {
193
- src: target.id,
194
- dist: downEls.length && swapIndex > -1 ? downEls[swapIndex].id : target.id
195
- };
196
- };
197
- const up = (deltaTop, target) => {
198
- const brothers = Array.from(target.parentNode?.children || []).filter(
199
- (node) => !node.id.startsWith(GHOST_EL_ID_PREFIX)
200
- );
201
- const index = brothers.indexOf(target);
202
- const upEls = brothers.slice(0, index);
203
- let addUpH = target.clientHeight;
204
- let swapIndex = upEls.length - 1;
205
- for (let i = upEls.length - 1; i >= 0; i--) {
206
- const ele = upEls[i];
207
- if (!ele)
208
- continue;
209
- if (ele.style.position === "fixed")
210
- continue;
211
- addUpH += ele.clientHeight / 2;
212
- if (-deltaTop <= addUpH)
213
- break;
214
- addUpH += ele.clientHeight / 2;
215
- swapIndex = i;
216
- }
217
- return {
218
- src: target.id,
219
- dist: upEls.length && swapIndex > -1 ? upEls[swapIndex].id : target.id
220
- };
221
- };
222
-
223
- class StageDragResize extends EventEmitter {
224
- core;
225
- mask;
226
- container;
227
- target;
228
- dragEl;
229
- moveable;
230
- horizontalGuidelines = [];
231
- verticalGuidelines = [];
232
- elementGuidelines = [];
233
- mode = Mode.ABSOLUTE;
234
- moveableOptions = {};
235
- dragStatus = StageDragStatus.END;
236
- ghostEl;
237
- moveableHelper;
238
- isContainerHighlight = false;
239
- constructor(config) {
240
- super();
241
- this.core = config.core;
242
- this.container = config.container;
243
- this.mask = config.mask;
244
- KeyController.global.keydown("alt", (e) => {
245
- e.inputEvent.preventDefault();
246
- this.isContainerHighlight = true;
247
- });
248
- KeyController.global.keyup("alt", (e) => {
249
- e.inputEvent.preventDefault();
250
- const doc = this.core.renderer.contentWindow?.document;
251
- if (doc && this.canContainerHighlight()) {
252
- removeClassNameByClassName(doc, this.core.containerHighlightClassName);
253
- }
254
- this.isContainerHighlight = false;
255
- });
256
- }
257
- select(el, event) {
258
- const oldTarget = this.target;
259
- this.target = el;
260
- if (!this.dragEl) {
261
- this.dragEl = globalThis.document.createElement("div");
262
- this.container.append(this.dragEl);
263
- }
264
- if (!this.moveable || this.target !== oldTarget) {
265
- this.init(el);
266
- this.moveableHelper = MoveableHelper.create({
267
- useBeforeRender: true,
268
- useRender: false,
269
- createAuto: true
270
- });
271
- this.initMoveable();
272
- } else {
273
- this.updateMoveable();
274
- }
275
- if (event) {
276
- this.moveable?.dragStart(event);
277
- }
278
- }
279
- updateMoveable(el = this.target) {
280
- if (!this.moveable)
281
- throw new Error("\u672A\u521D\u59CB\u5316moveable");
282
- if (!el)
283
- throw new Error("\u672A\u9009\u4E2D\u4EFB\u4F55\u8282\u70B9");
284
- this.target = el;
285
- this.init(el);
286
- Object.entries(this.moveableOptions).forEach(([key, value]) => {
287
- this.moveable[key] = value;
288
- });
289
- this.moveable.updateTarget();
290
- }
291
- setGuidelines(type, guidelines) {
292
- if (type === GuidesType.HORIZONTAL) {
293
- this.horizontalGuidelines = guidelines;
294
- this.moveableOptions.horizontalGuidelines = guidelines;
295
- } else if (type === GuidesType.VERTICAL) {
296
- this.verticalGuidelines = guidelines;
297
- this.moveableOptions.verticalGuidelines = guidelines;
298
- }
299
- if (this.moveable) {
300
- this.updateMoveable();
301
- }
302
- }
303
- clearGuides() {
304
- this.horizontalGuidelines = [];
305
- this.verticalGuidelines = [];
306
- this.moveableOptions.horizontalGuidelines = [];
307
- this.moveableOptions.verticalGuidelines = [];
308
- this.updateMoveable();
309
- }
310
- clearSelectStatus() {
311
- if (!this.moveable)
312
- return;
313
- this.destroyDragEl();
314
- this.dragEl = void 0;
315
- this.moveable.target = null;
316
- this.moveable.updateTarget();
317
- }
318
- destroyDragEl() {
319
- this.dragEl?.remove();
320
- }
321
- destroy() {
322
- this.moveable?.destroy();
323
- this.destroyGhostEl();
324
- this.destroyDragEl();
325
- this.dragStatus = StageDragStatus.END;
326
- this.removeAllListeners();
327
- }
328
- init(el) {
329
- if (/(auto|scroll)/.test(el.style.overflow)) {
330
- el.style.overflow = "hidden";
331
- }
332
- this.mode = getMode(el);
333
- this.destroyGhostEl();
334
- if (!this.dragEl) {
335
- return;
336
- }
337
- this.dragEl.style.cssText = getTargetElStyle(el);
338
- this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
339
- if (typeof this.core.config.updateDragEl === "function") {
340
- this.core.config.updateDragEl(this.dragEl, el);
341
- }
342
- this.moveableOptions = this.getOptions({
343
- target: this.dragEl
344
- });
345
- }
346
- setElementGuidelines(nodes) {
347
- this.elementGuidelines.forEach((node) => {
348
- node.remove();
349
- });
350
- this.elementGuidelines = [];
351
- if (this.mode === Mode.ABSOLUTE) {
352
- this.container.append(this.createGuidelineElements(nodes));
353
- }
354
- }
355
- createGuidelineElements(nodes) {
356
- const frame = globalThis.document.createDocumentFragment();
357
- for (const node of nodes) {
358
- const { width, height } = node.getBoundingClientRect();
359
- if (node === this.target)
360
- continue;
361
- const { left, top } = getOffset(node);
362
- const elementGuideline = globalThis.document.createElement("div");
363
- elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
364
- this.elementGuidelines.push(elementGuideline);
365
- frame.append(elementGuideline);
366
- }
367
- return frame;
368
- }
369
- initMoveable() {
370
- this.moveable?.destroy();
371
- this.moveable = new Moveable(this.container, {
372
- ...this.moveableOptions
373
- });
374
- this.bindResizeEvent();
375
- this.bindDragEvent();
376
- this.bindRotateEvent();
377
- this.bindScaleEvent();
378
- }
379
- bindResizeEvent() {
380
- if (!this.moveable)
381
- throw new Error("moveable \u672A\u521D\u59CB\u5316");
382
- const frame = {
383
- left: 0,
384
- top: 0
385
- };
386
- this.moveable.on("resizeStart", (e) => {
387
- if (!this.target)
388
- return;
389
- this.dragStatus = StageDragStatus.START;
390
- this.moveableHelper?.onResizeStart(e);
391
- frame.top = this.target.offsetTop;
392
- frame.left = this.target.offsetLeft;
393
- }).on("resize", (e) => {
394
- const { width, height, drag } = e;
395
- if (!this.moveable || !this.target || !this.dragEl)
396
- return;
397
- const { beforeTranslate } = drag;
398
- this.dragStatus = StageDragStatus.ING;
399
- if (this.mode === Mode.SORTABLE) {
400
- this.target.style.top = "0px";
401
- this.dragEl.style.width = `${width}px`;
402
- this.dragEl.style.height = `${height}px`;
403
- } else {
404
- this.moveableHelper?.onResize(e);
405
- this.target.style.left = `${frame.left + beforeTranslate[0]}px`;
406
- this.target.style.top = `${frame.top + beforeTranslate[1]}px`;
407
- }
408
- this.target.style.width = `${width}px`;
409
- this.target.style.height = `${height}px`;
410
- }).on("resizeEnd", () => {
411
- this.dragStatus = StageDragStatus.END;
412
- this.update(true);
413
- });
414
- }
415
- bindDragEvent() {
416
- if (!this.moveable)
417
- throw new Error("moveable \u672A\u521D\u59CB\u5316");
418
- const frame = {
419
- left: 0,
420
- top: 0
421
- };
422
- let timeout;
423
- const { contentWindow } = this.core.renderer;
424
- const doc = contentWindow?.document;
425
- this.moveable.on("dragStart", (e) => {
426
- if (!this.target)
427
- throw new Error("\u672A\u9009\u4E2D\u7EC4\u4EF6");
428
- this.dragStatus = StageDragStatus.START;
429
- this.moveableHelper?.onDragStart(e);
430
- if (this.mode === Mode.SORTABLE) {
431
- this.ghostEl = this.generateGhostEl(this.target);
432
- }
433
- frame.top = this.target.offsetTop;
434
- frame.left = this.target.offsetLeft;
435
- }).on("drag", (e) => {
436
- if (!this.target || !this.dragEl)
437
- return;
438
- if (timeout) {
439
- globalThis.clearTimeout(timeout);
440
- timeout = void 0;
441
- }
442
- if (this.canContainerHighlight()) {
443
- timeout = this.core.getAddContainerHighlightClassNameTimeout(e.inputEvent, [this.target]);
444
- }
445
- this.dragStatus = StageDragStatus.ING;
446
- if (this.ghostEl) {
447
- this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
448
- return;
449
- }
450
- this.moveableHelper?.onDrag(e);
451
- this.target.style.left = `${frame.left + e.beforeTranslate[0]}px`;
452
- this.target.style.top = `${frame.top + e.beforeTranslate[1]}px`;
453
- }).on("dragEnd", () => {
454
- if (timeout) {
455
- globalThis.clearTimeout(timeout);
456
- timeout = void 0;
457
- }
458
- let parentEl = null;
459
- if (doc && this.canContainerHighlight()) {
460
- parentEl = removeClassNameByClassName(doc, this.core.containerHighlightClassName);
461
- }
462
- if (this.dragStatus === StageDragStatus.ING) {
463
- if (parentEl) {
464
- this.update(false, parentEl);
465
- } else {
466
- switch (this.mode) {
467
- case Mode.SORTABLE:
468
- this.sort();
469
- break;
470
- default:
471
- this.update();
472
- }
473
- }
474
- }
475
- this.dragStatus = StageDragStatus.END;
476
- this.destroyGhostEl();
477
- });
478
- }
479
- bindRotateEvent() {
480
- if (!this.moveable)
481
- throw new Error("moveable \u672A\u521D\u59CB\u5316");
482
- this.moveable.on("rotateStart", (e) => {
483
- this.dragStatus = StageDragStatus.START;
484
- this.moveableHelper?.onRotateStart(e);
485
- }).on("rotate", (e) => {
486
- if (!this.target || !this.dragEl)
487
- return;
488
- this.dragStatus = StageDragStatus.ING;
489
- this.moveableHelper?.onRotate(e);
490
- const frame = this.moveableHelper?.getFrame(e.target);
491
- this.target.style.transform = frame?.toCSSObject().transform || "";
492
- }).on("rotateEnd", (e) => {
493
- this.dragStatus = StageDragStatus.END;
494
- const frame = this.moveableHelper?.getFrame(e.target);
495
- this.emit("update", {
496
- data: [
497
- {
498
- el: this.target,
499
- style: {
500
- transform: frame?.get("transform")
501
- }
502
- }
503
- ]
504
- });
505
- });
506
- }
507
- bindScaleEvent() {
508
- if (!this.moveable)
509
- throw new Error("moveable \u672A\u521D\u59CB\u5316");
510
- this.moveable.on("scaleStart", (e) => {
511
- this.dragStatus = StageDragStatus.START;
512
- this.moveableHelper?.onScaleStart(e);
513
- }).on("scale", (e) => {
514
- if (!this.target || !this.dragEl)
515
- return;
516
- this.dragStatus = StageDragStatus.ING;
517
- this.moveableHelper?.onScale(e);
518
- const frame = this.moveableHelper?.getFrame(e.target);
519
- this.target.style.transform = frame?.toCSSObject().transform || "";
520
- }).on("scaleEnd", (e) => {
521
- this.dragStatus = StageDragStatus.END;
522
- const frame = this.moveableHelper?.getFrame(e.target);
523
- this.emit("update", {
524
- data: [
525
- {
526
- el: this.target,
527
- style: {
528
- transform: frame?.get("transform")
529
- }
530
- }
531
- ]
532
- });
533
- });
534
- }
535
- sort() {
536
- if (!this.target || !this.ghostEl)
537
- throw new Error("\u672A\u77E5\u9519\u8BEF");
538
- const { top } = this.ghostEl.getBoundingClientRect();
539
- const { top: oriTop } = this.target.getBoundingClientRect();
540
- const deltaTop = top - oriTop;
541
- if (Math.abs(deltaTop) >= this.target.clientHeight / 2) {
542
- if (deltaTop > 0) {
543
- this.emit("sort", down(deltaTop, this.target));
544
- } else {
545
- this.emit("sort", up(deltaTop, this.target));
546
- }
547
- } else {
548
- this.emit("sort", {
549
- src: this.target.id,
550
- dist: this.target.id
551
- });
552
- }
553
- }
554
- update(isResize = false, parentEl = null) {
555
- if (!this.target)
556
- return;
557
- const { contentWindow } = this.core.renderer;
558
- const doc = contentWindow?.document;
559
- if (!doc)
560
- return;
561
- const offset = this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
562
- let left = calcValueByFontsize(doc, offset.left);
563
- let top = calcValueByFontsize(doc, offset.top);
564
- const width = calcValueByFontsize(doc, this.target.clientWidth);
565
- const height = calcValueByFontsize(doc, this.target.clientHeight);
566
- if (parentEl && this.mode === Mode.ABSOLUTE && this.dragEl) {
567
- const [translateX, translateY] = this.moveableHelper?.getFrame(this.dragEl).properties.transform.translate.value;
568
- const { left: parentLeft, top: parentTop } = getOffset(parentEl);
569
- left = calcValueByFontsize(doc, this.dragEl.offsetLeft) + parseFloat(translateX) - calcValueByFontsize(doc, parentLeft);
570
- top = calcValueByFontsize(doc, this.dragEl.offsetTop) + parseFloat(translateY) - calcValueByFontsize(doc, parentTop);
571
- }
572
- this.emit("update", {
573
- data: [
574
- {
575
- el: this.target,
576
- style: isResize ? { left, top, width, height } : { left, top }
577
- }
578
- ],
579
- parentEl
580
- });
581
- }
582
- generateGhostEl(el) {
583
- if (this.ghostEl) {
584
- this.destroyGhostEl();
585
- }
586
- const ghostEl = el.cloneNode(true);
587
- this.setGhostElChildrenId(ghostEl);
588
- const { top, left } = getAbsolutePosition(el, getOffset(el));
589
- ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
590
- ghostEl.style.zIndex = ZIndex.GHOST_EL;
591
- ghostEl.style.opacity = ".5";
592
- ghostEl.style.position = "absolute";
593
- ghostEl.style.left = `${left}px`;
594
- ghostEl.style.top = `${top}px`;
595
- el.after(ghostEl);
596
- return ghostEl;
597
- }
598
- setGhostElChildrenId(el) {
599
- for (const child of Array.from(el.children)) {
600
- if (child.id) {
601
- child.id = `${GHOST_EL_ID_PREFIX}${child.id}`;
602
- }
603
- if (child.children.length) {
604
- this.setGhostElChildrenId(child);
605
- }
606
- }
607
- }
608
- destroyGhostEl() {
609
- this.ghostEl?.remove();
610
- this.ghostEl = void 0;
611
- }
612
- getOptions(options = {}) {
613
- if (!this.target)
614
- return {};
615
- const isAbsolute = this.mode === Mode.ABSOLUTE;
616
- const isFixed = this.mode === Mode.FIXED;
617
- const isSortable = this.mode === Mode.SORTABLE;
618
- let { moveableOptions = {} } = this.core.config;
619
- if (typeof moveableOptions === "function") {
620
- moveableOptions = moveableOptions(this.core);
621
- }
622
- const elementGuidelines = moveableOptions.elementGuidelines || this.target.parentElement?.children || [];
623
- this.setElementGuidelines(elementGuidelines);
624
- if (moveableOptions.elementGuidelines) {
625
- delete moveableOptions.elementGuidelines;
626
- }
627
- return {
628
- origin: false,
629
- rootContainer: this.core.container,
630
- zoom: 1,
631
- dragArea: false,
632
- draggable: true,
633
- resizable: true,
634
- scalable: false,
635
- rotatable: false,
636
- snappable: isAbsolute || isFixed,
637
- snapGap: isAbsolute || isFixed,
638
- snapThreshold: 5,
639
- snapDigit: 0,
640
- throttleDrag: 0,
641
- isDisplaySnapDigit: isAbsolute,
642
- snapDirections: {
643
- top: isAbsolute,
644
- right: isAbsolute,
645
- bottom: isAbsolute,
646
- left: isAbsolute,
647
- center: isAbsolute,
648
- middle: isAbsolute
649
- },
650
- elementSnapDirections: {
651
- top: isAbsolute,
652
- right: isAbsolute,
653
- bottom: isAbsolute,
654
- left: isAbsolute
655
- },
656
- isDisplayInnerSnapDigit: true,
657
- horizontalGuidelines: this.horizontalGuidelines,
658
- verticalGuidelines: this.verticalGuidelines,
659
- elementGuidelines: this.elementGuidelines,
660
- bounds: {
661
- top: 0,
662
- left: -1,
663
- right: this.container.clientWidth - 1,
664
- bottom: isSortable ? void 0 : this.container.clientHeight,
665
- ...moveableOptions.bounds || {}
666
- },
667
- ...options,
668
- ...moveableOptions
669
- };
670
- }
671
- canContainerHighlight() {
672
- return this.core.containerHighlightType === ContainerHighlightType.DEFAULT || this.core.containerHighlightType === ContainerHighlightType.ALT && this.isContainerHighlight;
673
- }
674
- }
675
-
676
- class TargetCalibrate extends EventEmitter {
677
- parent;
678
- mask;
679
- dr;
680
- core;
681
- operationEl;
682
- constructor(config) {
683
- super();
684
- this.parent = config.parent;
685
- this.mask = config.mask;
686
- this.dr = config.dr;
687
- this.core = config.core;
688
- this.operationEl = globalThis.document.createElement("div");
689
- this.parent.append(this.operationEl);
690
- }
691
- update(el, prefix) {
692
- const { left, top } = this.getOffset(el);
693
- const { transform } = getComputedStyle(el);
694
- this.operationEl.style.cssText = `
695
- position: absolute;
696
- transform: ${transform};
697
- left: ${left}px;
698
- top: ${top}px;
699
- width: ${el.clientWidth}px;
700
- height: ${el.clientHeight}px;
701
- z-index: ${ZIndex.HIGHLIGHT_EL};
702
- `;
703
- this.operationEl.id = `${prefix}${el.id}`;
704
- if (typeof this.core.config.updateDragEl === "function") {
705
- this.core.config.updateDragEl(this.operationEl, el);
706
- }
707
- return this.operationEl;
708
- }
709
- destroy() {
710
- this.operationEl?.remove();
711
- }
712
- getOffset(el) {
713
- const { offsetParent } = el;
714
- const left = el.offsetLeft;
715
- const top = el.offsetTop;
716
- if (offsetParent) {
717
- const parentOffset = this.getOffset(offsetParent);
718
- return {
719
- left: left + parentOffset.left,
720
- top: top + parentOffset.top
721
- };
722
- }
723
- if (this.dr.mode === Mode.FIXED) {
724
- if (getMode(el) === Mode.FIXED) {
725
- return {
726
- left,
727
- top
728
- };
729
- }
730
- return {
731
- left: left - this.mask.scrollLeft,
732
- top: top - this.mask.scrollTop
733
- };
734
- }
735
- if (getMode(el) === Mode.FIXED) {
736
- return {
737
- left: left + this.mask.scrollLeft,
738
- top: top + this.mask.scrollTop
739
- };
740
- }
741
- return {
742
- left,
743
- top
744
- };
745
- }
746
- }
747
-
748
- class StageHighlight extends EventEmitter {
749
- core;
750
- container;
751
- target;
752
- moveable;
753
- calibrationTarget;
754
- constructor(config) {
755
- super();
756
- this.core = config.core;
757
- this.container = config.container;
758
- this.calibrationTarget = new TargetCalibrate({
759
- parent: this.core.mask.content,
760
- mask: this.core.mask,
761
- dr: this.core.dr,
762
- core: this.core
763
- });
764
- }
765
- highlight(el) {
766
- if (!el || el === this.target)
767
- return;
768
- this.target = el;
769
- this.moveable?.destroy();
770
- this.moveable = new Moveable(this.container, {
771
- target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
772
- origin: false,
773
- rootContainer: this.core.container,
774
- zoom: 2
775
- });
776
- }
777
- clearHighlight() {
778
- if (!this.moveable)
779
- return;
780
- this.target = void 0;
781
- this.moveable.target = null;
782
- this.moveable.updateTarget();
783
- }
784
- destroy() {
785
- this.moveable?.destroy();
786
- this.calibrationTarget.destroy();
787
- }
788
- }
789
-
790
- class Rule extends EventEmitter$1 {
791
- hGuides;
792
- vGuides;
793
- horizontalGuidelines = [];
794
- verticalGuidelines = [];
795
- container;
796
- containerResizeObserver;
797
- constructor(container) {
798
- super();
799
- this.container = container;
800
- this.hGuides = this.createGuides(GuidesType.HORIZONTAL, this.horizontalGuidelines);
801
- this.vGuides = this.createGuides(GuidesType.VERTICAL, this.verticalGuidelines);
802
- this.hGuides.on("changeGuides", this.hGuidesChangeGuidesHandler);
803
- this.vGuides.on("changeGuides", this.vGuidesChangeGuidesHandler);
804
- this.containerResizeObserver = new ResizeObserver(() => {
805
- this.vGuides.resize();
806
- this.hGuides.resize();
807
- });
808
- this.containerResizeObserver.observe(this.container);
809
- }
810
- showGuides(show = true) {
811
- this.hGuides.setState({
812
- showGuides: show
813
- });
814
- this.vGuides.setState({
815
- showGuides: show
816
- });
817
- }
818
- setGuides([hLines, vLines]) {
819
- this.horizontalGuidelines = hLines;
820
- this.verticalGuidelines = vLines;
821
- this.hGuides.setState({
822
- defaultGuides: hLines
823
- });
824
- this.vGuides.setState({
825
- defaultGuides: vLines
826
- });
827
- this.emit("changeGuides", {
828
- type: GuidesType.HORIZONTAL,
829
- guides: hLines
830
- });
831
- this.emit("changeGuides", {
832
- type: GuidesType.VERTICAL,
833
- guides: vLines
834
- });
835
- }
836
- clearGuides() {
837
- this.setGuides([[], []]);
838
- }
839
- showRule(show = true) {
840
- if (show) {
841
- this.hGuides.destroy();
842
- this.hGuides = this.createGuides(GuidesType.HORIZONTAL, this.horizontalGuidelines);
843
- this.vGuides.destroy();
844
- this.vGuides = this.createGuides(GuidesType.VERTICAL, this.verticalGuidelines);
845
- } else {
846
- this.hGuides.setState({
847
- rulerStyle: {
848
- visibility: "hidden"
849
- }
850
- });
851
- this.vGuides.setState({
852
- rulerStyle: {
853
- visibility: "hidden"
854
- }
855
- });
856
- }
857
- }
858
- scrollRule(scrollTop) {
859
- this.hGuides.scrollGuides(scrollTop);
860
- this.hGuides.scroll(0);
861
- this.vGuides.scrollGuides(0);
862
- this.vGuides.scroll(scrollTop);
863
- }
864
- destroy() {
865
- this.hGuides.off("changeGuides", this.hGuidesChangeGuidesHandler);
866
- this.vGuides.off("changeGuides", this.vGuidesChangeGuidesHandler);
867
- this.containerResizeObserver.disconnect();
868
- this.removeAllListeners();
869
- }
870
- getGuidesStyle = (type) => ({
871
- position: "fixed",
872
- zIndex: 1,
873
- left: type === GuidesType.HORIZONTAL ? 0 : "-30px",
874
- top: type === GuidesType.HORIZONTAL ? "-30px" : 0,
875
- width: type === GuidesType.HORIZONTAL ? "100%" : "30px",
876
- height: type === GuidesType.HORIZONTAL ? "30px" : "100%"
877
- });
878
- createGuides = (type, defaultGuides = []) => new Guides(this.container, {
879
- type,
880
- defaultGuides,
881
- displayDragPos: true,
882
- backgroundColor: "#fff",
883
- lineColor: "#000",
884
- textColor: "#000",
885
- style: this.getGuidesStyle(type)
886
- });
887
- hGuidesChangeGuidesHandler = (e) => {
888
- this.horizontalGuidelines = e.guides;
889
- this.emit("changeGuides", {
890
- type: GuidesType.HORIZONTAL,
891
- guides: this.horizontalGuidelines
892
- });
893
- };
894
- vGuidesChangeGuidesHandler = (e) => {
895
- this.verticalGuidelines = e.guides;
896
- this.emit("changeGuides", {
897
- type: GuidesType.VERTICAL,
898
- guides: this.verticalGuidelines
899
- });
900
- };
901
- }
902
-
903
- const wrapperClassName = "editor-mask-wrapper";
904
- const throttleTime = 100;
905
- const hideScrollbar = () => {
906
- injectStyle(globalThis.document, `.${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }`);
907
- };
908
- const createContent = () => createDiv({
909
- className: "editor-mask",
910
- cssText: `
911
- position: absolute;
912
- top: 0;
913
- left: 0;
914
- transform: translate3d(0, 0, 0);
915
- `
916
- });
917
- const createWrapper = () => {
918
- const el = createDiv({
919
- className: wrapperClassName,
920
- cssText: `
921
- position: absolute;
922
- top: 0;
923
- left: 0;
924
- height: 100%;
925
- width: 100%;
926
- overflow: hidden;
927
- z-index: ${ZIndex.MASK};
928
- `
929
- });
930
- hideScrollbar();
931
- return el;
932
- };
933
- class StageMask extends Rule {
934
- content = createContent();
935
- wrapper;
936
- core;
937
- page = null;
938
- pageScrollParent = null;
939
- scrollTop = 0;
940
- scrollLeft = 0;
941
- width = 0;
942
- height = 0;
943
- wrapperHeight = 0;
944
- wrapperWidth = 0;
945
- maxScrollTop = 0;
946
- maxScrollLeft = 0;
947
- intersectionObserver = null;
948
- isMultiSelectStatus = false;
949
- mode = Mode.ABSOLUTE;
950
- pageResizeObserver = null;
951
- wrapperResizeObserver = null;
952
- highlightHandler = throttle((event) => {
953
- this.emit("highlight", event);
954
- }, throttleTime);
955
- constructor(config) {
956
- const wrapper = createWrapper();
957
- super(wrapper);
958
- this.wrapper = wrapper;
959
- this.core = config.core;
960
- this.content.addEventListener("mousedown", this.mouseDownHandler);
961
- this.wrapper.appendChild(this.content);
962
- this.content.addEventListener("wheel", this.mouseWheelHandler);
963
- this.content.addEventListener("mousemove", this.highlightHandler);
964
- this.content.addEventListener("mouseleave", this.mouseLeaveHandler);
965
- const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
966
- const ctrl = isMac ? "meta" : "ctrl";
967
- KeyController.global.keydown(ctrl, (e) => {
968
- e.inputEvent.preventDefault();
969
- this.isMultiSelectStatus = true;
970
- });
971
- KeyController.global.on("blur", () => {
972
- this.isMultiSelectStatus = false;
973
- });
974
- KeyController.global.keyup(ctrl, (e) => {
975
- e.inputEvent.preventDefault();
976
- this.isMultiSelectStatus = false;
977
- });
978
- }
979
- setMode(mode) {
980
- this.mode = mode;
981
- this.scroll();
982
- if (mode === Mode.FIXED) {
983
- this.content.style.width = `${this.wrapperWidth}px`;
984
- this.content.style.height = `${this.wrapperHeight}px`;
985
- } else {
986
- this.content.style.width = `${this.width}px`;
987
- this.content.style.height = `${this.height}px`;
988
- }
989
- }
990
- observe(page) {
991
- if (!page)
992
- return;
993
- this.page = page;
994
- this.pageScrollParent = getScrollParent(page) || this.core.renderer.contentWindow?.document.documentElement || null;
995
- this.pageResizeObserver?.disconnect();
996
- this.wrapperResizeObserver?.disconnect();
997
- this.intersectionObserver?.disconnect();
998
- if (typeof IntersectionObserver !== "undefined") {
999
- this.intersectionObserver = new IntersectionObserver(
1000
- (entries) => {
1001
- entries.forEach((entry) => {
1002
- const { target, intersectionRatio } = entry;
1003
- if (intersectionRatio <= 0) {
1004
- this.scrollIntoView(target);
1005
- }
1006
- this.intersectionObserver?.unobserve(target);
1007
- });
1008
- },
1009
- {
1010
- root: this.pageScrollParent,
1011
- rootMargin: "0px",
1012
- threshold: 1
1013
- }
1014
- );
1015
- }
1016
- if (typeof ResizeObserver !== "undefined") {
1017
- this.pageResizeObserver = new ResizeObserver((entries) => {
1018
- const [entry] = entries;
1019
- const { clientHeight, clientWidth } = entry.target;
1020
- this.setHeight(clientHeight);
1021
- this.setWidth(clientWidth);
1022
- this.scroll();
1023
- if (this.core.dr.moveable) {
1024
- this.core.dr.updateMoveable();
1025
- }
1026
- });
1027
- this.pageResizeObserver.observe(page);
1028
- this.wrapperResizeObserver = new ResizeObserver((entries) => {
1029
- const [entry] = entries;
1030
- const { clientHeight, clientWidth } = entry.target;
1031
- this.wrapperHeight = clientHeight;
1032
- this.wrapperWidth = clientWidth;
1033
- this.setMaxScrollLeft();
1034
- this.setMaxScrollTop();
1035
- });
1036
- this.wrapperResizeObserver.observe(this.wrapper);
1037
- }
1038
- }
1039
- mount(el) {
1040
- if (!this.content)
1041
- throw new Error("content \u4E0D\u5B58\u5728");
1042
- el.appendChild(this.wrapper);
1043
- }
1044
- setLayout(el) {
1045
- this.setMode(isFixedParent(el) ? Mode.FIXED : Mode.ABSOLUTE);
1046
- }
1047
- scrollIntoView(el) {
1048
- el.scrollIntoView();
1049
- if (!this.pageScrollParent)
1050
- return;
1051
- this.scrollLeft = this.pageScrollParent.scrollLeft;
1052
- this.scrollTop = this.pageScrollParent.scrollTop;
1053
- this.scroll();
1054
- }
1055
- destroy() {
1056
- this.content?.remove();
1057
- this.page = null;
1058
- this.pageScrollParent = null;
1059
- this.pageResizeObserver?.disconnect();
1060
- this.wrapperResizeObserver?.disconnect();
1061
- this.content.removeEventListener("mouseleave", this.mouseLeaveHandler);
1062
- super.destroy();
1063
- }
1064
- scroll() {
1065
- this.fixScrollValue();
1066
- let { scrollLeft, scrollTop } = this;
1067
- if (this.pageScrollParent) {
1068
- this.pageScrollParent.scrollTo({
1069
- top: scrollTop,
1070
- left: scrollLeft
1071
- });
1072
- }
1073
- if (this.mode === Mode.FIXED) {
1074
- scrollLeft = 0;
1075
- scrollTop = 0;
1076
- }
1077
- this.scrollRule(scrollTop);
1078
- this.scrollTo(scrollLeft, scrollTop);
1079
- }
1080
- scrollTo(scrollLeft, scrollTop) {
1081
- this.content.style.transform = `translate3d(${-scrollLeft}px, ${-scrollTop}px, 0)`;
1082
- }
1083
- setHeight(height) {
1084
- this.height = height;
1085
- this.setMaxScrollTop();
1086
- this.content.style.height = `${height}px`;
1087
- }
1088
- setWidth(width) {
1089
- this.width = width;
1090
- this.setMaxScrollLeft();
1091
- this.content.style.width = `${width}px`;
1092
- }
1093
- setMaxScrollLeft() {
1094
- this.maxScrollLeft = Math.max(this.width - this.wrapperWidth, 0);
1095
- }
1096
- setMaxScrollTop() {
1097
- this.maxScrollTop = Math.max(this.height - this.wrapperHeight, 0);
1098
- }
1099
- fixScrollValue() {
1100
- if (this.scrollTop < 0)
1101
- this.scrollTop = 0;
1102
- if (this.scrollLeft < 0)
1103
- this.scrollLeft = 0;
1104
- if (this.maxScrollTop < this.scrollTop)
1105
- this.scrollTop = this.maxScrollTop;
1106
- if (this.maxScrollLeft < this.scrollLeft)
1107
- this.scrollLeft = this.maxScrollLeft;
1108
- }
1109
- mouseDownHandler = (event) => {
1110
- this.emit("clearHighlight");
1111
- event.stopImmediatePropagation();
1112
- event.stopPropagation();
1113
- if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
1114
- return;
1115
- if (!this.isMultiSelectStatus && event.target.className.indexOf("moveable-area") !== -1) {
1116
- return;
1117
- }
1118
- if (event.target.className.indexOf("moveable-control") !== -1) {
1119
- return;
1120
- }
1121
- this.content.removeEventListener("mousemove", this.highlightHandler);
1122
- if (this.isMultiSelectStatus) {
1123
- this.emit("beforeMultiSelect", event);
1124
- } else {
1125
- this.emit("beforeSelect", event);
1126
- }
1127
- globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
1128
- };
1129
- mouseUpHandler = () => {
1130
- globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
1131
- this.content.addEventListener("mousemove", this.highlightHandler);
1132
- if (!this.isMultiSelectStatus) {
1133
- this.emit("select");
1134
- }
1135
- };
1136
- mouseWheelHandler = (event) => {
1137
- this.emit("clearHighlight");
1138
- if (!this.page)
1139
- throw new Error("page \u672A\u521D\u59CB\u5316");
1140
- const { deltaY, deltaX } = event;
1141
- if (this.page.clientHeight < this.wrapperHeight && deltaY)
1142
- return;
1143
- if (this.page.clientWidth < this.wrapperWidth && deltaX)
1144
- return;
1145
- if (this.maxScrollTop > 0) {
1146
- this.scrollTop = this.scrollTop + deltaY;
1147
- }
1148
- if (this.maxScrollLeft > 0) {
1149
- this.scrollLeft = this.scrollLeft + deltaX;
1150
- }
1151
- this.scroll();
1152
- this.emit("scroll", event);
1153
- };
1154
- mouseLeaveHandler = () => {
1155
- setTimeout(() => this.emit("clearHighlight"), throttleTime);
1156
- };
1157
- }
1158
-
1159
- class StageMultiDragResize extends EventEmitter {
1160
- core;
1161
- mask;
1162
- container;
1163
- targetList = [];
1164
- dragElList = [];
1165
- moveableForMulti;
1166
- dragStatus = StageDragStatus.END;
1167
- multiMoveableHelper;
1168
- constructor(config) {
1169
- super();
1170
- this.core = config.core;
1171
- this.container = config.container;
1172
- this.mask = config.mask;
1173
- }
1174
- multiSelect(els) {
1175
- this.targetList = els;
1176
- this.core.dr.destroyDragEl();
1177
- this.destroyDragElList();
1178
- this.dragElList = els.map((elItem) => {
1179
- const dragElDiv = globalThis.document.createElement("div");
1180
- this.container.append(dragElDiv);
1181
- dragElDiv.style.cssText = getTargetElStyle(elItem);
1182
- dragElDiv.id = `${DRAG_EL_ID_PREFIX}${elItem.id}`;
1183
- if (typeof this.core.config.updateDragEl === "function") {
1184
- this.core.config.updateDragEl(dragElDiv, elItem);
1185
- }
1186
- return dragElDiv;
1187
- });
1188
- this.moveableForMulti?.destroy();
1189
- this.multiMoveableHelper?.clear();
1190
- this.moveableForMulti = new Moveable(
1191
- this.container,
1192
- this.getOptions({
1193
- target: this.dragElList
1194
- })
1195
- );
1196
- this.multiMoveableHelper = MoveableHelper.create({
1197
- useBeforeRender: true,
1198
- useRender: false,
1199
- createAuto: true
1200
- });
1201
- const frames = [];
1202
- const setFrames = (events) => {
1203
- events.forEach((ev) => {
1204
- const matchEventTarget = this.targetList.find(
1205
- (targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, "")
1206
- );
1207
- if (!matchEventTarget)
1208
- return;
1209
- frames.push({
1210
- left: matchEventTarget.offsetLeft,
1211
- top: matchEventTarget.offsetTop,
1212
- id: matchEventTarget.id
1213
- });
1214
- });
1215
- };
1216
- this.moveableForMulti.on("resizeGroupStart", (params) => {
1217
- const { events } = params;
1218
- this.multiMoveableHelper?.onResizeGroupStart(params);
1219
- setFrames(events);
1220
- this.dragStatus = StageDragStatus.START;
1221
- }).on("resizeGroup", (params) => {
1222
- const { events } = params;
1223
- events.forEach((ev) => {
1224
- const { width, height, beforeTranslate } = ev.drag;
1225
- const frameSnapShot = frames.find(
1226
- (frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, "")
1227
- );
1228
- if (!frameSnapShot)
1229
- return;
1230
- const targeEl = this.targetList.find(
1231
- (targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, "")
1232
- );
1233
- if (!targeEl)
1234
- return;
1235
- const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
1236
- if (!isParentIncluded) {
1237
- targeEl.style.left = `${frameSnapShot.left + beforeTranslate[0]}px`;
1238
- targeEl.style.top = `${frameSnapShot.top + beforeTranslate[1]}px`;
1239
- }
1240
- targeEl.style.width = `${width}px`;
1241
- targeEl.style.height = `${height}px`;
1242
- });
1243
- this.multiMoveableHelper?.onResizeGroup(params);
1244
- this.dragStatus = StageDragStatus.ING;
1245
- }).on("resizeGroupEnd", () => {
1246
- this.update(true);
1247
- this.dragStatus = StageDragStatus.END;
1248
- }).on("dragGroupStart", (params) => {
1249
- const { events } = params;
1250
- this.multiMoveableHelper?.onDragGroupStart(params);
1251
- setFrames(events);
1252
- this.dragStatus = StageDragStatus.START;
1253
- }).on("dragGroup", (params) => {
1254
- const { events } = params;
1255
- events.forEach((ev) => {
1256
- const frameSnapShot = frames.find(
1257
- (frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, "")
1258
- );
1259
- if (!frameSnapShot)
1260
- return;
1261
- const targeEl = this.targetList.find(
1262
- (targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, "")
1263
- );
1264
- if (!targeEl)
1265
- return;
1266
- const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
1267
- if (!isParentIncluded) {
1268
- targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
1269
- targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
1270
- }
1271
- });
1272
- this.multiMoveableHelper?.onDragGroup(params);
1273
- this.dragStatus = StageDragStatus.ING;
1274
- }).on("dragGroupEnd", () => {
1275
- this.update();
1276
- this.dragStatus = StageDragStatus.END;
1277
- }).on("clickGroup", (params) => {
1278
- const { inputTarget, targets } = params;
1279
- if (!this.mask.isMultiSelectStatus && targets.length > 1 && targets.includes(inputTarget)) {
1280
- this.emit("select", inputTarget.id.replace(DRAG_EL_ID_PREFIX, ""));
1281
- }
1282
- });
1283
- }
1284
- canSelect(el, stop) {
1285
- if (el.className.includes(PAGE_CLASS)) {
1286
- this.core.highlightedDom = void 0;
1287
- this.core.highlightLayer.clearHighlight();
1288
- stop();
1289
- return false;
1290
- }
1291
- const currentTargetMode = getMode(el);
1292
- let selectedDomMode = "";
1293
- if (this.core.selectedDom?.className.includes(PAGE_CLASS)) {
1294
- return true;
1295
- }
1296
- if (this.targetList.length === 0 && this.core.selectedDom) {
1297
- selectedDomMode = getMode(this.core.selectedDom);
1298
- } else if (this.targetList.length > 0) {
1299
- selectedDomMode = getMode(this.targetList[0]);
1300
- }
1301
- if (currentTargetMode !== selectedDomMode) {
1302
- return false;
1303
- }
1304
- return true;
1305
- }
1306
- clearSelectStatus() {
1307
- if (!this.moveableForMulti)
1308
- return;
1309
- this.destroyDragElList();
1310
- this.moveableForMulti.target = null;
1311
- this.moveableForMulti.updateTarget();
1312
- this.targetList = [];
1313
- }
1314
- destroy() {
1315
- this.moveableForMulti?.destroy();
1316
- this.destroyDragElList();
1317
- }
1318
- destroyDragElList() {
1319
- this.dragElList.forEach((dragElItem) => dragElItem?.remove());
1320
- }
1321
- update(isResize = false) {
1322
- if (this.targetList.length === 0)
1323
- return;
1324
- const { contentWindow } = this.core.renderer;
1325
- const doc = contentWindow?.document;
1326
- if (!doc)
1327
- return;
1328
- this.emit("update", {
1329
- data: this.targetList.map((targetItem) => {
1330
- const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop };
1331
- const left = calcValueByFontsize(doc, offset.left);
1332
- const top = calcValueByFontsize(doc, offset.top);
1333
- const width = calcValueByFontsize(doc, targetItem.clientWidth);
1334
- const height = calcValueByFontsize(doc, targetItem.clientHeight);
1335
- return {
1336
- el: targetItem,
1337
- style: isResize ? { left, top, width, height } : { left, top }
1338
- };
1339
- }),
1340
- parentEl: null
1341
- });
1342
- }
1343
- getOptions(options = {}) {
1344
- let { multiMoveableOptions = {} } = this.core.config;
1345
- if (typeof multiMoveableOptions === "function") {
1346
- multiMoveableOptions = multiMoveableOptions(this.core);
1347
- }
1348
- return {
1349
- defaultGroupRotate: 0,
1350
- defaultGroupOrigin: "50% 50%",
1351
- draggable: true,
1352
- resizable: true,
1353
- throttleDrag: 0,
1354
- startDragRotate: 0,
1355
- throttleDragRotate: 0,
1356
- zoom: 1,
1357
- origin: true,
1358
- padding: { left: 0, top: 0, right: 0, bottom: 0 },
1359
- snappable: true,
1360
- bounds: {
1361
- top: 0,
1362
- left: -1,
1363
- right: this.container.clientWidth - 1,
1364
- bottom: this.container.clientHeight,
1365
- ...multiMoveableOptions.bounds || {}
1366
- },
1367
- ...options,
1368
- ...multiMoveableOptions
1369
- };
1370
- }
1371
- }
1372
-
1373
- const style = ".tmagic-stage-container-highlight::after {\n content: '';\n position: absolute;\n width: 100%;\n height: 100%;\n top: 0;\n left: 0;\n background-color: #000;\n opacity: .1;\n pointer-events: none;\n}\n\n.magic-ui-container.magic-layout-relative {\n min-height: 50px;\n}\n";
1374
-
1375
- class StageRender extends EventEmitter {
1376
- contentWindow = null;
1377
- runtime = null;
1378
- iframe;
1379
- runtimeUrl;
1380
- core;
1381
- render;
1382
- constructor({ core }) {
1383
- super();
1384
- this.core = core;
1385
- this.runtimeUrl = core.config.runtimeUrl || "";
1386
- this.render = core.config.render;
1387
- this.iframe = globalThis.document.createElement("iframe");
1388
- this.iframe.src = isSameDomain(this.runtimeUrl) ? this.runtimeUrl : "";
1389
- this.iframe.style.cssText = `
1390
- border: 0;
1391
- width: 100%;
1392
- height: 100%;
1393
- `;
1394
- this.iframe.addEventListener("load", this.loadHandler);
1395
- }
1396
- getMagicApi = () => ({
1397
- onPageElUpdate: (el) => this.emit("page-el-update", el),
1398
- onRuntimeReady: (runtime) => {
1399
- this.runtime = runtime;
1400
- globalThis.runtime = runtime;
1401
- this.emit("runtime-ready", runtime);
1402
- }
1403
- });
1404
- async mount(el) {
1405
- if (!this.iframe) {
1406
- throw Error("mount \u5931\u8D25");
1407
- }
1408
- if (!isSameDomain(this.runtimeUrl) && this.runtimeUrl) {
1409
- let html = await fetch(this.runtimeUrl).then((res) => res.text());
1410
- const base = `${location.protocol}//${getHost(this.runtimeUrl)}`;
1411
- html = html.replace("<head>", `<head>
1412
- <base href="${base}">`);
1413
- this.iframe.srcdoc = html;
1414
- }
1415
- el.appendChild(this.iframe);
1416
- this.postTmagicRuntimeReady();
1417
- }
1418
- getRuntime = () => {
1419
- if (this.runtime)
1420
- return Promise.resolve(this.runtime);
1421
- return new Promise((resolve) => {
1422
- const listener = (runtime) => {
1423
- this.off("runtime-ready", listener);
1424
- resolve(runtime);
1425
- };
1426
- this.on("runtime-ready", listener);
1427
- });
1428
- };
1429
- destroy() {
1430
- this.iframe?.removeEventListener("load", this.loadHandler);
1431
- this.contentWindow = null;
1432
- this.iframe?.remove();
1433
- this.iframe = void 0;
1434
- this.removeAllListeners();
1435
- }
1436
- loadHandler = async () => {
1437
- if (!this.contentWindow?.magic) {
1438
- this.postTmagicRuntimeReady();
1439
- }
1440
- if (!this.contentWindow)
1441
- return;
1442
- if (this.render) {
1443
- const el = await this.render(this.core);
1444
- if (el) {
1445
- this.contentWindow.document?.body?.appendChild(el);
1446
- }
1447
- }
1448
- this.emit("onload");
1449
- injectStyle(this.contentWindow.document, style);
1450
- };
1451
- postTmagicRuntimeReady() {
1452
- this.contentWindow = this.iframe?.contentWindow;
1453
- this.contentWindow.magic = this.getMagicApi();
1454
- this.contentWindow.postMessage(
1455
- {
1456
- tmagicRuntimeReady: true
1457
- },
1458
- "*"
1459
- );
1460
- }
1461
- }
1462
-
1463
- class StageCore extends EventEmitter {
1464
- container;
1465
- selectedDom;
1466
- selectedDomList = [];
1467
- highlightedDom;
1468
- renderer;
1469
- mask;
1470
- dr;
1471
- multiDr;
1472
- highlightLayer;
1473
- config;
1474
- zoom = DEFAULT_ZOOM;
1475
- containerHighlightClassName;
1476
- containerHighlightDuration;
1477
- containerHighlightType;
1478
- isContainer;
1479
- canSelect;
1480
- constructor(config) {
1481
- super();
1482
- this.config = config;
1483
- this.setZoom(config.zoom);
1484
- this.canSelect = config.canSelect || ((el) => !!el.id);
1485
- this.isContainer = config.isContainer;
1486
- this.containerHighlightClassName = config.containerHighlightClassName || CONTAINER_HIGHLIGHT_CLASS;
1487
- this.containerHighlightDuration = config.containerHighlightDuration || 800;
1488
- this.containerHighlightType = config.containerHighlightType;
1489
- this.renderer = new StageRender({ core: this });
1490
- this.mask = new StageMask({ core: this });
1491
- this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
1492
- this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
1493
- this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
1494
- this.renderer.on("runtime-ready", (runtime) => {
1495
- this.emit("runtime-ready", runtime);
1496
- });
1497
- this.renderer.on("page-el-update", (el) => {
1498
- this.mask?.observe(el);
1499
- });
1500
- this.mask.on("beforeSelect", async (event) => {
1501
- this.clearSelectStatus("multiSelect");
1502
- const el = await this.getElementFromPoint(event);
1503
- if (!el)
1504
- return;
1505
- this.select(el, event);
1506
- }).on("select", () => {
1507
- this.emit("select", this.selectedDom);
1508
- }).on("changeGuides", (data) => {
1509
- this.dr.setGuidelines(data.type, data.guides);
1510
- this.emit("changeGuides", data);
1511
- }).on("highlight", async (event) => {
1512
- const el = await this.getElementFromPoint(event);
1513
- if (!el)
1514
- return;
1515
- if (this.multiDr.dragStatus === StageDragStatus.ING)
1516
- return;
1517
- await this.highlight(el);
1518
- if (this.highlightedDom === this.selectedDom) {
1519
- this.highlightLayer.clearHighlight();
1520
- return;
1521
- }
1522
- this.emit("highlight", this.highlightedDom);
1523
- }).on("clearHighlight", async () => {
1524
- this.highlightLayer.clearHighlight();
1525
- }).on("beforeMultiSelect", async (event) => {
1526
- const el = await this.getElementFromPoint(event);
1527
- if (!el)
1528
- return;
1529
- if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
1530
- this.selectedDomList.push(this.selectedDom);
1531
- this.selectedDom = void 0;
1532
- }
1533
- const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
1534
- if (existIndex !== -1) {
1535
- this.selectedDomList.splice(existIndex, 1);
1536
- } else {
1537
- this.selectedDomList.push(el);
1538
- }
1539
- this.multiSelect(this.selectedDomList);
1540
- });
1541
- this.dr.on("update", (data) => {
1542
- setTimeout(() => this.emit("update", data));
1543
- }).on("sort", (data) => {
1544
- setTimeout(() => this.emit("sort", data));
1545
- });
1546
- this.multiDr.on("update", (data) => {
1547
- setTimeout(() => this.emit("update", data));
1548
- }).on("select", async (id) => {
1549
- const el = await this.getTargetElement(id);
1550
- this.select(el);
1551
- setTimeout(() => this.emit("select", el));
1552
- });
1553
- }
1554
- getElementsFromPoint(event) {
1555
- const { renderer, zoom } = this;
1556
- const doc = renderer.contentWindow?.document;
1557
- let x = event.clientX;
1558
- let y = event.clientY;
1559
- if (renderer.iframe) {
1560
- const rect = renderer.iframe.getClientRects()[0];
1561
- if (rect) {
1562
- x = x - rect.left;
1563
- y = y - rect.top;
1564
- }
1565
- }
1566
- return doc?.elementsFromPoint(x / zoom, y / zoom);
1567
- }
1568
- async getElementFromPoint(event) {
1569
- const els = this.getElementsFromPoint(event);
1570
- let stopped = false;
1571
- const stop = () => stopped = true;
1572
- for (const el of els) {
1573
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isElCanSelect(el, event, stop)) {
1574
- if (stopped)
1575
- break;
1576
- return el;
1577
- }
1578
- }
1579
- }
1580
- async isElCanSelect(el, event, stop) {
1581
- const canSelectByProp = await this.canSelect(el, event, stop);
1582
- if (!canSelectByProp)
1583
- return false;
1584
- if (this.mask.isMultiSelectStatus) {
1585
- return this.multiDr.canSelect(el, stop);
1586
- }
1587
- return true;
1588
- }
1589
- async select(idOrEl, event) {
1590
- this.clearSelectStatus("multiSelect");
1591
- const el = await this.getTargetElement(idOrEl);
1592
- if (el === this.selectedDom)
1593
- return;
1594
- const runtime = await this.renderer.getRuntime();
1595
- await runtime?.select?.(el.id);
1596
- if (runtime?.beforeSelect) {
1597
- await runtime.beforeSelect(el);
1598
- }
1599
- this.mask.setLayout(el);
1600
- this.dr.select(el, event);
1601
- if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
1602
- this.mask.intersectionObserver?.observe(el);
1603
- }
1604
- this.selectedDom = el;
1605
- if (this.renderer.contentWindow) {
1606
- removeSelectedClassName(this.renderer.contentWindow.document);
1607
- if (this.selectedDom) {
1608
- addSelectedClassName(this.selectedDom, this.renderer.contentWindow.document);
1609
- }
1610
- }
1611
- }
1612
- async multiSelect(idOrElList) {
1613
- this.clearSelectStatus("select");
1614
- const elList = await Promise.all(idOrElList.map(async (idOrEl) => await this.getTargetElement(idOrEl)));
1615
- this.multiDr.multiSelect(elList);
1616
- this.emit("multiSelect", elList);
1617
- }
1618
- update(data) {
1619
- const { config } = data;
1620
- return this.renderer?.getRuntime().then((runtime) => {
1621
- runtime?.update?.(data);
1622
- setTimeout(() => {
1623
- const el = this.renderer.contentWindow?.document.getElementById(`${config.id}`);
1624
- if (el && el.id === this.selectedDom?.id) {
1625
- this.selectedDom = el;
1626
- this.mask.setLayout(el);
1627
- this.dr.updateMoveable(el);
1628
- }
1629
- }, 0);
1630
- });
1631
- }
1632
- async highlight(idOrEl) {
1633
- let el;
1634
- try {
1635
- el = await this.getTargetElement(idOrEl);
1636
- } catch (error) {
1637
- this.highlightLayer.clearHighlight();
1638
- return;
1639
- }
1640
- if (el === this.highlightedDom || !el)
1641
- return;
1642
- this.highlightLayer.highlight(el);
1643
- this.highlightedDom = el;
1644
- }
1645
- sortNode(data) {
1646
- return this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
1647
- }
1648
- add(data) {
1649
- return this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
1650
- }
1651
- remove(data) {
1652
- return this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
1653
- }
1654
- setZoom(zoom = DEFAULT_ZOOM) {
1655
- this.zoom = zoom;
1656
- }
1657
- clearSelectStatus(selectType) {
1658
- if (selectType === "multiSelect") {
1659
- this.multiDr.clearSelectStatus();
1660
- this.selectedDomList = [];
1661
- } else {
1662
- this.dr.clearSelectStatus();
1663
- }
1664
- }
1665
- async mount(el) {
1666
- this.container = el;
1667
- const { mask, renderer } = this;
1668
- await renderer.mount(el);
1669
- mask.mount(el);
1670
- this.emit("mounted");
1671
- }
1672
- clearGuides() {
1673
- this.mask.clearGuides();
1674
- this.dr.clearGuides();
1675
- }
1676
- async addContainerHighlightClassName(event, exclude) {
1677
- const els = this.getElementsFromPoint(event);
1678
- const { renderer } = this;
1679
- const doc = renderer.contentWindow?.document;
1680
- if (!doc)
1681
- return;
1682
- for (const el of els) {
1683
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isContainer(el) && !exclude.includes(el)) {
1684
- addClassName(el, doc, this.containerHighlightClassName);
1685
- break;
1686
- }
1687
- }
1688
- }
1689
- getAddContainerHighlightClassNameTimeout(event, exclude = []) {
1690
- return globalThis.setTimeout(() => {
1691
- this.addContainerHighlightClassName(event, exclude);
1692
- }, this.containerHighlightDuration);
1693
- }
1694
- destroy() {
1695
- const { mask, renderer, dr, highlightLayer } = this;
1696
- renderer.destroy();
1697
- mask.destroy();
1698
- dr.destroy();
1699
- highlightLayer.destroy();
1700
- this.removeAllListeners();
1701
- this.container = void 0;
1702
- }
1703
- async getTargetElement(idOrEl) {
1704
- if (typeof idOrEl === "string" || typeof idOrEl === "number") {
1705
- const el = this.renderer.contentWindow?.document.getElementById(`${idOrEl}`);
1706
- if (!el)
1707
- throw new Error(`\u4E0D\u5B58\u5728ID\u4E3A${idOrEl}\u7684\u5143\u7D20`);
1708
- return el;
1709
- }
1710
- return idOrEl;
1711
- }
1712
- }
1713
-
1714
- export { CONTAINER_HIGHLIGHT_CLASS, ContainerHighlightType, DEFAULT_ZOOM, DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, HIGHLIGHT_EL_ID_PREFIX, Mode, MouseButton, PAGE_CLASS, SELECTED_CLASS, StageDragResize, StageDragStatus, StageMask, StageRender, ZIndex, addSelectedClassName, calcValueByFontsize, StageCore as default, down, getAbsolutePosition, getMode, getOffset, getScrollParent, getTargetElStyle, isAbsolute, isFixed, isFixedParent, isRelative, isStatic, removeSelectedClassName, up };
1715
- //# sourceMappingURL=tmagic-stage.mjs.map