@tmagic/editor 1.8.0-beta.20 → 1.8.0-beta.22

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 (31) hide show
  1. package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +5 -2
  2. package/dist/es/fields/StyleSetter/components/Box.vue_vue_type_script_setup_true_lang.js +2 -2
  3. package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +6 -1
  4. package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +35 -3
  5. package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +26 -5
  6. package/dist/es/index.js +2 -2
  7. package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +23 -12
  8. package/dist/es/layouts/sidebar/ComponentListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
  9. package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +1 -1
  10. package/dist/es/services/editor.js +12 -8
  11. package/dist/es/services/events.js +2 -2
  12. package/dist/es/utils/dep/idle-task.js +28 -5
  13. package/dist/es/utils/event.js +19 -7
  14. package/dist/es/utils/type-match-rules.js +17 -9
  15. package/dist/tmagic-editor.umd.cjs +173 -57
  16. package/package.json +7 -7
  17. package/src/fields/EventSelect.vue +7 -5
  18. package/src/fields/StyleSetter/components/Box.vue +1 -1
  19. package/src/fields/StyleSetter/components/Position.vue +1 -1
  20. package/src/fields/StyleSetter/pro/Background.vue +7 -0
  21. package/src/fields/StyleSetter/pro/Font.vue +57 -0
  22. package/src/fields/StyleSetter/pro/Position.vue +31 -0
  23. package/src/layouts/props-panel/PropsPanel.vue +30 -16
  24. package/src/layouts/sidebar/ComponentListPanel.vue +5 -1
  25. package/src/layouts/sidebar/layer/LayerPanel.vue +1 -1
  26. package/src/services/editor.ts +27 -8
  27. package/src/services/events.ts +3 -3
  28. package/src/utils/dep/idle-task.ts +43 -11
  29. package/src/utils/event.ts +25 -12
  30. package/src/utils/type-match-rules.ts +37 -4
  31. package/types/index.d.ts +33 -4
@@ -7818,14 +7818,14 @@
7818
7818
  remove: removedPages
7819
7819
  });
7820
7820
  }
7821
- async doUpdate(config, { changeRecords = [], historySource } = {}) {
7821
+ async doUpdate(config, { changeRecords = [], historySource, replace = false } = {}) {
7822
7822
  if (!this.get("root")) throw new Error("root为空");
7823
7823
  if (!config?.id) throw new Error("没有配置或者配置缺少id值");
7824
7824
  const info = this.getNodeInfo(config.id, false);
7825
7825
  if (!info.node) throw new Error(`获取不到id为${config.id}的节点`);
7826
7826
  const node = (0, vue.toRaw)(info.node);
7827
- let newConfig = await toggleFixedPosition((0, vue.toRaw)(config), node, info.path, this.getLayout);
7828
- newConfig = mergeWith(cloneDeep$1(node), newConfig, editorNodeMergeCustomizer);
7827
+ let newConfig = replace ? cloneDeep$1((0, vue.toRaw)(config)) : await toggleFixedPosition((0, vue.toRaw)(config), node, info.path, this.getLayout);
7828
+ if (!replace) newConfig = mergeWith(cloneDeep$1(node), newConfig, editorNodeMergeCustomizer);
7829
7829
  if (!newConfig.type) throw new Error("配置缺少type值");
7830
7830
  if (newConfig.type === _tmagic_core.NodeType.ROOT) {
7831
7831
  this.set("root", newConfig, { historySource });
@@ -7840,9 +7840,11 @@
7840
7840
  const parentNodeItems = parent.items;
7841
7841
  const index = getNodeIndex(newConfig.id, parent);
7842
7842
  if (!parentNodeItems || typeof index === "undefined" || index === -1) throw new Error("更新的节点未找到");
7843
- const newLayout = await this.getLayout(newConfig);
7844
- const layout = await this.getLayout(node);
7845
- if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
7843
+ if (!replace) {
7844
+ const newLayout = await this.getLayout(newConfig);
7845
+ const layout = await this.getLayout(node);
7846
+ if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
7847
+ }
7846
7848
  parentNodeItems[index] = newConfig;
7847
7849
  const selectedNodes = this.get("nodes");
7848
7850
  const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
@@ -7870,17 +7872,19 @@
7870
7872
  * @param data.changeRecordList 多节点 form 端变更记录列表,按 config 数组同序对应每个节点;优先级高于 changeRecords
7871
7873
  * @param data.doNotPushHistory 是否不写入历史记录(默认 false)
7872
7874
  * @param data.historyDescription 入栈时附带的人类可读描述,用于历史面板展示(不影响 undo/redo 行为)
7875
+ * @param data.replace 是否整节点替换:为 true 时跳过 mergeWith / toggleFixedPosition / setChildrenLayout,直接用传入配置覆盖(默认 false)
7873
7876
  * @returns 更新后的节点配置
7874
7877
  */
7875
7878
  async update(config, data = {}) {
7876
7879
  this.captureSelectionBeforeOp();
7877
- const { doNotPushHistory = false, changeRecordList, changeRecords, historyDescription, historySource, invalidInfo } = data;
7880
+ const { doNotPushHistory = false, changeRecordList, changeRecords, historyDescription, historySource, replace = false, invalidInfo } = data;
7878
7881
  const nodes = Array.isArray(config) ? config : [config];
7879
7882
  const updateData = await Promise.all(nodes.map((node, index) => {
7880
7883
  const recordsForNode = changeRecordList ? changeRecordList[index] ?? [] : changeRecords ?? [];
7881
7884
  return this.doUpdate(node, {
7882
7885
  changeRecords: recordsForNode,
7883
- historySource
7886
+ historySource,
7887
+ replace
7884
7888
  });
7885
7889
  }));
7886
7890
  this.applyInvalidInfo(config, invalidInfo);
@@ -9647,6 +9651,16 @@
9647
9651
  };
9648
9652
  //#endregion
9649
9653
  //#region packages/editor/src/utils/dep/idle-task.ts
9654
+ /**
9655
+ * 回调因 timeout 触发(主线程一直没有空闲)时,单次回调执行任务的时间预算,单位 ms
9656
+ * 参考一帧内可让出的余量:既保证队列有进展,又不长时间阻塞主线程
9657
+ */
9658
+ var TIMEOUT_RUN_BUDGET = 5;
9659
+ /**
9660
+ * 回调因 timeout 触发时,每两次读取时钟之间执行的任务数
9661
+ * 与空闲时间 <=5ms 时的批量保持一致,避免每个任务都读一次时钟
9662
+ */
9663
+ var TIMEOUT_BATCH_SIZE = 10;
9650
9664
  globalThis.requestIdleCallback = globalThis.requestIdleCallback || function(cb) {
9651
9665
  const start = Date.now();
9652
9666
  return setTimeout(() => {
@@ -9698,6 +9712,13 @@
9698
9712
  runTaskQueue(deadline) {
9699
9713
  this.taskHandle = null;
9700
9714
  try {
9715
+ if (deadline.didTimeout) {
9716
+ const start = Date.now();
9717
+ do
9718
+ this.runTaskBatch(TIMEOUT_BATCH_SIZE);
9719
+ while (this.getTaskLength() && Date.now() - start < TIMEOUT_RUN_BUDGET);
9720
+ return;
9721
+ }
9701
9722
  while (deadline.timeRemaining() > 0 && this.getTaskLength()) {
9702
9723
  const timeRemaining = deadline.timeRemaining();
9703
9724
  let times = 0;
@@ -9705,17 +9726,23 @@
9705
9726
  else if (timeRemaining <= 10) times = 100;
9706
9727
  else if (timeRemaining <= 15) times = 300;
9707
9728
  else times = 600;
9708
- for (let i = 0; i < times; i++) {
9709
- const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
9710
- if (task) this.runTask(task);
9711
- if (!this.getTaskLength()) break;
9712
- }
9729
+ this.runTaskBatch(times);
9713
9730
  }
9714
9731
  } finally {
9715
9732
  this.finishRun();
9716
9733
  }
9717
9734
  }
9718
9735
  /**
9736
+ * 执行一批任务,队列被清空时提前结束
9737
+ */
9738
+ runTaskBatch(times) {
9739
+ for (let i = 0; i < times; i++) {
9740
+ const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
9741
+ if (task) this.runTask(task);
9742
+ if (!this.getTaskLength()) break;
9743
+ }
9744
+ }
9745
+ /**
9719
9746
  * 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
9720
9747
  * 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
9721
9748
  */
@@ -11066,15 +11093,22 @@
11066
11093
  if (config.value === "key") return true;
11067
11094
  return `${value[0]}`.startsWith(_tmagic_utils.DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX);
11068
11095
  };
11069
- var validateDataSourceFieldSelect = (value, { mForm, message, props }) => {
11096
+ /**
11097
+ * data-source-field-select 的 typeMatch 校验逻辑,可供自定义 rules.validator 复用。
11098
+ */
11099
+ var validateDataSourceFieldSelectValue = (value, context, options) => {
11100
+ const { mForm, message, props } = context;
11070
11101
  const config = props.config || {};
11071
- if (config.fieldConfig && !isDataSourceFieldPathValue(value, config)) return (0, _tmagic_form.validateTypeMatch)(value, mForm, {
11072
- ...props,
11073
- config: {
11074
- name: config.name,
11075
- ...config.fieldConfig
11076
- }
11077
- }, message);
11102
+ if (!isDataSourceFieldPathValue(value, config)) {
11103
+ if (options?.validatePlainValue) return options.validatePlainValue(value, context);
11104
+ if (config.fieldConfig) return (0, _tmagic_form.validateTypeMatch)(value, mForm, {
11105
+ ...props,
11106
+ config: {
11107
+ name: config.name,
11108
+ ...config.fieldConfig
11109
+ }
11110
+ }, message);
11111
+ }
11078
11112
  if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) return defaultMessage(message, `${value}类型应为字符串数组`, dataSourceFieldPathSuggestion());
11079
11113
  return validateDataSourceFieldPath(value, {
11080
11114
  dataSourceId: config.dataSourceId,
@@ -11083,6 +11117,7 @@
11083
11117
  message
11084
11118
  });
11085
11119
  };
11120
+ var validateDataSourceFieldSelect = (value, context) => validateDataSourceFieldSelectValue(value, context);
11086
11121
  var validateDataSourceSelect = (value, { message, props }) => {
11087
11122
  const config = props.config || {};
11088
11123
  const dataSources = getDataSources();
@@ -11193,7 +11228,7 @@
11193
11228
  setEvent(type, events) {
11194
11229
  eventMap[(0, _tmagic_utils.toLine)(type)] = [...events];
11195
11230
  }
11196
- getEvent(type) {
11231
+ getEvent(type, _data = {}) {
11197
11232
  return cloneDeep$1(eventMap[(0, _tmagic_utils.toLine)(type)]) || [];
11198
11233
  }
11199
11234
  setMethods(methods) {
@@ -11204,7 +11239,7 @@
11204
11239
  setMethod(type, method) {
11205
11240
  methodMap[(0, _tmagic_utils.toLine)(type)] = [...method];
11206
11241
  }
11207
- getMethod(type, _targetId) {
11242
+ getMethod(type, _data = {}) {
11208
11243
  return cloneDeep$1(methodMap[(0, _tmagic_utils.toLine)(type)]) || [];
11209
11244
  }
11210
11245
  resetState() {
@@ -11238,7 +11273,8 @@
11238
11273
  var getEventNameOptions = (src, formValue = {}) => {
11239
11274
  if (!formValue.type) return [];
11240
11275
  if (src === "component") {
11241
- let events = events_default.getEvent(formValue.type) || [];
11276
+ const sourceNode = editor_default.getNodeById(formValue.id);
11277
+ let events = events_default.getEvent(formValue.type, { node: sourceNode }) || [];
11242
11278
  if (formValue.type === "page-fragment-container" && formValue.pageFragmentId) {
11243
11279
  const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === formValue.pageFragmentId);
11244
11280
  if (!pageFragment) return [];
@@ -11247,9 +11283,11 @@
11247
11283
  value: pageFragment.id,
11248
11284
  children: events
11249
11285
  }];
11250
- (pageFragment.items || []).forEach((node) => {
11251
- (0, _tmagic_utils.traverseNode)(node, (current) => {
11252
- const nodeEvents = current.type && events_default.getEvent(current.type) || [];
11286
+ (pageFragment.items || []).forEach((item) => {
11287
+ (0, _tmagic_utils.traverseNode)(item, (current) => {
11288
+ if (!current.type) return;
11289
+ const node = editor_default.getNodeById(current.id) || current;
11290
+ const nodeEvents = events_default.getEvent(current.type, { node }) || [];
11253
11291
  events.push({
11254
11292
  label: `${current.name}_${current.id}`,
11255
11293
  value: `${current.id}`,
@@ -11308,15 +11346,24 @@
11308
11346
  if (typeof toId === "undefined" || toId === null || toId === "") return [];
11309
11347
  const node = editor_default.getNodeById(toId);
11310
11348
  if (!node?.type) return [];
11311
- let methods = events_default.getMethod(node.type, toId) || [];
11349
+ let methods = events_default.getMethod(node.type, {
11350
+ targetId: toId,
11351
+ node
11352
+ }) || [];
11312
11353
  if (node.type === "page-fragment-container" && node.pageFragmentId) {
11313
11354
  const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === node.pageFragmentId);
11314
11355
  if (!pageFragment) return [];
11315
11356
  methods = [];
11316
11357
  (pageFragment.items || []).forEach((item) => {
11317
11358
  (0, _tmagic_utils.traverseNode)(item, (current) => {
11318
- const nodeMethods = current.type && events_default.getMethod(current.type, current.id) || [];
11319
- if (nodeMethods.length) methods.push({
11359
+ const node = editor_default.getNodeById(current.id) || current;
11360
+ if (!current.type) return;
11361
+ const nodeMethods = events_default.getMethod(current.type, {
11362
+ targetId: current.id,
11363
+ node
11364
+ }) || [];
11365
+ if (!nodeMethods.length) return;
11366
+ methods.push({
11320
11367
  label: `${current.name}_${current.id}`,
11321
11368
  value: `${current.id}`,
11322
11369
  children: nodeMethods
@@ -15113,22 +15160,33 @@
15113
15160
  const submit = async (v, eventData, error, source = "props") => {
15114
15161
  try {
15115
15162
  if (!v.id) v.id = values.value.id;
15116
- const newValue = {
15117
- ...v,
15118
- style: {}
15119
- };
15120
- if (v.style) if (eventData) {
15121
- Object.entries(v.style).forEach(([key, value]) => {
15122
- if (value !== "" && newValue.style) newValue.style[key] = value;
15123
- });
15124
- eventData.changeRecords?.forEach((record) => {
15125
- if (record.propPath?.startsWith("style") && record.value === "") (0, _tmagic_utils.setValueByKeyPath)(record.propPath, record.value, newValue);
15126
- });
15127
- } else newValue.style = { ...v.style };
15128
15163
  const historySource = eventData ? "props" : "code";
15164
+ const replace = historySource === "code";
15165
+ let newValue;
15166
+ if (replace) if (source === "style") newValue = {
15167
+ ...values.value,
15168
+ id: v.id || values.value.id,
15169
+ style: { ...v.style || {} }
15170
+ };
15171
+ else newValue = { ...v };
15172
+ else {
15173
+ newValue = {
15174
+ ...v,
15175
+ style: {}
15176
+ };
15177
+ if (v.style) {
15178
+ Object.entries(v.style).forEach(([key, value]) => {
15179
+ if (value !== "" && newValue.style) newValue.style[key] = value;
15180
+ });
15181
+ eventData?.changeRecords?.forEach((record) => {
15182
+ if (record.propPath?.startsWith("style") && record.value === "") (0, _tmagic_utils.setValueByKeyPath)(record.propPath, record.value, newValue);
15183
+ });
15184
+ }
15185
+ }
15129
15186
  editorService.update(newValue, {
15130
15187
  changeRecords: eventData?.changeRecords,
15131
15188
  historySource,
15189
+ replace,
15132
15190
  ...enablePropsFormValidate && error ? { invalidInfo: {
15133
15191
  id: newValue.id,
15134
15192
  source,
@@ -17771,7 +17829,7 @@
17771
17829
  let name = "";
17772
17830
  if (data.name) name = data.name;
17773
17831
  else if (data.items) name = "container";
17774
- return `${data.id}${name}${data.type}`.includes(v);
17832
+ return `${data.id}${name}${data.type || ""}`.toLocaleLowerCase().includes(v.toLocaleLowerCase());
17775
17833
  };
17776
17834
  const { filterTextChangeHandler } = useFilter(nodeData, nodeStatusMap, filterNodeMethod);
17777
17835
  const collapseAllHandler = () => {
@@ -17866,7 +17924,7 @@
17866
17924
  const stage = (0, vue.computed)(() => editorService.get("stage"));
17867
17925
  const list = (0, vue.computed)(() => componentListService.getList().map((group) => ({
17868
17926
  ...group,
17869
- items: group.items.filter((item) => item.text.includes(searchText.value))
17927
+ items: group.items.filter((item) => `${item.text || ""}${item.desc || ""}${item.type}`.toLocaleLowerCase().includes(searchText.value.toLocaleLowerCase()))
17870
17928
  })));
17871
17929
  const collapseValue = (0, vue.ref)();
17872
17930
  (0, vue.watch)(list, () => {
@@ -23003,7 +23061,7 @@
23003
23061
  name: "name",
23004
23062
  label: "事件名",
23005
23063
  type: eventNameConfig.value.type,
23006
- options: (mForm, { formValue }) => eventsService.getEvent(formValue.type).map((option) => ({
23064
+ options: (mForm, { formValue }) => eventsService.getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) }).map((option) => ({
23007
23065
  text: option.label,
23008
23066
  value: option.value
23009
23067
  }))
@@ -23020,7 +23078,10 @@
23020
23078
  options: (mForm, { model }) => {
23021
23079
  const node = editorService.getNodeById(model.to);
23022
23080
  if (!node?.type) return [];
23023
- return eventsService.getMethod(node.type, model.to).map((option) => ({
23081
+ return eventsService.getMethod(node.type, {
23082
+ targetId: model.to,
23083
+ node
23084
+ }).map((option) => ({
23024
23085
  text: option.label,
23025
23086
  value: option.value
23026
23087
  }));
@@ -24016,7 +24077,11 @@
24016
24077
  text: "背景色",
24017
24078
  labelWidth: "68px",
24018
24079
  type: "data-source-field-select",
24019
- fieldConfig: { type: "colorPicker" }
24080
+ fieldConfig: { type: "colorPicker" },
24081
+ rules: [{
24082
+ typeMatch: true,
24083
+ message: (0, _tmagic_design.appendValidateSuggestion)("背景色应为字符串", "请参考以下示例值:\"#000000\"")
24084
+ }]
24020
24085
  },
24021
24086
  {
24022
24087
  name: "backgroundImage",
@@ -24194,7 +24259,11 @@
24194
24259
  name: "fontSize",
24195
24260
  text: "字号",
24196
24261
  type: "data-source-field-select",
24197
- fieldConfig: { type: "text" }
24262
+ fieldConfig: { type: "text" },
24263
+ rules: [{
24264
+ typeMatch: true,
24265
+ message: (0, _tmagic_design.appendValidateSuggestion)("字号应为字符串或数字", "请参考以下示例值:24 或 \"24\"")
24266
+ }]
24198
24267
  }, {
24199
24268
  labelWidth: "68px",
24200
24269
  name: "lineHeight",
@@ -24208,20 +24277,46 @@
24208
24277
  text: "字重",
24209
24278
  labelWidth: "68px",
24210
24279
  type: "data-source-field-select",
24280
+ dataSourceFieldType: ["string", "number"],
24211
24281
  fieldConfig: {
24212
24282
  type: "select",
24283
+ allowCreate: true,
24213
24284
  options: ["normal", "bold"].concat(Array(7).fill(1).map((x, i) => `${i + 1}00`)).map((item) => ({
24214
24285
  value: item,
24215
24286
  text: item
24216
24287
  }))
24217
- }
24288
+ },
24289
+ rules: [{ typeMatch: false }, { validator: ({ value, callback }, { config, model, prop }, mForm) => {
24290
+ if (value === "" || value === null || value === void 0) return callback();
24291
+ const result = validateDataSourceFieldSelectValue(value, {
24292
+ fieldType: "data-source-field-select",
24293
+ mForm,
24294
+ props: {
24295
+ config,
24296
+ model,
24297
+ prop
24298
+ }
24299
+ }, { validatePlainValue: (plainValue) => {
24300
+ if (typeof plainValue === "string" || typeof plainValue === "number" && !Number.isNaN(plainValue)) return;
24301
+ return "字重应为字符串或数字";
24302
+ } });
24303
+ if (result && typeof result.then === "function") {
24304
+ result.then((error) => callback(error), (error) => callback(error));
24305
+ return;
24306
+ }
24307
+ return callback(result);
24308
+ } }]
24218
24309
  },
24219
24310
  {
24220
24311
  labelWidth: "68px",
24221
24312
  name: "color",
24222
24313
  text: "颜色",
24223
24314
  type: "data-source-field-select",
24224
- fieldConfig: { type: "colorPicker" }
24315
+ fieldConfig: { type: "colorPicker" },
24316
+ rules: [{
24317
+ typeMatch: true,
24318
+ message: (0, _tmagic_design.appendValidateSuggestion)("颜色应为字符串", "请参考以下示例值:\"#000000\"")
24319
+ }]
24225
24320
  },
24226
24321
  {
24227
24322
  name: "textAlign",
@@ -24293,7 +24388,7 @@
24293
24388
  };
24294
24389
  var _hoisted_3$1 = { class: "next-input" };
24295
24390
  var _hoisted_4$1 = [
24296
- "model-value",
24391
+ "value",
24297
24392
  "title",
24298
24393
  "disabled",
24299
24394
  "onChange"
@@ -24355,7 +24450,7 @@
24355
24450
  key: index,
24356
24451
  class: (0, vue.normalizeClass)(item.class)
24357
24452
  }, [item.text ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_2$1, (0, vue.toDisplayString)(item.text), 1)) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createElementVNode)("span", _hoisted_3$1, [(0, vue.createElementVNode)("input", {
24358
- "model-value": __props.model[item.name],
24453
+ value: __props.model[item.name],
24359
24454
  placeholder: "0",
24360
24455
  title: __props.model[item.name],
24361
24456
  disabled: __props.disabled,
@@ -25194,12 +25289,20 @@
25194
25289
  name: "left",
25195
25290
  type: "data-source-field-select",
25196
25291
  text: "left",
25197
- fieldConfig: { type: "text" }
25292
+ fieldConfig: { type: "text" },
25293
+ rules: [{
25294
+ typeMatch: true,
25295
+ message: (0, _tmagic_design.appendValidateSuggestion)("left 应为字符串", "请参考以下示例值:\"10\"")
25296
+ }]
25198
25297
  }, {
25199
25298
  name: "top",
25200
25299
  type: "data-source-field-select",
25201
25300
  text: "top",
25202
- fieldConfig: { type: "text" }
25301
+ fieldConfig: { type: "text" },
25302
+ rules: [{
25303
+ typeMatch: true,
25304
+ message: (0, _tmagic_design.appendValidateSuggestion)("top 应为字符串", "请参考以下示例值:\"10\"")
25305
+ }]
25203
25306
  }]
25204
25307
  },
25205
25308
  {
@@ -25210,12 +25313,20 @@
25210
25313
  name: "right",
25211
25314
  type: "data-source-field-select",
25212
25315
  text: "right",
25213
- fieldConfig: { type: "text" }
25316
+ fieldConfig: { type: "text" },
25317
+ rules: [{
25318
+ typeMatch: true,
25319
+ message: (0, _tmagic_design.appendValidateSuggestion)("right 应为字符串", "请参考以下示例值:\"10\"")
25320
+ }]
25214
25321
  }, {
25215
25322
  name: "bottom",
25216
25323
  type: "data-source-field-select",
25217
25324
  text: "bottom",
25218
- fieldConfig: { type: "text" }
25325
+ fieldConfig: { type: "text" },
25326
+ rules: [{
25327
+ typeMatch: true,
25328
+ message: (0, _tmagic_design.appendValidateSuggestion)("bottom 应为字符串", "请参考以下示例值:\"10\"")
25329
+ }]
25219
25330
  }]
25220
25331
  },
25221
25332
  {
@@ -25223,7 +25334,11 @@
25223
25334
  name: "zIndex",
25224
25335
  text: "zIndex",
25225
25336
  type: "data-source-field-select",
25226
- fieldConfig: { type: "text" }
25337
+ fieldConfig: { type: "text" },
25338
+ rules: [{
25339
+ typeMatch: true,
25340
+ message: (0, _tmagic_design.appendValidateSuggestion)("zIndex 应为数字", "请参考以下示例值:10")
25341
+ }]
25227
25342
  }
25228
25343
  ]);
25229
25344
  const change = (value, eventData) => {
@@ -26188,6 +26303,7 @@
26188
26303
  exports.useServices = useServices;
26189
26304
  exports.useStage = useStage;
26190
26305
  exports.useWindowRect = useWindowRect;
26306
+ exports.validateDataSourceFieldSelectValue = validateDataSourceFieldSelectValue;
26191
26307
  exports.warn = warn;
26192
26308
  Object.keys(_tmagic_form).forEach(function(k) {
26193
26309
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.20",
2
+ "version": "1.8.0-beta.22",
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.8.0-beta.20",
62
- "@tmagic/form": "1.8.0-beta.20",
63
- "@tmagic/stage": "1.8.0-beta.20",
64
- "@tmagic/table": "1.8.0-beta.20",
65
- "@tmagic/utils": "1.8.0-beta.20"
61
+ "@tmagic/design": "1.8.0-beta.22",
62
+ "@tmagic/form": "1.8.0-beta.22",
63
+ "@tmagic/utils": "1.8.0-beta.22",
64
+ "@tmagic/table": "1.8.0-beta.22",
65
+ "@tmagic/stage": "1.8.0-beta.22"
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.40",
79
- "@tmagic/core": "1.8.0-beta.20"
79
+ "@tmagic/core": "1.8.0-beta.22"
80
80
  },
81
81
  "peerDependenciesMeta": {
82
82
  "typescript": {
@@ -311,10 +311,12 @@ const tableConfig = computed(
311
311
  label: '事件名',
312
312
  type: eventNameConfig.value.type,
313
313
  options: (mForm: FormState, { formValue }: any) =>
314
- eventsService.getEvent(formValue.type).map((option: any) => ({
315
- text: option.label,
316
- value: option.value,
317
- })),
314
+ eventsService
315
+ .getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) })
316
+ .map((option: any) => ({
317
+ text: option.label,
318
+ value: option.value,
319
+ })),
318
320
  },
319
321
  {
320
322
  name: 'to',
@@ -329,7 +331,7 @@ const tableConfig = computed(
329
331
  const node = editorService.getNodeById(model.to);
330
332
  if (!node?.type) return [];
331
333
 
332
- return eventsService.getMethod(node.type, model.to).map((option: any) => ({
334
+ return eventsService.getMethod(node.type, { targetId: model.to, node }).map((option: any) => ({
333
335
  text: option.label,
334
336
  value: option.value,
335
337
  }));
@@ -4,7 +4,7 @@
4
4
  <span class="help-txt" v-if="item.text">{{ item.text }}</span>
5
5
  <span class="next-input">
6
6
  <input
7
- :model-value="model[item.name]"
7
+ :value="model[item.name]"
8
8
  placeholder="0"
9
9
  :title="model[item.name]"
10
10
  :disabled="disabled"
@@ -3,7 +3,7 @@
3
3
  <div v-for="(item, index) in list" :key="index" :class="item.class">
4
4
  <span class="next-input">
5
5
  <input
6
- :model-value="model[item.name]"
6
+ :value="model[item.name]"
7
7
  placeholder="0"
8
8
  :title="model[item.name]"
9
9
  :disabled="disabled"
@@ -17,6 +17,7 @@
17
17
  <script lang="ts" setup>
18
18
  import { markRaw } from 'vue';
19
19
 
20
+ import { appendValidateSuggestion } from '@tmagic/design';
20
21
  import { type ContainerChangeEventData, defineFormConfig, MContainer } from '@tmagic/form';
21
22
  import type { StyleSchema } from '@tmagic/schema';
22
23
 
@@ -47,6 +48,12 @@ const formConfig = defineFormConfig([
47
48
  fieldConfig: {
48
49
  type: 'colorPicker',
49
50
  },
51
+ rules: [
52
+ {
53
+ typeMatch: true,
54
+ message: appendValidateSuggestion('背景色应为字符串', '请参考以下示例值:"#000000"'),
55
+ },
56
+ ],
50
57
  },
51
58
  {
52
59
  name: 'backgroundImage',
@@ -17,9 +17,12 @@
17
17
  <script lang="ts" setup>
18
18
  import { markRaw } from 'vue';
19
19
 
20
+ import { appendValidateSuggestion } from '@tmagic/design';
20
21
  import { type ContainerChangeEventData, defineFormConfig, MContainer } from '@tmagic/form';
21
22
  import type { StyleSchema } from '@tmagic/schema';
22
23
 
24
+ import { validateDataSourceFieldSelectValue } from '@editor/utils/type-match-rules';
25
+
23
26
  import { AlignCenter, AlignLeft, AlignRight } from '../icons/text-align';
24
27
 
25
28
  defineProps<{
@@ -48,6 +51,12 @@ const formConfig = defineFormConfig([
48
51
  fieldConfig: {
49
52
  type: 'text',
50
53
  },
54
+ rules: [
55
+ {
56
+ typeMatch: true,
57
+ message: appendValidateSuggestion('字号应为字符串或数字', '请参考以下示例值:24 或 "24"'),
58
+ },
59
+ ],
51
60
  },
52
61
  {
53
62
  labelWidth: '68px',
@@ -65,8 +74,10 @@ const formConfig = defineFormConfig([
65
74
  text: '字重',
66
75
  labelWidth: '68px',
67
76
  type: 'data-source-field-select',
77
+ dataSourceFieldType: ['string', 'number'],
68
78
  fieldConfig: {
69
79
  type: 'select',
80
+ allowCreate: true,
70
81
  options: ['normal', 'bold']
71
82
  .concat(
72
83
  Array(7)
@@ -78,6 +89,46 @@ const formConfig = defineFormConfig([
78
89
  text: item,
79
90
  })),
80
91
  },
92
+ rules: [
93
+ {
94
+ typeMatch: false,
95
+ },
96
+ {
97
+ validator: ({ value, callback }, { config, model, prop }, mForm) => {
98
+ if (value === '' || value === null || value === undefined) {
99
+ return callback();
100
+ }
101
+
102
+ const result = validateDataSourceFieldSelectValue(
103
+ value,
104
+ {
105
+ fieldType: 'data-source-field-select',
106
+ mForm,
107
+ props: { config, model, prop },
108
+ },
109
+ {
110
+ // 字重允许 string(含可创建项)与 number(如 700)
111
+ validatePlainValue: (plainValue) => {
112
+ if (typeof plainValue === 'string' || (typeof plainValue === 'number' && !Number.isNaN(plainValue))) {
113
+ return undefined;
114
+ }
115
+ return '字重应为字符串或数字';
116
+ },
117
+ },
118
+ );
119
+
120
+ if (result && typeof (result as Promise<string | undefined>).then === 'function') {
121
+ (result as Promise<string | undefined>).then(
122
+ (error) => callback(error),
123
+ (error) => callback(error),
124
+ );
125
+ return;
126
+ }
127
+
128
+ return callback(result);
129
+ },
130
+ },
131
+ ],
81
132
  },
82
133
  {
83
134
  labelWidth: '68px',
@@ -87,6 +138,12 @@ const formConfig = defineFormConfig([
87
138
  fieldConfig: {
88
139
  type: 'colorPicker',
89
140
  },
141
+ rules: [
142
+ {
143
+ typeMatch: true,
144
+ message: appendValidateSuggestion('颜色应为字符串', '请参考以下示例值:"#000000"'),
145
+ },
146
+ ],
90
147
  },
91
148
  {
92
149
  name: 'textAlign',