@tmagic/editor 1.0.6 → 1.1.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,16 @@
1
1
  import { defineComponent, computed, resolveComponent, openBlock, createBlock, normalizeStyle, ref, watchEffect, inject, markRaw, createElementBlock, createVNode, withCtx, withModifiers, createCommentVNode, createTextVNode, toDisplayString, watch, onMounted, onUnmounted, reactive, toRaw, createElementVNode, renderSlot, Fragment, normalizeClass, resolveDynamicComponent, renderList, normalizeProps, mergeProps, getCurrentInstance, nextTick, Teleport, toHandlers, createSlots, provide } from 'vue';
2
2
  import serialize from 'serialize-javascript';
3
- import { Delete, Pointer, Close, Plus, Edit, ArrowDown, Grid, ScaleToOriginal, ZoomOut, ZoomIn, Right, Back, Files, DocumentCopy, Coin, ArrowLeftBold, ArrowRightBold, CaretBottom, Top, Bottom } from '@element-plus/icons';
3
+ import { Delete, Pointer, Close, Plus, Edit, ArrowDown, Grid, ScaleToOriginal, ZoomOut, ZoomIn, Right, Back, Files, DocumentCopy, Coin, ArrowLeftBold, ArrowRightBold, CaretBottom, Top, Bottom } from '@element-plus/icons-vue';
4
4
  import { throttle, cloneDeep, mergeWith, random } from 'lodash-es';
5
5
  import * as monaco from 'monaco-editor';
6
+ import StageCore, { GHOST_EL_ID_PREFIX, GuidesType, getOffset, calcValueByFontsize, CONTAINER_HIGHLIGHT_CLASS } from '@tmagic/stage';
6
7
  import { NodeType } from '@tmagic/schema';
7
- import { toLine, isPop, getNodePath, isNumber, isPage } from '@tmagic/utils';
8
+ import { toLine, isPop, getNodePath, isNumber, isPage, removeClassNameByClassName, addClassName } from '@tmagic/utils';
8
9
  import { EventEmitter } from 'events';
9
10
  import { DEFAULT_EVENTS, DEFAULT_METHODS } from '@tmagic/core';
10
11
  import Gesto from 'gesto';
11
12
  import { ElMessage } from 'element-plus';
12
13
  import KeyController from 'keycon';
13
- import StageCore, { GuidesType } from '@tmagic/stage';
14
14
 
15
15
  if (typeof global === "undefined") {
16
16
  window.global = window;
@@ -750,56 +750,50 @@ const getNodeIndex = (node, parent) => {
750
750
  const items = parent?.items || [];
751
751
  return items.findIndex((item) => `${item.id}` === `${node.id}`);
752
752
  };
753
- const toRelative = (node) => {
754
- node.style = {
755
- ...node.style || {},
756
- position: "relative",
757
- top: 0,
758
- left: 0
759
- };
760
- return node;
761
- };
762
- const setTop2Middle = (node, parentNode, stage) => {
763
- const style = node.style || {};
753
+ const getRelativeStyle = (style = {}) => ({
754
+ ...style,
755
+ position: "relative",
756
+ top: 0,
757
+ left: 0
758
+ });
759
+ const getMiddleTop = (style = {}, parentNode, stage) => {
764
760
  let height = style.height || 0;
765
761
  if (!stage || typeof style.top !== "undefined" || !parentNode.style)
766
- return style;
762
+ return style.top;
767
763
  if (!isNumber(height)) {
768
764
  height = 0;
769
765
  }
770
766
  const { height: parentHeight } = parentNode.style;
771
767
  if (isPage(parentNode)) {
772
768
  const { scrollTop = 0, wrapperHeight } = stage.mask;
773
- style.top = (wrapperHeight - height) / 2 + scrollTop;
774
- } else {
775
- style.top = (parentHeight - height) / 2;
769
+ return (wrapperHeight - height) / 2 + scrollTop;
776
770
  }
777
- return style;
771
+ return (parentHeight - height) / 2;
778
772
  };
779
- const initPosition = (node, layout, parentNode, stage) => {
773
+ const getInitPositionStyle = (style = {}, layout, parentNode, stage) => {
780
774
  if (layout === Layout.ABSOLUTE) {
781
- node.style = {
775
+ return {
776
+ ...style,
782
777
  position: "absolute",
783
- ...setTop2Middle(node, parentNode, stage)
778
+ top: getMiddleTop(style, parentNode, stage)
784
779
  };
785
- return node;
786
780
  }
787
781
  if (layout === Layout.RELATIVE) {
788
- return toRelative(node);
782
+ return getRelativeStyle(style);
789
783
  }
790
- return node;
784
+ return style;
791
785
  };
792
786
  const setLayout = (node, layout) => {
793
787
  node.items?.forEach((child) => {
794
788
  if (isPop(child))
795
789
  return;
796
- child.style = child.style || {};
797
- if (child.style.position === "fixed")
790
+ const style = child.style || {};
791
+ if (style.position === "fixed")
798
792
  return;
799
793
  if (layout !== Layout.RELATIVE) {
800
- child.style.position = "absolute";
794
+ style.position = "absolute";
801
795
  } else {
802
- toRelative(child);
796
+ child.style = getRelativeStyle(style);
803
797
  child.style.right = "auto";
804
798
  child.style.bottom = "auto";
805
799
  }
@@ -816,11 +810,10 @@ const change2Fixed = (node, root) => {
816
810
  offset.left = offset.left + globalThis.parseFloat(value.style?.left || 0);
817
811
  offset.top = offset.top + globalThis.parseFloat(value.style?.top || 0);
818
812
  });
819
- node.style = {
813
+ return {
820
814
  ...node.style || {},
821
815
  ...offset
822
816
  };
823
- return node;
824
817
  };
825
818
  const Fixed2Other = async (node, root, getLayout) => {
826
819
  const path = getNodePath(node.id, root.items);
@@ -835,20 +828,20 @@ const Fixed2Other = async (node, root, getLayout) => {
835
828
  offset.left = offset.left - globalThis.parseFloat(value.style?.left || 0);
836
829
  offset.top = offset.top - globalThis.parseFloat(value.style?.top || 0);
837
830
  });
831
+ const style = node.style || {};
838
832
  const parent = path.pop();
839
833
  if (!parent) {
840
- return toRelative(node);
834
+ return getRelativeStyle(style);
841
835
  }
842
836
  const layout = await getLayout(parent);
843
837
  if (layout !== Layout.RELATIVE) {
844
- node.style = {
845
- ...node.style || {},
838
+ return {
839
+ ...style,
846
840
  ...offset,
847
841
  position: "absolute"
848
842
  };
849
- return node;
850
843
  }
851
- return toRelative(node);
844
+ return getRelativeStyle(style);
852
845
  };
853
846
  const getGuideLineFromCache = (key) => {
854
847
  if (!key)
@@ -863,6 +856,16 @@ const getGuideLineFromCache = (key) => {
863
856
  }
864
857
  return [];
865
858
  };
859
+ const fixNodeLeft = (config, parent, doc) => {
860
+ if (!doc || !config.style || !isNumber(config.style.left))
861
+ return config.style?.left;
862
+ const el = doc.getElementById(`${config.id}`);
863
+ const parentEl = doc.getElementById(`${parent.id}`);
864
+ if (el && parentEl && el.offsetWidth + config.style?.left > parentEl.offsetWidth) {
865
+ return parentEl.offsetWidth - el.offsetWidth;
866
+ }
867
+ return config.style.left;
868
+ };
866
869
 
867
870
  const log = (...args) => {
868
871
  };
@@ -888,6 +891,7 @@ class Editor$1 extends BaseService {
888
891
  "paste",
889
892
  "alignCenter",
890
893
  "moveLayer",
894
+ "moveToContainer",
891
895
  "move",
892
896
  "undo",
893
897
  "redo",
@@ -1027,13 +1031,22 @@ class Editor$1 extends BaseService {
1027
1031
  if (!parentNode)
1028
1032
  throw new Error("\u672A\u627E\u5230\u7236\u5143\u7D20");
1029
1033
  const layout = await this.getLayout(toRaw(parentNode), addNode);
1030
- const newNode = initPosition({ ...toRaw(await propsService.getPropsValue(type, config2)) }, layout, parentNode, this.get("stage"));
1034
+ const newNode = { ...toRaw(await propsService.getPropsValue(type, config2)) };
1035
+ newNode.style = getInitPositionStyle(newNode.style, layout, parentNode, this.get("stage"));
1031
1036
  if ((parentNode?.type === NodeType.ROOT || curNode.type === NodeType.ROOT) && newNode.type !== NodeType.PAGE) {
1032
1037
  throw new Error("app\u4E0B\u4E0D\u80FD\u6DFB\u52A0\u7EC4\u4EF6");
1033
1038
  }
1034
1039
  parentNode?.items?.push(newNode);
1035
1040
  const stage = this.get("stage");
1036
- await stage?.add({ config: cloneDeep(newNode), root: cloneDeep(this.get("root")) });
1041
+ const root = this.get("root");
1042
+ await stage?.add({ config: cloneDeep(newNode), root: cloneDeep(root) });
1043
+ if (layout === Layout.ABSOLUTE) {
1044
+ const fixedLeft = fixNodeLeft(newNode, parentNode, stage?.renderer.contentWindow?.document);
1045
+ if (typeof fixedLeft !== "undefined") {
1046
+ newNode.style.left = fixedLeft;
1047
+ await stage?.update({ config: cloneDeep(newNode), root: cloneDeep(root) });
1048
+ }
1049
+ }
1037
1050
  await this.select(newNode);
1038
1051
  this.addModifiedNodeId(newNode.id);
1039
1052
  if (!isPage2) {
@@ -1060,7 +1073,7 @@ class Editor$1 extends BaseService {
1060
1073
  throw new Error("\u627E\u4E0D\u8981\u5220\u9664\u7684\u8282\u70B9");
1061
1074
  parent.items?.splice(index, 1);
1062
1075
  const stage = this.get("stage");
1063
- stage?.remove({ id: node.id, root: this.get("root") });
1076
+ stage?.remove({ id: node.id, root: cloneDeep(this.get("root")) });
1064
1077
  if (node.type === NodeType.PAGE) {
1065
1078
  this.state.pageLength -= 1;
1066
1079
  if (root.items[0]) {
@@ -1121,7 +1134,7 @@ class Editor$1 extends BaseService {
1121
1134
  if (`${newConfig.id}` === `${this.get("node").id}`) {
1122
1135
  this.set("node", newConfig);
1123
1136
  }
1124
- this.get("stage")?.update({ config: cloneDeep(newConfig), root: this.get("root") });
1137
+ this.get("stage")?.update({ config: cloneDeep(newConfig), root: cloneDeep(this.get("root")) });
1125
1138
  if (newConfig.type === NodeType.PAGE) {
1126
1139
  this.set("page", newConfig);
1127
1140
  }
@@ -1140,7 +1153,7 @@ class Editor$1 extends BaseService {
1140
1153
  parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
1141
1154
  await this.update(parent);
1142
1155
  await this.select(node);
1143
- this.get("stage")?.update({ config: cloneDeep(node), root: this.get("root") });
1156
+ this.get("stage")?.update({ config: cloneDeep(node), root: cloneDeep(this.get("root")) });
1144
1157
  this.addModifiedNodeId(parent.id);
1145
1158
  this.pushHistoryState();
1146
1159
  }
@@ -1192,7 +1205,10 @@ class Editor$1 extends BaseService {
1192
1205
  node.style.left = (parent.style.width - node.style.width) / 2;
1193
1206
  }
1194
1207
  await this.update(node);
1195
- this.get("stage")?.update({ config: cloneDeep(toRaw(node)), root: this.get("root") });
1208
+ this.get("stage")?.update({
1209
+ config: cloneDeep(toRaw(node)),
1210
+ root: cloneDeep(this.get("root"))
1211
+ });
1196
1212
  this.addModifiedNodeId(config2.id);
1197
1213
  this.pushHistoryState();
1198
1214
  return config2;
@@ -1209,7 +1225,37 @@ class Editor$1 extends BaseService {
1209
1225
  } else {
1210
1226
  brothers.splice(index + parseInt(`${offset}`, 10), 0, brothers.splice(index, 1)[0]);
1211
1227
  }
1212
- this.get("stage")?.update({ config: cloneDeep(toRaw(parent)), root: this.get("root") });
1228
+ this.get("stage")?.update({
1229
+ config: cloneDeep(toRaw(parent)),
1230
+ root: cloneDeep(this.get("root"))
1231
+ });
1232
+ }
1233
+ async moveToContainer(config2, targetId) {
1234
+ const { node, parent } = this.getNodeInfo(config2.id, false);
1235
+ const target = this.getNodeById(targetId, false);
1236
+ const stage = this.get("stage");
1237
+ if (node && parent && stage) {
1238
+ const root = cloneDeep(this.get("root"));
1239
+ const index = getNodeIndex(node, parent);
1240
+ parent.items?.splice(index, 1);
1241
+ await stage.remove({ id: node.id, root });
1242
+ const layout = await this.getLayout(target);
1243
+ const newConfig = mergeWith(cloneDeep(node), config2, (objValue, srcValue) => {
1244
+ if (Array.isArray(srcValue)) {
1245
+ return srcValue;
1246
+ }
1247
+ });
1248
+ newConfig.style = getInitPositionStyle(newConfig.style, layout, target, stage);
1249
+ target.items.push(newConfig);
1250
+ await stage.select(targetId);
1251
+ await stage.update({ config: cloneDeep(target), root });
1252
+ await this.select(newConfig);
1253
+ stage.select(newConfig.id);
1254
+ this.addModifiedNodeId(target.id);
1255
+ this.addModifiedNodeId(parent.id);
1256
+ this.pushHistoryState();
1257
+ return newConfig;
1258
+ }
1213
1259
  }
1214
1260
  async undo() {
1215
1261
  const value = historyService.undo();
@@ -1281,12 +1327,12 @@ class Editor$1 extends BaseService {
1281
1327
  }, 0);
1282
1328
  }
1283
1329
  async toggleFixedPosition(dist, src, root) {
1284
- let newConfig = cloneDeep(dist);
1330
+ const newConfig = cloneDeep(dist);
1285
1331
  if (!isPop(src) && newConfig.style?.position) {
1286
1332
  if (isFixed(newConfig) && !isFixed(src)) {
1287
- newConfig = change2Fixed(newConfig, root);
1333
+ newConfig.style = change2Fixed(newConfig, root);
1288
1334
  } else if (!isFixed(newConfig) && isFixed(src)) {
1289
- newConfig = await Fixed2Other(newConfig, root, this.getLayout);
1335
+ newConfig.style = await Fixed2Other(newConfig, root, this.getLayout);
1290
1336
  }
1291
1337
  }
1292
1338
  return newConfig;
@@ -2190,11 +2236,16 @@ const _sfc_main$b = defineComponent({
2190
2236
  setup() {
2191
2237
  const searchText = ref("");
2192
2238
  const services = inject("services");
2239
+ const stageOptions = inject("stageOptions");
2240
+ const stage = computed(() => services?.editorService.get("stage"));
2193
2241
  const list = computed(() => services?.componentListService.getList().map((group) => ({
2194
2242
  ...group,
2195
2243
  items: group.items.filter((item) => item.text.includes(searchText.value))
2196
2244
  })));
2197
2245
  const collapseValue = computed(() => Array(list.value?.length).fill(1).map((x, i) => i));
2246
+ let timeout;
2247
+ let clientX;
2248
+ let clientY;
2198
2249
  return {
2199
2250
  searchText,
2200
2251
  collapseValue,
@@ -2215,6 +2266,43 @@ const _sfc_main$b = defineComponent({
2215
2266
  ...data
2216
2267
  }).replace(/"(\w+)":\s/g, "$1: "));
2217
2268
  }
2269
+ },
2270
+ dragendHandler() {
2271
+ if (timeout) {
2272
+ globalThis.clearTimeout(timeout);
2273
+ timeout = void 0;
2274
+ }
2275
+ const doc = stage.value?.renderer.contentWindow?.document;
2276
+ if (doc && stageOptions) {
2277
+ removeClassNameByClassName(doc, stageOptions.containerHighlightClassName);
2278
+ }
2279
+ clientX = 0;
2280
+ clientY = 0;
2281
+ },
2282
+ dragHandler(e) {
2283
+ if (e.clientX !== clientX || e.clientY !== clientY) {
2284
+ clientX = e.clientX;
2285
+ clientY = e.clientY;
2286
+ if (timeout) {
2287
+ globalThis.clearTimeout(timeout);
2288
+ timeout = void 0;
2289
+ }
2290
+ return;
2291
+ }
2292
+ if (timeout)
2293
+ return;
2294
+ timeout = globalThis.setTimeout(async () => {
2295
+ if (!stageOptions || !stage.value)
2296
+ return;
2297
+ const doc = stage.value.renderer.contentWindow?.document;
2298
+ const els = stage.value.getElementsFromPoint(e);
2299
+ for (const el of els) {
2300
+ if (doc && !el.id.startsWith(GHOST_EL_ID_PREFIX) && await stageOptions.isContainer(el)) {
2301
+ addClassName(el, doc, stageOptions?.containerHighlightClassName);
2302
+ break;
2303
+ }
2304
+ }
2305
+ }, stageOptions?.containerHighlightDuration);
2218
2306
  }
2219
2307
  };
2220
2308
  }
@@ -2262,7 +2350,9 @@ function _sfc_render$b(_ctx, _cache, $props, $setup, $data, $options) {
2262
2350
  draggable: "true",
2263
2351
  key: item.type,
2264
2352
  onClick: ($event) => _ctx.appendComponent(item),
2265
- onDragstart: ($event) => _ctx.dragstartHandler(item, $event)
2353
+ onDragstart: ($event) => _ctx.dragstartHandler(item, $event),
2354
+ onDragend: _cache[1] || (_cache[1] = (...args) => _ctx.dragendHandler && _ctx.dragendHandler(...args)),
2355
+ onDrag: _cache[2] || (_cache[2] = (...args) => _ctx.dragHandler && _ctx.dragHandler(...args))
2266
2356
  }, [
2267
2357
  createVNode(_component_m_icon, {
2268
2358
  icon: item.icon
@@ -3471,6 +3561,9 @@ const _sfc_main$2 = defineComponent({
3471
3561
  runtimeUrl: stageOptions.runtimeUrl,
3472
3562
  zoom: zoom.value,
3473
3563
  autoScrollIntoView: stageOptions.autoScrollIntoView,
3564
+ isContainer: stageOptions.isContainer,
3565
+ containerHighlightClassName: stageOptions.containerHighlightClassName,
3566
+ containerHighlightDuration: stageOptions.containerHighlightDuration,
3474
3567
  canSelect: (el, event, stop) => {
3475
3568
  const elCanSelect = stageOptions.canSelect(el);
3476
3569
  if (uiSelectMode.value && elCanSelect && event.type === "mousedown") {
@@ -3495,6 +3588,10 @@ const _sfc_main$2 = defineComponent({
3495
3588
  services?.editorService.highlight(el.id);
3496
3589
  });
3497
3590
  stage?.on("update", (ev) => {
3591
+ if (ev.parentEl) {
3592
+ services?.editorService.moveToContainer({ id: ev.el.id, style: ev.style }, ev.parentEl.id);
3593
+ return;
3594
+ }
3498
3595
  services?.editorService.update({ id: ev.el.id, style: ev.style });
3499
3596
  });
3500
3597
  stage?.on("sort", (ev) => {
@@ -3566,20 +3663,38 @@ const _sfc_main$2 = defineComponent({
3566
3663
  },
3567
3664
  async dropHandler(e) {
3568
3665
  e.preventDefault();
3569
- if (e.dataTransfer && page.value && stageContainer.value && stage) {
3666
+ const doc = stage?.renderer.contentWindow?.document;
3667
+ const parentEl = doc?.querySelector(`.${stageOptions?.containerHighlightClassName}`);
3668
+ let parent = page.value;
3669
+ if (parentEl) {
3670
+ parent = services?.editorService.getNodeById(parentEl.id, false);
3671
+ }
3672
+ if (e.dataTransfer && parent && stageContainer.value && stage) {
3570
3673
  const config = eval(`(${e.dataTransfer.getData("data")})`);
3571
- const layout = await services?.editorService.getLayout(page.value);
3674
+ const layout = await services?.editorService.getLayout(parent);
3572
3675
  const containerRect = stageContainer.value.getBoundingClientRect();
3573
3676
  const { scrollTop, scrollLeft } = stage.mask;
3677
+ const { style = {} } = config;
3678
+ let top = 0;
3679
+ let left = 0;
3680
+ let position = "relative";
3574
3681
  if (layout === Layout.ABSOLUTE) {
3575
- config.style = {
3576
- ...config.style || {},
3577
- position: "absolute",
3578
- top: e.clientY - containerRect.top + scrollTop,
3579
- left: e.clientX - containerRect.left + scrollLeft
3580
- };
3682
+ position = "absolute";
3683
+ top = e.clientY - containerRect.top + scrollTop;
3684
+ left = e.clientX - containerRect.left + scrollLeft;
3685
+ if (parentEl && doc) {
3686
+ const { left: parentLeft, top: parentTop } = getOffset(parentEl);
3687
+ left = left - calcValueByFontsize(doc, parentLeft);
3688
+ top = top - calcValueByFontsize(doc, parentTop);
3689
+ }
3581
3690
  }
3582
- services?.editorService.add(config, page.value);
3691
+ config.style = {
3692
+ ...style,
3693
+ position,
3694
+ top,
3695
+ left
3696
+ };
3697
+ services?.editorService.add(config, parent);
3583
3698
  }
3584
3699
  }
3585
3700
  };
@@ -3940,6 +4055,18 @@ const _sfc_main = defineComponent({
3940
4055
  type: Function,
3941
4056
  default: (el) => Boolean(el.id)
3942
4057
  },
4058
+ isContainer: {
4059
+ type: Function,
4060
+ default: (el) => el.classList.contains("magic-ui-container")
4061
+ },
4062
+ containerHighlightClassName: {
4063
+ type: String,
4064
+ default: CONTAINER_HIGHLIGHT_CLASS
4065
+ },
4066
+ containerHighlightDuration: {
4067
+ type: Number,
4068
+ default: 800
4069
+ },
3943
4070
  stageRect: {
3944
4071
  type: [String, Object]
3945
4072
  },
@@ -4006,7 +4133,10 @@ const _sfc_main = defineComponent({
4006
4133
  render: props.render,
4007
4134
  moveableOptions: props.moveableOptions,
4008
4135
  canSelect: props.canSelect,
4009
- updateDragEl: props.updateDragEl
4136
+ updateDragEl: props.updateDragEl,
4137
+ isContainer: props.isContainer,
4138
+ containerHighlightClassName: props.containerHighlightClassName,
4139
+ containerHighlightDuration: props.containerHighlightDuration
4010
4140
  }));
4011
4141
  return services;
4012
4142
  }
@@ -4089,5 +4219,5 @@ var index = {
4089
4219
  }
4090
4220
  };
4091
4221
 
4092
- export { COPY_STORAGE_KEY, ComponentListPanel, DEFAULT_CONFIG, Fixed2Other, H_GUIDE_LINE_STORAGE_KEY, Keys, LayerOffset, LayerPanel, Layout, PropsPanel, CodeEditor as TMagicCodeEditor, Editor as TMagicEditor, ToolButton, V_GUIDE_LINE_STORAGE_KEY, change2Fixed, debug, index as default, editorService, error, eventsService, fillConfig, generatePageName, generatePageNameByApp, getConfig, getDefaultPropsValue, getGuideLineFromCache, getNodeIndex, getPageList, getPageNameList, historyService, info, initPosition, isFixed, log, propsService, setConfig, setLayout, toRelative, uiService, warn };
4222
+ export { COPY_STORAGE_KEY, ComponentListPanel, DEFAULT_CONFIG, Fixed2Other, H_GUIDE_LINE_STORAGE_KEY, Keys, LayerOffset, LayerPanel, Layout, PropsPanel, CodeEditor as TMagicCodeEditor, Editor as TMagicEditor, ToolButton, V_GUIDE_LINE_STORAGE_KEY, change2Fixed, debug, index as default, editorService, error, eventsService, fillConfig, fixNodeLeft, generatePageName, generatePageNameByApp, getConfig, getDefaultPropsValue, getGuideLineFromCache, getInitPositionStyle, getNodeIndex, getPageList, getPageNameList, getRelativeStyle, historyService, info, isFixed, log, propsService, setConfig, setLayout, uiService, warn };
4093
4223
  //# sourceMappingURL=tmagic-editor.es.js.map