@tmagic/editor 1.7.14-beta.1 → 1.7.14-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,7 +1,7 @@
1
1
  import { useServices } from "../hooks/use-services.js";
2
2
  import Icon_default from "./Icon.js";
3
3
  import { TMagicButton, TMagicDivider, TMagicDropdown, TMagicDropdownItem, TMagicDropdownMenu, TMagicIcon, TMagicTooltip } from "@tmagic/design";
4
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderList, resolveDynamicComponent, toDisplayString, toHandlers, unref, withCtx } from "vue";
4
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderList, resolveDynamicComponent, toDisplayString, toHandlers, unref, useTemplateRef, withCtx } from "vue";
5
5
  import { ArrowDown } from "@element-plus/icons-vue";
6
6
  //#region packages/editor/src/components/ToolButton.vue?vue&type=script&setup=true&lang.ts
7
7
  var _hoisted_1 = {
@@ -19,9 +19,11 @@ var ToolButton_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
19
19
  }) },
20
20
  eventType: { default: "click" }
21
21
  },
22
- setup(__props) {
22
+ setup(__props, { expose: __expose }) {
23
23
  const props = __props;
24
24
  const services = useServices();
25
+ const rootElRef = useTemplateRef("rootEl");
26
+ const getElRef = () => rootElRef;
25
27
  const disabled = computed(() => {
26
28
  if (typeof props.data === "string") return false;
27
29
  if (props.data.type === "component") return false;
@@ -53,9 +55,11 @@ var ToolButton_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
53
55
  if (props.eventType !== "mouseup") return;
54
56
  if (item.type === "button" && event.button === 0) buttonHandler(item, event);
55
57
  };
58
+ __expose({ getElRef });
56
59
  return (_ctx, _cache) => {
57
60
  return display.value ? (openBlock(), createElementBlock("div", {
58
61
  key: 0,
62
+ ref: "rootEl",
59
63
  class: normalizeClass(["menu-item", `${__props.data.type} ${__props.data.className || ""}`]),
60
64
  onClick: _cache[0] || (_cache[0] = ($event) => clickHandler(__props.data, $event)),
61
65
  onMousedown: _cache[1] || (_cache[1] = ($event) => mousedownHandler(__props.data, $event)),
@@ -124,23 +124,23 @@ var CodeEditor_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
124
124
  if (props.type === "diff") {
125
125
  const originalModel = monaco.editor.createModel(values.value, "text/javascript");
126
126
  const modifiedModel = monaco.editor.createModel(toString(m, props.language), "text/javascript");
127
- const position = vsDiffEditor?.getPosition();
127
+ const viewState = vsDiffEditor?.saveViewState();
128
128
  const result = vsDiffEditor?.setModel({
129
129
  original: originalModel,
130
130
  modified: modifiedModel
131
131
  });
132
- if (position) {
133
- vsDiffEditor?.setPosition(position);
132
+ if (viewState) nextTick(() => {
133
+ vsDiffEditor?.restoreViewState(viewState);
134
134
  vsDiffEditor?.focus();
135
- }
135
+ });
136
136
  return result;
137
137
  }
138
- const position = vsEditor?.getPosition();
138
+ const viewState = vsEditor?.saveViewState();
139
139
  const result = vsEditor?.setValue(values.value);
140
- if (position) {
141
- vsEditor?.setPosition(position);
140
+ if (viewState) nextTick(() => {
141
+ vsEditor?.restoreViewState(viewState);
142
142
  vsEditor?.focus();
143
- }
143
+ });
144
144
  return result;
145
145
  };
146
146
  const getEditorValue = () => (props.type === "diff" ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || "";
@@ -1,8 +1,8 @@
1
1
  import { ColumnLayout } from "../type.js";
2
2
  import { useServices } from "../hooks/use-services.js";
3
- import ToolButton_default from "../components/ToolButton.js";
3
+ import NavMenuColumn_default from "./NavMenuColumn.js";
4
4
  import { NodeType } from "@tmagic/core";
5
- import { Fragment, computed, createBlock, createElementBlock, defineComponent, markRaw, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, renderList, unref, useTemplateRef } from "vue";
5
+ import { Fragment, computed, createBlock, createElementBlock, defineComponent, markRaw, normalizeStyle, onBeforeUnmount, onMounted, openBlock, renderList, unref, useTemplateRef } from "vue";
6
6
  import { Back, Delete, FullScreen, Grid, Memo, Right, ScaleToOriginal, ZoomIn, ZoomOut } from "@element-plus/icons-vue";
7
7
  //#region packages/editor/src/layouts/NavMenu.vue?vue&type=script&setup=true&lang.ts
8
8
  var NavMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
@@ -165,16 +165,16 @@ var NavMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
165
165
  style: normalizeStyle({ height: `${__props.height}px` }),
166
166
  ref: "navMenu"
167
167
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(keys), (key) => {
168
- return openBlock(), createElementBlock("div", {
169
- class: normalizeClass(`menu-${key}`),
168
+ return openBlock(), createBlock(NavMenuColumn_default, {
170
169
  key,
171
- style: normalizeStyle(`width: ${columnWidth.value?.[key]}px`)
172
- }, [(openBlock(true), createElementBlock(Fragment, null, renderList(buttons.value[key], (item, index) => {
173
- return openBlock(), createBlock(ToolButton_default, {
174
- data: item,
175
- key: index
176
- }, null, 8, ["data"]);
177
- }), 128))], 6);
170
+ "column-key": key,
171
+ items: buttons.value[key],
172
+ width: columnWidth.value?.[key]
173
+ }, null, 8, [
174
+ "column-key",
175
+ "items",
176
+ "width"
177
+ ]);
178
178
  }), 128))], 4);
179
179
  };
180
180
  }
@@ -0,0 +1,5 @@
1
+ import NavMenuColumn_vue_vue_type_script_setup_true_lang_default from "./NavMenuColumn.vue_vue_type_script_setup_true_lang.js";
2
+ //#region packages/editor/src/layouts/NavMenuColumn.vue
3
+ var NavMenuColumn_default = NavMenuColumn_vue_vue_type_script_setup_true_lang_default;
4
+ //#endregion
5
+ export { NavMenuColumn_default as default };
@@ -0,0 +1,201 @@
1
+ import ToolButton_default from "../components/ToolButton.js";
2
+ import { TMagicButton, TMagicPopover } from "@tmagic/design";
3
+ import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, unref, useTemplateRef, watch, withCtx } from "vue";
4
+ import { ArrowDown, ArrowUp } from "@element-plus/icons-vue";
5
+ //#region packages/editor/src/layouts/NavMenuColumn.vue?vue&type=script&setup=true&lang.ts
6
+ var _hoisted_1 = { class: "m-editor-nav-menu-overflow-list" };
7
+ var NavMenuColumn_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
8
+ name: "MEditorNavMenuColumn",
9
+ __name: "NavMenuColumn",
10
+ props: {
11
+ columnKey: {},
12
+ items: { default: () => [] },
13
+ width: {},
14
+ gap: { default: 3 },
15
+ popoverWidth: { default: 180 }
16
+ },
17
+ setup(__props) {
18
+ const props = __props;
19
+ const columnEl = useTemplateRef("columnEl");
20
+ const moreWrapperEl = useTemplateRef("moreWrapperEl");
21
+ const popoverVisible = ref(false);
22
+ const togglePopover = () => {
23
+ popoverVisible.value = !popoverVisible.value;
24
+ };
25
+ const itemInstances = ref([]);
26
+ let slotsRO;
27
+ const observedEls = /* @__PURE__ */ new Set();
28
+ const setItemRef = (inst, index) => {
29
+ itemInstances.value[index] = inst ?? null;
30
+ };
31
+ const itemEls = computed(() => itemInstances.value.map((inst) => inst?.getElRef?.().value ?? null));
32
+ const reobserveSlots = () => {
33
+ if (!slotsRO) return;
34
+ for (const el of observedEls) slotsRO.unobserve(el);
35
+ observedEls.clear();
36
+ for (const el of itemEls.value) if (el) {
37
+ slotsRO.observe(el);
38
+ observedEls.add(el);
39
+ }
40
+ };
41
+ const cachedWidths = ref(/* @__PURE__ */ new Map());
42
+ const moreWidth = ref(0);
43
+ const containerWidth = ref(0);
44
+ const hiddenIndexSet = ref(/* @__PURE__ */ new Set());
45
+ const hasOverflow = computed(() => hiddenIndexSet.value.size > 0);
46
+ const overflowItems = computed(() => props.items.filter((_, index) => hiddenIndexSet.value.has(index)));
47
+ const measureAndCompute = () => {
48
+ if (!columnEl.value) return;
49
+ containerWidth.value = columnEl.value.clientWidth;
50
+ const els = itemEls.value;
51
+ for (let i = 0; i < props.items.length; i++) {
52
+ const el = els[i];
53
+ if (!el) {
54
+ cachedWidths.value.delete(i);
55
+ continue;
56
+ }
57
+ const w = el.getBoundingClientRect().width;
58
+ if (w > 0) cachedWidths.value.set(i, w);
59
+ else cachedWidths.value.delete(i);
60
+ }
61
+ if (moreWrapperEl.value) {
62
+ const w = moreWrapperEl.value.getBoundingClientRect().width;
63
+ if (w > 0) moreWidth.value = w;
64
+ }
65
+ const total = props.items.length;
66
+ if (total === 0 || containerWidth.value <= 0) {
67
+ if (hiddenIndexSet.value.size > 0) hiddenIndexSet.value = /* @__PURE__ */ new Set();
68
+ return;
69
+ }
70
+ let fullSum = 0;
71
+ let positive = 0;
72
+ for (let i = 0; i < total; i++) {
73
+ const w = cachedWidths.value.get(i) ?? 0;
74
+ if (w > 0) {
75
+ fullSum += w;
76
+ positive += 1;
77
+ }
78
+ }
79
+ fullSum += props.gap * Math.max(0, positive - 1);
80
+ const effectiveMoreWidth = moreWidth.value > 0 ? moreWidth.value : 32;
81
+ const reservedMore = effectiveMoreWidth + (positive > 0 ? props.gap : 0);
82
+ let nextHidden = null;
83
+ if (fullSum + reservedMore <= containerWidth.value + .5) {
84
+ if (hiddenIndexSet.value.size > 0) nextHidden = /* @__PURE__ */ new Set();
85
+ } else {
86
+ const newHidden = /* @__PURE__ */ new Set();
87
+ let used = effectiveMoreWidth;
88
+ let cutoff = -1;
89
+ for (let i = 0; i < total; i++) {
90
+ const w = cachedWidths.value.get(i) ?? 0;
91
+ if (w === 0) continue;
92
+ const need = props.gap + w;
93
+ if (used + need > containerWidth.value) {
94
+ cutoff = i;
95
+ break;
96
+ }
97
+ used += need;
98
+ }
99
+ if (cutoff >= 0) for (let j = cutoff; j < total; j++) newHidden.add(j);
100
+ nextHidden = newHidden;
101
+ }
102
+ if (nextHidden) {
103
+ if (!(nextHidden.size === hiddenIndexSet.value.size && [...nextHidden].every((v) => hiddenIndexSet.value.has(v)))) hiddenIndexSet.value = nextHidden;
104
+ }
105
+ };
106
+ let raf = 0;
107
+ const scheduleMeasure = () => {
108
+ if (raf) cancelAnimationFrame(raf);
109
+ raf = requestAnimationFrame(() => {
110
+ raf = 0;
111
+ measureAndCompute();
112
+ if (hasOverflow.value && moreWidth.value === 0) raf = requestAnimationFrame(() => {
113
+ raf = 0;
114
+ measureAndCompute();
115
+ });
116
+ });
117
+ };
118
+ watch(hasOverflow, (value) => {
119
+ if (!value) popoverVisible.value = false;
120
+ });
121
+ watch(() => props.items, () => {
122
+ cachedWidths.value = /* @__PURE__ */ new Map();
123
+ hiddenIndexSet.value = /* @__PURE__ */ new Set();
124
+ }, { deep: true });
125
+ watch(itemEls, () => {
126
+ cachedWidths.value = /* @__PURE__ */ new Map();
127
+ reobserveSlots();
128
+ scheduleMeasure();
129
+ });
130
+ watch(() => props.width, () => scheduleMeasure());
131
+ let ro;
132
+ onMounted(() => {
133
+ if (typeof ResizeObserver !== "undefined") {
134
+ if (columnEl.value) {
135
+ ro = new ResizeObserver(() => scheduleMeasure());
136
+ ro.observe(columnEl.value);
137
+ }
138
+ slotsRO = new ResizeObserver(() => scheduleMeasure());
139
+ reobserveSlots();
140
+ }
141
+ scheduleMeasure();
142
+ });
143
+ onBeforeUnmount(() => {
144
+ if (raf) cancelAnimationFrame(raf);
145
+ ro?.disconnect();
146
+ slotsRO?.disconnect();
147
+ slotsRO = void 0;
148
+ observedEls.clear();
149
+ });
150
+ return (_ctx, _cache) => {
151
+ return openBlock(), createElementBlock("div", {
152
+ class: normalizeClass(`menu-${__props.columnKey} m-editor-nav-menu-column`),
153
+ style: normalizeStyle(__props.width != null ? `width: ${__props.width}px` : ""),
154
+ ref_key: "columnEl",
155
+ ref: columnEl
156
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item, index) => {
157
+ return openBlock(), createBlock(ToolButton_default, {
158
+ data: item,
159
+ key: `item-${index}`,
160
+ class: normalizeClass({ "m-editor-nav-menu-slot-hidden": hiddenIndexSet.value.has(index) }),
161
+ ref_for: true,
162
+ ref: (comp) => setItemRef(comp, index)
163
+ }, null, 8, ["data", "class"]);
164
+ }), 128)), createElementVNode("div", {
165
+ class: normalizeClass(["m-editor-nav-menu-more-wrapper", { "m-editor-nav-menu-more-wrapper-hidden": !hasOverflow.value }]),
166
+ ref_key: "moreWrapperEl",
167
+ ref: moreWrapperEl
168
+ }, [createVNode(unref(TMagicPopover), {
169
+ placement: "bottom-end",
170
+ "popper-class": "m-editor-nav-menu-popover",
171
+ width: __props.popoverWidth,
172
+ visible: popoverVisible.value
173
+ }, {
174
+ reference: withCtx(() => [createElementVNode("div", {
175
+ class: "menu-item button m-editor-nav-menu-more",
176
+ ref: "referenceEl",
177
+ onClick: togglePopover
178
+ }, [createVNode(unref(TMagicButton), {
179
+ size: "small",
180
+ text: "",
181
+ icon: popoverVisible.value ? unref(ArrowUp) : unref(ArrowDown),
182
+ bg: popoverVisible.value,
183
+ type: popoverVisible.value ? "primary" : ""
184
+ }, null, 8, [
185
+ "icon",
186
+ "bg",
187
+ "type"
188
+ ])], 512)]),
189
+ default: withCtx(() => [createElementVNode("div", _hoisted_1, [(openBlock(true), createElementBlock(Fragment, null, renderList(overflowItems.value, (item, index) => {
190
+ return openBlock(), createBlock(ToolButton_default, {
191
+ data: item,
192
+ key: `o-${index}`
193
+ }, null, 8, ["data"]);
194
+ }), 128))])]),
195
+ _: 1
196
+ }, 8, ["width", "visible"])], 2)], 6);
197
+ };
198
+ }
199
+ });
200
+ //#endregion
201
+ export { NavMenuColumn_vue_vue_type_script_setup_true_lang_default as default };
@@ -12,6 +12,23 @@ import { NodeType } from "@tmagic/core";
12
12
  import { reactive, toRaw } from "vue";
13
13
  import { cloneDeep, isObject, mergeWith, uniq } from "lodash-es";
14
14
  //#region packages/editor/src/services/editor.ts
15
+ /**
16
+ * 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
17
+ * 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
18
+ */
19
+ var safeOptions = (options) => {
20
+ const empty = {};
21
+ if (!options || typeof options === "function") return empty;
22
+ return options;
23
+ };
24
+ /**
25
+ * 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
26
+ * 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
27
+ */
28
+ var safeParent = (parent) => {
29
+ if (!parent || typeof parent === "function") return null;
30
+ return parent;
31
+ };
15
32
  var Editor = class extends BaseService_default {
16
33
  state = reactive({
17
34
  root: null,
@@ -222,9 +239,13 @@ var Editor = class extends BaseService_default {
222
239
  * 向指点容器添加组件节点
223
240
  * @param addConfig 将要添加的组件节点配置
224
241
  * @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
242
+ * @param options 可选配置
243
+ * @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
225
244
  * @returns 添加后的节点
226
245
  */
227
- async add(addNode, parent) {
246
+ async add(addNode, parent, options) {
247
+ const safeParentNode = safeParent(parent);
248
+ const { doNotSelect = false } = safeOptions(options);
228
249
  this.captureSelectionBeforeOp();
229
250
  const stage = this.get("stage");
230
251
  const addNodes = [];
@@ -236,19 +257,21 @@ var Editor = class extends BaseService_default {
236
257
  const newNodes = await Promise.all(addNodes.map((node) => {
237
258
  const root = this.get("root");
238
259
  if ((isPage(node) || isPageFragment(node)) && root) return this.doAdd(node, root);
239
- const parentNode = parent && typeof parent !== "function" ? parent : getAddParent(node);
260
+ const parentNode = safeParentNode ?? getAddParent(node);
240
261
  if (!parentNode) throw new Error("未找到父元素");
241
262
  return this.doAdd(node, parentNode);
242
263
  }));
243
264
  if (newNodes.length > 1) {
244
- const newNodeIds = newNodes.map((node) => node.id);
245
- stage?.multiSelect(newNodeIds);
246
- await this.multiSelect(newNodeIds);
265
+ if (!doNotSelect) {
266
+ const newNodeIds = newNodes.map((node) => node.id);
267
+ stage?.multiSelect(newNodeIds);
268
+ await this.multiSelect(newNodeIds);
269
+ }
247
270
  } else {
248
- await this.select(newNodes[0]);
271
+ if (!doNotSelect) await this.select(newNodes[0]);
249
272
  if (isPage(newNodes[0])) this.state.pageLength += 1;
250
273
  else if (isPageFragment(newNodes[0])) this.state.pageFragmentLength += 1;
251
- else stage?.select(newNodes[0].id);
274
+ else if (!doNotSelect) stage?.select(newNodes[0].id);
252
275
  }
253
276
  if (!(isPage(newNodes[0]) || isPageFragment(newNodes[0]))) {
254
277
  const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
@@ -267,7 +290,8 @@ var Editor = class extends BaseService_default {
267
290
  this.emit("add", newNodes);
268
291
  return Array.isArray(addNode) ? newNodes : newNodes[0];
269
292
  }
270
- async doRemove(node) {
293
+ async doRemove(node, options) {
294
+ const { doNotSelect = false } = safeOptions(options);
271
295
  const root = this.get("root");
272
296
  if (!root) throw new Error("root不能为空");
273
297
  const { parent, node: curNode } = this.getNodeInfo(node.id, false);
@@ -281,6 +305,19 @@ var Editor = class extends BaseService_default {
281
305
  parentId: parent.id,
282
306
  root: cloneDeep(root)
283
307
  });
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
+ }
320
+ }
284
321
  const selectDefault = async (pages) => {
285
322
  if (pages[0]) {
286
323
  await this.select(pages[0]);
@@ -293,13 +330,15 @@ var Editor = class extends BaseService_default {
293
330
  const rootItems = root.items || [];
294
331
  if (isPage(node)) {
295
332
  this.state.pageLength -= 1;
296
- await selectDefault(rootItems);
333
+ if (!doNotSelect) await selectDefault(rootItems);
297
334
  } else if (isPageFragment(node)) {
298
335
  this.state.pageFragmentLength -= 1;
299
- await selectDefault(rootItems);
336
+ if (!doNotSelect) await selectDefault(rootItems);
300
337
  } else {
301
- await this.select(parent);
302
- stage?.select(parent.id);
338
+ if (!doNotSelect) {
339
+ await this.select(parent);
340
+ stage?.select(parent.id);
341
+ }
303
342
  this.addModifiedNodeId(parent.id);
304
343
  }
305
344
  if (!rootItems.length) {
@@ -309,9 +348,12 @@ var Editor = class extends BaseService_default {
309
348
  }
310
349
  /**
311
350
  * 删除组件
312
- * @param {Object} node
351
+ * @param {Object} node 要删除的节点或节点集合
352
+ * @param options 可选配置
353
+ * @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
313
354
  */
314
- async remove(nodeOrNodeList) {
355
+ async remove(nodeOrNodeList, options) {
356
+ const { doNotSelect = false } = safeOptions(options);
315
357
  this.captureSelectionBeforeOp();
316
358
  const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
317
359
  const removedItems = [];
@@ -331,11 +373,11 @@ var Editor = class extends BaseService_default {
331
373
  });
332
374
  }
333
375
  }
334
- await Promise.all(nodes.map((node) => this.doRemove(node)));
376
+ await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
335
377
  if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
336
378
  this.emit("remove", nodes);
337
379
  }
338
- async doUpdate(config, { changeRecords = [], selectedAfterUpdate = true } = {}) {
380
+ async doUpdate(config, { changeRecords = [] } = {}) {
339
381
  const root = this.get("root");
340
382
  if (!root) throw new Error("root为空");
341
383
  if (!config?.id) throw new Error("没有配置或者配置缺少id值");
@@ -362,11 +404,11 @@ var Editor = class extends BaseService_default {
362
404
  const layout = await this.getLayout(node);
363
405
  if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
364
406
  parentNodeItems[index] = newConfig;
365
- if (selectedAfterUpdate) {
366
- const nodes = this.get("nodes");
367
- const targetIndex = nodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
368
- nodes.splice(targetIndex, 1, newConfig);
369
- this.set("nodes", [...nodes]);
407
+ const selectedNodes = this.get("nodes");
408
+ const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
409
+ if (targetIndex !== -1) {
410
+ selectedNodes.splice(targetIndex, 1, newConfig);
411
+ this.set("nodes", [...selectedNodes]);
370
412
  }
371
413
  if (isPage(newConfig) || isPageFragment(newConfig)) this.set("page", newConfig);
372
414
  this.addModifiedNodeId(newConfig.id);
@@ -407,9 +449,12 @@ var Editor = class extends BaseService_default {
407
449
  * 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
408
450
  * @param id1 组件ID
409
451
  * @param id2 组件ID
452
+ * @param options 可选配置
453
+ * @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
410
454
  * @returns void
411
455
  */
412
- async sort(id1, id2) {
456
+ async sort(id1, id2, options) {
457
+ const { doNotSelect = false } = safeOptions(options);
413
458
  this.captureSelectionBeforeOp();
414
459
  const root = this.get("root");
415
460
  if (!root) throw new Error("root为空");
@@ -422,7 +467,7 @@ var Editor = class extends BaseService_default {
422
467
  const index1 = parent.items.findIndex((node) => `${node.id}` === `${id1}`);
423
468
  parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
424
469
  await this.update(parent);
425
- await this.select(node);
470
+ if (!doNotSelect) await this.select(node);
426
471
  this.get("stage")?.update({
427
472
  config: cloneDeep(node),
428
473
  parentId: parent.id,
@@ -450,9 +495,13 @@ var Editor = class extends BaseService_default {
450
495
  /**
451
496
  * 从localStorage中获取节点,然后添加到当前容器中
452
497
  * @param position 粘贴的坐标
498
+ * @param collectorOptions 可选的依赖收集器配置
499
+ * @param options 可选配置
500
+ * @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
453
501
  * @returns 添加后的组件节点配置
454
502
  */
455
- async paste(position = {}, collectorOptions) {
503
+ async paste(position = {}, collectorOptions, options) {
504
+ const { doNotSelect = false } = safeOptions(options);
456
505
  const config = storage_default.getItem(COPY_STORAGE_KEY);
457
506
  if (!Array.isArray(config)) return;
458
507
  const node = this.get("node");
@@ -463,7 +512,7 @@ var Editor = class extends BaseService_default {
463
512
  }
464
513
  const pasteConfigs = await this.doPaste(config, position);
465
514
  if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
466
- return this.add(pasteConfigs, parent);
515
+ return this.add(pasteConfigs, parent, { doNotSelect });
467
516
  }
468
517
  async doPaste(config, position = {}) {
469
518
  props_default.clearRelateId();
@@ -484,14 +533,17 @@ var Editor = class extends BaseService_default {
484
533
  /**
485
534
  * 将指点节点设置居中
486
535
  * @param config 组件节点配置
536
+ * @param options 可选配置
537
+ * @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
487
538
  * @returns 当前组件节点配置
488
539
  */
489
- async alignCenter(config) {
540
+ async alignCenter(config, options) {
541
+ const { doNotSelect = false } = safeOptions(options);
490
542
  const nodes = Array.isArray(config) ? config : [config];
491
543
  const stage = this.get("stage");
492
544
  const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
493
545
  const newNode = await this.update(newNodes);
494
- if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
546
+ if (!doNotSelect) if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
495
547
  else await stage?.select(newNodes[0].id);
496
548
  return newNode;
497
549
  }
@@ -536,8 +588,11 @@ var Editor = class extends BaseService_default {
536
588
  * 移动到指定容器中
537
589
  * @param config 需要移动的节点
538
590
  * @param targetId 容器ID
591
+ * @param options 可选配置
592
+ * @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
539
593
  */
540
- async moveToContainer(config, targetId) {
594
+ async moveToContainer(config, targetId, options) {
595
+ const { doNotSelect = false } = safeOptions(options);
541
596
  this.captureSelectionBeforeOp();
542
597
  const root = this.get("root");
543
598
  const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
@@ -559,15 +614,17 @@ var Editor = class extends BaseService_default {
559
614
  });
560
615
  newConfig.style = getInitPositionStyle(newConfig.style, layout);
561
616
  target.items.push(newConfig);
562
- await stage.select(targetId);
617
+ if (!doNotSelect) await stage.select(targetId);
563
618
  const targetParent = this.getParentById(target.id);
564
619
  await stage.update({
565
620
  config: cloneDeep(target),
566
621
  parentId: targetParent?.id,
567
622
  root: cloneDeep(root)
568
623
  });
569
- await this.select(newConfig);
570
- stage.select(newConfig.id);
624
+ if (!doNotSelect) {
625
+ await this.select(newConfig);
626
+ stage.select(newConfig.id);
627
+ }
571
628
  this.addModifiedNodeId(target.id);
572
629
  this.addModifiedNodeId(parent.id);
573
630
  this.pushOpHistory("update", { updatedItems: [{
@@ -64,10 +64,10 @@ var WebStorage = class extends BaseService_default {
64
64
  const { protocol = options.protocol, item } = this.getValueAndProtocol(storage.getItem(`${options.namespace || namespace}:${key}`));
65
65
  if (item === null) return null;
66
66
  switch (protocol) {
67
- case Protocol.OBJECT: return getEditorConfig("parseDSL")(`(${item})`);
68
- case Protocol.JSON: return JSON.parse(item);
69
- case Protocol.NUMBER: return Number(item);
70
- case Protocol.BOOLEAN:
67
+ case "object": return getEditorConfig("parseDSL")(`(${item})`);
68
+ case "json": return JSON.parse(item);
69
+ case "number": return Number(item);
70
+ case "boolean":
71
71
  if (item === "true") return true;
72
72
  if (item === "false") return false;
73
73
  default: return item;
@@ -95,7 +95,7 @@ var WebStorage = class extends BaseService_default {
95
95
  const namespace = this.getNamespace();
96
96
  let item = value;
97
97
  const protocol = options.protocol ? `${options.protocol}:` : "";
98
- if (typeof value === Protocol.STRING || typeof value === Protocol.NUMBER) item = `${protocol}${value}`;
98
+ if (typeof value === "string" || typeof value === "number") item = `${protocol}${value}`;
99
99
  else item = `${protocol}${serialize(value)}`;
100
100
  storage.setItem(`${options.namespace || namespace}:${key}`, item);
101
101
  }