@tmagic/editor 1.8.0-beta.11 → 1.8.0-beta.13

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.
Files changed (119) hide show
  1. package/dist/es/Editor.vue_vue_type_script_setup_true_lang.js +7 -4
  2. package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +5 -1
  3. package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +2 -1
  4. package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +18 -123
  5. package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +60 -14
  6. package/dist/es/components/ScrollBar.js +0 -1
  7. package/dist/es/components/ViewForm.js +5 -0
  8. package/dist/es/components/ViewForm.vue_vue_type_script_setup_true_lang.js +58 -0
  9. package/dist/es/editorProps.js +6 -1
  10. package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +15 -3
  11. package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +2 -17
  12. package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +2 -1
  13. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +7 -0
  14. package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +5 -17
  15. package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -0
  16. package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +29 -3
  17. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +50 -88
  18. package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +2 -5
  19. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +48 -23
  20. package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +6 -3
  21. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +28 -22
  22. package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +28 -22
  23. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +28 -22
  24. package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +6 -3
  25. package/dist/es/fields/UISelect.js +0 -1
  26. package/dist/es/hooks/use-compare-form.js +119 -0
  27. package/dist/es/index.js +13 -8
  28. package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +21 -6
  29. package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +9 -6
  30. package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +4 -1
  31. package/dist/es/layouts/history-list/composables.js +1 -1
  32. package/dist/es/layouts/history-list/useHistoryRevert.js +7 -3
  33. package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +44 -5
  34. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +15 -8
  35. package/dist/es/layouts/props-panel/use-style-panel.js +3 -2
  36. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +15 -31
  37. package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
  38. package/dist/es/layouts/sidebar/code-block/useContentMenu.js +18 -3
  39. package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +4 -0
  40. package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
  41. package/dist/es/layouts/sidebar/data-source/useContentMenu.js +18 -3
  42. package/dist/es/layouts/sidebar/layer/LayerNodeContent.js +5 -0
  43. package/dist/es/layouts/sidebar/layer/LayerNodeContent.vue_vue_type_script_setup_true_lang.js +46 -0
  44. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +2 -1
  45. package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +8 -2
  46. package/dist/es/plugin.js +3 -1
  47. package/dist/es/services/codeBlock.js +1 -1
  48. package/dist/es/services/editor.js +104 -5
  49. package/dist/es/services/history.js +1 -1
  50. package/dist/es/services/props.js +3 -2
  51. package/dist/es/services/storage.js +2 -2
  52. package/dist/es/services/ui.js +3 -0
  53. package/dist/es/style.css +104 -55
  54. package/dist/es/utils/data-source/index.js +30 -11
  55. package/dist/es/utils/event.js +123 -0
  56. package/dist/es/utils/monaco-editor.js +22 -6
  57. package/dist/es/utils/props.js +119 -8
  58. package/dist/es/utils/type-match-rules.js +360 -0
  59. package/dist/style.css +104 -55
  60. package/dist/tmagic-editor.umd.cjs +16996 -15806
  61. package/package.json +8 -8
  62. package/src/Editor.vue +3 -1
  63. package/src/components/CodeBlockEditor.vue +3 -0
  64. package/src/components/CompareForm.vue +16 -196
  65. package/src/components/FloatingBox.vue +77 -8
  66. package/src/components/ScrollBar.vue +0 -67
  67. package/src/components/ViewForm.vue +55 -0
  68. package/src/editorProps.ts +13 -0
  69. package/src/fields/CodeSelect.vue +4 -1
  70. package/src/fields/CondOpSelect.vue +2 -24
  71. package/src/fields/DataSourceFields.vue +5 -0
  72. package/src/fields/DataSourceInput.vue +7 -25
  73. package/src/fields/DataSourceMocks.vue +3 -0
  74. package/src/fields/DisplayConds.vue +14 -0
  75. package/src/fields/EventSelect.vue +84 -129
  76. package/src/fields/StyleSetter/Index.vue +2 -8
  77. package/src/fields/StyleSetter/pro/Background.vue +94 -55
  78. package/src/fields/StyleSetter/pro/Border.vue +9 -11
  79. package/src/fields/StyleSetter/pro/Font.vue +66 -64
  80. package/src/fields/StyleSetter/pro/Layout.vue +140 -138
  81. package/src/fields/StyleSetter/pro/Position.vue +69 -67
  82. package/src/fields/StyleSetter/pro/Transform.vue +23 -25
  83. package/src/fields/UISelect.vue +0 -12
  84. package/src/hooks/index.ts +1 -0
  85. package/src/hooks/use-compare-form.ts +187 -0
  86. package/src/index.ts +2 -0
  87. package/src/layouts/CodeEditor.vue +32 -6
  88. package/src/layouts/Framework.vue +7 -6
  89. package/src/layouts/history-list/HistoryDiffDialog.vue +11 -1
  90. package/src/layouts/history-list/useHistoryRevert.ts +4 -0
  91. package/src/layouts/props-panel/FormPanel.vue +66 -5
  92. package/src/layouts/props-panel/PropsPanel.vue +20 -6
  93. package/src/layouts/props-panel/use-style-panel.ts +4 -3
  94. package/src/layouts/sidebar/Sidebar.vue +2 -0
  95. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +4 -1
  96. package/src/layouts/sidebar/code-block/useContentMenu.ts +13 -1
  97. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +3 -0
  98. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +2 -2
  99. package/src/layouts/sidebar/data-source/useContentMenu.ts +13 -1
  100. package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
  101. package/src/layouts/sidebar/layer/LayerPanel.vue +4 -1
  102. package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
  103. package/src/plugin.ts +3 -1
  104. package/src/services/editor.ts +168 -3
  105. package/src/services/ui.ts +6 -0
  106. package/src/theme/event.scss +8 -0
  107. package/src/theme/floating-box.scss +9 -1
  108. package/src/theme/layer-node-content.scss +14 -0
  109. package/src/theme/scroll-bar.scss +64 -0
  110. package/src/theme/theme.scss +3 -0
  111. package/src/theme/ui-select.scss +9 -0
  112. package/src/type.ts +105 -2
  113. package/src/utils/data-source/index.ts +30 -12
  114. package/src/utils/event.ts +224 -0
  115. package/src/utils/index.ts +2 -0
  116. package/src/utils/monaco-editor.ts +27 -0
  117. package/src/utils/props.ts +189 -2
  118. package/src/utils/type-match-rules.ts +678 -0
  119. package/types/index.d.ts +558 -213
@@ -7,7 +7,7 @@ import storage_default, { Protocol } from "./storage.js";
7
7
  import { COPY_STORAGE_KEY, calcAlignCenterStyle, calcLayerTargetIndex, calcMoveStyle, classifyDragSources, collectRelatedNodes, describeStepForRevert, editorNodeMergeCustomizer, fixNodePosition, getInitPositionStyle, getNodeIndex, getPageFragmentList, getPageList, moveItemsInContainer, resolveSelectedNode, setChildrenLayout, setLayout, toggleFixedPosition } from "../utils/editor.js";
8
8
  import { beforePaste, getAddParent } from "../utils/operator.js";
9
9
  import { isFixed } from "@tmagic/stage";
10
- import { getNodeInfo, getNodePath, getValueByKeyPath, guid, isPage, isPageFragment, setValueByKeyPath } from "@tmagic/utils";
10
+ import { getNodeInfo, getNodePath, getValueByKeyPath, guid, isPage, isPageFragment, setValueByKeyPath, traverseNode } from "@tmagic/utils";
11
11
  import { NodeType } from "@tmagic/core";
12
12
  import { reactive, toRaw } from "vue";
13
13
  import { cloneDeep as cloneDeep$1, isEmpty, isEqual, isObject, mergeWith, uniq } from "lodash-es";
@@ -33,6 +33,7 @@ var Editor = class extends BaseService {
33
33
  stageLoading: true,
34
34
  highlightNode: null,
35
35
  modifiedNodeIds: /* @__PURE__ */ new Map(),
36
+ invalidNodeIds: /* @__PURE__ */ new Map(),
36
37
  pageLength: 0,
37
38
  pageFragmentLength: 0,
38
39
  disabledMultiSelect: false,
@@ -40,6 +41,11 @@ var Editor = class extends BaseService {
40
41
  });
41
42
  selectionBeforeOp = null;
42
43
  /**
44
+ * 操作前的节点校验错误快照,与 selectionBeforeOp 同时在 captureSelectionBeforeOp 中捕获,
45
+ * 供 pushOpHistory 写入 step.extra.invalidNodeIdsBefore,用于撤销时还原到「操作前」的错误状态。
46
+ */
47
+ invalidNodeIdsBeforeOp = null;
48
+ /**
43
49
  * 最近一次 pushOpHistory 写入的历史记录 uuid。
44
50
  * 供 *AndGetHistoryId 系列方法在调用普通操作后取回本次产生的历史记录 id;
45
51
  * 普通操作不会读取它,调用前由 *AndGetHistoryId 重置为 null。
@@ -57,7 +63,7 @@ var Editor = class extends BaseService {
57
63
  }
58
64
  /**
59
65
  * 设置当前指点节点配置
60
- * @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength
66
+ * @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'invalidNodeIds' | 'pageLength' | 'pageFragmentLength
61
67
  * @param value MNode
62
68
  * @param options.historySource 设置 root 时,本次变更写入历史记录的「操作来源」(仅 name === 'root' 时生效)
63
69
  */
@@ -85,11 +91,12 @@ var Editor = class extends BaseService {
85
91
  this.state.stageLoading = false;
86
92
  }
87
93
  this.emit("root-change", value, preValue, options);
94
+ this.pruneInvalidNodeIds();
88
95
  }
89
96
  }
90
97
  /**
91
98
  * 获取当前指点节点配置
92
- * @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'pageLength' | 'pageFragmentLength'
99
+ * @param name 'root' | 'page' | 'parent' | 'node' | 'highlightNode' | 'nodes' | 'stage' | 'modifiedNodeIds' | 'invalidNodeIds' | 'pageLength' | 'pageFragmentLength'
93
100
  * @returns MNode
94
101
  */
95
102
  get(name) {
@@ -430,6 +437,7 @@ var Editor = class extends BaseService {
430
437
  doNotSelect,
431
438
  doNotSwitchPage
432
439
  })));
440
+ this.removeInvalidNodesBySubtree(nodes);
433
441
  if (removedItems.length > 0 && pageForOp) if (!doNotPushHistory) this.pushOpHistory("remove", {
434
442
  diff: removedItems,
435
443
  pageData: pageForOp,
@@ -499,7 +507,7 @@ var Editor = class extends BaseService {
499
507
  */
500
508
  async update(config, data = {}) {
501
509
  this.captureSelectionBeforeOp();
502
- const { doNotPushHistory = false, changeRecordList, changeRecords, historyDescription, historySource } = data;
510
+ const { doNotPushHistory = false, changeRecordList, changeRecords, historyDescription, historySource, invalidInfo } = data;
503
511
  const nodes = Array.isArray(config) ? config : [config];
504
512
  const updateData = await Promise.all(nodes.map((node, index) => {
505
513
  const recordsForNode = changeRecordList ? changeRecordList[index] ?? [] : changeRecords ?? [];
@@ -508,6 +516,7 @@ var Editor = class extends BaseService {
508
516
  historySource
509
517
  });
510
518
  }));
519
+ this.applyInvalidInfo(config, invalidInfo);
511
520
  if (updateData[0].oldNode?.type !== NodeType.ROOT) {
512
521
  if (this.get("nodes").length) if (!doNotPushHistory) {
513
522
  const pageForOp = this.getNodeInfo(nodes[0].id, false).page;
@@ -1078,6 +1087,7 @@ var Editor = class extends BaseService {
1078
1087
  this.set("stage", null);
1079
1088
  this.set("highlightNode", null);
1080
1089
  this.set("modifiedNodeIds", /* @__PURE__ */ new Map());
1090
+ this.set("invalidNodeIds", /* @__PURE__ */ new Map());
1081
1091
  this.set("pageLength", 0);
1082
1092
  }
1083
1093
  destroy() {
@@ -1088,6 +1098,51 @@ var Editor = class extends BaseService {
1088
1098
  resetModifiedNodeId() {
1089
1099
  this.get("modifiedNodeIds").clear();
1090
1100
  }
1101
+ /**
1102
+ * 记录(或覆盖)某个节点在指定来源(属性表单 / 样式表单)上的校验错误信息。
1103
+ * @param id 节点 id
1104
+ * @param source 错误来源:'props'(属性表单)| 'style'(样式表单)
1105
+ * @param message 错误文案(可能是包含 <br> 的 HTML)
1106
+ */
1107
+ setInvalidNode(id, source, message) {
1108
+ const map = this.get("invalidNodeIds");
1109
+ const info = { ...map.get(id) || {} };
1110
+ info[source] = message;
1111
+ map.set(id, info);
1112
+ this.emit("invalid-node-change", map);
1113
+ }
1114
+ /**
1115
+ * 删除节点的校验错误记录。
1116
+ * @param id 节点 id
1117
+ * @param source 指定来源则仅删除该来源;不传则删除该节点全部来源的错误
1118
+ */
1119
+ deleteInvalidNode(id, source) {
1120
+ const map = this.get("invalidNodeIds");
1121
+ if (!map.has(id)) return;
1122
+ if (!source) map.delete(id);
1123
+ else {
1124
+ const info = { ...map.get(id) || {} };
1125
+ delete info[source];
1126
+ if (info.props || info.style) map.set(id, info);
1127
+ else map.delete(id);
1128
+ }
1129
+ this.emit("invalid-node-change", map);
1130
+ }
1131
+ /** 获取当前存在校验错误的节点错误 Map(key 为节点 id) */
1132
+ getInvalidNodeIds() {
1133
+ return this.get("invalidNodeIds");
1134
+ }
1135
+ /** 获取指定节点的校验错误信息 */
1136
+ getInvalidNodeInfo(id) {
1137
+ return this.get("invalidNodeIds").get(id);
1138
+ }
1139
+ /** 清空全部校验错误记录 */
1140
+ resetInvalidNodeId() {
1141
+ const map = this.get("invalidNodeIds");
1142
+ if (map.size === 0) return;
1143
+ map.clear();
1144
+ this.emit("invalid-node-change", map);
1145
+ }
1091
1146
  usePlugin(options) {
1092
1147
  super.usePlugin(options);
1093
1148
  }
@@ -1100,6 +1155,43 @@ var Editor = class extends BaseService {
1100
1155
  emit(eventName, ...args) {
1101
1156
  return super.emit(eventName, ...args);
1102
1157
  }
1158
+ /**
1159
+ * 应用一次属性面板提交携带的校验错误信息(在写入历史记录之前调用,使历史快照与本次变更对齐)。
1160
+ * - invalidInfo 为空(调用方未携带):认为本次更新对应的节点已无校验错误,清除其全部来源的错误;
1161
+ * - error 非空则记录错误,为空则清除对应来源的错误。
1162
+ */
1163
+ applyInvalidInfo(config, invalidInfo) {
1164
+ if (!invalidInfo) {
1165
+ (Array.isArray(config) ? config : [config]).map((node) => node.id).filter((id) => id !== void 0).forEach((id) => this.deleteInvalidNode(id));
1166
+ return;
1167
+ }
1168
+ const { id, source, error } = invalidInfo;
1169
+ if (error) this.setInvalidNode(id, source, error);
1170
+ else this.deleteInvalidNode(id, source);
1171
+ }
1172
+ /** 删除被移除节点(含其子树)的校验错误记录,避免残留误报 */
1173
+ removeInvalidNodesBySubtree(nodes) {
1174
+ const map = this.get("invalidNodeIds");
1175
+ if (map.size === 0) return;
1176
+ let changed = false;
1177
+ nodes.forEach((node) => {
1178
+ traverseNode(node, (n) => {
1179
+ if (n.id !== void 0 && map.delete(n.id)) changed = true;
1180
+ });
1181
+ });
1182
+ if (changed) this.emit("invalid-node-change", map);
1183
+ }
1184
+ /** 清理不在当前 DSL 中的失效节点错误记录(用于整体替换 root 后) */
1185
+ pruneInvalidNodeIds() {
1186
+ const map = this.get("invalidNodeIds");
1187
+ if (map.size === 0) return;
1188
+ let changed = false;
1189
+ for (const id of [...map.keys()]) if (!this.getNodeById(id, false)) {
1190
+ map.delete(id);
1191
+ changed = true;
1192
+ }
1193
+ if (changed) this.emit("invalid-node-change", map);
1194
+ }
1103
1195
  addModifiedNodeId(id) {
1104
1196
  this.get("modifiedNodeIds").set(id, id);
1105
1197
  }
@@ -1119,6 +1211,7 @@ var Editor = class extends BaseService {
1119
1211
  captureSelectionBeforeOp() {
1120
1212
  if (this.selectionBeforeOp) return;
1121
1213
  this.selectionBeforeOp = this.get("nodes").map((n) => n.id);
1214
+ this.invalidNodeIdsBeforeOp = new Map(this.get("invalidNodeIds"));
1122
1215
  }
1123
1216
  /**
1124
1217
  * 比较「上一次 root」与「新 root」的页面 / 页面片,按页面粒度把整体替换拆成历史记录:
@@ -1191,7 +1284,9 @@ var Editor = class extends BaseService {
1191
1284
  extra: {
1192
1285
  selectedBefore: this.selectionBeforeOp ?? [],
1193
1286
  selectedAfter: this.get("nodes").map((n) => n.id),
1194
- modifiedNodeIds: new Map(this.get("modifiedNodeIds"))
1287
+ modifiedNodeIds: new Map(this.get("modifiedNodeIds")),
1288
+ invalidNodeIdsBefore: new Map(this.invalidNodeIdsBeforeOp ?? this.get("invalidNodeIds")),
1289
+ invalidNodeIdsAfter: new Map(this.get("invalidNodeIds"))
1195
1290
  },
1196
1291
  diff
1197
1292
  };
@@ -1200,6 +1295,7 @@ var Editor = class extends BaseService {
1200
1295
  const historyId = history_default.push("page", step, pageData.id) ? step.uuid : null;
1201
1296
  this.lastPushedHistoryId = historyId;
1202
1297
  this.selectionBeforeOp = null;
1298
+ this.invalidNodeIdsBeforeOp = null;
1203
1299
  return historyId;
1204
1300
  }
1205
1301
  /**
@@ -1299,6 +1395,9 @@ var Editor = class extends BaseService {
1299
1395
  }
1300
1396
  }
1301
1397
  this.set("modifiedNodeIds", step.extra?.modifiedNodeIds ?? /* @__PURE__ */ new Map());
1398
+ const invalidToRestore = (reverse ? step.extra?.invalidNodeIdsBefore : step.extra?.invalidNodeIdsAfter) ?? /* @__PURE__ */ new Map();
1399
+ this.set("invalidNodeIds", new Map(invalidToRestore));
1400
+ this.emit("invalid-node-change", this.get("invalidNodeIds"));
1302
1401
  const page = toRaw(this.get("page"));
1303
1402
  if (page) {
1304
1403
  const selectIds = (reverse ? step.extra?.selectedBefore : step.extra?.selectedAfter) ?? [];
@@ -1,5 +1,5 @@
1
- import BaseService from "./BaseService.js";
2
1
  import { getEditorConfig } from "../utils/config.js";
2
+ import BaseService from "./BaseService.js";
3
3
  import { UndoRedo } from "../utils/undo-redo.js";
4
4
  import { deserializeStacks, getOrCreateStack, markStackSaved, mergeSteps, serializeStacks, undoFloor } from "../utils/history.js";
5
5
  import { idbGet, idbSet } from "../utils/indexed-db.js";
@@ -1,5 +1,5 @@
1
- import BaseService from "./BaseService.js";
2
1
  import { fillConfig } from "../utils/props.js";
2
+ import BaseService from "./BaseService.js";
3
3
  import editor_default from "./editor.js";
4
4
  import { getNodePath, getValueByKeyPath, guid, setValueByKeyPath, toLine } from "@tmagic/utils";
5
5
  import { Target, Watcher } from "@tmagic/core";
@@ -187,7 +187,8 @@ var Props = class extends BaseService {
187
187
  const targetConfig = path[path.length - 1];
188
188
  if (!targetConfig) return;
189
189
  target.deps[config.id]?.keys?.forEach((fullKey) => {
190
- const relateTargetId = relateIdMap[getValueByKeyPath(fullKey, config)];
190
+ const relateOriginId = getValueByKeyPath(fullKey, config);
191
+ const relateTargetId = relateIdMap[relateOriginId];
191
192
  if (!relateTargetId) return;
192
193
  setValueByKeyPath(fullKey, relateTargetId, targetConfig);
193
194
  });
@@ -1,5 +1,5 @@
1
- import BaseService from "./BaseService.js";
2
1
  import { getEditorConfig } from "../utils/config.js";
2
+ import BaseService from "./BaseService.js";
3
3
  import serialize from "serialize-javascript";
4
4
  //#region packages/editor/src/services/storage.ts
5
5
  var Protocol = /* @__PURE__ */ function(Protocol) {
@@ -124,4 +124,4 @@ var WebStorage = class extends BaseService {
124
124
  };
125
125
  var storage_default = new WebStorage();
126
126
  //#endregion
127
- export { Protocol, storage_default as default };
127
+ export { Protocol, WebStorage, storage_default as default };
@@ -23,6 +23,9 @@ var state = shallowReactive({
23
23
  center: 0,
24
24
  right: storage_default.getItem("$MagicEditorRightColumnWidthData", { protocol: Protocol.NUMBER }) || 480
25
25
  },
26
+ minLeftColumnWidth: 200,
27
+ minCenterColumnWidth: 400,
28
+ minRightColumnWidth: 300,
26
29
  showGuides: true,
27
30
  hasGuides: false,
28
31
  showRule: true,
package/dist/es/style.css CHANGED
@@ -1,55 +1,4 @@
1
- @charset "UTF-8";.m-editor-scroll-bar {
2
- position: absolute;
3
- background-color: transparent;
4
- opacity: 0.3;
5
- transition: background-color 0.2s linear, opacity 0.2s linear;
6
- }
7
- .m-editor-scroll-bar .m-editor-scroll-bar-thumb {
8
- background-color: #aaa;
9
- border-radius: 6px;
10
- position: absolute;
11
- }
12
- .m-editor-scroll-bar.horizontal {
13
- width: 100%;
14
- height: 15px;
15
- bottom: 0;
16
- }
17
- .m-editor-scroll-bar.horizontal .m-editor-scroll-bar-thumb {
18
- height: 6px;
19
- transition: background-color 0.2s linear, height 0.2s ease-in-out;
20
- bottom: 2px;
21
- }
22
- .m-editor-scroll-bar.vertical {
23
- height: 100%;
24
- width: 15px;
25
- right: 5px;
26
- }
27
- .m-editor-scroll-bar.vertical .m-editor-scroll-bar-thumb {
28
- width: 6px;
29
- transition: background-color 0.2s linear, width 0.2s ease-in-out;
30
- right: 2px;
31
- }
32
- .m-editor-scroll-bar:hover, .m-editor-scroll-bar:focus {
33
- background-color: #eee;
34
- opacity: 0.9;
35
- }
36
- .m-editor-scroll-bar:hover .m-editor-scroll-bar-thumb, .m-editor-scroll-bar:focus .m-editor-scroll-bar-thumb {
37
- background-color: #999;
38
- }
39
- .m-editor-scroll-bar:hover.horizontal .m-editor-scroll-bar-thumb, .m-editor-scroll-bar:focus.horizontal .m-editor-scroll-bar-thumb {
40
- height: 11px;
41
- }
42
- .m-editor-scroll-bar:hover.vertical .m-editor-scroll-bar-thumb, .m-editor-scroll-bar:focus.vertical .m-editor-scroll-bar-thumb {
43
- width: 11px;
44
- }.m-fields-ui-select {
45
- cursor: pointer;
46
- }
47
- .m-fields-ui-select i {
48
- margin-right: 3px;
49
- }
50
- .m-fields-ui-select span {
51
- color: #2882e0;
52
- }
1
+ @charset "UTF-8";
53
2
  .tmagic-design-popper {
54
3
  min-width: 150px;
55
4
  line-height: 1.4;
@@ -115,6 +64,22 @@
115
64
  color: #999;
116
65
  }
117
66
 
67
+ .tmagic-table-sub-actions {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: 4px;
71
+ align-items: flex-start;
72
+ }
73
+ .tmagic-table-sub-actions .sub-action-btn {
74
+ width: 100%;
75
+ }
76
+ .tmagic-table-sub-actions .tmagic-design-button + .tmagic-design-button {
77
+ margin-left: 0;
78
+ }
79
+ .tmagic-table-sub-actions .tmagic-design-button {
80
+ justify-content: flex-start;
81
+ }
82
+
118
83
  .tmagic-design-form-inline .m-form-container {
119
84
  display: inline-flex;
120
85
  }
@@ -139,7 +104,7 @@
139
104
  .m-form-dialog .m-dialog-body {
140
105
  padding: 0 20px;
141
106
  }
142
- .m-form-dialog .el-table .m-form-item .el-form-item {
107
+ .m-form-dialog .el-table .m-form-item .el-form-item:not(.is-error) {
143
108
  margin-bottom: 0;
144
109
  }
145
110
 
@@ -363,6 +328,10 @@ fieldset.m-fieldset .m-form-tip {
363
328
  width: 95vw !important;
364
329
  }
365
330
 
331
+ .el-form-item .m-fields-table .el-form-item.is-error {
332
+ margin-bottom: 18px;
333
+ }
334
+
366
335
  .m-fields-table {
367
336
  width: 100%;
368
337
  }
@@ -385,7 +354,7 @@ fieldset.m-fieldset .m-form-tip {
385
354
  .m-fields-table .el-table__expanded-cell .m-form-tip {
386
355
  margin-left: 80px;
387
356
  }
388
- .m-fields-table .el-form-item {
357
+ .m-fields-table .el-form-item:not(.is-error) {
389
358
  margin-bottom: 0;
390
359
  }
391
360
  .m-fields-table .tmagic-form-table-drag-target {
@@ -1808,6 +1777,10 @@ fieldset.m-fieldset .m-form-tip {
1808
1777
  margin-right: 5px;
1809
1778
  }
1810
1779
 
1780
+ .el-form-item .el-form-item.is-error {
1781
+ margin-bottom: 18px;
1782
+ }
1783
+
1811
1784
  .m-editor-layout {
1812
1785
  width: 100%;
1813
1786
  display: flex;
@@ -2020,13 +1993,21 @@ fieldset.m-fieldset .m-form-tip {
2020
1993
  .m-editor-float-box .m-editor-float-box-body {
2021
1994
  overflow: auto;
2022
1995
  flex: 1;
2023
- padding: 0 16px;
2024
1996
  }
2025
1997
 
2026
1998
  .m-editor-floating-box-moveable {
2027
1999
  opacity: 0;
2028
2000
  }
2029
2001
 
2002
+ .m-editor-float-box-drag-mask {
2003
+ position: fixed;
2004
+ top: 0;
2005
+ left: 0;
2006
+ width: 100%;
2007
+ height: 100%;
2008
+ background-color: transparent;
2009
+ }
2010
+
2030
2011
  .m-fields-page-fragment-select {
2031
2012
  width: 100%;
2032
2013
  }
@@ -2076,6 +2057,74 @@ fieldset.m-fieldset .m-form-tip {
2076
2057
  padding: 5px 8px;
2077
2058
  }
2078
2059
 
2060
+ .m-editor-scroll-bar {
2061
+ position: absolute;
2062
+ background-color: transparent;
2063
+ opacity: 0.3;
2064
+ transition: background-color 0.2s linear, opacity 0.2s linear;
2065
+ }
2066
+ .m-editor-scroll-bar .m-editor-scroll-bar-thumb {
2067
+ background-color: #aaa;
2068
+ border-radius: 6px;
2069
+ position: absolute;
2070
+ }
2071
+ .m-editor-scroll-bar.horizontal {
2072
+ width: 100%;
2073
+ height: 15px;
2074
+ bottom: 0;
2075
+ }
2076
+ .m-editor-scroll-bar.horizontal .m-editor-scroll-bar-thumb {
2077
+ height: 6px;
2078
+ transition: background-color 0.2s linear, height 0.2s ease-in-out;
2079
+ bottom: 2px;
2080
+ }
2081
+ .m-editor-scroll-bar.vertical {
2082
+ height: 100%;
2083
+ width: 15px;
2084
+ right: 5px;
2085
+ }
2086
+ .m-editor-scroll-bar.vertical .m-editor-scroll-bar-thumb {
2087
+ width: 6px;
2088
+ transition: background-color 0.2s linear, width 0.2s ease-in-out;
2089
+ right: 2px;
2090
+ }
2091
+ .m-editor-scroll-bar:hover, .m-editor-scroll-bar:focus {
2092
+ background-color: #eee;
2093
+ opacity: 0.9;
2094
+ }
2095
+ .m-editor-scroll-bar:hover .m-editor-scroll-bar-thumb, .m-editor-scroll-bar:focus .m-editor-scroll-bar-thumb {
2096
+ background-color: #999;
2097
+ }
2098
+ .m-editor-scroll-bar:hover.horizontal .m-editor-scroll-bar-thumb, .m-editor-scroll-bar:focus.horizontal .m-editor-scroll-bar-thumb {
2099
+ height: 11px;
2100
+ }
2101
+ .m-editor-scroll-bar:hover.vertical .m-editor-scroll-bar-thumb, .m-editor-scroll-bar:focus.vertical .m-editor-scroll-bar-thumb {
2102
+ width: 11px;
2103
+ }
2104
+
2105
+ .m-fields-ui-select {
2106
+ cursor: pointer;
2107
+ }
2108
+ .m-fields-ui-select i {
2109
+ margin-right: 3px;
2110
+ }
2111
+ .m-fields-ui-select span {
2112
+ color: #2882e0;
2113
+ }
2114
+
2115
+ .m-editor-layer-node-content {
2116
+ display: inline-flex;
2117
+ align-items: center;
2118
+ }
2119
+ .m-editor-layer-node-content.is-invalid .m-editor-layer-node-label {
2120
+ color: var(--el-color-danger, #f56c6c);
2121
+ }
2122
+ .m-editor-layer-node-content .m-editor-layer-node-error-icon {
2123
+ margin-left: 4px;
2124
+ color: var(--el-color-danger, #f56c6c);
2125
+ cursor: help;
2126
+ }
2127
+
2079
2128
  .border-box-container {
2080
2129
  display: flex;
2081
2130
  }
@@ -188,17 +188,36 @@ var getCascaderOptionsFromFields = (fields = [], dataSourceFieldType = ["any"])
188
188
  }
189
189
  return result;
190
190
  };
191
- var getFieldType = (ds, fieldNames) => {
192
- let fields = ds?.fields;
193
- let type = "";
194
- for (const fieldName of fieldNames) {
195
- if (!fields?.length) return "";
196
- const field = fields.find((f) => f.name === fieldName);
197
- if (!field) return "";
198
- type = field.type || "";
199
- fields = field.fields;
191
+ /**
192
+ * 按字段名路径下钻 DataSchema。
193
+ * @param skipNumberIndices 为 true 时跳过数字段(模板路径中的数组下标,如 arr[0].x)
194
+ */
195
+ var resolveFieldByPath = (fields, fieldNames, options = {}) => {
196
+ let currentFields = fields || [];
197
+ let field;
198
+ for (const name of fieldNames) {
199
+ if (options.skipNumberIndices && isNumber(name)) continue;
200
+ if (!currentFields.length) return {
201
+ ok: false,
202
+ fields: currentFields
203
+ };
204
+ field = currentFields.find((item) => item.name === name);
205
+ if (!field) return {
206
+ ok: false,
207
+ fields: currentFields
208
+ };
209
+ currentFields = field.fields || [];
200
210
  }
201
- return type;
211
+ return {
212
+ field,
213
+ ok: true,
214
+ fields: currentFields
215
+ };
216
+ };
217
+ var getFieldType = (ds, fieldNames) => {
218
+ const { ok, field } = resolveFieldByPath(ds?.fields, fieldNames);
219
+ if (!ok) return "";
220
+ return field?.type || "";
202
221
  };
203
222
  //#endregion
204
- export { getCascaderOptionsFromFields, getDisplayField, getFieldType, getFormConfig, getFormValue };
223
+ export { getCascaderOptionsFromFields, getDisplayField, getFieldType, getFormConfig, getFormValue, resolveFieldByPath };
@@ -0,0 +1,123 @@
1
+ import editor_default from "../services/editor.js";
2
+ import { getCascaderOptionsFromFields } from "./data-source/index.js";
3
+ import dataSource_default from "../services/dataSource.js";
4
+ import events_default from "../services/events.js";
5
+ import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX, traverseNode } from "@tmagic/utils";
6
+ //#region packages/editor/src/utils/event.ts
7
+ var EVENT_NAME_VALUE_SEPARATOR = ".";
8
+ /** 与 EventSelect 中 checkStrictly 一致:component 为 false,其余为 true */
9
+ var isEventNameCheckStrictly = (src) => src !== "component";
10
+ /** 将动作 method 值规范为与 collectEventNameOptionValues 一致的字符串(cascader 无 valueSeparator 时存数组) */
11
+ var normalizeCompActionValue = (value) => {
12
+ if (Array.isArray(value)) return value.map((item) => `${item}`).join(".");
13
+ if (value === null || value === void 0 || value === "") return "";
14
+ return `${value}`;
15
+ };
16
+ /**
17
+ * 组装事件名称下拉/级联 options,与 EventSelect 默认 eventNameConfig.options 逻辑一致。
18
+ */
19
+ var getEventNameOptions = (src, formValue = {}) => {
20
+ if (!formValue.type) return [];
21
+ if (src === "component") {
22
+ let events = events_default.getEvent(formValue.type) || [];
23
+ if (formValue.type === "page-fragment-container" && formValue.pageFragmentId) {
24
+ const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === formValue.pageFragmentId);
25
+ if (!pageFragment) return [];
26
+ events = [{
27
+ label: pageFragment.name || "页面片容器",
28
+ value: pageFragment.id,
29
+ children: events
30
+ }];
31
+ (pageFragment.items || []).forEach((node) => {
32
+ traverseNode(node, (current) => {
33
+ const nodeEvents = current.type && events_default.getEvent(current.type) || [];
34
+ events.push({
35
+ label: `${current.name}_${current.id}`,
36
+ value: `${current.id}`,
37
+ children: nodeEvents
38
+ });
39
+ });
40
+ });
41
+ return events;
42
+ }
43
+ return events.map((option) => ({
44
+ text: option.label,
45
+ value: option.value
46
+ }));
47
+ }
48
+ if (src === "datasource") {
49
+ const events = dataSource_default.getFormEvent(formValue.type) || [];
50
+ const fields = dataSource_default.getDataSourceById(formValue.id)?.fields || [];
51
+ if (fields.length > 0) return [...events, {
52
+ label: "数据变化",
53
+ value: DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX,
54
+ children: getCascaderOptionsFromFields(fields)
55
+ }];
56
+ return events;
57
+ }
58
+ return [];
59
+ };
60
+ /** 将 select / cascader options 展平为最终写入 name 的字符串集合(cascader 用 `.` 拼接) */
61
+ var collectEventNameOptionValues = (options, checkStrictly, prefix = [], result = /* @__PURE__ */ new Set()) => {
62
+ options.forEach((option) => {
63
+ if (typeof option?.value === "undefined") return;
64
+ const path = [...prefix, option.value];
65
+ const joined = path.map((item) => `${item}`).join(".");
66
+ const children = "children" in option ? option.children : void 0;
67
+ if (Array.isArray(children) && children.length) {
68
+ if (checkStrictly) result.add(joined);
69
+ collectEventNameOptionValues(children, checkStrictly, path, result);
70
+ return;
71
+ }
72
+ result.add(joined);
73
+ });
74
+ return result;
75
+ };
76
+ /**
77
+ * 解析 event-select 允许的 name 集合。
78
+ * 自定义 eventNameConfig.options 时返回 null(跳过枚举校验)。
79
+ */
80
+ var getEventNameAllowedValues = (config = {}, formValue = {}) => {
81
+ if (typeof config.eventNameConfig?.options !== "undefined") return null;
82
+ if (config.src !== "component" && config.src !== "datasource") return null;
83
+ return collectEventNameOptionValues(getEventNameOptions(config.src, formValue), isEventNameCheckStrictly(config.src));
84
+ };
85
+ /**
86
+ * 组装联动组件动作下拉/级联 options,与 EventSelect 默认 compActionConfig.options 逻辑一致。
87
+ */
88
+ var getCompActionOptions = (toId) => {
89
+ if (typeof toId === "undefined" || toId === null || toId === "") return [];
90
+ const node = editor_default.getNodeById(toId);
91
+ if (!node?.type) return [];
92
+ let methods = events_default.getMethod(node.type, toId) || [];
93
+ if (node.type === "page-fragment-container" && node.pageFragmentId) {
94
+ const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === node.pageFragmentId);
95
+ if (!pageFragment) return [];
96
+ methods = [];
97
+ (pageFragment.items || []).forEach((item) => {
98
+ traverseNode(item, (current) => {
99
+ const nodeMethods = current.type && events_default.getMethod(current.type, current.id) || [];
100
+ if (nodeMethods.length) methods.push({
101
+ label: `${current.name}_${current.id}`,
102
+ value: `${current.id}`,
103
+ children: nodeMethods
104
+ });
105
+ });
106
+ });
107
+ return methods;
108
+ }
109
+ return methods.map((method) => ({
110
+ text: method.label,
111
+ value: method.value
112
+ }));
113
+ };
114
+ /**
115
+ * 解析 event-select 联动组件动作允许的 method 集合。
116
+ * 自定义 compActionConfig.options 时返回 null(跳过枚举校验)。
117
+ */
118
+ var getCompActionAllowedValues = (config = {}, model = {}) => {
119
+ if (typeof config.compActionConfig?.options !== "undefined") return null;
120
+ return collectEventNameOptionValues(getCompActionOptions(model.to), isEventNameCheckStrictly(config.src));
121
+ };
122
+ //#endregion
123
+ export { EVENT_NAME_VALUE_SEPARATOR, collectEventNameOptionValues, getCompActionAllowedValues, getCompActionOptions, getEventNameAllowedValues, getEventNameOptions, isEventNameCheckStrictly, normalizeCompActionValue };
@@ -1,12 +1,28 @@
1
1
  //#region packages/editor/src/utils/monaco-editor.ts
2
2
  var cached;
3
- var monaco_editor_default = () => {
4
- if (!cached) cached = Promise.all([import("emmet-monaco-es"), import("monaco-editor")]).then(([emmet, monaco]) => {
5
- const { emmetHTML, emmetCSS } = emmet;
6
- emmetHTML(monaco);
7
- emmetCSS(monaco, ["css", "scss"]);
8
- return monaco;
3
+ var isMonacoCanceledError = (reason) => {
4
+ if (!reason) return false;
5
+ if (reason instanceof Error) return reason.name === "Canceled" || reason.message === "Canceled";
6
+ return reason === "Canceled";
7
+ };
8
+ var canceledRejectionHandlerInstalled = false;
9
+ var installCanceledRejectionHandler = () => {
10
+ if (canceledRejectionHandlerInstalled || typeof globalThis.addEventListener !== "function") return;
11
+ canceledRejectionHandlerInstalled = true;
12
+ globalThis.addEventListener("unhandledrejection", (event) => {
13
+ if (isMonacoCanceledError(event.reason)) event.preventDefault();
9
14
  });
15
+ };
16
+ var monaco_editor_default = () => {
17
+ if (!cached) {
18
+ installCanceledRejectionHandler();
19
+ cached = Promise.all([import("emmet-monaco-es"), import("monaco-editor")]).then(([emmet, monaco]) => {
20
+ const { emmetHTML, emmetCSS } = emmet;
21
+ emmetHTML(monaco);
22
+ emmetCSS(monaco, ["css", "scss"]);
23
+ return monaco;
24
+ });
25
+ }
10
26
  return cached;
11
27
  };
12
28
  //#endregion