@tmagic/form 1.8.0-beta.12 → 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.
@@ -255,16 +255,18 @@ var Container_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
255
255
  "data-tmagic-form-item-prop": itemProp.value,
256
256
  class: normalizeClass(`m-form-container m-container-${type.value || ""} ${__props.config.className || ""}${__props.config.tip ? " has-tip" : ""}`),
257
257
  style: normalizeStyle(__props.config.style)
258
- }, [type.value === "hidden" ? (openBlock(), createBlock(Hidden_default, {
259
- key: 0,
260
- name: `${name.value}`,
261
- prop: itemProp.value,
262
- model: __props.model
263
- }, null, 8, [
264
- "name",
265
- "prop",
266
- "model"
267
- ])) : items.value && !text.value && type.value && display$1.value ? (openBlock(), createBlock(resolveDynamicComponent(tagName.value), mergeProps({ key: 1 }, fieldsProps.value, {
258
+ }, [type.value === "hidden" ? (openBlock(), createBlock(unref(TMagicFormItem), mergeProps({ key: 0 }, formItemProps.value, { style: { "display": "none" } }), {
259
+ default: withCtx(() => [createVNode(Hidden_default, {
260
+ name: `${name.value}`,
261
+ prop: itemProp.value,
262
+ model: __props.model
263
+ }, null, 8, [
264
+ "name",
265
+ "prop",
266
+ "model"
267
+ ])]),
268
+ _: 1
269
+ }, 16)) : items.value && !text.value && type.value && display$1.value ? (openBlock(), createBlock(resolveDynamicComponent(tagName.value), mergeProps({ key: 1 }, fieldsProps.value, {
268
270
  model: __props.model,
269
271
  "last-values": __props.lastValues,
270
272
  "is-compare": __props.isCompare,
package/dist/es/index.js CHANGED
@@ -7,7 +7,7 @@ import { clearTypeMatchRules, deleteTypeMatchRule, getTypeMatchRule, registerTyp
7
7
  import { adaptFormValidator, createObjectProp, createValues, datetimeFormatter, display, filterFunction, getDataByPage, getRules, initValue, sortArray, sortChange } from "./utils/form.js";
8
8
  import Container_default from "./containers/Container.js";
9
9
  import Form_default from "./Form.js";
10
- import { submitForm, validateForm } from "./submitForm.js";
10
+ import { stripTabItemsLazy, submitForm, validateForm } from "./submitForm.js";
11
11
  import FormDialog_default from "./FormDialog.js";
12
12
  import FormDrawer_default from "./FormDrawer.js";
13
13
  import FormBox_default from "./FormBox.js";
@@ -40,4 +40,4 @@ import plugin_default from "./plugin.js";
40
40
  export * from "@tmagic/form-schema";
41
41
  var createForm = (config) => config;
42
42
  //#endregion
43
- export { FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, Cascader_default as MCascader, Checkbox_default as MCheckbox, CheckboxGroup_default as MCheckboxGroup, ColorPicker_default as MColorPicker, Container_default as MContainer, Date_default as MDate, DateTime_default as MDateTime, Daterange_default as MDaterange, Display_default as MDisplay, DynamicField_default as MDynamicField, Fieldset_default as MFieldset, FlexLayout_default as MFlexLayout, Form_default as MForm, FormBox_default as MFormBox, FormDialog_default as MFormDialog, FormDrawer_default as MFormDrawer, TableGroupList_default as MGroupList, Hidden_default as MHidden, Link_default as MLink, Number_default as MNumber, NumberRange_default as MNumberRange, Panel_default as MPanel, RadioGroup_default as MRadioGroup, Row_default as MRow, Select_default as MSelect, Switch_default as MSwitch, TableGroupList_default as MTable, TableGroupList_default as MTableGroupList, Tabs_default as MTabs, Text_default as MText, Textarea_default as MTextarea, Time_default as MTime, Timerange_default as MTimerange, adaptFormValidator, clearTypeMatchRules, createForm, createObjectProp, createValues, datetimeFormatter, plugin_default as default, deleteField as deleteFormField, deleteTypeMatchRule, display, filterFunction, getDataByPage, getField as getFormField, getRules, getTypeMatchRule, initValue, registerField as registerFormField, registerTypeMatchRule, registerTypeMatchRules, sortArray, sortChange, submitForm, useAddField, validateForm, validateTypeMatch };
43
+ export { FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, Cascader_default as MCascader, Checkbox_default as MCheckbox, CheckboxGroup_default as MCheckboxGroup, ColorPicker_default as MColorPicker, Container_default as MContainer, Date_default as MDate, DateTime_default as MDateTime, Daterange_default as MDaterange, Display_default as MDisplay, DynamicField_default as MDynamicField, Fieldset_default as MFieldset, FlexLayout_default as MFlexLayout, Form_default as MForm, FormBox_default as MFormBox, FormDialog_default as MFormDialog, FormDrawer_default as MFormDrawer, TableGroupList_default as MGroupList, Hidden_default as MHidden, Link_default as MLink, Number_default as MNumber, NumberRange_default as MNumberRange, Panel_default as MPanel, RadioGroup_default as MRadioGroup, Row_default as MRow, Select_default as MSelect, Switch_default as MSwitch, TableGroupList_default as MTable, TableGroupList_default as MTableGroupList, Tabs_default as MTabs, Text_default as MText, Textarea_default as MTextarea, Time_default as MTime, Timerange_default as MTimerange, adaptFormValidator, clearTypeMatchRules, createForm, createObjectProp, createValues, datetimeFormatter, plugin_default as default, deleteField as deleteFormField, deleteTypeMatchRule, display, filterFunction, getDataByPage, getField as getFormField, getRules, getTypeMatchRule, initValue, registerField as registerFormField, registerTypeMatchRule, registerTypeMatchRules, sortArray, sortChange, stripTabItemsLazy, submitForm, useAddField, validateForm, validateTypeMatch };
@@ -419,4 +419,4 @@ var validateForm = (options) => {
419
419
  });
420
420
  };
421
421
  //#endregion
422
- export { submitForm, validateForm };
422
+ export { stripTabItemsLazy, submitForm, validateForm };
@@ -1,15 +1,15 @@
1
1
  import { readonly } from "vue";
2
2
  import { appendValidateSuggestion } from "@tmagic/design";
3
- import { getValueByKeyPath } from "@tmagic/utils";
3
+ import { getValueByKeyPath, toLine } from "@tmagic/utils";
4
4
  import dayjs from "dayjs";
5
5
  import customParseFormat from "dayjs/plugin/customParseFormat";
6
6
  //#region packages/form/src/utils/typeMatch.ts
7
7
  dayjs.extend(customParseFormat);
8
8
  var typeMatchRuleRegistry = /* @__PURE__ */ new Map();
9
- var normalizeType = (type) => type.replace(/([A-Z])/g, "-$1").toLowerCase();
9
+ var isPromise = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
10
10
  /** 注册或覆盖某个字段 type 的 typeMatch 校验规则 */
11
11
  var registerTypeMatchRule = (type, validator) => {
12
- typeMatchRuleRegistry.set(normalizeType(type), validator);
12
+ typeMatchRuleRegistry.set(toLine(type), validator);
13
13
  };
14
14
  /** 批量注册 typeMatch 校验规则 */
15
15
  var registerTypeMatchRules = (rules) => {
@@ -18,9 +18,9 @@ var registerTypeMatchRules = (rules) => {
18
18
  });
19
19
  };
20
20
  /** 获取某个字段 type 的自定义 typeMatch 校验规则 */
21
- var getTypeMatchRule = (type) => typeMatchRuleRegistry.get(normalizeType(type));
21
+ var getTypeMatchRule = (type) => typeMatchRuleRegistry.get(toLine(type));
22
22
  /** 删除某个字段 type 的自定义 typeMatch 校验规则 */
23
- var deleteTypeMatchRule = (type) => typeMatchRuleRegistry.delete(normalizeType(type));
23
+ var deleteTypeMatchRule = (type) => typeMatchRuleRegistry.delete(toLine(type));
24
24
  /** 清空所有自定义 typeMatch 校验规则 */
25
25
  var clearTypeMatchRules = () => {
26
26
  typeMatchRuleRegistry.clear();
@@ -124,7 +124,9 @@ var toggleSuggestion = (activeValue, inactiveValue) => `请使用以下某一个
124
124
  var resolveFieldDefaultValue = (mForm, props) => {
125
125
  const { defaultValue } = props.config || {};
126
126
  if (typeof defaultValue === "undefined" || defaultValue === "undefined") return void 0;
127
- return resolveConfig(mForm, defaultValue, props);
127
+ const resolvedDefaultValue = resolveConfig(mForm, defaultValue, props);
128
+ if (isPromise(resolvedDefaultValue)) return;
129
+ return resolvedDefaultValue;
128
130
  };
129
131
  var isNumberValue = (value) => typeof value === "number" && !Number.isNaN(value);
130
132
  var isStringValue = (value) => typeof value === "string";
@@ -175,12 +177,6 @@ var dateRangeSuggestion = (valueFormat) => {
175
177
  return `请参考以下示例值:["${example}", "${example}"]`;
176
178
  };
177
179
  var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? "值类型应为时间戳数字" : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
178
- var resolveFieldType = (mForm, props) => {
179
- let type = "type" in (props.config || {}) ? props.config.type : "";
180
- type = type ? resolveConfig(mForm, type, props) || "" : "";
181
- if (type === "form" || type === "container") return "";
182
- return normalizeType(type || "") || (props.config?.items ? "" : "text");
183
- };
184
180
  var resolveToggleValues = (config) => {
185
181
  const filterIsNumber = config.filter === "number";
186
182
  const { activeValue: configActiveValue, inactiveValue: configInactiveValue } = config;
@@ -206,11 +202,9 @@ var flattenSelectOptions = (options) => {
206
202
  });
207
203
  return values;
208
204
  };
209
- var resolveOptions = (mForm, props) => {
205
+ var resolveOptions = (props) => {
210
206
  const { options } = props.config || {};
211
- if (Array.isArray(options)) return options;
212
- if (typeof options === "function") return resolveConfig(mForm, options, props) || [];
213
- return [];
207
+ return Array.isArray(options) ? options : [];
214
208
  };
215
209
  var includesOptionValue = (optionValues, value) => optionValues.some((item) => Object.is(item, value));
216
210
  var collectCascaderLeafValues = (options, result = []) => {
@@ -263,6 +257,7 @@ var cascaderExampleSuggestion = (options, config, valueSeparator, fallbackExampl
263
257
  return `请参考以下示例值:${stringifyExampleValue(example)}`;
264
258
  };
265
259
  var validateSelectValue = (value, config, optionValues, message) => {
260
+ if (optionValues.length === 0) return;
266
261
  if (config.allowCreate || config.remote) {
267
262
  if (config.multiple) {
268
263
  if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
@@ -280,10 +275,12 @@ var validateSelectValue = (value, config, optionValues, message) => {
280
275
  if (isStaticOptions && !includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
281
276
  };
282
277
  var validateCascaderValue = (value, config, props, mForm, message) => {
278
+ const options = resolveOptions(props);
279
+ if (!options.length) return;
283
280
  const valueSeparator = resolveConfig(mForm, config.valueSeparator, props);
281
+ if (isPromise(valueSeparator)) return;
284
282
  const emitPath = config.emitPath !== false;
285
283
  const multiple = Boolean(config.multiple);
286
- const options = resolveOptions(mForm, props);
287
284
  const cascaderExample = (fallbackExample) => cascaderExampleSuggestion(options, config, valueSeparator, fallbackExample);
288
285
  if (valueSeparator) {
289
286
  if (typeof value !== "string" && !Array.isArray(value)) return defaultMessage(message, `${value} 类型应为字符串或数组`, cascaderExample("\"选项1,选项2\" 或 [\"选项1\", \"选项2\"]"));
@@ -337,14 +334,16 @@ var validateBuiltinTypeMatch = (value, fieldType, mForm, props, message) => {
337
334
  if (!Object.is(value, activeValue) && !Object.is(value, inactiveValue)) return defaultMessage(message, `${value} 不在合法开关值中`, toggleSuggestion(activeValue, inactiveValue));
338
335
  return;
339
336
  }
340
- if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(mForm, props)), message);
337
+ if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(props)), message);
341
338
  if (fieldType === "radio-group") {
342
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
339
+ const optionValues = flattenSelectOptions(resolveOptions(props));
340
+ if (optionValues.length === 0) return;
343
341
  if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
344
342
  return;
345
343
  }
346
344
  if (fieldType === "checkbox-group") {
347
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
345
+ const optionValues = flattenSelectOptions(resolveOptions(props));
346
+ if (optionValues.length === 0) return;
348
347
  if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
349
348
  if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
350
349
  return;
@@ -363,7 +362,9 @@ var validateBuiltinTypeMatch = (value, fieldType, mForm, props, message) => {
363
362
  };
364
363
  var validateTypeMatch = (value, mForm, props, message) => {
365
364
  if (isEmptyValue(value) || isEmptyArray(value)) return;
366
- const fieldType = resolveFieldType(mForm, props);
365
+ const rawFieldType = "type" in (props.config || {}) ? props.config.type : "";
366
+ if (typeof rawFieldType !== "string" || !rawFieldType) return;
367
+ const fieldType = toLine(rawFieldType);
367
368
  const customValidator = getTypeMatchRule(fieldType);
368
369
  if (customValidator) return customValidator(value, {
369
370
  fieldType,
@@ -377,10 +378,14 @@ var createTypeMatchValidator = (mForm, props, rule) => {
377
378
  const originalValidator = typeof rule.validator === "function" ? rule.validator : void 0;
378
379
  return (asyncValidatorRule, value, callback, source, options) => {
379
380
  const actualValue = props.config?.names ? props.model : value;
380
- const error = validateTypeMatch(actualValue, mForm, props, rule.message);
381
- if (error) {
382
- callback(new Error(error));
383
- return;
381
+ try {
382
+ const error = validateTypeMatch(actualValue, mForm, props, rule.message);
383
+ if (error) {
384
+ callback(new Error(error));
385
+ return;
386
+ }
387
+ } catch (error) {
388
+ console.error(error);
384
389
  }
385
390
  if (originalValidator) return originalValidator({
386
391
  rule: asyncValidatorRule,
@@ -2769,10 +2769,10 @@
2769
2769
  //#region packages/form/src/utils/typeMatch.ts
2770
2770
  dayjs.default.extend(dayjs_plugin_customParseFormat.default);
2771
2771
  var typeMatchRuleRegistry = /* @__PURE__ */ new Map();
2772
- var normalizeType = (type) => type.replace(/([A-Z])/g, "-$1").toLowerCase();
2772
+ var isPromise = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
2773
2773
  /** 注册或覆盖某个字段 type 的 typeMatch 校验规则 */
2774
2774
  var registerTypeMatchRule = (type, validator) => {
2775
- typeMatchRuleRegistry.set(normalizeType(type), validator);
2775
+ typeMatchRuleRegistry.set((0, _tmagic_utils.toLine)(type), validator);
2776
2776
  };
2777
2777
  /** 批量注册 typeMatch 校验规则 */
2778
2778
  var registerTypeMatchRules = (rules) => {
@@ -2781,9 +2781,9 @@
2781
2781
  });
2782
2782
  };
2783
2783
  /** 获取某个字段 type 的自定义 typeMatch 校验规则 */
2784
- var getTypeMatchRule = (type) => typeMatchRuleRegistry.get(normalizeType(type));
2784
+ var getTypeMatchRule = (type) => typeMatchRuleRegistry.get((0, _tmagic_utils.toLine)(type));
2785
2785
  /** 删除某个字段 type 的自定义 typeMatch 校验规则 */
2786
- var deleteTypeMatchRule = (type) => typeMatchRuleRegistry.delete(normalizeType(type));
2786
+ var deleteTypeMatchRule = (type) => typeMatchRuleRegistry.delete((0, _tmagic_utils.toLine)(type));
2787
2787
  /** 清空所有自定义 typeMatch 校验规则 */
2788
2788
  var clearTypeMatchRules = () => {
2789
2789
  typeMatchRuleRegistry.clear();
@@ -2887,7 +2887,9 @@
2887
2887
  var resolveFieldDefaultValue = (mForm, props) => {
2888
2888
  const { defaultValue } = props.config || {};
2889
2889
  if (typeof defaultValue === "undefined" || defaultValue === "undefined") return void 0;
2890
- return resolveConfig(mForm, defaultValue, props);
2890
+ const resolvedDefaultValue = resolveConfig(mForm, defaultValue, props);
2891
+ if (isPromise(resolvedDefaultValue)) return;
2892
+ return resolvedDefaultValue;
2891
2893
  };
2892
2894
  var isNumberValue = (value) => typeof value === "number" && !Number.isNaN(value);
2893
2895
  var isStringValue = (value) => typeof value === "string";
@@ -2938,12 +2940,6 @@
2938
2940
  return `请参考以下示例值:["${example}", "${example}"]`;
2939
2941
  };
2940
2942
  var dateValueFormatErrorMessage = (message, valueFormat) => defaultMessage(message, isTimestampValueFormat(valueFormat) ? "值类型应为时间戳数字" : `值格式应为 ${valueFormat}`, dateSuggestion(valueFormat));
2941
- var resolveFieldType = (mForm, props) => {
2942
- let type = "type" in (props.config || {}) ? props.config.type : "";
2943
- type = type ? resolveConfig(mForm, type, props) || "" : "";
2944
- if (type === "form" || type === "container") return "";
2945
- return normalizeType(type || "") || (props.config?.items ? "" : "text");
2946
- };
2947
2943
  var resolveToggleValues = (config) => {
2948
2944
  const filterIsNumber = config.filter === "number";
2949
2945
  const { activeValue: configActiveValue, inactiveValue: configInactiveValue } = config;
@@ -2969,11 +2965,9 @@
2969
2965
  });
2970
2966
  return values;
2971
2967
  };
2972
- var resolveOptions = (mForm, props) => {
2968
+ var resolveOptions = (props) => {
2973
2969
  const { options } = props.config || {};
2974
- if (Array.isArray(options)) return options;
2975
- if (typeof options === "function") return resolveConfig(mForm, options, props) || [];
2976
- return [];
2970
+ return Array.isArray(options) ? options : [];
2977
2971
  };
2978
2972
  var includesOptionValue = (optionValues, value) => optionValues.some((item) => Object.is(item, value));
2979
2973
  var collectCascaderLeafValues = (options, result = []) => {
@@ -3026,6 +3020,7 @@
3026
3020
  return `请参考以下示例值:${stringifyExampleValue(example)}`;
3027
3021
  };
3028
3022
  var validateSelectValue = (value, config, optionValues, message) => {
3023
+ if (optionValues.length === 0) return;
3029
3024
  if (config.allowCreate || config.remote) {
3030
3025
  if (config.multiple) {
3031
3026
  if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
@@ -3043,10 +3038,12 @@
3043
3038
  if (isStaticOptions && !includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
3044
3039
  };
3045
3040
  var validateCascaderValue = (value, config, props, mForm, message) => {
3041
+ const options = resolveOptions(props);
3042
+ if (!options.length) return;
3046
3043
  const valueSeparator = resolveConfig(mForm, config.valueSeparator, props);
3044
+ if (isPromise(valueSeparator)) return;
3047
3045
  const emitPath = config.emitPath !== false;
3048
3046
  const multiple = Boolean(config.multiple);
3049
- const options = resolveOptions(mForm, props);
3050
3047
  const cascaderExample = (fallbackExample) => cascaderExampleSuggestion(options, config, valueSeparator, fallbackExample);
3051
3048
  if (valueSeparator) {
3052
3049
  if (typeof value !== "string" && !Array.isArray(value)) return defaultMessage(message, `${value} 类型应为字符串或数组`, cascaderExample("\"选项1,选项2\" 或 [\"选项1\", \"选项2\"]"));
@@ -3100,14 +3097,16 @@
3100
3097
  if (!Object.is(value, activeValue) && !Object.is(value, inactiveValue)) return defaultMessage(message, `${value} 不在合法开关值中`, toggleSuggestion(activeValue, inactiveValue));
3101
3098
  return;
3102
3099
  }
3103
- if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(mForm, props)), message);
3100
+ if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(props)), message);
3104
3101
  if (fieldType === "radio-group") {
3105
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
3102
+ const optionValues = flattenSelectOptions(resolveOptions(props));
3103
+ if (optionValues.length === 0) return;
3106
3104
  if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
3107
3105
  return;
3108
3106
  }
3109
3107
  if (fieldType === "checkbox-group") {
3110
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
3108
+ const optionValues = flattenSelectOptions(resolveOptions(props));
3109
+ if (optionValues.length === 0) return;
3111
3110
  if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
3112
3111
  if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
3113
3112
  return;
@@ -3126,7 +3125,9 @@
3126
3125
  };
3127
3126
  var validateTypeMatch = (value, mForm, props, message) => {
3128
3127
  if (isEmptyValue(value) || isEmptyArray(value)) return;
3129
- const fieldType = resolveFieldType(mForm, props);
3128
+ const rawFieldType = "type" in (props.config || {}) ? props.config.type : "";
3129
+ if (typeof rawFieldType !== "string" || !rawFieldType) return;
3130
+ const fieldType = (0, _tmagic_utils.toLine)(rawFieldType);
3130
3131
  const customValidator = getTypeMatchRule(fieldType);
3131
3132
  if (customValidator) return customValidator(value, {
3132
3133
  fieldType,
@@ -3140,10 +3141,14 @@
3140
3141
  const originalValidator = typeof rule.validator === "function" ? rule.validator : void 0;
3141
3142
  return (asyncValidatorRule, value, callback, source, options) => {
3142
3143
  const actualValue = props.config?.names ? props.model : value;
3143
- const error = validateTypeMatch(actualValue, mForm, props, rule.message);
3144
- if (error) {
3145
- callback(new Error(error));
3146
- return;
3144
+ try {
3145
+ const error = validateTypeMatch(actualValue, mForm, props, rule.message);
3146
+ if (error) {
3147
+ callback(new Error(error));
3148
+ return;
3149
+ }
3150
+ } catch (error) {
3151
+ console.error(error);
3147
3152
  }
3148
3153
  if (originalValidator) return originalValidator({
3149
3154
  rule: asyncValidatorRule,
@@ -3668,16 +3673,18 @@
3668
3673
  "data-tmagic-form-item-prop": itemProp.value,
3669
3674
  class: (0, vue.normalizeClass)(`m-form-container m-container-${type.value || ""} ${__props.config.className || ""}${__props.config.tip ? " has-tip" : ""}`),
3670
3675
  style: (0, vue.normalizeStyle)(__props.config.style)
3671
- }, [type.value === "hidden" ? ((0, vue.openBlock)(), (0, vue.createBlock)(Hidden_default, {
3672
- key: 0,
3673
- name: `${name.value}`,
3674
- prop: itemProp.value,
3675
- model: __props.model
3676
- }, null, 8, [
3677
- "name",
3678
- "prop",
3679
- "model"
3680
- ])) : items.value && !text.value && type.value && display$3.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
3676
+ }, [type.value === "hidden" ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_tmagic_design.TMagicFormItem), (0, vue.mergeProps)({ key: 0 }, formItemProps.value, { style: { "display": "none" } }), {
3677
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)(Hidden_default, {
3678
+ name: `${name.value}`,
3679
+ prop: itemProp.value,
3680
+ model: __props.model
3681
+ }, null, 8, [
3682
+ "name",
3683
+ "prop",
3684
+ "model"
3685
+ ])]),
3686
+ _: 1
3687
+ }, 16)) : items.value && !text.value && type.value && display$3.value ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)({ key: 1 }, fieldsProps.value, {
3681
3688
  model: __props.model,
3682
3689
  "last-values": __props.lastValues,
3683
3690
  "is-compare": __props.isCompare,
@@ -9008,6 +9015,7 @@
9008
9015
  exports.registerTypeMatchRules = registerTypeMatchRules;
9009
9016
  exports.sortArray = sortArray;
9010
9017
  exports.sortChange = sortChange;
9018
+ exports.stripTabItemsLazy = stripTabItemsLazy;
9011
9019
  exports.submitForm = submitForm;
9012
9020
  exports.useAddField = useAddField;
9013
9021
  exports.validateForm = validateForm;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0-beta.12",
2
+ "version": "1.8.0-beta.13",
3
3
  "name": "@tmagic/form",
4
4
  "type": "module",
5
5
  "sideEffects": [
@@ -52,9 +52,9 @@
52
52
  "peerDependencies": {
53
53
  "vue": "^3.5.40",
54
54
  "typescript": "^6.0.3",
55
- "@tmagic/design": "1.8.0-beta.12",
56
- "@tmagic/utils": "1.8.0-beta.12",
57
- "@tmagic/form-schema": "1.8.0-beta.12"
55
+ "@tmagic/form-schema": "1.8.0-beta.13",
56
+ "@tmagic/utils": "1.8.0-beta.13",
57
+ "@tmagic/design": "1.8.0-beta.13"
58
58
  },
59
59
  "peerDependenciesMeta": {
60
60
  "typescript": {
@@ -5,7 +5,9 @@
5
5
  :class="`m-form-container m-container-${type || ''} ${config.className || ''}${config.tip ? ' has-tip' : ''}`"
6
6
  :style="config.style"
7
7
  >
8
- <MHidden v-if="type === 'hidden'" :name="`${name}`" :prop="itemProp" :model="model"></MHidden>
8
+ <TMagicFormItem v-if="type === 'hidden'" v-bind="formItemProps" style="display: none">
9
+ <MHidden :name="`${name}`" :prop="itemProp" :model="model"></MHidden>
10
+ </TMagicFormItem>
9
11
 
10
12
  <component
11
13
  v-else-if="items && !text && type && display"
package/src/submitForm.ts CHANGED
@@ -590,7 +590,7 @@ const removeTabItemsLazy = (node: any): void => {
590
590
  * 无法校验到这些标签页内的字段。校验场景需要一次性渲染全部字段,故在此统一去除 lazy。
591
591
  * 处理基于深拷贝,不会污染调用方传入的原始 config。
592
592
  */
593
- const stripTabItemsLazy = (config: FormConfig): FormConfig => {
593
+ export const stripTabItemsLazy = (config: FormConfig): FormConfig => {
594
594
  const cloned = cloneConfigValue(config);
595
595
  removeTabItemsLazy(cloned);
596
596
  return cloned;
@@ -21,7 +21,7 @@ import dayjs from 'dayjs';
21
21
  import customParseFormat from 'dayjs/plugin/customParseFormat';
22
22
 
23
23
  import { appendValidateSuggestion } from '@tmagic/design';
24
- import { getValueByKeyPath } from '@tmagic/utils';
24
+ import { getValueByKeyPath, toLine } from '@tmagic/utils';
25
25
 
26
26
  import type { CascaderOption, FormState, Rule } from '../schema';
27
27
 
@@ -44,11 +44,12 @@ export type TypeMatchValidator = (value: any, context: TypeMatchValidateContext)
44
44
 
45
45
  const typeMatchRuleRegistry = new Map<string, TypeMatchValidator>();
46
46
 
47
- const normalizeType = (type: string) => type.replace(/([A-Z])/g, '-$1').toLowerCase();
47
+ const isPromise = (value: any): value is Promise<unknown> =>
48
+ typeof value === 'object' && value !== null && typeof value.then === 'function';
48
49
 
49
50
  /** 注册或覆盖某个字段 type 的 typeMatch 校验规则 */
50
51
  export const registerTypeMatchRule = (type: string, validator: TypeMatchValidator): void => {
51
- typeMatchRuleRegistry.set(normalizeType(type), validator);
52
+ typeMatchRuleRegistry.set(toLine(type), validator);
52
53
  };
53
54
 
54
55
  /** 批量注册 typeMatch 校验规则 */
@@ -60,10 +61,10 @@ export const registerTypeMatchRules = (rules: Record<string, TypeMatchValidator>
60
61
 
61
62
  /** 获取某个字段 type 的自定义 typeMatch 校验规则 */
62
63
  export const getTypeMatchRule = (type: string): TypeMatchValidator | undefined =>
63
- typeMatchRuleRegistry.get(normalizeType(type));
64
+ typeMatchRuleRegistry.get(toLine(type));
64
65
 
65
66
  /** 删除某个字段 type 的自定义 typeMatch 校验规则 */
66
- export const deleteTypeMatchRule = (type: string): boolean => typeMatchRuleRegistry.delete(normalizeType(type));
67
+ export const deleteTypeMatchRule = (type: string): boolean => typeMatchRuleRegistry.delete(toLine(type));
67
68
 
68
69
  /** 清空所有自定义 typeMatch 校验规则 */
69
70
  export const clearTypeMatchRules = (): void => {
@@ -182,7 +183,12 @@ const toggleSuggestion = (activeValue: any, inactiveValue: any): string =>
182
183
  const resolveFieldDefaultValue = (mForm: FormState | undefined, props: any): any => {
183
184
  const { defaultValue } = props.config || {};
184
185
  if (typeof defaultValue === 'undefined' || defaultValue === 'undefined') return undefined;
185
- return resolveConfig(mForm, defaultValue, props);
186
+ const resolvedDefaultValue = resolveConfig(mForm, defaultValue, props);
187
+ // resolveConfig 返回 Promise(如 defaultValue 为异步函数)时无法同步获取默认值,回退到通用示例
188
+ if (isPromise(resolvedDefaultValue)) {
189
+ return undefined;
190
+ }
191
+ return resolvedDefaultValue;
186
192
  };
187
193
 
188
194
  const isNumberValue = (value: any) => typeof value === 'number' && !Number.isNaN(value);
@@ -271,13 +277,6 @@ const dateValueFormatErrorMessage = (message: string | undefined, valueFormat: s
271
277
  dateSuggestion(valueFormat),
272
278
  );
273
279
 
274
- const resolveFieldType = (mForm: FormState | undefined, props: any): string => {
275
- let type = 'type' in (props.config || {}) ? props.config.type : '';
276
- type = type ? resolveConfig<string>(mForm, type, props) || '' : '';
277
- if (type === 'form' || type === 'container') return '';
278
- return normalizeType(type || '') || (props.config?.items ? '' : 'text');
279
- };
280
-
281
280
  const resolveToggleValues = (config: any) => {
282
281
  const filterIsNumber = config.filter === 'number';
283
282
  const { activeValue: configActiveValue, inactiveValue: configInactiveValue } = config;
@@ -317,13 +316,9 @@ const flattenSelectOptions = (options: any[]): any[] => {
317
316
  return values;
318
317
  };
319
318
 
320
- const resolveOptions = (mForm: FormState | undefined, props: any): any[] => {
319
+ const resolveOptions = (props: any): any[] => {
321
320
  const { options } = props.config || {};
322
- if (Array.isArray(options)) return options;
323
- if (typeof options === 'function') {
324
- return resolveConfig(mForm, options, props) || [];
325
- }
326
- return [];
321
+ return Array.isArray(options) ? options : [];
327
322
  };
328
323
 
329
324
  const includesOptionValue = (optionValues: any[], value: any) => optionValues.some((item) => Object.is(item, value));
@@ -404,6 +399,10 @@ const validateSelectValue = (
404
399
  optionValues: any[],
405
400
  message: string | undefined,
406
401
  ): string | undefined => {
402
+ if (optionValues.length === 0) {
403
+ return undefined;
404
+ }
405
+
407
406
  if (config.allowCreate || config.remote) {
408
407
  if (config.multiple) {
409
408
  if (!Array.isArray(value)) {
@@ -456,10 +455,19 @@ const validateCascaderValue = (
456
455
  mForm: FormState | undefined,
457
456
  message: string | undefined,
458
457
  ): string | undefined => {
458
+ const options = resolveOptions(props) as CascaderOption[];
459
+
460
+ if (!options.length) {
461
+ return;
462
+ }
463
+
459
464
  const valueSeparator = resolveConfig<string | undefined>(mForm, config.valueSeparator, props);
465
+ // resolveConfig 返回 Promise(如 valueSeparator 为异步函数)时无法同步确定分隔符,跳过校验
466
+ if (isPromise(valueSeparator)) {
467
+ return undefined;
468
+ }
460
469
  const emitPath = config.emitPath !== false;
461
470
  const multiple = Boolean(config.multiple);
462
- const options = resolveOptions(mForm, props) as CascaderOption[];
463
471
  const cascaderExample = (fallbackExample: string) =>
464
472
  cascaderExampleSuggestion(options, config, valueSeparator, fallbackExample);
465
473
 
@@ -603,12 +611,17 @@ const validateBuiltinTypeMatch = (
603
611
  }
604
612
 
605
613
  if (fieldType === 'select') {
606
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
614
+ const optionValues = flattenSelectOptions(resolveOptions(props));
607
615
  return validateSelectValue(value, config, optionValues, message);
608
616
  }
609
617
 
610
618
  if (fieldType === 'radio-group') {
611
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
619
+ const optionValues = flattenSelectOptions(resolveOptions(props));
620
+
621
+ if (optionValues.length === 0) {
622
+ return undefined;
623
+ }
624
+
612
625
  if (!includesOptionValue(optionValues, value)) {
613
626
  return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
614
627
  }
@@ -616,7 +629,12 @@ const validateBuiltinTypeMatch = (
616
629
  }
617
630
 
618
631
  if (fieldType === 'checkbox-group') {
619
- const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
632
+ const optionValues = flattenSelectOptions(resolveOptions(props));
633
+
634
+ if (optionValues.length === 0) {
635
+ return undefined;
636
+ }
637
+
620
638
  if (!Array.isArray(value)) {
621
639
  return defaultMessage(
622
640
  message,
@@ -679,7 +697,14 @@ export const validateTypeMatch = (
679
697
  return undefined;
680
698
  }
681
699
 
682
- const fieldType = resolveFieldType(mForm, props);
700
+ const rawFieldType = 'type' in (props.config || {}) ? props.config.type : '';
701
+ if (typeof rawFieldType !== 'string' || !rawFieldType) {
702
+ return;
703
+ }
704
+
705
+ // 统一将驼峰形式(如 radioGroup)归一化为连字符形式(radio-group),与内置规则的 key 保持一致
706
+ const fieldType = toLine(rawFieldType);
707
+
683
708
  const customValidator = getTypeMatchRule(fieldType);
684
709
 
685
710
  // 自定义规则优先:可覆盖内置规则,也可为业务自定义字段 type 扩展校验
@@ -695,11 +720,15 @@ export const createTypeMatchValidator = (mForm: FormState | undefined, props: an
695
720
 
696
721
  return (asyncValidatorRule: any, value: any, callback: Function, source: any, options: any) => {
697
722
  const actualValue = props.config?.names ? props.model : value;
698
- const error = validateTypeMatch(actualValue, mForm, props, rule.message);
723
+ try {
724
+ const error = validateTypeMatch(actualValue, mForm, props, rule.message);
699
725
 
700
- if (error) {
701
- callback(new Error(error));
702
- return;
726
+ if (error) {
727
+ callback(new Error(error));
728
+ return;
729
+ }
730
+ } catch (error) {
731
+ console.error(error);
703
732
  }
704
733
 
705
734
  if (originalValidator) {
package/types/index.d.ts CHANGED
@@ -200,6 +200,14 @@ interface ValidateFormOptions {
200
200
  debug?: boolean;
201
201
  typeMatchValid?: boolean;
202
202
  }
203
+ /**
204
+ * 返回一份去除了 tab 标签页 lazy 的配置副本。
205
+ *
206
+ * tab 容器开启 lazy 时,非激活标签页的内容不会渲染,导致 validateForm 静默挂载后
207
+ * 无法校验到这些标签页内的字段。校验场景需要一次性渲染全部字段,故在此统一去除 lazy。
208
+ * 处理基于深拷贝,不会污染调用方传入的原始 config。
209
+ */
210
+ declare const stripTabItemsLazy: (config: schema_d_exports.FormConfig) => schema_d_exports.FormConfig;
203
211
  /**
204
212
  * 以命令式方式对一份「表单配置 + 值」做一次静默校验,**不依赖也不影响任何已渲染的表单**。
205
213
  *
@@ -2138,8 +2146,8 @@ declare const _default$31: {
2138
2146
  install(app: App, opt?: FormInstallOptions): void;
2139
2147
  };
2140
2148
  declare namespace index_d_exports {
2141
- export { ChangeRecord, ContainerChangeEventData, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FormDiffConfig, FormInstallOptions, FormLabelSlotProps, FormSlots, _default as MCascader, _default$1 as MCheckbox, _default$2 as MCheckboxGroup, _default$3 as MColorPicker, _default$4 as MContainer, _default$5 as MDate, _default$6 as MDateTime, _default$7 as MDaterange, _default$8 as MDisplay, _default$9 as MDynamicField, _default$10 as MFieldset, _default$11 as MFlexLayout, _default$12 as MForm, _default$13 as MFormBox, _default$14 as MFormDialog, _default$15 as MFormDrawer, _default$16 as MGroupList, _default$17 as MHidden, _default$18 as MLink, _default$19 as MNumber, _default$20 as MNumberRange, _default$21 as MPanel, _default$22 as MRadioGroup, _default$23 as MRow, _default$24 as MSelect, _default$25 as MSwitch, _default$16 as MTable, _default$16 as MTableGroupList, _default$26 as MTabs, _default$27 as MText, _default$28 as MTextarea, _default$29 as MTime, _default$30 as MTimerange, SubmitFormOptions, SubmitFormResult, TypeMatchValidateContext, TypeMatchValidator, ValidateError, ValidateFormOptions, adaptFormValidator, clearTypeMatchRules, createForm, createObjectProp, createValues, datetimeFormatter, _default$31 as default, deleteField as deleteFormField, deleteTypeMatchRule, display, filterFunction, getDataByPage, getField as getFormField, getRules, getTypeMatchRule, initValue, registerField as registerFormField, registerTypeMatchRule, registerTypeMatchRules, sortArray, sortChange, submitForm, useAddField, validateForm, validateTypeMatch };
2149
+ export { ChangeRecord, ContainerChangeEventData, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FormDiffConfig, FormInstallOptions, FormLabelSlotProps, FormSlots, _default as MCascader, _default$1 as MCheckbox, _default$2 as MCheckboxGroup, _default$3 as MColorPicker, _default$4 as MContainer, _default$5 as MDate, _default$6 as MDateTime, _default$7 as MDaterange, _default$8 as MDisplay, _default$9 as MDynamicField, _default$10 as MFieldset, _default$11 as MFlexLayout, _default$12 as MForm, _default$13 as MFormBox, _default$14 as MFormDialog, _default$15 as MFormDrawer, _default$16 as MGroupList, _default$17 as MHidden, _default$18 as MLink, _default$19 as MNumber, _default$20 as MNumberRange, _default$21 as MPanel, _default$22 as MRadioGroup, _default$23 as MRow, _default$24 as MSelect, _default$25 as MSwitch, _default$16 as MTable, _default$16 as MTableGroupList, _default$26 as MTabs, _default$27 as MText, _default$28 as MTextarea, _default$29 as MTime, _default$30 as MTimerange, SubmitFormOptions, SubmitFormResult, TypeMatchValidateContext, TypeMatchValidator, ValidateError, ValidateFormOptions, adaptFormValidator, clearTypeMatchRules, createForm, createObjectProp, createValues, datetimeFormatter, _default$31 as default, deleteField as deleteFormField, deleteTypeMatchRule, display, filterFunction, getDataByPage, getField as getFormField, getRules, getTypeMatchRule, initValue, registerField as registerFormField, registerTypeMatchRule, registerTypeMatchRules, sortArray, sortChange, stripTabItemsLazy, submitForm, useAddField, validateForm, validateTypeMatch };
2142
2150
  }
2143
2151
  declare const createForm: <T extends [] = []>(config: schema_d_exports.FormConfig | T) => schema_d_exports.FormConfig | T;
2144
2152
  //#endregion
2145
- export { ChangeRecord, ContainerChangeEventData, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FormDiffConfig, type FormInstallOptions, FormLabelSlotProps, FormSlots, _default as MCascader, _default$1 as MCheckbox, _default$2 as MCheckboxGroup, _default$3 as MColorPicker, _default$4 as MContainer, _default$5 as MDate, _default$6 as MDateTime, _default$7 as MDaterange, _default$8 as MDisplay, _default$9 as MDynamicField, _default$10 as MFieldset, _default$11 as MFlexLayout, _default$12 as MForm, _default$13 as MFormBox, _default$14 as MFormDialog, _default$15 as MFormDrawer, _default$16 as MGroupList, _default$16 as MTable, _default$16 as MTableGroupList, _default$17 as MHidden, _default$18 as MLink, _default$19 as MNumber, _default$20 as MNumberRange, _default$21 as MPanel, _default$22 as MRadioGroup, _default$23 as MRow, _default$24 as MSelect, _default$25 as MSwitch, _default$26 as MTabs, _default$27 as MText, _default$28 as MTextarea, _default$29 as MTime, _default$30 as MTimerange, SubmitFormOptions, SubmitFormResult, type TypeMatchValidateContext, type TypeMatchValidator, ValidateError, ValidateFormOptions, adaptFormValidator, clearTypeMatchRules, createForm, createObjectProp, createValues, datetimeFormatter, _default$31 as default, deleteField as deleteFormField, deleteTypeMatchRule, display, filterFunction, getDataByPage, getField as getFormField, getRules, getTypeMatchRule, initValue, registerField as registerFormField, registerTypeMatchRule, registerTypeMatchRules, sortArray, sortChange, submitForm, useAddField, validateForm, validateTypeMatch };
2153
+ export { ChangeRecord, ContainerChangeEventData, FORM_DIFF_CONFIG_KEY, FORM_TYPE_MATCH_VALID_KEY, FormDiffConfig, type FormInstallOptions, FormLabelSlotProps, FormSlots, _default as MCascader, _default$1 as MCheckbox, _default$2 as MCheckboxGroup, _default$3 as MColorPicker, _default$4 as MContainer, _default$5 as MDate, _default$6 as MDateTime, _default$7 as MDaterange, _default$8 as MDisplay, _default$9 as MDynamicField, _default$10 as MFieldset, _default$11 as MFlexLayout, _default$12 as MForm, _default$13 as MFormBox, _default$14 as MFormDialog, _default$15 as MFormDrawer, _default$16 as MGroupList, _default$16 as MTable, _default$16 as MTableGroupList, _default$17 as MHidden, _default$18 as MLink, _default$19 as MNumber, _default$20 as MNumberRange, _default$21 as MPanel, _default$22 as MRadioGroup, _default$23 as MRow, _default$24 as MSelect, _default$25 as MSwitch, _default$26 as MTabs, _default$27 as MText, _default$28 as MTextarea, _default$29 as MTime, _default$30 as MTimerange, SubmitFormOptions, SubmitFormResult, type TypeMatchValidateContext, type TypeMatchValidator, ValidateError, ValidateFormOptions, adaptFormValidator, clearTypeMatchRules, createForm, createObjectProp, createValues, datetimeFormatter, _default$31 as default, deleteField as deleteFormField, deleteTypeMatchRule, display, filterFunction, getDataByPage, getField as getFormField, getRules, getTypeMatchRule, initValue, registerField as registerFormField, registerTypeMatchRule, registerTypeMatchRules, sortArray, sortChange, stripTabItemsLazy, submitForm, useAddField, validateForm, validateTypeMatch };