@tmagic/stage 1.1.0-beta.2 → 1.1.0-beta.3

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,20 +1,22 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('moveable'), require('moveable-helper'), require('@tmagic/utils'), require('lodash-es'), require('@scena/guides')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'events', 'moveable', 'moveable-helper', '@tmagic/utils', 'lodash-es', '@scena/guides'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TMagicStage = {}, global.EventEmitter, global.Moveable, global.MoveableHelper, global.utils, global.lodashEs, global.Guides));
5
- })(this, (function (exports, EventEmitter, Moveable, MoveableHelper, utils, lodashEs, Guides) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('events'), require('@tmagic/utils'), require('moveable'), require('moveable-helper'), require('keycon'), require('lodash-es'), require('@scena/guides')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'events', '@tmagic/utils', 'moveable', 'moveable-helper', 'keycon', 'lodash-es', '@scena/guides'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.TMagicStage = {}, global.EventEmitter, global.utils, global.Moveable, global.MoveableHelper, global.KeyController, global.lodashEs, global.Guides));
5
+ })(this, (function (exports, EventEmitter, utils, Moveable, MoveableHelper, KeyController, 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
11
  var MoveableHelper__default = /*#__PURE__*/_interopDefaultLegacy(MoveableHelper);
12
+ var KeyController__default = /*#__PURE__*/_interopDefaultLegacy(KeyController);
12
13
  var Guides__default = /*#__PURE__*/_interopDefaultLegacy(Guides);
13
14
 
14
15
  const GHOST_EL_ID_PREFIX = "ghost_el_";
15
16
  const DRAG_EL_ID_PREFIX = "drag_el_";
16
17
  const HIGHLIGHT_EL_ID_PREFIX = "highlight_el_";
17
18
  const CONTAINER_HIGHLIGHT_CLASS = "tmagic-stage-container-highlight";
19
+ const PAGE_CLASS = "magic-ui-page";
18
20
  const DEFAULT_ZOOM = 1;
19
21
  var GuidesType = /* @__PURE__ */ ((GuidesType2) => {
20
22
  GuidesType2["HORIZONTAL"] = "horizontal";
@@ -67,6 +69,19 @@
67
69
  top
68
70
  };
69
71
  };
72
+ const getTargetElStyle = (el) => {
73
+ const offset = getOffset(el);
74
+ const { transform } = getComputedStyle(el);
75
+ return `
76
+ position: absolute;
77
+ transform: ${transform};
78
+ left: ${offset.left}px;
79
+ top: ${offset.top}px;
80
+ width: ${el.clientWidth}px;
81
+ height: ${el.clientHeight}px;
82
+ z-index: ${ZIndex.DRAG_EL};
83
+ `;
84
+ };
70
85
  const getAbsolutePosition = (el, { top, left }) => {
71
86
  const { offsetParent } = el;
72
87
  if (offsetParent) {
@@ -159,8 +174,7 @@
159
174
  this.dragStatus = "end" /* END */;
160
175
  this.core = config.core;
161
176
  this.container = config.container;
162
- this.dragEl = globalThis.document.createElement("div");
163
- this.container.append(this.dragEl);
177
+ this.mask = config.mask;
164
178
  }
165
179
  select(el, event) {
166
180
  const oldTarget = this.target;
@@ -211,6 +225,16 @@
211
225
  this.moveableOptions.verticalGuidelines = [];
212
226
  this.updateMoveable();
213
227
  }
228
+ clearSelectStatus() {
229
+ if (!this.moveable)
230
+ return;
231
+ this.destroyDragEl();
232
+ this.moveable.target = null;
233
+ this.moveable.updateTarget();
234
+ }
235
+ destroyDragEl() {
236
+ this.dragEl?.remove();
237
+ }
214
238
  destroy() {
215
239
  this.moveable?.destroy();
216
240
  this.destroyGhostEl();
@@ -224,7 +248,14 @@
224
248
  }
225
249
  this.mode = getMode(el);
226
250
  this.destroyGhostEl();
227
- this.updateDragEl(el);
251
+ this.destroyDragEl();
252
+ this.dragEl = globalThis.document.createElement("div");
253
+ this.container.append(this.dragEl);
254
+ this.dragEl.style.cssText = getTargetElStyle(el);
255
+ this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
256
+ if (typeof this.core.config.updateDragEl === "function") {
257
+ this.core.config.updateDragEl(this.dragEl, el);
258
+ }
228
259
  this.moveableOptions = this.getOptions({
229
260
  target: this.dragEl
230
261
  });
@@ -323,15 +354,7 @@
323
354
  globalThis.clearTimeout(timeout);
324
355
  timeout = void 0;
325
356
  }
326
- timeout = globalThis.setTimeout(async () => {
327
- const els = this.core.getElementsFromPoint(e.inputEvent);
328
- for (const el of els) {
329
- if (doc && !el.id.startsWith(GHOST_EL_ID_PREFIX) && el !== this.target && await this.core.isContainer(el)) {
330
- utils.addClassName(el, doc, this.core.containerHighlightClassName);
331
- break;
332
- }
333
- }
334
- }, this.core.containerHighlightDuration);
357
+ timeout = this.core.getAddContainerHighlightClassNameTimeout(e.inputEvent, [this.target]);
335
358
  this.dragStatus = "ing" /* ING */;
336
359
  if (this.ghostEl) {
337
360
  this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
@@ -462,6 +485,7 @@
462
485
  this.destroyGhostEl();
463
486
  }
464
487
  const ghostEl = el.cloneNode(true);
488
+ this.setGhostElChildrenId(ghostEl);
465
489
  const { top, left } = getAbsolutePosition(el, getOffset(el));
466
490
  ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
467
491
  ghostEl.style.zIndex = ZIndex.GHOST_EL;
@@ -472,30 +496,20 @@
472
496
  el.after(ghostEl);
473
497
  return ghostEl;
474
498
  }
499
+ setGhostElChildrenId(el) {
500
+ for (const child of el.children) {
501
+ if (child.id) {
502
+ child.id = `${GHOST_EL_ID_PREFIX}${child.id}`;
503
+ }
504
+ if (child.children.length) {
505
+ this.setGhostElChildrenId(child);
506
+ }
507
+ }
508
+ }
475
509
  destroyGhostEl() {
476
510
  this.ghostEl?.remove();
477
511
  this.ghostEl = void 0;
478
512
  }
479
- updateDragEl(el) {
480
- const offset = getOffset(el);
481
- const { transform } = getComputedStyle(el);
482
- this.dragEl.style.cssText = `
483
- position: absolute;
484
- transform: ${transform};
485
- left: ${offset.left}px;
486
- top: ${offset.top}px;
487
- width: ${el.clientWidth}px;
488
- height: ${el.clientHeight}px;
489
- z-index: ${ZIndex.DRAG_EL};
490
- `;
491
- this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
492
- if (typeof this.core.config.updateDragEl === "function") {
493
- this.core.config.updateDragEl(this.dragEl, el);
494
- }
495
- }
496
- destroyDragEl() {
497
- this.dragEl?.remove();
498
- }
499
513
  getOptions(options = {}) {
500
514
  if (!this.target)
501
515
  return {};
@@ -860,6 +874,7 @@
860
874
  this.maxScrollTop = 0;
861
875
  this.maxScrollLeft = 0;
862
876
  this.intersectionObserver = null;
877
+ this.shiftKeyDown = false;
863
878
  this.mode = Mode.ABSOLUTE;
864
879
  this.pageResizeObserver = null;
865
880
  this.wrapperResizeObserver = null;
@@ -872,12 +887,19 @@
872
887
  event.stopPropagation();
873
888
  if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT)
874
889
  return;
890
+ if (!this.shiftKeyDown && event.target.className.indexOf("moveable-area") !== -1) {
891
+ return;
892
+ }
875
893
  if (event.target.className.indexOf("moveable-control") !== -1) {
876
894
  return;
877
895
  }
878
896
  this.content.removeEventListener("mousemove", this.highlightHandler);
879
- this.emit("beforeSelect", event);
880
- globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
897
+ if (this.shiftKeyDown) {
898
+ this.emit("beforeMultiSelect", event);
899
+ } else {
900
+ this.emit("beforeSelect", event);
901
+ globalThis.document.addEventListener("mouseup", this.mouseUpHandler);
902
+ }
881
903
  };
882
904
  this.mouseUpHandler = () => {
883
905
  globalThis.document.removeEventListener("mouseup", this.mouseUpHandler);
@@ -912,6 +934,14 @@
912
934
  this.content.addEventListener("wheel", this.mouseWheelHandler);
913
935
  this.content.addEventListener("mousemove", this.highlightHandler);
914
936
  this.content.addEventListener("mouseleave", this.mouseLeaveHandler);
937
+ KeyController__default["default"].global.keydown("shift", (e) => {
938
+ e.inputEvent.preventDefault();
939
+ this.shiftKeyDown = true;
940
+ });
941
+ KeyController__default["default"].global.keyup("shift", (e) => {
942
+ e.inputEvent.preventDefault();
943
+ this.shiftKeyDown = false;
944
+ });
915
945
  }
916
946
  setMode(mode) {
917
947
  this.mode = mode;
@@ -1042,6 +1072,118 @@
1042
1072
  }
1043
1073
  }
1044
1074
 
1075
+ class StageMultiDragResize extends EventEmitter.EventEmitter {
1076
+ constructor(config) {
1077
+ super();
1078
+ this.targetList = [];
1079
+ this.dragElList = [];
1080
+ this.core = config.core;
1081
+ this.container = config.container;
1082
+ this.mask = config.mask;
1083
+ }
1084
+ multiSelect(els) {
1085
+ this.targetList = els;
1086
+ this.core.dr.destroyDragEl();
1087
+ this.destroyDragElList();
1088
+ this.dragElList = els.map((elItem) => {
1089
+ const dragElDiv = globalThis.document.createElement("div");
1090
+ this.container.append(dragElDiv);
1091
+ dragElDiv.style.cssText = getTargetElStyle(elItem);
1092
+ dragElDiv.id = `${DRAG_EL_ID_PREFIX}${elItem.id}`;
1093
+ if (typeof this.core.config.updateDragEl === "function") {
1094
+ this.core.config.updateDragEl(dragElDiv, elItem);
1095
+ }
1096
+ return dragElDiv;
1097
+ });
1098
+ this.moveableForMulti?.destroy();
1099
+ this.multiMoveableHelper?.clear();
1100
+ this.moveableForMulti = new Moveable__default["default"](this.container, {
1101
+ target: this.dragElList,
1102
+ defaultGroupRotate: 0,
1103
+ defaultGroupOrigin: "50% 50%",
1104
+ draggable: true,
1105
+ resizable: true,
1106
+ throttleDrag: 0,
1107
+ startDragRotate: 0,
1108
+ throttleDragRotate: 0,
1109
+ zoom: 1,
1110
+ origin: true,
1111
+ padding: { left: 0, top: 0, right: 0, bottom: 0 }
1112
+ });
1113
+ this.multiMoveableHelper = MoveableHelper__default["default"].create({
1114
+ useBeforeRender: true,
1115
+ useRender: false,
1116
+ createAuto: true
1117
+ });
1118
+ const frames = [];
1119
+ this.moveableForMulti.on("dragGroupStart", (params) => {
1120
+ const { events } = params;
1121
+ this.multiMoveableHelper?.onDragGroupStart(params);
1122
+ events.forEach((ev) => {
1123
+ const matchEventTarget = this.targetList.find((targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1124
+ if (!matchEventTarget)
1125
+ return;
1126
+ frames.push({
1127
+ left: matchEventTarget.offsetLeft,
1128
+ top: matchEventTarget.offsetTop,
1129
+ id: matchEventTarget.id
1130
+ });
1131
+ });
1132
+ }).on("dragGroup", (params) => {
1133
+ const { events } = params;
1134
+ events.forEach((ev) => {
1135
+ const frameSnapShot = frames.find((frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1136
+ if (!frameSnapShot)
1137
+ return;
1138
+ const targeEl = this.targetList.find((targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ""));
1139
+ if (!targeEl)
1140
+ return;
1141
+ const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
1142
+ if (!isParentIncluded) {
1143
+ targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
1144
+ targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
1145
+ }
1146
+ });
1147
+ this.multiMoveableHelper?.onDragGroup(params);
1148
+ }).on("dragGroupEnd", () => {
1149
+ this.update();
1150
+ });
1151
+ }
1152
+ clearSelectStatus() {
1153
+ if (!this.moveableForMulti)
1154
+ return;
1155
+ this.destroyDragElList();
1156
+ this.moveableForMulti.target = null;
1157
+ this.moveableForMulti.updateTarget();
1158
+ }
1159
+ destroy() {
1160
+ this.moveableForMulti?.destroy();
1161
+ this.destroyDragElList();
1162
+ }
1163
+ destroyDragElList() {
1164
+ this.dragElList.forEach((dragElItem) => dragElItem?.remove());
1165
+ }
1166
+ update(isResize = false) {
1167
+ if (this.targetList.length === 0)
1168
+ return;
1169
+ const { contentWindow } = this.core.renderer;
1170
+ const doc = contentWindow?.document;
1171
+ if (!doc)
1172
+ return;
1173
+ this.targetList.forEach((targetItem) => {
1174
+ const offset = { left: targetItem.offsetLeft, top: targetItem.offsetTop };
1175
+ const left = calcValueByFontsize(doc, offset.left);
1176
+ const top = calcValueByFontsize(doc, offset.top);
1177
+ const width = calcValueByFontsize(doc, targetItem.clientWidth);
1178
+ const height = calcValueByFontsize(doc, targetItem.clientHeight);
1179
+ this.emit("update", {
1180
+ el: targetItem,
1181
+ style: isResize ? { left, top, width, height } : { left, top }
1182
+ });
1183
+ });
1184
+ }
1185
+ }
1186
+
1045
1187
  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";
1046
1188
 
1047
1189
  class StageRender extends EventEmitter.EventEmitter {
@@ -1121,6 +1263,7 @@
1121
1263
  class StageCore extends EventEmitter.EventEmitter {
1122
1264
  constructor(config) {
1123
1265
  super();
1266
+ this.selectedDomList = [];
1124
1267
  this.zoom = DEFAULT_ZOOM;
1125
1268
  this.config = config;
1126
1269
  this.setZoom(config.zoom);
@@ -1130,7 +1273,8 @@
1130
1273
  this.containerHighlightDuration = config.containerHighlightDuration;
1131
1274
  this.renderer = new StageRender({ core: this });
1132
1275
  this.mask = new StageMask({ core: this });
1133
- this.dr = new StageDragResize({ core: this, container: this.mask.content });
1276
+ this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
1277
+ this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
1134
1278
  this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
1135
1279
  this.renderer.on("runtime-ready", (runtime) => {
1136
1280
  this.emit("runtime-ready", runtime);
@@ -1138,29 +1282,57 @@
1138
1282
  this.renderer.on("page-el-update", (el) => {
1139
1283
  this.mask?.observe(el);
1140
1284
  });
1141
- this.mask.on("beforeSelect", (event) => {
1142
- this.setElementFromPoint(event);
1285
+ this.mask.on("beforeSelect", async (event) => {
1286
+ this.clearSelectStatus("multiSelect");
1287
+ const el = await this.getElementFromPoint(event);
1288
+ if (!el)
1289
+ return;
1290
+ this.select(el, event);
1143
1291
  }).on("select", () => {
1144
1292
  this.emit("select", this.selectedDom);
1145
1293
  }).on("changeGuides", (data) => {
1146
1294
  this.dr.setGuidelines(data.type, data.guides);
1147
1295
  this.emit("changeGuides", data);
1148
1296
  }).on("highlight", async (event) => {
1149
- await this.setElementFromPoint(event);
1297
+ const el = await this.getElementFromPoint(event, "mousemove");
1298
+ if (!el)
1299
+ return;
1300
+ await this.highlight(el);
1150
1301
  if (this.highlightedDom === this.selectedDom) {
1151
1302
  this.highlightLayer.clearHighlight();
1152
1303
  return;
1153
1304
  }
1154
- this.highlightLayer.highlight(this.highlightedDom);
1155
1305
  this.emit("highlight", this.highlightedDom);
1156
1306
  }).on("clearHighlight", async () => {
1157
1307
  this.highlightLayer.clearHighlight();
1308
+ }).on("beforeMultiSelect", async (event) => {
1309
+ const el = await this.getElementFromPoint(event);
1310
+ if (!el)
1311
+ return;
1312
+ if (el.className.includes(PAGE_CLASS))
1313
+ return;
1314
+ this.clearSelectStatus("select");
1315
+ if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
1316
+ this.selectedDomList.push(this.selectedDom);
1317
+ this.selectedDom = void 0;
1318
+ }
1319
+ const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
1320
+ if (existIndex !== -1) {
1321
+ this.selectedDomList.splice(existIndex, 1);
1322
+ } else {
1323
+ this.selectedDomList.push(el);
1324
+ }
1325
+ this.multiDr.multiSelect(this.selectedDomList);
1326
+ this.emit("multiSelect", this.selectedDomList);
1158
1327
  });
1159
1328
  this.dr.on("update", (data) => {
1160
1329
  setTimeout(() => this.emit("update", data));
1161
1330
  }).on("sort", (data) => {
1162
1331
  setTimeout(() => this.emit("sort", data));
1163
1332
  });
1333
+ this.multiDr.on("update", (data) => {
1334
+ setTimeout(() => this.emit("update", data));
1335
+ });
1164
1336
  }
1165
1337
  getElementsFromPoint(event) {
1166
1338
  const { renderer, zoom } = this;
@@ -1176,7 +1348,7 @@
1176
1348
  }
1177
1349
  return doc?.elementsFromPoint(x / zoom, y / zoom);
1178
1350
  }
1179
- async setElementFromPoint(event) {
1351
+ async getElementFromPoint(event, type) {
1180
1352
  const els = this.getElementsFromPoint(event);
1181
1353
  let stopped = false;
1182
1354
  const stop = () => stopped = true;
@@ -1184,12 +1356,10 @@
1184
1356
  if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.canSelect(el, event, stop)) {
1185
1357
  if (stopped)
1186
1358
  break;
1187
- if (event.type === "mousemove") {
1188
- this.highlight(el);
1189
- break;
1359
+ if (event.type === type) {
1360
+ return el;
1190
1361
  }
1191
- this.select(el, event);
1192
- break;
1362
+ return el;
1193
1363
  }
1194
1364
  }
1195
1365
  }
@@ -1203,6 +1373,7 @@
1203
1373
  await runtime.beforeSelect(el);
1204
1374
  }
1205
1375
  this.mask.setLayout(el);
1376
+ this.multiDr.destroyDragElList();
1206
1377
  this.dr.select(el, event);
1207
1378
  if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
1208
1379
  this.mask.intersectionObserver?.observe(el);
@@ -1237,7 +1408,7 @@
1237
1408
  this.highlightLayer.clearHighlight();
1238
1409
  return;
1239
1410
  }
1240
- if (el === this.highlightedDom)
1411
+ if (el === this.highlightedDom || !el)
1241
1412
  return;
1242
1413
  this.highlightLayer.highlight(el);
1243
1414
  this.highlightedDom = el;
@@ -1254,6 +1425,14 @@
1254
1425
  setZoom(zoom = DEFAULT_ZOOM) {
1255
1426
  this.zoom = zoom;
1256
1427
  }
1428
+ clearSelectStatus(selectType) {
1429
+ if (selectType === "multiSelect") {
1430
+ this.multiDr.clearSelectStatus();
1431
+ this.selectedDomList = [];
1432
+ } else {
1433
+ this.dr.clearSelectStatus();
1434
+ }
1435
+ }
1257
1436
  async mount(el) {
1258
1437
  this.container = el;
1259
1438
  const { mask, renderer } = this;
@@ -1265,6 +1444,24 @@
1265
1444
  this.mask.clearGuides();
1266
1445
  this.dr.clearGuides();
1267
1446
  }
1447
+ async addContainerHighlightClassName(event, exclude) {
1448
+ const els = this.getElementsFromPoint(event);
1449
+ const { renderer } = this;
1450
+ const doc = renderer.contentWindow?.document;
1451
+ if (!doc)
1452
+ return;
1453
+ for (const el of els) {
1454
+ if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && await this.isContainer(el) && !exclude.includes(el)) {
1455
+ utils.addClassName(el, doc, this.containerHighlightClassName);
1456
+ break;
1457
+ }
1458
+ }
1459
+ }
1460
+ getAddContainerHighlightClassNameTimeout(event, exclude = []) {
1461
+ return globalThis.setTimeout(() => {
1462
+ this.addContainerHighlightClassName(event, exclude);
1463
+ }, this.containerHighlightDuration);
1464
+ }
1268
1465
  destroy() {
1269
1466
  const { mask, renderer, dr, highlightLayer } = this;
1270
1467
  renderer.destroy();
@@ -1293,6 +1490,7 @@
1293
1490
  exports.HIGHLIGHT_EL_ID_PREFIX = HIGHLIGHT_EL_ID_PREFIX;
1294
1491
  exports.Mode = Mode;
1295
1492
  exports.MouseButton = MouseButton;
1493
+ exports.PAGE_CLASS = PAGE_CLASS;
1296
1494
  exports.SELECTED_CLASS = SELECTED_CLASS;
1297
1495
  exports.StageDragResize = StageDragResize;
1298
1496
  exports.StageMask = StageMask;
@@ -1305,6 +1503,7 @@
1305
1503
  exports.getMode = getMode;
1306
1504
  exports.getOffset = getOffset;
1307
1505
  exports.getScrollParent = getScrollParent;
1506
+ exports.getTargetElStyle = getTargetElStyle;
1308
1507
  exports.isAbsolute = isAbsolute;
1309
1508
  exports.isFixed = isFixed;
1310
1509
  exports.isFixedParent = isFixedParent;