@tmagic/editor 1.7.14-beta.3 → 1.8.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -74,7 +74,7 @@ var FormPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defi
74
74
  createVNode(unref(TMagicScrollbar), null, {
75
75
  default: withCtx(() => [createVNode(unref(MForm), {
76
76
  ref: "configForm",
77
- class: normalizeClass(propsPanelSize.value),
77
+ class: normalizeClass([propsPanelSize.value, "m-editor-props-form-panel-form"]),
78
78
  "popper-class": `m-editor-props-panel-popper ${propsPanelSize.value}`,
79
79
  "label-width": __props.labelWidth,
80
80
  "label-position": __props.labelPosition,
@@ -121,6 +121,19 @@ var Editor = class extends BaseService_default {
121
121
  return parent;
122
122
  }
123
123
  /**
124
+ * 判断给定节点是否位于非当前页面(即选中该节点将会引起当前页面切换)
125
+ * @param node 节点
126
+ * @returns true 表示该节点位于非当前页面
127
+ */
128
+ isOnDifferentPage(node) {
129
+ const currentPageId = this.get("page")?.id;
130
+ if (currentPageId === void 0 || currentPageId === null) return false;
131
+ if (isPage(node) || isPageFragment(node)) return `${node.id}` !== `${currentPageId}`;
132
+ const nodePage = this.getNodeInfo(node.id, false).page;
133
+ if (!nodePage) return false;
134
+ return `${nodePage.id}` !== `${currentPageId}`;
135
+ }
136
+ /**
124
137
  * 只有容器拥有布局
125
138
  */
126
139
  async getLayout(parent, node) {
@@ -241,11 +254,12 @@ var Editor = class extends BaseService_default {
241
254
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
242
255
  * @param options 可选配置
243
256
  * @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
257
+ * @param options.doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作)
244
258
  * @returns 添加后的节点
245
259
  */
246
260
  async add(addNode, parent, options) {
247
261
  const safeParentNode = safeParent(parent);
248
- const { doNotSelect = false } = safeOptions(options);
262
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
249
263
  this.captureSelectionBeforeOp();
250
264
  const stage = this.get("stage");
251
265
  const addNodes = [];
@@ -262,16 +276,19 @@ var Editor = class extends BaseService_default {
262
276
  return this.doAdd(node, parentNode);
263
277
  }));
264
278
  if (newNodes.length > 1) {
265
- if (!doNotSelect) {
279
+ const wouldSwitchPage = newNodes.some((n) => this.isOnDifferentPage(n));
280
+ if (!doNotSelect && !(doNotSwitchPage && wouldSwitchPage)) {
266
281
  const newNodeIds = newNodes.map((node) => node.id);
267
282
  stage?.multiSelect(newNodeIds);
268
283
  await this.multiSelect(newNodeIds);
269
284
  }
270
285
  } else {
271
- if (!doNotSelect) await this.select(newNodes[0]);
286
+ const wouldSwitchPage = this.isOnDifferentPage(newNodes[0]);
287
+ const skipSelect = doNotSelect || doNotSwitchPage && wouldSwitchPage;
288
+ if (!skipSelect) await this.select(newNodes[0]);
272
289
  if (isPage(newNodes[0])) this.state.pageLength += 1;
273
290
  else if (isPageFragment(newNodes[0])) this.state.pageFragmentLength += 1;
274
- else if (!doNotSelect) stage?.select(newNodes[0].id);
291
+ else if (!skipSelect) stage?.select(newNodes[0].id);
275
292
  }
276
293
  if (!(isPage(newNodes[0]) || isPageFragment(newNodes[0]))) {
277
294
  const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
@@ -291,7 +308,7 @@ var Editor = class extends BaseService_default {
291
308
  return Array.isArray(addNode) ? newNodes : newNodes[0];
292
309
  }
293
310
  async doRemove(node, options) {
294
- const { doNotSelect = false } = safeOptions(options);
311
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
295
312
  const root = this.get("root");
296
313
  if (!root) throw new Error("root不能为空");
297
314
  const { parent, node: curNode } = this.getNodeInfo(node.id, false);
@@ -305,18 +322,16 @@ var Editor = class extends BaseService_default {
305
322
  parentId: parent.id,
306
323
  root: cloneDeep(root)
307
324
  });
308
- if (doNotSelect) {
309
- const selectedNodes = this.get("nodes");
310
- const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
311
- if (removedSelectedIndex !== -1) {
312
- const nextSelected = [...selectedNodes];
313
- nextSelected.splice(removedSelectedIndex, 1);
314
- this.set("nodes", nextSelected);
315
- }
316
- if (isPage(node) || isPageFragment(node)) {
317
- const currentPage = this.get("page");
318
- if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
319
- }
325
+ const selectedNodes = this.get("nodes");
326
+ const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
327
+ if (removedSelectedIndex !== -1) {
328
+ const nextSelected = [...selectedNodes];
329
+ nextSelected.splice(removedSelectedIndex, 1);
330
+ this.set("nodes", nextSelected);
331
+ }
332
+ if (isPage(node) || isPageFragment(node)) {
333
+ const currentPage = this.get("page");
334
+ if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
320
335
  }
321
336
  const selectDefault = async (pages) => {
322
337
  if (pages[0]) {
@@ -330,10 +345,10 @@ var Editor = class extends BaseService_default {
330
345
  const rootItems = root.items || [];
331
346
  if (isPage(node)) {
332
347
  this.state.pageLength -= 1;
333
- if (!doNotSelect) await selectDefault(rootItems);
348
+ if (!doNotSelect && !doNotSwitchPage) await selectDefault(rootItems);
334
349
  } else if (isPageFragment(node)) {
335
350
  this.state.pageFragmentLength -= 1;
336
- if (!doNotSelect) await selectDefault(rootItems);
351
+ if (!doNotSelect && !doNotSwitchPage) await selectDefault(rootItems);
337
352
  } else {
338
353
  if (!doNotSelect) {
339
354
  await this.select(parent);
@@ -351,9 +366,10 @@ var Editor = class extends BaseService_default {
351
366
  * @param {Object} node 要删除的节点或节点集合
352
367
  * @param options 可选配置
353
368
  * @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
369
+ * @param options.doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
354
370
  */
355
371
  async remove(nodeOrNodeList, options) {
356
- const { doNotSelect = false } = safeOptions(options);
372
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
357
373
  this.captureSelectionBeforeOp();
358
374
  const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
359
375
  const removedItems = [];
@@ -373,7 +389,10 @@ var Editor = class extends BaseService_default {
373
389
  });
374
390
  }
375
391
  }
376
- await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
392
+ await Promise.all(nodes.map((node) => this.doRemove(node, {
393
+ doNotSelect,
394
+ doNotSwitchPage
395
+ })));
377
396
  if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
378
397
  this.emit("remove", nodes);
379
398
  }
@@ -410,7 +429,10 @@ var Editor = class extends BaseService_default {
410
429
  selectedNodes.splice(targetIndex, 1, newConfig);
411
430
  this.set("nodes", [...selectedNodes]);
412
431
  }
413
- if (isPage(newConfig) || isPageFragment(newConfig)) this.set("page", newConfig);
432
+ if (isPage(newConfig) || isPageFragment(newConfig)) {
433
+ const currentPage = this.get("page");
434
+ if (currentPage && `${currentPage.id}` === `${newConfig.id}`) this.set("page", newConfig);
435
+ }
414
436
  this.addModifiedNodeId(newConfig.id);
415
437
  return {
416
438
  oldNode: node,
@@ -451,6 +473,7 @@ var Editor = class extends BaseService_default {
451
473
  * @param id2 组件ID
452
474
  * @param options 可选配置
453
475
  * @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
476
+ * @param options.doNotSwitchPage 排序后是否不切换当前页面(排序只发生在同一父节点内,方法内为空操作;保留以与其它 DSL 操作 API 一致)
454
477
  * @returns void
455
478
  */
456
479
  async sort(id1, id2, options) {
@@ -498,10 +521,11 @@ var Editor = class extends BaseService_default {
498
521
  * @param collectorOptions 可选的依赖收集器配置
499
522
  * @param options 可选配置
500
523
  * @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
524
+ * @param options.doNotSwitchPage 粘贴后是否不切换当前页面(默认 false;跨页粘贴时为 true 会跳过页面切换)
501
525
  * @returns 添加后的组件节点配置
502
526
  */
503
527
  async paste(position = {}, collectorOptions, options) {
504
- const { doNotSelect = false } = safeOptions(options);
528
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
505
529
  const config = storage_default.getItem(COPY_STORAGE_KEY);
506
530
  if (!Array.isArray(config)) return;
507
531
  const node = this.get("node");
@@ -512,7 +536,10 @@ var Editor = class extends BaseService_default {
512
536
  }
513
537
  const pasteConfigs = await this.doPaste(config, position);
514
538
  if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
515
- return this.add(pasteConfigs, parent, { doNotSelect });
539
+ return this.add(pasteConfigs, parent, {
540
+ doNotSelect,
541
+ doNotSwitchPage
542
+ });
516
543
  }
517
544
  async doPaste(config, position = {}) {
518
545
  props_default.clearRelateId();
@@ -535,6 +562,7 @@ var Editor = class extends BaseService_default {
535
562
  * @param config 组件节点配置
536
563
  * @param options 可选配置
537
564
  * @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
565
+ * @param options.doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致)
538
566
  * @returns 当前组件节点配置
539
567
  */
540
568
  async alignCenter(config, options) {
@@ -590,9 +618,10 @@ var Editor = class extends BaseService_default {
590
618
  * @param targetId 容器ID
591
619
  * @param options 可选配置
592
620
  * @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
621
+ * @param options.doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换)
593
622
  */
594
623
  async moveToContainer(config, targetId, options) {
595
- const { doNotSelect = false } = safeOptions(options);
624
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
596
625
  this.captureSelectionBeforeOp();
597
626
  const root = this.get("root");
598
627
  const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
@@ -614,14 +643,16 @@ var Editor = class extends BaseService_default {
614
643
  });
615
644
  newConfig.style = getInitPositionStyle(newConfig.style, layout);
616
645
  target.items.push(newConfig);
617
- if (!doNotSelect) await stage.select(targetId);
646
+ const targetWouldSwitchPage = this.isOnDifferentPage(target);
647
+ const skipSelect = doNotSelect || doNotSwitchPage && targetWouldSwitchPage;
648
+ if (!skipSelect) await stage.select(targetId);
618
649
  const targetParent = this.getParentById(target.id);
619
650
  await stage.update({
620
651
  config: cloneDeep(target),
621
652
  parentId: targetParent?.id,
622
653
  root: cloneDeep(root)
623
654
  });
624
- if (!doNotSelect) {
655
+ if (!skipSelect) {
625
656
  await this.select(newConfig);
626
657
  stage.select(newConfig.id);
627
658
  }
package/dist/es/style.css CHANGED
@@ -1048,20 +1048,6 @@ fieldset.m-fieldset .m-form-tip {
1048
1048
  .m-editor-props-panel .m-editor-props-property-panel.show-style-panel .m-editor-props-panel-src-icon {
1049
1049
  right: calc(15px + var(--props-style-panel-width));
1050
1050
  }
1051
- .m-editor-props-panel .m-editor-props-property-panel .tmagic-design-form {
1052
- padding-right: 10px;
1053
- padding-left: 10px;
1054
- }
1055
- .m-editor-props-panel .m-editor-props-property-panel .tmagic-design-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__content {
1056
- padding-top: 55px;
1057
- }
1058
- .m-editor-props-panel .m-editor-props-property-panel .tmagic-design-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__header.is-top {
1059
- position: absolute;
1060
- top: 0;
1061
- width: 100%;
1062
- background: #fff;
1063
- z-index: 3;
1064
- }
1065
1051
  .m-editor-props-panel .m-editor-props-style-panel {
1066
1052
  position: absolute;
1067
1053
  width: var(--props-style-panel-width);
@@ -1133,6 +1119,21 @@ fieldset.m-fieldset .m-form-tip {
1133
1119
  font-size: 12px;
1134
1120
  }
1135
1121
 
1122
+ .m-editor-props-form-panel-form {
1123
+ padding-right: 10px;
1124
+ padding-left: 10px;
1125
+ }
1126
+ .m-editor-props-form-panel-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__content {
1127
+ padding-top: 55px;
1128
+ }
1129
+ .m-editor-props-form-panel-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__header.is-top {
1130
+ position: absolute;
1131
+ top: 0;
1132
+ width: 100%;
1133
+ background: #fff;
1134
+ z-index: 3;
1135
+ }
1136
+
1136
1137
  .m-editor-props-panel-popper.small span,
1137
1138
  .m-editor-props-panel-popper.small a,
1138
1139
  .m-editor-props-panel-popper.small p {
package/dist/style.css CHANGED
@@ -1048,20 +1048,6 @@ fieldset.m-fieldset .m-form-tip {
1048
1048
  .m-editor-props-panel .m-editor-props-property-panel.show-style-panel .m-editor-props-panel-src-icon {
1049
1049
  right: calc(15px + var(--props-style-panel-width));
1050
1050
  }
1051
- .m-editor-props-panel .m-editor-props-property-panel .tmagic-design-form {
1052
- padding-right: 10px;
1053
- padding-left: 10px;
1054
- }
1055
- .m-editor-props-panel .m-editor-props-property-panel .tmagic-design-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__content {
1056
- padding-top: 55px;
1057
- }
1058
- .m-editor-props-panel .m-editor-props-property-panel .tmagic-design-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__header.is-top {
1059
- position: absolute;
1060
- top: 0;
1061
- width: 100%;
1062
- background: #fff;
1063
- z-index: 3;
1064
- }
1065
1051
  .m-editor-props-panel .m-editor-props-style-panel {
1066
1052
  position: absolute;
1067
1053
  width: var(--props-style-panel-width);
@@ -1133,6 +1119,21 @@ fieldset.m-fieldset .m-form-tip {
1133
1119
  font-size: 12px;
1134
1120
  }
1135
1121
 
1122
+ .m-editor-props-form-panel-form {
1123
+ padding-right: 10px;
1124
+ padding-left: 10px;
1125
+ }
1126
+ .m-editor-props-form-panel-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__content {
1127
+ padding-top: 55px;
1128
+ }
1129
+ .m-editor-props-form-panel-form > .m-container-tab > .tmagic-design-tabs > .el-tabs__header.is-top {
1130
+ position: absolute;
1131
+ top: 0;
1132
+ width: 100%;
1133
+ background: #fff;
1134
+ z-index: 3;
1135
+ }
1136
+
1136
1137
  .m-editor-props-panel-popper.small span,
1137
1138
  .m-editor-props-panel-popper.small a,
1138
1139
  .m-editor-props-panel-popper.small p {
@@ -5902,6 +5902,19 @@
5902
5902
  return parent;
5903
5903
  }
5904
5904
  /**
5905
+ * 判断给定节点是否位于非当前页面(即选中该节点将会引起当前页面切换)
5906
+ * @param node 节点
5907
+ * @returns true 表示该节点位于非当前页面
5908
+ */
5909
+ isOnDifferentPage(node) {
5910
+ const currentPageId = this.get("page")?.id;
5911
+ if (currentPageId === void 0 || currentPageId === null) return false;
5912
+ if ((0, _tmagic_utils.isPage)(node) || (0, _tmagic_utils.isPageFragment)(node)) return `${node.id}` !== `${currentPageId}`;
5913
+ const nodePage = this.getNodeInfo(node.id, false).page;
5914
+ if (!nodePage) return false;
5915
+ return `${nodePage.id}` !== `${currentPageId}`;
5916
+ }
5917
+ /**
5905
5918
  * 只有容器拥有布局
5906
5919
  */
5907
5920
  async getLayout(parent, node) {
@@ -6022,11 +6035,12 @@
6022
6035
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
6023
6036
  * @param options 可选配置
6024
6037
  * @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
6038
+ * @param options.doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作)
6025
6039
  * @returns 添加后的节点
6026
6040
  */
6027
6041
  async add(addNode, parent, options) {
6028
6042
  const safeParentNode = safeParent(parent);
6029
- const { doNotSelect = false } = safeOptions(options);
6043
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6030
6044
  this.captureSelectionBeforeOp();
6031
6045
  const stage = this.get("stage");
6032
6046
  const addNodes = [];
@@ -6043,16 +6057,19 @@
6043
6057
  return this.doAdd(node, parentNode);
6044
6058
  }));
6045
6059
  if (newNodes.length > 1) {
6046
- if (!doNotSelect) {
6060
+ const wouldSwitchPage = newNodes.some((n) => this.isOnDifferentPage(n));
6061
+ if (!doNotSelect && !(doNotSwitchPage && wouldSwitchPage)) {
6047
6062
  const newNodeIds = newNodes.map((node) => node.id);
6048
6063
  stage?.multiSelect(newNodeIds);
6049
6064
  await this.multiSelect(newNodeIds);
6050
6065
  }
6051
6066
  } else {
6052
- if (!doNotSelect) await this.select(newNodes[0]);
6067
+ const wouldSwitchPage = this.isOnDifferentPage(newNodes[0]);
6068
+ const skipSelect = doNotSelect || doNotSwitchPage && wouldSwitchPage;
6069
+ if (!skipSelect) await this.select(newNodes[0]);
6053
6070
  if ((0, _tmagic_utils.isPage)(newNodes[0])) this.state.pageLength += 1;
6054
6071
  else if ((0, _tmagic_utils.isPageFragment)(newNodes[0])) this.state.pageFragmentLength += 1;
6055
- else if (!doNotSelect) stage?.select(newNodes[0].id);
6072
+ else if (!skipSelect) stage?.select(newNodes[0].id);
6056
6073
  }
6057
6074
  if (!((0, _tmagic_utils.isPage)(newNodes[0]) || (0, _tmagic_utils.isPageFragment)(newNodes[0]))) {
6058
6075
  const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
@@ -6072,7 +6089,7 @@
6072
6089
  return Array.isArray(addNode) ? newNodes : newNodes[0];
6073
6090
  }
6074
6091
  async doRemove(node, options) {
6075
- const { doNotSelect = false } = safeOptions(options);
6092
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6076
6093
  const root = this.get("root");
6077
6094
  if (!root) throw new Error("root不能为空");
6078
6095
  const { parent, node: curNode } = this.getNodeInfo(node.id, false);
@@ -6086,18 +6103,16 @@
6086
6103
  parentId: parent.id,
6087
6104
  root: cloneDeep(root)
6088
6105
  });
6089
- if (doNotSelect) {
6090
- const selectedNodes = this.get("nodes");
6091
- const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
6092
- if (removedSelectedIndex !== -1) {
6093
- const nextSelected = [...selectedNodes];
6094
- nextSelected.splice(removedSelectedIndex, 1);
6095
- this.set("nodes", nextSelected);
6096
- }
6097
- if ((0, _tmagic_utils.isPage)(node) || (0, _tmagic_utils.isPageFragment)(node)) {
6098
- const currentPage = this.get("page");
6099
- if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
6100
- }
6106
+ const selectedNodes = this.get("nodes");
6107
+ const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
6108
+ if (removedSelectedIndex !== -1) {
6109
+ const nextSelected = [...selectedNodes];
6110
+ nextSelected.splice(removedSelectedIndex, 1);
6111
+ this.set("nodes", nextSelected);
6112
+ }
6113
+ if ((0, _tmagic_utils.isPage)(node) || (0, _tmagic_utils.isPageFragment)(node)) {
6114
+ const currentPage = this.get("page");
6115
+ if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
6101
6116
  }
6102
6117
  const selectDefault = async (pages) => {
6103
6118
  if (pages[0]) {
@@ -6111,10 +6126,10 @@
6111
6126
  const rootItems = root.items || [];
6112
6127
  if ((0, _tmagic_utils.isPage)(node)) {
6113
6128
  this.state.pageLength -= 1;
6114
- if (!doNotSelect) await selectDefault(rootItems);
6129
+ if (!doNotSelect && !doNotSwitchPage) await selectDefault(rootItems);
6115
6130
  } else if ((0, _tmagic_utils.isPageFragment)(node)) {
6116
6131
  this.state.pageFragmentLength -= 1;
6117
- if (!doNotSelect) await selectDefault(rootItems);
6132
+ if (!doNotSelect && !doNotSwitchPage) await selectDefault(rootItems);
6118
6133
  } else {
6119
6134
  if (!doNotSelect) {
6120
6135
  await this.select(parent);
@@ -6132,9 +6147,10 @@
6132
6147
  * @param {Object} node 要删除的节点或节点集合
6133
6148
  * @param options 可选配置
6134
6149
  * @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
6150
+ * @param options.doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
6135
6151
  */
6136
6152
  async remove(nodeOrNodeList, options) {
6137
- const { doNotSelect = false } = safeOptions(options);
6153
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6138
6154
  this.captureSelectionBeforeOp();
6139
6155
  const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
6140
6156
  const removedItems = [];
@@ -6154,7 +6170,10 @@
6154
6170
  });
6155
6171
  }
6156
6172
  }
6157
- await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
6173
+ await Promise.all(nodes.map((node) => this.doRemove(node, {
6174
+ doNotSelect,
6175
+ doNotSwitchPage
6176
+ })));
6158
6177
  if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
6159
6178
  this.emit("remove", nodes);
6160
6179
  }
@@ -6191,7 +6210,10 @@
6191
6210
  selectedNodes.splice(targetIndex, 1, newConfig);
6192
6211
  this.set("nodes", [...selectedNodes]);
6193
6212
  }
6194
- if ((0, _tmagic_utils.isPage)(newConfig) || (0, _tmagic_utils.isPageFragment)(newConfig)) this.set("page", newConfig);
6213
+ if ((0, _tmagic_utils.isPage)(newConfig) || (0, _tmagic_utils.isPageFragment)(newConfig)) {
6214
+ const currentPage = this.get("page");
6215
+ if (currentPage && `${currentPage.id}` === `${newConfig.id}`) this.set("page", newConfig);
6216
+ }
6195
6217
  this.addModifiedNodeId(newConfig.id);
6196
6218
  return {
6197
6219
  oldNode: node,
@@ -6232,6 +6254,7 @@
6232
6254
  * @param id2 组件ID
6233
6255
  * @param options 可选配置
6234
6256
  * @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
6257
+ * @param options.doNotSwitchPage 排序后是否不切换当前页面(排序只发生在同一父节点内,方法内为空操作;保留以与其它 DSL 操作 API 一致)
6235
6258
  * @returns void
6236
6259
  */
6237
6260
  async sort(id1, id2, options) {
@@ -6279,10 +6302,11 @@
6279
6302
  * @param collectorOptions 可选的依赖收集器配置
6280
6303
  * @param options 可选配置
6281
6304
  * @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
6305
+ * @param options.doNotSwitchPage 粘贴后是否不切换当前页面(默认 false;跨页粘贴时为 true 会跳过页面切换)
6282
6306
  * @returns 添加后的组件节点配置
6283
6307
  */
6284
6308
  async paste(position = {}, collectorOptions, options) {
6285
- const { doNotSelect = false } = safeOptions(options);
6309
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6286
6310
  const config = storage_default.getItem(COPY_STORAGE_KEY);
6287
6311
  if (!Array.isArray(config)) return;
6288
6312
  const node = this.get("node");
@@ -6293,7 +6317,10 @@
6293
6317
  }
6294
6318
  const pasteConfigs = await this.doPaste(config, position);
6295
6319
  if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
6296
- return this.add(pasteConfigs, parent, { doNotSelect });
6320
+ return this.add(pasteConfigs, parent, {
6321
+ doNotSelect,
6322
+ doNotSwitchPage
6323
+ });
6297
6324
  }
6298
6325
  async doPaste(config, position = {}) {
6299
6326
  props_default.clearRelateId();
@@ -6316,6 +6343,7 @@
6316
6343
  * @param config 组件节点配置
6317
6344
  * @param options 可选配置
6318
6345
  * @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
6346
+ * @param options.doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致)
6319
6347
  * @returns 当前组件节点配置
6320
6348
  */
6321
6349
  async alignCenter(config, options) {
@@ -6371,9 +6399,10 @@
6371
6399
  * @param targetId 容器ID
6372
6400
  * @param options 可选配置
6373
6401
  * @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
6402
+ * @param options.doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换)
6374
6403
  */
6375
6404
  async moveToContainer(config, targetId, options) {
6376
- const { doNotSelect = false } = safeOptions(options);
6405
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6377
6406
  this.captureSelectionBeforeOp();
6378
6407
  const root = this.get("root");
6379
6408
  const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
@@ -6395,14 +6424,16 @@
6395
6424
  });
6396
6425
  newConfig.style = getInitPositionStyle(newConfig.style, layout);
6397
6426
  target.items.push(newConfig);
6398
- if (!doNotSelect) await stage.select(targetId);
6427
+ const targetWouldSwitchPage = this.isOnDifferentPage(target);
6428
+ const skipSelect = doNotSelect || doNotSwitchPage && targetWouldSwitchPage;
6429
+ if (!skipSelect) await stage.select(targetId);
6399
6430
  const targetParent = this.getParentById(target.id);
6400
6431
  await stage.update({
6401
6432
  config: cloneDeep(target),
6402
6433
  parentId: targetParent?.id,
6403
6434
  root: cloneDeep(root)
6404
6435
  });
6405
- if (!doNotSelect) {
6436
+ if (!skipSelect) {
6406
6437
  await this.select(newConfig);
6407
6438
  stage.select(newConfig.id);
6408
6439
  }
@@ -9173,7 +9204,7 @@
9173
9204
  (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicScrollbar), null, {
9174
9205
  default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_form.MForm), {
9175
9206
  ref: "configForm",
9176
- class: (0, vue.normalizeClass)(propsPanelSize.value),
9207
+ class: (0, vue.normalizeClass)([propsPanelSize.value, "m-editor-props-form-panel-form"]),
9177
9208
  "popper-class": `m-editor-props-panel-popper ${propsPanelSize.value}`,
9178
9209
  "label-width": __props.labelWidth,
9179
9210
  "label-position": __props.labelPosition,
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.14-beta.3",
2
+ "version": "1.8.0-beta.0",
3
3
  "name": "@tmagic/editor",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -58,11 +58,11 @@
58
58
  "moveable": "^0.53.0",
59
59
  "serialize-javascript": "^7.0.0",
60
60
  "sortablejs": "^1.15.6",
61
- "@tmagic/design": "1.7.14-beta.3",
62
- "@tmagic/form": "1.7.14-beta.3",
63
- "@tmagic/stage": "1.7.14-beta.3",
64
- "@tmagic/table": "1.7.14-beta.3",
65
- "@tmagic/utils": "1.7.14-beta.3"
61
+ "@tmagic/design": "1.8.0-beta.0",
62
+ "@tmagic/form": "1.8.0-beta.0",
63
+ "@tmagic/stage": "1.8.0-beta.0",
64
+ "@tmagic/utils": "1.8.0-beta.0",
65
+ "@tmagic/table": "1.8.0-beta.0"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@types/events": "^3.0.3",
@@ -76,7 +76,7 @@
76
76
  "type-fest": "^5.2.0",
77
77
  "typescript": "^6.0.3",
78
78
  "vue": "^3.5.34",
79
- "@tmagic/core": "1.7.14-beta.3"
79
+ "@tmagic/core": "1.8.0-beta.0"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "typescript": {
@@ -5,7 +5,7 @@
5
5
  <TMagicScrollbar>
6
6
  <MForm
7
7
  ref="configForm"
8
- :class="propsPanelSize"
8
+ :class="[propsPanelSize, 'm-editor-props-form-panel-form']"
9
9
  :popper-class="`m-editor-props-panel-popper ${propsPanelSize}`"
10
10
  :label-width="labelWidth"
11
11
  :label-position="labelPosition"
@@ -33,6 +33,7 @@ import type {
33
33
  AddMNode,
34
34
  AsyncHookPlugin,
35
35
  AsyncMethodName,
36
+ DslOpOptions,
36
37
  EditorEvents,
37
38
  EditorNodeInfo,
38
39
  HistoryOpType,
@@ -191,6 +192,22 @@ class Editor extends BaseService {
191
192
  return parent;
192
193
  }
193
194
 
195
+ /**
196
+ * 判断给定节点是否位于非当前页面(即选中该节点将会引起当前页面切换)
197
+ * @param node 节点
198
+ * @returns true 表示该节点位于非当前页面
199
+ */
200
+ public isOnDifferentPage(node: MNode): boolean {
201
+ const currentPageId = this.get('page')?.id;
202
+ if (currentPageId === undefined || currentPageId === null) return false;
203
+ if (isPage(node) || isPageFragment(node)) {
204
+ return `${node.id}` !== `${currentPageId}`;
205
+ }
206
+ const nodePage = this.getNodeInfo(node.id, false).page;
207
+ if (!nodePage) return false;
208
+ return `${nodePage.id}` !== `${currentPageId}`;
209
+ }
210
+
194
211
  /**
195
212
  * 只有容器拥有布局
196
213
  */
@@ -370,15 +387,16 @@ class Editor extends BaseService {
370
387
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
371
388
  * @param options 可选配置
372
389
  * @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
390
+ * @param options.doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作)
373
391
  * @returns 添加后的节点
374
392
  */
375
393
  public async add(
376
394
  addNode: AddMNode | MNode[],
377
395
  parent?: MContainer | null,
378
- options?: { doNotSelect?: boolean },
396
+ options?: DslOpOptions,
379
397
  ): Promise<MNode | MNode[]> {
380
398
  const safeParentNode = safeParent(parent);
381
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
399
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions<DslOpOptions>(options);
382
400
 
383
401
  this.captureSelectionBeforeOp();
384
402
 
@@ -409,14 +427,19 @@ class Editor extends BaseService {
409
427
  );
410
428
 
411
429
  if (newNodes.length > 1) {
412
- if (!doNotSelect) {
430
+ // 多选时只要任一新增节点位于非当前页面,触发的 multiSelect 就会引起页面切换
431
+ const wouldSwitchPage = newNodes.some((n) => this.isOnDifferentPage(n));
432
+ if (!doNotSelect && !(doNotSwitchPage && wouldSwitchPage)) {
413
433
  const newNodeIds = newNodes.map((node) => node.id);
414
434
  // 触发选中样式
415
435
  stage?.multiSelect(newNodeIds);
416
436
  await this.multiSelect(newNodeIds);
417
437
  }
418
438
  } else {
419
- if (!doNotSelect) {
439
+ const wouldSwitchPage = this.isOnDifferentPage(newNodes[0]);
440
+ const skipSelect = doNotSelect || (doNotSwitchPage && wouldSwitchPage);
441
+
442
+ if (!skipSelect) {
420
443
  await this.select(newNodes[0]);
421
444
  }
422
445
 
@@ -424,7 +447,7 @@ class Editor extends BaseService {
424
447
  this.state.pageLength += 1;
425
448
  } else if (isPageFragment(newNodes[0])) {
426
449
  this.state.pageFragmentLength += 1;
427
- } else if (!doNotSelect) {
450
+ } else if (!skipSelect) {
428
451
  // 新增页面,这个时候页面还有渲染出来,此时select会出错,在runtime-ready的时候回去select
429
452
  stage?.select(newNodes[0].id);
430
453
  }
@@ -453,8 +476,8 @@ class Editor extends BaseService {
453
476
  return Array.isArray(addNode) ? newNodes : newNodes[0];
454
477
  }
455
478
 
456
- public async doRemove(node: MNode, options?: { doNotSelect?: boolean }): Promise<void> {
457
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
479
+ public async doRemove(node: MNode, options?: DslOpOptions): Promise<void> {
480
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions<DslOpOptions>(options);
458
481
 
459
482
  const root = this.get('root');
460
483
  if (!root) throw new Error('root不能为空');
@@ -471,21 +494,19 @@ class Editor extends BaseService {
471
494
  const stage = this.get('stage');
472
495
  stage?.remove({ id: node.id, parentId: parent.id, root: cloneDeep(root) });
473
496
 
474
- if (doNotSelect) {
475
- // 当被删除节点正好在当前选中列表中时,必须从 state 中移除引用,避免 state 持有已删除节点(与 doNotSelect 无关)
476
- const selectedNodes = this.get('nodes');
477
- const removedSelectedIndex = selectedNodes.findIndex((n: MNode) => `${n.id}` === `${node.id}`);
478
- if (removedSelectedIndex !== -1) {
479
- const nextSelected = [...selectedNodes];
480
- nextSelected.splice(removedSelectedIndex, 1);
481
- this.set('nodes', nextSelected);
482
- }
483
- // 同理,如果被删除的是当前 page,也清空 state.page,避免持有已删除页面
484
- if (isPage(node) || isPageFragment(node)) {
485
- const currentPage = this.get('page');
486
- if (currentPage && `${currentPage.id}` === `${node.id}`) {
487
- this.set('page', null);
488
- }
497
+ // 始终清理已删除节点在 state 中的残留引用:
498
+ // - 即使后续会调用 selectDefault / select(parent) 覆盖,跳过这些调用(doNotSelect / doNotSwitchPage)时也不能让 state 持有已删除节点
499
+ const selectedNodes = this.get('nodes');
500
+ const removedSelectedIndex = selectedNodes.findIndex((n: MNode) => `${n.id}` === `${node.id}`);
501
+ if (removedSelectedIndex !== -1) {
502
+ const nextSelected = [...selectedNodes];
503
+ nextSelected.splice(removedSelectedIndex, 1);
504
+ this.set('nodes', nextSelected);
505
+ }
506
+ if (isPage(node) || isPageFragment(node)) {
507
+ const currentPage = this.get('page');
508
+ if (currentPage && `${currentPage.id}` === `${node.id}`) {
509
+ this.set('page', null);
489
510
  }
490
511
  }
491
512
 
@@ -505,13 +526,14 @@ class Editor extends BaseService {
505
526
  if (isPage(node)) {
506
527
  this.state.pageLength -= 1;
507
528
 
508
- if (!doNotSelect) {
529
+ // 删除页面后默认会切到首个剩余页面(selectDefault),doNotSwitchPage 时跳过这次自动切换
530
+ if (!doNotSelect && !doNotSwitchPage) {
509
531
  await selectDefault(rootItems);
510
532
  }
511
533
  } else if (isPageFragment(node)) {
512
534
  this.state.pageFragmentLength -= 1;
513
535
 
514
- if (!doNotSelect) {
536
+ if (!doNotSelect && !doNotSwitchPage) {
515
537
  await selectDefault(rootItems);
516
538
  }
517
539
  } else {
@@ -534,9 +556,10 @@ class Editor extends BaseService {
534
556
  * @param {Object} node 要删除的节点或节点集合
535
557
  * @param options 可选配置
536
558
  * @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
559
+ * @param options.doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
537
560
  */
538
- public async remove(nodeOrNodeList: MNode | MNode[], options?: { doNotSelect?: boolean }): Promise<void> {
539
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
561
+ public async remove(nodeOrNodeList: MNode | MNode[], options?: DslOpOptions): Promise<void> {
562
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions<DslOpOptions>(options);
540
563
 
541
564
  this.captureSelectionBeforeOp();
542
565
 
@@ -561,7 +584,7 @@ class Editor extends BaseService {
561
584
  }
562
585
  }
563
586
 
564
- await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
587
+ await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect, doNotSwitchPage })));
565
588
 
566
589
  if (removedItems.length > 0 && pageForOp) {
567
590
  this.pushOpHistory('remove', { removedItems }, pageForOp);
@@ -624,8 +647,12 @@ class Editor extends BaseService {
624
647
  this.set('nodes', [...selectedNodes]);
625
648
  }
626
649
 
650
+ // 只有被更新节点正好是当前选中页面时才同步 state.page,避免「更新非当前页」误将编辑器切到该页
627
651
  if (isPage(newConfig) || isPageFragment(newConfig)) {
628
- this.set('page', newConfig as MPage | MPageFragment);
652
+ const currentPage = this.get('page');
653
+ if (currentPage && `${currentPage.id}` === `${newConfig.id}`) {
654
+ this.set('page', newConfig as MPage | MPageFragment);
655
+ }
629
656
  }
630
657
 
631
658
  this.addModifiedNodeId(newConfig.id);
@@ -681,10 +708,11 @@ class Editor extends BaseService {
681
708
  * @param id2 组件ID
682
709
  * @param options 可选配置
683
710
  * @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
711
+ * @param options.doNotSwitchPage 排序后是否不切换当前页面(排序只发生在同一父节点内,方法内为空操作;保留以与其它 DSL 操作 API 一致)
684
712
  * @returns void
685
713
  */
686
- public async sort(id1: Id, id2: Id, options?: { doNotSelect?: boolean }): Promise<void> {
687
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
714
+ public async sort(id1: Id, id2: Id, options?: DslOpOptions): Promise<void> {
715
+ const { doNotSelect = false } = safeOptions<DslOpOptions>(options);
688
716
 
689
717
  this.captureSelectionBeforeOp();
690
718
 
@@ -750,14 +778,15 @@ class Editor extends BaseService {
750
778
  * @param collectorOptions 可选的依赖收集器配置
751
779
  * @param options 可选配置
752
780
  * @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
781
+ * @param options.doNotSwitchPage 粘贴后是否不切换当前页面(默认 false;跨页粘贴时为 true 会跳过页面切换)
753
782
  * @returns 添加后的组件节点配置
754
783
  */
755
784
  public async paste(
756
785
  position: PastePosition = {},
757
786
  collectorOptions?: TargetOptions,
758
- options?: { doNotSelect?: boolean },
787
+ options?: DslOpOptions,
759
788
  ): Promise<MNode | MNode[] | void> {
760
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
789
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions<DslOpOptions>(options);
761
790
 
762
791
  const config: MNode[] = storageService.getItem(COPY_STORAGE_KEY);
763
792
  if (!Array.isArray(config)) return;
@@ -778,7 +807,7 @@ class Editor extends BaseService {
778
807
  propsService.replaceRelateId(config, pasteConfigs, collectorOptions);
779
808
  }
780
809
 
781
- return this.add(pasteConfigs, parent, { doNotSelect });
810
+ return this.add(pasteConfigs, parent, { doNotSelect, doNotSwitchPage });
782
811
  }
783
812
 
784
813
  public async doPaste(config: MNode[], position: PastePosition = {}): Promise<MNode[]> {
@@ -808,10 +837,11 @@ class Editor extends BaseService {
808
837
  * @param config 组件节点配置
809
838
  * @param options 可选配置
810
839
  * @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
840
+ * @param options.doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致)
811
841
  * @returns 当前组件节点配置
812
842
  */
813
- public async alignCenter(config: MNode | MNode[], options?: { doNotSelect?: boolean }): Promise<MNode | MNode[]> {
814
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
843
+ public async alignCenter(config: MNode | MNode[], options?: DslOpOptions): Promise<MNode | MNode[]> {
844
+ const { doNotSelect = false } = safeOptions<DslOpOptions>(options);
815
845
 
816
846
  const nodes = Array.isArray(config) ? config : [config];
817
847
  const stage = this.get('stage');
@@ -890,13 +920,10 @@ class Editor extends BaseService {
890
920
  * @param targetId 容器ID
891
921
  * @param options 可选配置
892
922
  * @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
923
+ * @param options.doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换)
893
924
  */
894
- public async moveToContainer(
895
- config: MNode,
896
- targetId: Id,
897
- options?: { doNotSelect?: boolean },
898
- ): Promise<MNode | undefined> {
899
- const { doNotSelect = false } = safeOptions<{ doNotSelect?: boolean }>(options);
925
+ public async moveToContainer(config: MNode, targetId: Id, options?: DslOpOptions): Promise<MNode | undefined> {
926
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions<DslOpOptions>(options);
900
927
 
901
928
  this.captureSelectionBeforeOp();
902
929
 
@@ -925,7 +952,11 @@ class Editor extends BaseService {
925
952
 
926
953
  target.items.push(newConfig);
927
954
 
928
- if (!doNotSelect) {
955
+ // 目标容器是否在非当前页面:选中目标会触发当前页面切换
956
+ const targetWouldSwitchPage = this.isOnDifferentPage(target);
957
+ const skipSelect = doNotSelect || (doNotSwitchPage && targetWouldSwitchPage);
958
+
959
+ if (!skipSelect) {
929
960
  await stage.select(targetId);
930
961
  }
931
962
 
@@ -936,7 +967,7 @@ class Editor extends BaseService {
936
967
  root: cloneDeep(root),
937
968
  });
938
969
 
939
- if (!doNotSelect) {
970
+ if (!skipSelect) {
940
971
  await this.select(newConfig);
941
972
  stage.select(newConfig.id);
942
973
  }
@@ -25,26 +25,6 @@
25
25
  right: calc(15px + var(--props-style-panel-width));
26
26
  }
27
27
  }
28
-
29
- .tmagic-design-form {
30
- padding-right: 10px;
31
- padding-left: 10px;
32
-
33
- > .m-container-tab {
34
- > .tmagic-design-tabs {
35
- > .el-tabs__content {
36
- padding-top: 55px;
37
- }
38
- > .el-tabs__header.is-top {
39
- position: absolute;
40
- top: 0;
41
- width: 100%;
42
- background: #fff;
43
- z-index: 3;
44
- }
45
- }
46
- }
47
- }
48
28
  }
49
29
 
50
30
  .m-editor-props-style-panel {
@@ -142,6 +122,26 @@
142
122
  }
143
123
  }
144
124
 
125
+ .m-editor-props-form-panel-form {
126
+ padding-right: 10px;
127
+ padding-left: 10px;
128
+
129
+ > .m-container-tab {
130
+ > .tmagic-design-tabs {
131
+ > .el-tabs__content {
132
+ padding-top: 55px;
133
+ }
134
+ > .el-tabs__header.is-top {
135
+ position: absolute;
136
+ top: 0;
137
+ width: 100%;
138
+ background: #fff;
139
+ z-index: 3;
140
+ }
141
+ }
142
+ }
143
+ }
144
+
145
145
  .m-editor-props-panel-popper {
146
146
  &.small {
147
147
  span,
package/src/type.ts CHANGED
@@ -873,3 +873,13 @@ export const canUsePluginMethods = {
873
873
  };
874
874
 
875
875
  export type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
876
+
877
+ /**
878
+ * DSL 修改类操作的通用配置
879
+ * - doNotSelect: 操作后是否不要自动触发选中(不调用 this.select / this.multiSelect / stage.select / stage.multiSelect)
880
+ * - doNotSwitchPage: 操作若会引发当前页面切换(如新增 / 删除 / 跨页移动),是否跳过这次切换
881
+ */
882
+ export type DslOpOptions = {
883
+ doNotSelect?: boolean;
884
+ doNotSwitchPage?: boolean;
885
+ };
package/types/index.d.ts CHANGED
@@ -375,6 +375,12 @@ declare class Editor extends export_default {
375
375
  * @returns 指点组件的父节点配置
376
376
  */
377
377
  getParentById(id: Id, raw?: boolean): MContainer | null;
378
+ /**
379
+ * 判断给定节点是否位于非当前页面(即选中该节点将会引起当前页面切换)
380
+ * @param node 节点
381
+ * @returns true 表示该节点位于非当前页面
382
+ */
383
+ isOnDifferentPage(node: MNode): boolean;
378
384
  /**
379
385
  * 只有容器拥有布局
380
386
  */
@@ -407,23 +413,19 @@ declare class Editor extends export_default {
407
413
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
408
414
  * @param options 可选配置
409
415
  * @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
416
+ * @param options.doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作)
410
417
  * @returns 添加后的节点
411
418
  */
412
- add(addNode: AddMNode | MNode[], parent?: MContainer | null, options?: {
413
- doNotSelect?: boolean;
414
- }): Promise<MNode | MNode[]>;
415
- doRemove(node: MNode, options?: {
416
- doNotSelect?: boolean;
417
- }): Promise<void>;
419
+ add(addNode: AddMNode | MNode[], parent?: MContainer | null, options?: DslOpOptions): Promise<MNode | MNode[]>;
420
+ doRemove(node: MNode, options?: DslOpOptions): Promise<void>;
418
421
  /**
419
422
  * 删除组件
420
423
  * @param {Object} node 要删除的节点或节点集合
421
424
  * @param options 可选配置
422
425
  * @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
426
+ * @param options.doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
423
427
  */
424
- remove(nodeOrNodeList: MNode | MNode[], options?: {
425
- doNotSelect?: boolean;
426
- }): Promise<void>;
428
+ remove(nodeOrNodeList: MNode | MNode[], options?: DslOpOptions): Promise<void>;
427
429
  doUpdate(config: MNode, {
428
430
  changeRecords
429
431
  }?: {
@@ -448,11 +450,10 @@ declare class Editor extends export_default {
448
450
  * @param id2 组件ID
449
451
  * @param options 可选配置
450
452
  * @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
453
+ * @param options.doNotSwitchPage 排序后是否不切换当前页面(排序只发生在同一父节点内,方法内为空操作;保留以与其它 DSL 操作 API 一致)
451
454
  * @returns void
452
455
  */
453
- sort(id1: Id, id2: Id, options?: {
454
- doNotSelect?: boolean;
455
- }): Promise<void>;
456
+ sort(id1: Id, id2: Id, options?: DslOpOptions): Promise<void>;
456
457
  /**
457
458
  * 将组件节点配置存储到localStorage中
458
459
  * @param config 组件节点配置
@@ -471,11 +472,10 @@ declare class Editor extends export_default {
471
472
  * @param collectorOptions 可选的依赖收集器配置
472
473
  * @param options 可选配置
473
474
  * @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
475
+ * @param options.doNotSwitchPage 粘贴后是否不切换当前页面(默认 false;跨页粘贴时为 true 会跳过页面切换)
474
476
  * @returns 添加后的组件节点配置
475
477
  */
476
- paste(position?: PastePosition, collectorOptions?: TargetOptions, options?: {
477
- doNotSelect?: boolean;
478
- }): Promise<MNode | MNode[] | void>;
478
+ paste(position?: PastePosition, collectorOptions?: TargetOptions, options?: DslOpOptions): Promise<MNode | MNode[] | void>;
479
479
  doPaste(config: MNode[], position?: PastePosition): Promise<MNode[]>;
480
480
  doAlignCenter(config: MNode): Promise<MNode>;
481
481
  /**
@@ -483,11 +483,10 @@ declare class Editor extends export_default {
483
483
  * @param config 组件节点配置
484
484
  * @param options 可选配置
485
485
  * @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
486
+ * @param options.doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致)
486
487
  * @returns 当前组件节点配置
487
488
  */
488
- alignCenter(config: MNode | MNode[], options?: {
489
- doNotSelect?: boolean;
490
- }): Promise<MNode | MNode[]>;
489
+ alignCenter(config: MNode | MNode[], options?: DslOpOptions): Promise<MNode | MNode[]>;
491
490
  /**
492
491
  * 移动当前选中节点位置
493
492
  * @param offset 偏移量
@@ -499,10 +498,9 @@ declare class Editor extends export_default {
499
498
  * @param targetId 容器ID
500
499
  * @param options 可选配置
501
500
  * @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
501
+ * @param options.doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换)
502
502
  */
503
- moveToContainer(config: MNode, targetId: Id, options?: {
504
- doNotSelect?: boolean;
505
- }): Promise<MNode | undefined>;
503
+ moveToContainer(config: MNode, targetId: Id, options?: DslOpOptions): Promise<MNode | undefined>;
506
504
  dragTo(config: MNode | MNode[], targetParent: MContainer, targetIndex: number): Promise<void>;
507
505
  /**
508
506
  * 撤销当前操作
@@ -1509,6 +1507,15 @@ declare const canUsePluginMethods: {
1509
1507
  sync: never[];
1510
1508
  };
1511
1509
  type AsyncMethodName = Writable<(typeof canUsePluginMethods)['async']>;
1510
+ /**
1511
+ * DSL 修改类操作的通用配置
1512
+ * - doNotSelect: 操作后是否不要自动触发选中(不调用 this.select / this.multiSelect / stage.select / stage.multiSelect)
1513
+ * - doNotSwitchPage: 操作若会引发当前页面切换(如新增 / 删除 / 跨页移动),是否跳过这次切换
1514
+ */
1515
+ type DslOpOptions = {
1516
+ doNotSelect?: boolean;
1517
+ doNotSwitchPage?: boolean;
1518
+ };
1512
1519
  //#endregion
1513
1520
  //#region temp/packages/form/src/schema.d.ts
1514
1521
  interface ChangeRecord$1 {
@@ -4172,4 +4179,4 @@ declare const _default$36: {
4172
4179
  install: (app: App, opt?: Partial<EditorInstallOptions | DesignPluginOptions | FormInstallOptions>) => void;
4173
4180
  };
4174
4181
  //#endregion
4175
- export { AddMNode, AddPrefixToObject, AsyncAfterHook, AsyncBeforeHook, AsyncHookPlugin, AsyncMethodName, BeforeAdd, CODE_DRAFT_STORAGE_KEY, COPY_CODE_STORAGE_KEY, COPY_DS_STORAGE_KEY, COPY_STORAGE_KEY, CanDropInFunction, CanDropInScene, _default as CodeBlockEditor, _default$1 as CodeBlockList, _default$2 as CodeBlockListPanel, CodeBlockListPanelSlots, CodeBlockListSlots, CodeDeleteErrorType, CodeDslItem, CodeParamStatement, CodeRelation, _default$3 as CodeSelect, _default$4 as CodeSelectCol, CodeState, ColumnLayout, CombineInfo, ComponentGroup, ComponentGroupState, ComponentItem, _default$5 as ComponentListPanel, ComponentListPanelSlots, _default$6 as CondOpSelect, _default$7 as ContentMenu, CustomContentMenuFunction, DEFAULT_LEFT_COLUMN_WIDTH, DEFAULT_RIGHT_COLUMN_WIDTH, _default$8 as DataSourceAddButton, _default$9 as DataSourceConfigPanel, _default$10 as DataSourceFieldSelect, _default$11 as DataSourceFields, _default$12 as DataSourceInput, DataSourceListSlots, _default$13 as DataSourceMethodSelect, _default$14 as DataSourceMethods, _default$15 as DataSourceMocks, _default$16 as DataSourceSelect, DatasourceTypeOption, DepTargetType, _default$17 as DisplayConds, DragClassification, DragType, EditorEvents, EditorInstallOptions, EditorNodeInfo, EditorSlots, EventBus, EventBusEvent, _default$18 as EventSelect, Fixed2Other, _default$19 as FloatingBox, FrameworkSlots, GetColumnWidth, GetConfig, H_GUIDE_LINE_STORAGE_KEY, HistoryOpType, HistoryState, _default$20 as Icon, IdleTask, IdleTaskEvents, IsExpandableFunction, KeyBindingCacheItem, KeyBindingCommand, KeyBindingItem, _default$21 as KeyValue, Keys, LEFT_COLUMN_WIDTH_STORAGE_KEY, LayerNodeSlots, LayerNodeStatus, LayerOffset, _default$22 as LayerPanel, LayerPanelSlots, Layout, _default$23 as LayoutContainer, _default$23 as SplitView, ListState, MIN_CENTER_COLUMN_WIDTH, MIN_LEFT_COLUMN_WIDTH, MIN_RIGHT_COLUMN_WIDTH, MenuBarData, MenuButton, MenuComponent, MenuItem, type OnDrag, PROPS_PANEL_WIDTH_STORAGE_KEY, PageBarSortOptions, _default$24 as PageFragmentSelect, PartSortableOptions, PastePosition, PropsFormConfigFunction, _default$25 as PropsFormPanel, PropsFormValueFunction, _default$26 as PropsPanel, PropsPanelSlots, PropsState, RIGHT_COLUMN_WIDTH_STORAGE_KEY, _default$27 as Resizer, ScrollViewer, ScrollViewerEvent, ScrollViewerSlots, Services, SetColumnWidth, SideBarData, SideComponent, SideItem, SideItemKey, SidebarSlots, StageCore, StageOptions, StageOverlayState, StageRect, StageSlots, StepValue, StoreState, StoreStateKey, _default$28 as StyleSetter, SyncAfterHook, SyncBeforeHook, SyncHookPlugin, _default$29 as TMagicCodeEditor, _default$30 as TMagicEditor, _default$31 as ToolButton, _default$32 as Tree, _default$33 as TreeNode, TreeNodeData, UI_SELECT_MODE_EVENT_NAME, UiState, UndoRedo, V_GUIDE_LINE_STORAGE_KEY, WorkspaceSlots, advancedTabConfig, arrayOptions, beforePaste, buildChangeRecords, calcAlignCenterStyle, calcLayerTargetIndex, calcMoveStyle, canUsePluginMethods, change2Fixed, classifyDragSources, _default$34 as codeBlockService, collectRelatedNodes, _default$35 as dataSourceService, debug, _default$36 as default, defaultIsExpandable, _default$37 as depService, designPlugin, displayTabConfig, editorNodeMergeCustomizer, _default$38 as editorService, eqOptions, error, eventTabConfig, _default$39 as eventsService, fillConfig, fixNodeLeft, fixNodePosition, formPlugin, generatePageName, generatePageNameByApp, getAddParent, getCascaderOptionsFromFields, getDefaultConfig, getDisplayField, getEditorConfig, getFieldType, getFormConfig, getFormValue, getGuideLineFromCache, getInitPositionStyle, getNodeIndex, getPageFragmentList, getPageList, getPageNameList, getPositionInContainer, getRelativeStyle, _default$40 as historyService, info, isIncludeDataSource, _default$41 as loadMonaco, log, moveItemsInContainer, numberOptions, _default$42 as propsService, resolveSelectedNode, serializeConfig, setChildrenLayout, setEditorConfig, setLayout, _default$43 as stageOverlayService, _default$44 as storageService, styleTabConfig, tablePlugin, toggleFixedPosition, _default$45 as uiService, updateStatus, useCodeBlockEdit, useEditorContentHeight, useFilter, useFloatBox, useGetSo, useNextFloatBoxPosition, useNodeStatus, useServices, useStage, useWindowRect, warn };
4182
+ export { AddMNode, AddPrefixToObject, AsyncAfterHook, AsyncBeforeHook, AsyncHookPlugin, AsyncMethodName, BeforeAdd, CODE_DRAFT_STORAGE_KEY, COPY_CODE_STORAGE_KEY, COPY_DS_STORAGE_KEY, COPY_STORAGE_KEY, CanDropInFunction, CanDropInScene, _default as CodeBlockEditor, _default$1 as CodeBlockList, _default$2 as CodeBlockListPanel, CodeBlockListPanelSlots, CodeBlockListSlots, CodeDeleteErrorType, CodeDslItem, CodeParamStatement, CodeRelation, _default$3 as CodeSelect, _default$4 as CodeSelectCol, CodeState, ColumnLayout, CombineInfo, ComponentGroup, ComponentGroupState, ComponentItem, _default$5 as ComponentListPanel, ComponentListPanelSlots, _default$6 as CondOpSelect, _default$7 as ContentMenu, CustomContentMenuFunction, DEFAULT_LEFT_COLUMN_WIDTH, DEFAULT_RIGHT_COLUMN_WIDTH, _default$8 as DataSourceAddButton, _default$9 as DataSourceConfigPanel, _default$10 as DataSourceFieldSelect, _default$11 as DataSourceFields, _default$12 as DataSourceInput, DataSourceListSlots, _default$13 as DataSourceMethodSelect, _default$14 as DataSourceMethods, _default$15 as DataSourceMocks, _default$16 as DataSourceSelect, DatasourceTypeOption, DepTargetType, _default$17 as DisplayConds, DragClassification, DragType, DslOpOptions, EditorEvents, EditorInstallOptions, EditorNodeInfo, EditorSlots, EventBus, EventBusEvent, _default$18 as EventSelect, Fixed2Other, _default$19 as FloatingBox, FrameworkSlots, GetColumnWidth, GetConfig, H_GUIDE_LINE_STORAGE_KEY, HistoryOpType, HistoryState, _default$20 as Icon, IdleTask, IdleTaskEvents, IsExpandableFunction, KeyBindingCacheItem, KeyBindingCommand, KeyBindingItem, _default$21 as KeyValue, Keys, LEFT_COLUMN_WIDTH_STORAGE_KEY, LayerNodeSlots, LayerNodeStatus, LayerOffset, _default$22 as LayerPanel, LayerPanelSlots, Layout, _default$23 as LayoutContainer, _default$23 as SplitView, ListState, MIN_CENTER_COLUMN_WIDTH, MIN_LEFT_COLUMN_WIDTH, MIN_RIGHT_COLUMN_WIDTH, MenuBarData, MenuButton, MenuComponent, MenuItem, type OnDrag, PROPS_PANEL_WIDTH_STORAGE_KEY, PageBarSortOptions, _default$24 as PageFragmentSelect, PartSortableOptions, PastePosition, PropsFormConfigFunction, _default$25 as PropsFormPanel, PropsFormValueFunction, _default$26 as PropsPanel, PropsPanelSlots, PropsState, RIGHT_COLUMN_WIDTH_STORAGE_KEY, _default$27 as Resizer, ScrollViewer, ScrollViewerEvent, ScrollViewerSlots, Services, SetColumnWidth, SideBarData, SideComponent, SideItem, SideItemKey, SidebarSlots, StageCore, StageOptions, StageOverlayState, StageRect, StageSlots, StepValue, StoreState, StoreStateKey, _default$28 as StyleSetter, SyncAfterHook, SyncBeforeHook, SyncHookPlugin, _default$29 as TMagicCodeEditor, _default$30 as TMagicEditor, _default$31 as ToolButton, _default$32 as Tree, _default$33 as TreeNode, TreeNodeData, UI_SELECT_MODE_EVENT_NAME, UiState, UndoRedo, V_GUIDE_LINE_STORAGE_KEY, WorkspaceSlots, advancedTabConfig, arrayOptions, beforePaste, buildChangeRecords, calcAlignCenterStyle, calcLayerTargetIndex, calcMoveStyle, canUsePluginMethods, change2Fixed, classifyDragSources, _default$34 as codeBlockService, collectRelatedNodes, _default$35 as dataSourceService, debug, _default$36 as default, defaultIsExpandable, _default$37 as depService, designPlugin, displayTabConfig, editorNodeMergeCustomizer, _default$38 as editorService, eqOptions, error, eventTabConfig, _default$39 as eventsService, fillConfig, fixNodeLeft, fixNodePosition, formPlugin, generatePageName, generatePageNameByApp, getAddParent, getCascaderOptionsFromFields, getDefaultConfig, getDisplayField, getEditorConfig, getFieldType, getFormConfig, getFormValue, getGuideLineFromCache, getInitPositionStyle, getNodeIndex, getPageFragmentList, getPageList, getPageNameList, getPositionInContainer, getRelativeStyle, _default$40 as historyService, info, isIncludeDataSource, _default$41 as loadMonaco, log, moveItemsInContainer, numberOptions, _default$42 as propsService, resolveSelectedNode, serializeConfig, setChildrenLayout, setEditorConfig, setLayout, _default$43 as stageOverlayService, _default$44 as storageService, styleTabConfig, tablePlugin, toggleFixedPosition, _default$45 as uiService, updateStatus, useCodeBlockEdit, useEditorContentHeight, useFilter, useFloatBox, useGetSo, useNextFloatBoxPosition, useNodeStatus, useServices, useStage, useWindowRect, warn };