@tmagic/editor 1.7.14-beta.2 → 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.
@@ -5793,6 +5793,23 @@
5793
5793
  };
5794
5794
  //#endregion
5795
5795
  //#region packages/editor/src/services/editor.ts
5796
+ /**
5797
+ * 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
5798
+ * 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
5799
+ */
5800
+ var safeOptions = (options) => {
5801
+ const empty = {};
5802
+ if (!options || typeof options === "function") return empty;
5803
+ return options;
5804
+ };
5805
+ /**
5806
+ * 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
5807
+ * 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
5808
+ */
5809
+ var safeParent = (parent) => {
5810
+ if (!parent || typeof parent === "function") return null;
5811
+ return parent;
5812
+ };
5796
5813
  var Editor = class extends BaseService_default {
5797
5814
  state = (0, vue.reactive)({
5798
5815
  root: null,
@@ -5885,6 +5902,19 @@
5885
5902
  return parent;
5886
5903
  }
5887
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
+ /**
5888
5918
  * 只有容器拥有布局
5889
5919
  */
5890
5920
  async getLayout(parent, node) {
@@ -6003,9 +6033,14 @@
6003
6033
  * 向指点容器添加组件节点
6004
6034
  * @param addConfig 将要添加的组件节点配置
6005
6035
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
6036
+ * @param options 可选配置
6037
+ * @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
6038
+ * @param options.doNotSwitchPage 添加后是否不切换当前页面(默认 false;新增页面 / 跨页新增时为 true 会跳过会引发页面切换的选中操作)
6006
6039
  * @returns 添加后的节点
6007
6040
  */
6008
- async add(addNode, parent) {
6041
+ async add(addNode, parent, options) {
6042
+ const safeParentNode = safeParent(parent);
6043
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6009
6044
  this.captureSelectionBeforeOp();
6010
6045
  const stage = this.get("stage");
6011
6046
  const addNodes = [];
@@ -6017,19 +6052,24 @@
6017
6052
  const newNodes = await Promise.all(addNodes.map((node) => {
6018
6053
  const root = this.get("root");
6019
6054
  if (((0, _tmagic_utils.isPage)(node) || (0, _tmagic_utils.isPageFragment)(node)) && root) return this.doAdd(node, root);
6020
- const parentNode = parent && typeof parent !== "function" ? parent : getAddParent(node);
6055
+ const parentNode = safeParentNode ?? getAddParent(node);
6021
6056
  if (!parentNode) throw new Error("未找到父元素");
6022
6057
  return this.doAdd(node, parentNode);
6023
6058
  }));
6024
6059
  if (newNodes.length > 1) {
6025
- const newNodeIds = newNodes.map((node) => node.id);
6026
- stage?.multiSelect(newNodeIds);
6027
- await this.multiSelect(newNodeIds);
6060
+ const wouldSwitchPage = newNodes.some((n) => this.isOnDifferentPage(n));
6061
+ if (!doNotSelect && !(doNotSwitchPage && wouldSwitchPage)) {
6062
+ const newNodeIds = newNodes.map((node) => node.id);
6063
+ stage?.multiSelect(newNodeIds);
6064
+ await this.multiSelect(newNodeIds);
6065
+ }
6028
6066
  } else {
6029
- 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]);
6030
6070
  if ((0, _tmagic_utils.isPage)(newNodes[0])) this.state.pageLength += 1;
6031
6071
  else if ((0, _tmagic_utils.isPageFragment)(newNodes[0])) this.state.pageFragmentLength += 1;
6032
- else stage?.select(newNodes[0].id);
6072
+ else if (!skipSelect) stage?.select(newNodes[0].id);
6033
6073
  }
6034
6074
  if (!((0, _tmagic_utils.isPage)(newNodes[0]) || (0, _tmagic_utils.isPageFragment)(newNodes[0]))) {
6035
6075
  const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
@@ -6048,7 +6088,8 @@
6048
6088
  this.emit("add", newNodes);
6049
6089
  return Array.isArray(addNode) ? newNodes : newNodes[0];
6050
6090
  }
6051
- async doRemove(node) {
6091
+ async doRemove(node, options) {
6092
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6052
6093
  const root = this.get("root");
6053
6094
  if (!root) throw new Error("root不能为空");
6054
6095
  const { parent, node: curNode } = this.getNodeInfo(node.id, false);
@@ -6062,6 +6103,17 @@
6062
6103
  parentId: parent.id,
6063
6104
  root: cloneDeep(root)
6064
6105
  });
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);
6116
+ }
6065
6117
  const selectDefault = async (pages) => {
6066
6118
  if (pages[0]) {
6067
6119
  await this.select(pages[0]);
@@ -6074,13 +6126,15 @@
6074
6126
  const rootItems = root.items || [];
6075
6127
  if ((0, _tmagic_utils.isPage)(node)) {
6076
6128
  this.state.pageLength -= 1;
6077
- await selectDefault(rootItems);
6129
+ if (!doNotSelect && !doNotSwitchPage) await selectDefault(rootItems);
6078
6130
  } else if ((0, _tmagic_utils.isPageFragment)(node)) {
6079
6131
  this.state.pageFragmentLength -= 1;
6080
- await selectDefault(rootItems);
6132
+ if (!doNotSelect && !doNotSwitchPage) await selectDefault(rootItems);
6081
6133
  } else {
6082
- await this.select(parent);
6083
- stage?.select(parent.id);
6134
+ if (!doNotSelect) {
6135
+ await this.select(parent);
6136
+ stage?.select(parent.id);
6137
+ }
6084
6138
  this.addModifiedNodeId(parent.id);
6085
6139
  }
6086
6140
  if (!rootItems.length) {
@@ -6090,9 +6144,13 @@
6090
6144
  }
6091
6145
  /**
6092
6146
  * 删除组件
6093
- * @param {Object} node
6147
+ * @param {Object} node 要删除的节点或节点集合
6148
+ * @param options 可选配置
6149
+ * @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
6150
+ * @param options.doNotSwitchPage 删除后是否不切换当前页面(默认 false;删除页面 / 页面片段时为 true 会跳过自动切换到首个剩余页面)
6094
6151
  */
6095
- async remove(nodeOrNodeList) {
6152
+ async remove(nodeOrNodeList, options) {
6153
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6096
6154
  this.captureSelectionBeforeOp();
6097
6155
  const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
6098
6156
  const removedItems = [];
@@ -6112,11 +6170,14 @@
6112
6170
  });
6113
6171
  }
6114
6172
  }
6115
- await Promise.all(nodes.map((node) => this.doRemove(node)));
6173
+ await Promise.all(nodes.map((node) => this.doRemove(node, {
6174
+ doNotSelect,
6175
+ doNotSwitchPage
6176
+ })));
6116
6177
  if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
6117
6178
  this.emit("remove", nodes);
6118
6179
  }
6119
- async doUpdate(config, { changeRecords = [], selectedAfterUpdate = true } = {}) {
6180
+ async doUpdate(config, { changeRecords = [] } = {}) {
6120
6181
  const root = this.get("root");
6121
6182
  if (!root) throw new Error("root为空");
6122
6183
  if (!config?.id) throw new Error("没有配置或者配置缺少id值");
@@ -6143,13 +6204,16 @@
6143
6204
  const layout = await this.getLayout(node);
6144
6205
  if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
6145
6206
  parentNodeItems[index] = newConfig;
6146
- if (selectedAfterUpdate) {
6147
- const nodes = this.get("nodes");
6148
- const targetIndex = nodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
6149
- nodes.splice(targetIndex, 1, newConfig);
6150
- this.set("nodes", [...nodes]);
6207
+ const selectedNodes = this.get("nodes");
6208
+ const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
6209
+ if (targetIndex !== -1) {
6210
+ selectedNodes.splice(targetIndex, 1, newConfig);
6211
+ this.set("nodes", [...selectedNodes]);
6212
+ }
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);
6151
6216
  }
6152
- if ((0, _tmagic_utils.isPage)(newConfig) || (0, _tmagic_utils.isPageFragment)(newConfig)) this.set("page", newConfig);
6153
6217
  this.addModifiedNodeId(newConfig.id);
6154
6218
  return {
6155
6219
  oldNode: node,
@@ -6188,9 +6252,13 @@
6188
6252
  * 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
6189
6253
  * @param id1 组件ID
6190
6254
  * @param id2 组件ID
6255
+ * @param options 可选配置
6256
+ * @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
6257
+ * @param options.doNotSwitchPage 排序后是否不切换当前页面(排序只发生在同一父节点内,方法内为空操作;保留以与其它 DSL 操作 API 一致)
6191
6258
  * @returns void
6192
6259
  */
6193
- async sort(id1, id2) {
6260
+ async sort(id1, id2, options) {
6261
+ const { doNotSelect = false } = safeOptions(options);
6194
6262
  this.captureSelectionBeforeOp();
6195
6263
  const root = this.get("root");
6196
6264
  if (!root) throw new Error("root为空");
@@ -6203,7 +6271,7 @@
6203
6271
  const index1 = parent.items.findIndex((node) => `${node.id}` === `${id1}`);
6204
6272
  parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
6205
6273
  await this.update(parent);
6206
- await this.select(node);
6274
+ if (!doNotSelect) await this.select(node);
6207
6275
  this.get("stage")?.update({
6208
6276
  config: cloneDeep(node),
6209
6277
  parentId: parent.id,
@@ -6231,9 +6299,14 @@
6231
6299
  /**
6232
6300
  * 从localStorage中获取节点,然后添加到当前容器中
6233
6301
  * @param position 粘贴的坐标
6302
+ * @param collectorOptions 可选的依赖收集器配置
6303
+ * @param options 可选配置
6304
+ * @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
6305
+ * @param options.doNotSwitchPage 粘贴后是否不切换当前页面(默认 false;跨页粘贴时为 true 会跳过页面切换)
6234
6306
  * @returns 添加后的组件节点配置
6235
6307
  */
6236
- async paste(position = {}, collectorOptions) {
6308
+ async paste(position = {}, collectorOptions, options) {
6309
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6237
6310
  const config = storage_default.getItem(COPY_STORAGE_KEY);
6238
6311
  if (!Array.isArray(config)) return;
6239
6312
  const node = this.get("node");
@@ -6244,7 +6317,10 @@
6244
6317
  }
6245
6318
  const pasteConfigs = await this.doPaste(config, position);
6246
6319
  if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
6247
- return this.add(pasteConfigs, parent);
6320
+ return this.add(pasteConfigs, parent, {
6321
+ doNotSelect,
6322
+ doNotSwitchPage
6323
+ });
6248
6324
  }
6249
6325
  async doPaste(config, position = {}) {
6250
6326
  props_default.clearRelateId();
@@ -6265,14 +6341,18 @@
6265
6341
  /**
6266
6342
  * 将指点节点设置居中
6267
6343
  * @param config 组件节点配置
6344
+ * @param options 可选配置
6345
+ * @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
6346
+ * @param options.doNotSwitchPage 居中后是否不切换当前页面(居中只更新节点 style,方法内为空操作;保留以与其它 DSL 操作 API 一致)
6268
6347
  * @returns 当前组件节点配置
6269
6348
  */
6270
- async alignCenter(config) {
6349
+ async alignCenter(config, options) {
6350
+ const { doNotSelect = false } = safeOptions(options);
6271
6351
  const nodes = Array.isArray(config) ? config : [config];
6272
6352
  const stage = this.get("stage");
6273
6353
  const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
6274
6354
  const newNode = await this.update(newNodes);
6275
- if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
6355
+ if (!doNotSelect) if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
6276
6356
  else await stage?.select(newNodes[0].id);
6277
6357
  return newNode;
6278
6358
  }
@@ -6317,8 +6397,12 @@
6317
6397
  * 移动到指定容器中
6318
6398
  * @param config 需要移动的节点
6319
6399
  * @param targetId 容器ID
6400
+ * @param options 可选配置
6401
+ * @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
6402
+ * @param options.doNotSwitchPage 移动后是否不切换当前页面(默认 false;目标容器位于其它页面时为 true 会跳过自动选中以避免页面切换)
6320
6403
  */
6321
- async moveToContainer(config, targetId) {
6404
+ async moveToContainer(config, targetId, options) {
6405
+ const { doNotSelect = false, doNotSwitchPage = false } = safeOptions(options);
6322
6406
  this.captureSelectionBeforeOp();
6323
6407
  const root = this.get("root");
6324
6408
  const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
@@ -6340,15 +6424,19 @@
6340
6424
  });
6341
6425
  newConfig.style = getInitPositionStyle(newConfig.style, layout);
6342
6426
  target.items.push(newConfig);
6343
- await stage.select(targetId);
6427
+ const targetWouldSwitchPage = this.isOnDifferentPage(target);
6428
+ const skipSelect = doNotSelect || doNotSwitchPage && targetWouldSwitchPage;
6429
+ if (!skipSelect) await stage.select(targetId);
6344
6430
  const targetParent = this.getParentById(target.id);
6345
6431
  await stage.update({
6346
6432
  config: cloneDeep(target),
6347
6433
  parentId: targetParent?.id,
6348
6434
  root: cloneDeep(root)
6349
6435
  });
6350
- await this.select(newConfig);
6351
- stage.select(newConfig.id);
6436
+ if (!skipSelect) {
6437
+ await this.select(newConfig);
6438
+ stage.select(newConfig.id);
6439
+ }
6352
6440
  this.addModifiedNodeId(target.id);
6353
6441
  this.addModifiedNodeId(parent.id);
6354
6442
  this.pushOpHistory("update", { updatedItems: [{
@@ -9116,7 +9204,7 @@
9116
9204
  (0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicScrollbar), null, {
9117
9205
  default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_tmagic_form.MForm), {
9118
9206
  ref: "configForm",
9119
- class: (0, vue.normalizeClass)(propsPanelSize.value),
9207
+ class: (0, vue.normalizeClass)([propsPanelSize.value, "m-editor-props-form-panel-form"]),
9120
9208
  "popper-class": `m-editor-props-panel-popper ${propsPanelSize.value}`,
9121
9209
  "label-width": __props.labelWidth,
9122
9210
  "label-position": __props.labelPosition,
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.14-beta.2",
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.2",
62
- "@tmagic/form": "1.7.14-beta.2",
63
- "@tmagic/stage": "1.7.14-beta.2",
64
- "@tmagic/table": "1.7.14-beta.2",
65
- "@tmagic/utils": "1.7.14-beta.2"
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.2"
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"