@tmagic/form 1.8.0-beta.27 → 1.8.0-beta.29
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.
- package/dist/es/containers/GroupList.vue_vue_type_script_setup_true_lang.js +26 -12
- package/dist/es/fields/Text.vue_vue_type_script_setup_true_lang.js +11 -8
- package/dist/es/style.css +40 -14
- package/dist/es/utils/form.js +14 -10
- package/dist/es/utils/tableGroupList.js +20 -1
- package/dist/es/utils/typeMatch.js +53 -24
- package/dist/style.css +40 -14
- package/dist/themes/magic-admin.css +40 -14
- package/dist/tmagic-form-headless.umd.cjs +71 -36
- package/dist/tmagic-form.umd.cjs +132 -63
- package/package.json +7 -7
- package/src/containers/GroupList.vue +23 -2
- package/src/theme/group-list.scss +52 -27
- package/src/utils/form.ts +4 -1
- package/src/utils/tableGroupList.ts +28 -1
- package/src/utils/typeMatch.ts +48 -17
- package/types/headless.d.ts +54 -54
- package/types/index.d.ts +57 -57
|
@@ -91,8 +91,10 @@
|
|
|
91
91
|
var unmasked = true;
|
|
92
92
|
} catch (e) {}
|
|
93
93
|
var result = nativeObjectToString$1.call(value);
|
|
94
|
-
if (unmasked)
|
|
95
|
-
|
|
94
|
+
if (unmasked) {
|
|
95
|
+
if (isOwn) value[symToStringTag$1] = tag;
|
|
96
|
+
else delete value[symToStringTag$1];
|
|
97
|
+
}
|
|
96
98
|
return result;
|
|
97
99
|
}
|
|
98
100
|
//#endregion
|
|
@@ -2049,6 +2051,14 @@
|
|
|
2049
2051
|
var extraTypeMatchRules = /* @__PURE__ */ new Map();
|
|
2050
2052
|
var builtInTypeMatchRules = /* @__PURE__ */ new Map();
|
|
2051
2053
|
var isPromise = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
2054
|
+
/**
|
|
2055
|
+
* 同步校验无法等待 Promise。调用方会丢掉返回值,这里挂上空 handler,避免变成未捕获 rejection。
|
|
2056
|
+
*/
|
|
2057
|
+
var ignorePromise = (value) => {
|
|
2058
|
+
if (!isPromise(value)) return false;
|
|
2059
|
+
value.then(() => {}, () => {});
|
|
2060
|
+
return true;
|
|
2061
|
+
};
|
|
2052
2062
|
/** 注册或覆盖某个字段 type 的 typeMatch 校验规则。`builtIn` 登记不受 `clearTypeMatchRules` / `deleteTypeMatchRule` 影响。 */
|
|
2053
2063
|
var registerTypeMatchRule = (type, validator, builtIn = false) => {
|
|
2054
2064
|
(builtIn ? builtInTypeMatchRules : extraTypeMatchRules).set((0, _tmagic_utils.toLine)(type), validator);
|
|
@@ -2066,16 +2076,20 @@
|
|
|
2066
2076
|
};
|
|
2067
2077
|
/** 本地解析配置函数,避免与 form.ts 循环依赖 */
|
|
2068
2078
|
var resolveConfig = (mForm, config, props) => {
|
|
2069
|
-
if (typeof config === "function")
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
+
if (typeof config === "function") {
|
|
2080
|
+
const formValue = (0, vue.readonly)(mForm?.values || props.model);
|
|
2081
|
+
return config(mForm, {
|
|
2082
|
+
values: (0, vue.readonly)(mForm?.initValues || {}),
|
|
2083
|
+
model: (0, vue.readonly)(props.model),
|
|
2084
|
+
parent: (0, vue.readonly)(mForm?.parentValues || {}),
|
|
2085
|
+
formValue,
|
|
2086
|
+
formValues: formValue,
|
|
2087
|
+
prop: props.prop,
|
|
2088
|
+
config: props.config,
|
|
2089
|
+
index: props.index,
|
|
2090
|
+
getFormValue: (prop) => (0, _tmagic_utils.getValueByKeyPath)(prop, mForm?.values || props.model)
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2079
2093
|
return config;
|
|
2080
2094
|
};
|
|
2081
2095
|
var SKIP_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -2167,7 +2181,7 @@
|
|
|
2167
2181
|
const { defaultValue } = props.config || {};
|
|
2168
2182
|
if (typeof defaultValue === "undefined" || defaultValue === "undefined") return void 0;
|
|
2169
2183
|
const resolvedDefaultValue = resolveConfig(mForm, defaultValue, props);
|
|
2170
|
-
if (
|
|
2184
|
+
if (ignorePromise(resolvedDefaultValue)) return;
|
|
2171
2185
|
return resolvedDefaultValue;
|
|
2172
2186
|
};
|
|
2173
2187
|
var isNumberValue = (value) => typeof value === "number" && !Number.isNaN(value);
|
|
@@ -2244,9 +2258,21 @@
|
|
|
2244
2258
|
});
|
|
2245
2259
|
return values;
|
|
2246
2260
|
};
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2261
|
+
/**
|
|
2262
|
+
* 解析字段 options:静态数组原样返回;函数型与 `display` / `type` 一样当场求值。
|
|
2263
|
+
*
|
|
2264
|
+
* 函数返回 Promise、非数组或抛错时当作「还没有可选项」,交由调用方按空 options 跳过枚举。
|
|
2265
|
+
* `remote` / `allowCreate` 仍由 `validateSelectValue` 单独放行,不在这里区分。
|
|
2266
|
+
*/
|
|
2267
|
+
var resolveOptions = (mForm, props) => {
|
|
2268
|
+
let resolved;
|
|
2269
|
+
try {
|
|
2270
|
+
resolved = resolveConfig(mForm, props.config?.options, props);
|
|
2271
|
+
} catch {
|
|
2272
|
+
return [];
|
|
2273
|
+
}
|
|
2274
|
+
if (ignorePromise(resolved) || !Array.isArray(resolved)) return [];
|
|
2275
|
+
return resolved;
|
|
2250
2276
|
};
|
|
2251
2277
|
var includesOptionValue = (optionValues, value) => optionValues.some((item) => Object.is(item, value));
|
|
2252
2278
|
var collectCascaderLeafValues = (options, result = []) => {
|
|
@@ -2308,19 +2334,18 @@
|
|
|
2308
2334
|
if (typeof value === "object") return defaultMessage(message, `${value} 类型不合法`, optionExampleSuggestion(optionValues, "\"文本内容\" 或 123", false));
|
|
2309
2335
|
return;
|
|
2310
2336
|
}
|
|
2311
|
-
const isStaticOptions = Array.isArray(config.options);
|
|
2312
2337
|
if (config.multiple) {
|
|
2313
2338
|
if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
|
|
2314
|
-
if (
|
|
2339
|
+
if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
2315
2340
|
return;
|
|
2316
2341
|
}
|
|
2317
|
-
if (
|
|
2342
|
+
if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
2318
2343
|
};
|
|
2319
2344
|
var validateCascaderValue = (value, config, props, mForm, message) => {
|
|
2320
|
-
const options = resolveOptions(props);
|
|
2345
|
+
const options = resolveOptions(mForm, props);
|
|
2321
2346
|
if (!options.length) return;
|
|
2322
2347
|
const valueSeparator = resolveConfig(mForm, config.valueSeparator, props);
|
|
2323
|
-
if (
|
|
2348
|
+
if (ignorePromise(valueSeparator)) return;
|
|
2324
2349
|
const emitPath = config.emitPath !== false;
|
|
2325
2350
|
const multiple = Boolean(config.multiple);
|
|
2326
2351
|
const cascaderExample = (fallbackExample) => cascaderExampleSuggestion(options, config, valueSeparator, fallbackExample);
|
|
@@ -2377,15 +2402,15 @@
|
|
|
2377
2402
|
if (!Object.is(value, activeValue) && !Object.is(value, inactiveValue)) return defaultMessage(message, `${value} 不在合法开关值中`, toggleSuggestion(activeValue, inactiveValue));
|
|
2378
2403
|
return;
|
|
2379
2404
|
}
|
|
2380
|
-
if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(props)), message);
|
|
2405
|
+
if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(mForm, props)), message);
|
|
2381
2406
|
if (fieldType === "radio-group") {
|
|
2382
|
-
const optionValues = flattenSelectOptions(resolveOptions(props));
|
|
2407
|
+
const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
|
|
2383
2408
|
if (optionValues.length === 0) return;
|
|
2384
2409
|
if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
2385
2410
|
return;
|
|
2386
2411
|
}
|
|
2387
2412
|
if (fieldType === "checkbox-group") {
|
|
2388
|
-
const optionValues = flattenSelectOptions(resolveOptions(props));
|
|
2413
|
+
const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
|
|
2389
2414
|
if (optionValues.length === 0) return;
|
|
2390
2415
|
if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
|
|
2391
2416
|
if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
@@ -2412,8 +2437,14 @@
|
|
|
2412
2437
|
if (isEmptyValue(value) || isEmptyArray(value)) return;
|
|
2413
2438
|
if (!props.config?.name) return;
|
|
2414
2439
|
const rawFieldType = "type" in (props.config || {}) ? props.config.type : "";
|
|
2415
|
-
|
|
2416
|
-
|
|
2440
|
+
let resolvedType;
|
|
2441
|
+
try {
|
|
2442
|
+
resolvedType = resolveConfig(mForm, rawFieldType, props);
|
|
2443
|
+
} catch {
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2446
|
+
if (ignorePromise(resolvedType) || typeof resolvedType !== "string" || !resolvedType) return;
|
|
2447
|
+
const fieldType = (0, _tmagic_utils.toLine)(resolvedType);
|
|
2417
2448
|
const customValidator = getTypeMatchRule(fieldType);
|
|
2418
2449
|
if (customValidator) return customValidator(value, {
|
|
2419
2450
|
fieldType,
|
|
@@ -2820,16 +2851,20 @@
|
|
|
2820
2851
|
return type?.replace(/([A-Z])/g, "-$1").toLowerCase() || (config?.items ? "" : "text");
|
|
2821
2852
|
};
|
|
2822
2853
|
var filterFunction = (mForm, config, props) => {
|
|
2823
|
-
if (typeof config === "function")
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2854
|
+
if (typeof config === "function") {
|
|
2855
|
+
const formValue = (0, vue.readonly)(mForm?.values || props.model);
|
|
2856
|
+
return config(mForm, {
|
|
2857
|
+
values: (0, vue.readonly)(mForm?.initValues || {}),
|
|
2858
|
+
model: (0, vue.readonly)(props.model),
|
|
2859
|
+
parent: (0, vue.readonly)(mForm?.parentValues || {}),
|
|
2860
|
+
formValue,
|
|
2861
|
+
formValues: formValue,
|
|
2862
|
+
prop: props.prop,
|
|
2863
|
+
config: props.config,
|
|
2864
|
+
index: props.index,
|
|
2865
|
+
getFormValue: (prop) => (0, _tmagic_utils.getValueByKeyPath)(prop, mForm?.values || props.model)
|
|
2866
|
+
});
|
|
2867
|
+
}
|
|
2833
2868
|
return config;
|
|
2834
2869
|
};
|
|
2835
2870
|
var display = function(mForm, config, props) {
|
package/dist/tmagic-form.umd.cjs
CHANGED
|
@@ -97,8 +97,10 @@
|
|
|
97
97
|
var unmasked = true;
|
|
98
98
|
} catch (e) {}
|
|
99
99
|
var result = nativeObjectToString$1.call(value);
|
|
100
|
-
if (unmasked)
|
|
101
|
-
|
|
100
|
+
if (unmasked) {
|
|
101
|
+
if (isOwn) value[symToStringTag$1] = tag;
|
|
102
|
+
else delete value[symToStringTag$1];
|
|
103
|
+
}
|
|
102
104
|
return result;
|
|
103
105
|
}
|
|
104
106
|
//#endregion
|
|
@@ -2903,6 +2905,14 @@
|
|
|
2903
2905
|
var extraTypeMatchRules = /* @__PURE__ */ new Map();
|
|
2904
2906
|
var builtInTypeMatchRules = /* @__PURE__ */ new Map();
|
|
2905
2907
|
var isPromise = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
2908
|
+
/**
|
|
2909
|
+
* 同步校验无法等待 Promise。调用方会丢掉返回值,这里挂上空 handler,避免变成未捕获 rejection。
|
|
2910
|
+
*/
|
|
2911
|
+
var ignorePromise = (value) => {
|
|
2912
|
+
if (!isPromise(value)) return false;
|
|
2913
|
+
value.then(() => {}, () => {});
|
|
2914
|
+
return true;
|
|
2915
|
+
};
|
|
2906
2916
|
/** 注册或覆盖某个字段 type 的 typeMatch 校验规则。`builtIn` 登记不受 `clearTypeMatchRules` / `deleteTypeMatchRule` 影响。 */
|
|
2907
2917
|
var registerTypeMatchRule = (type, validator, builtIn = false) => {
|
|
2908
2918
|
(builtIn ? builtInTypeMatchRules : extraTypeMatchRules).set((0, _tmagic_utils.toLine)(type), validator);
|
|
@@ -2920,16 +2930,20 @@
|
|
|
2920
2930
|
};
|
|
2921
2931
|
/** 本地解析配置函数,避免与 form.ts 循环依赖 */
|
|
2922
2932
|
var resolveConfig = (mForm, config, props) => {
|
|
2923
|
-
if (typeof config === "function")
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
+
if (typeof config === "function") {
|
|
2934
|
+
const formValue = (0, vue.readonly)(mForm?.values || props.model);
|
|
2935
|
+
return config(mForm, {
|
|
2936
|
+
values: (0, vue.readonly)(mForm?.initValues || {}),
|
|
2937
|
+
model: (0, vue.readonly)(props.model),
|
|
2938
|
+
parent: (0, vue.readonly)(mForm?.parentValues || {}),
|
|
2939
|
+
formValue,
|
|
2940
|
+
formValues: formValue,
|
|
2941
|
+
prop: props.prop,
|
|
2942
|
+
config: props.config,
|
|
2943
|
+
index: props.index,
|
|
2944
|
+
getFormValue: (prop) => (0, _tmagic_utils.getValueByKeyPath)(prop, mForm?.values || props.model)
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2933
2947
|
return config;
|
|
2934
2948
|
};
|
|
2935
2949
|
var SKIP_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -3021,7 +3035,7 @@
|
|
|
3021
3035
|
const { defaultValue } = props.config || {};
|
|
3022
3036
|
if (typeof defaultValue === "undefined" || defaultValue === "undefined") return void 0;
|
|
3023
3037
|
const resolvedDefaultValue = resolveConfig(mForm, defaultValue, props);
|
|
3024
|
-
if (
|
|
3038
|
+
if (ignorePromise(resolvedDefaultValue)) return;
|
|
3025
3039
|
return resolvedDefaultValue;
|
|
3026
3040
|
};
|
|
3027
3041
|
var isNumberValue = (value) => typeof value === "number" && !Number.isNaN(value);
|
|
@@ -3098,9 +3112,21 @@
|
|
|
3098
3112
|
});
|
|
3099
3113
|
return values;
|
|
3100
3114
|
};
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3115
|
+
/**
|
|
3116
|
+
* 解析字段 options:静态数组原样返回;函数型与 `display` / `type` 一样当场求值。
|
|
3117
|
+
*
|
|
3118
|
+
* 函数返回 Promise、非数组或抛错时当作「还没有可选项」,交由调用方按空 options 跳过枚举。
|
|
3119
|
+
* `remote` / `allowCreate` 仍由 `validateSelectValue` 单独放行,不在这里区分。
|
|
3120
|
+
*/
|
|
3121
|
+
var resolveOptions = (mForm, props) => {
|
|
3122
|
+
let resolved;
|
|
3123
|
+
try {
|
|
3124
|
+
resolved = resolveConfig(mForm, props.config?.options, props);
|
|
3125
|
+
} catch {
|
|
3126
|
+
return [];
|
|
3127
|
+
}
|
|
3128
|
+
if (ignorePromise(resolved) || !Array.isArray(resolved)) return [];
|
|
3129
|
+
return resolved;
|
|
3104
3130
|
};
|
|
3105
3131
|
var includesOptionValue = (optionValues, value) => optionValues.some((item) => Object.is(item, value));
|
|
3106
3132
|
var collectCascaderLeafValues = (options, result = []) => {
|
|
@@ -3162,19 +3188,18 @@
|
|
|
3162
3188
|
if (typeof value === "object") return defaultMessage(message, `${value} 类型不合法`, optionExampleSuggestion(optionValues, "\"文本内容\" 或 123", false));
|
|
3163
3189
|
return;
|
|
3164
3190
|
}
|
|
3165
|
-
const isStaticOptions = Array.isArray(config.options);
|
|
3166
3191
|
if (config.multiple) {
|
|
3167
3192
|
if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
|
|
3168
|
-
if (
|
|
3193
|
+
if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
3169
3194
|
return;
|
|
3170
3195
|
}
|
|
3171
|
-
if (
|
|
3196
|
+
if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
3172
3197
|
};
|
|
3173
3198
|
var validateCascaderValue = (value, config, props, mForm, message) => {
|
|
3174
|
-
const options = resolveOptions(props);
|
|
3199
|
+
const options = resolveOptions(mForm, props);
|
|
3175
3200
|
if (!options.length) return;
|
|
3176
3201
|
const valueSeparator = resolveConfig(mForm, config.valueSeparator, props);
|
|
3177
|
-
if (
|
|
3202
|
+
if (ignorePromise(valueSeparator)) return;
|
|
3178
3203
|
const emitPath = config.emitPath !== false;
|
|
3179
3204
|
const multiple = Boolean(config.multiple);
|
|
3180
3205
|
const cascaderExample = (fallbackExample) => cascaderExampleSuggestion(options, config, valueSeparator, fallbackExample);
|
|
@@ -3231,15 +3256,15 @@
|
|
|
3231
3256
|
if (!Object.is(value, activeValue) && !Object.is(value, inactiveValue)) return defaultMessage(message, `${value} 不在合法开关值中`, toggleSuggestion(activeValue, inactiveValue));
|
|
3232
3257
|
return;
|
|
3233
3258
|
}
|
|
3234
|
-
if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(props)), message);
|
|
3259
|
+
if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(mForm, props)), message);
|
|
3235
3260
|
if (fieldType === "radio-group") {
|
|
3236
|
-
const optionValues = flattenSelectOptions(resolveOptions(props));
|
|
3261
|
+
const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
|
|
3237
3262
|
if (optionValues.length === 0) return;
|
|
3238
3263
|
if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
3239
3264
|
return;
|
|
3240
3265
|
}
|
|
3241
3266
|
if (fieldType === "checkbox-group") {
|
|
3242
|
-
const optionValues = flattenSelectOptions(resolveOptions(props));
|
|
3267
|
+
const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
|
|
3243
3268
|
if (optionValues.length === 0) return;
|
|
3244
3269
|
if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
|
|
3245
3270
|
if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
@@ -3266,8 +3291,14 @@
|
|
|
3266
3291
|
if (isEmptyValue(value) || isEmptyArray(value)) return;
|
|
3267
3292
|
if (!props.config?.name) return;
|
|
3268
3293
|
const rawFieldType = "type" in (props.config || {}) ? props.config.type : "";
|
|
3269
|
-
|
|
3270
|
-
|
|
3294
|
+
let resolvedType;
|
|
3295
|
+
try {
|
|
3296
|
+
resolvedType = resolveConfig(mForm, rawFieldType, props);
|
|
3297
|
+
} catch {
|
|
3298
|
+
return;
|
|
3299
|
+
}
|
|
3300
|
+
if (ignorePromise(resolvedType) || typeof resolvedType !== "string" || !resolvedType) return;
|
|
3301
|
+
const fieldType = (0, _tmagic_utils.toLine)(resolvedType);
|
|
3271
3302
|
const customValidator = getTypeMatchRule(fieldType);
|
|
3272
3303
|
if (customValidator) return customValidator(value, {
|
|
3273
3304
|
fieldType,
|
|
@@ -3674,16 +3705,20 @@
|
|
|
3674
3705
|
return type?.replace(/([A-Z])/g, "-$1").toLowerCase() || (config?.items ? "" : "text");
|
|
3675
3706
|
};
|
|
3676
3707
|
var filterFunction = (mForm, config, props) => {
|
|
3677
|
-
if (typeof config === "function")
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3708
|
+
if (typeof config === "function") {
|
|
3709
|
+
const formValue = (0, vue.readonly)(mForm?.values || props.model);
|
|
3710
|
+
return config(mForm, {
|
|
3711
|
+
values: (0, vue.readonly)(mForm?.initValues || {}),
|
|
3712
|
+
model: (0, vue.readonly)(props.model),
|
|
3713
|
+
parent: (0, vue.readonly)(mForm?.parentValues || {}),
|
|
3714
|
+
formValue,
|
|
3715
|
+
formValues: formValue,
|
|
3716
|
+
prop: props.prop,
|
|
3717
|
+
config: props.config,
|
|
3718
|
+
index: props.index,
|
|
3719
|
+
getFormValue: (prop) => (0, _tmagic_utils.getValueByKeyPath)(prop, mForm?.values || props.model)
|
|
3720
|
+
});
|
|
3721
|
+
}
|
|
3687
3722
|
return config;
|
|
3688
3723
|
};
|
|
3689
3724
|
var display = function(mForm, config, props) {
|
|
@@ -3795,6 +3830,24 @@
|
|
|
3795
3830
|
*/
|
|
3796
3831
|
/** group-list 形态的 type(兼容驼峰与中划线两种写法) */
|
|
3797
3832
|
var isGroupListType = (type) => type === "groupList" || type === "group-list";
|
|
3833
|
+
/**
|
|
3834
|
+
* 归一成带单位的 CSS 长度。
|
|
3835
|
+
*
|
|
3836
|
+
* 配置常常来自 JSON 或表单输入,`'48'` 这类无单位数字串很常见;直接写进 CSS 变量会让
|
|
3837
|
+
* 嵌套层的 `calc()` 整体失效、吸顶静默失灵,所以纯数字一律补 `px`。
|
|
3838
|
+
*/
|
|
3839
|
+
var toCssLength = (height) => {
|
|
3840
|
+
const value = `${height ?? ""}`.trim();
|
|
3841
|
+
if (!value) return void 0;
|
|
3842
|
+
if ((0, _tmagic_utils.isNumber)(value)) return `${value}px`;
|
|
3843
|
+
return typeof height === "number" ? void 0 : value;
|
|
3844
|
+
};
|
|
3845
|
+
/** header.sticky 开启时把 height 写成 CSS 变量,给嵌套吸顶偏移用 */
|
|
3846
|
+
var getGroupListHeaderVars = (header) => {
|
|
3847
|
+
if (!header?.sticky) return void 0;
|
|
3848
|
+
const height = toCssLength(header.height);
|
|
3849
|
+
return height ? { "--m-group-list-header-height": height } : void 0;
|
|
3850
|
+
};
|
|
3798
3851
|
/** 按 label 文案长度估算 label 宽度(中文按 20px、其他按 8px,最小 80px) */
|
|
3799
3852
|
var calcLabelWidth = (label) => {
|
|
3800
3853
|
if (!label) return "0px";
|
|
@@ -4725,7 +4778,7 @@
|
|
|
4725
4778
|
};
|
|
4726
4779
|
var _hoisted_3$7 = ["innerHTML"];
|
|
4727
4780
|
var _hoisted_4$6 = ["innerHTML"];
|
|
4728
|
-
var _hoisted_5$
|
|
4781
|
+
var _hoisted_5$4 = ["innerHTML"];
|
|
4729
4782
|
var _hoisted_6$3 = ["innerHTML"];
|
|
4730
4783
|
var _hoisted_7$2 = ["innerHTML"];
|
|
4731
4784
|
var _hoisted_8$2 = ["innerHTML"];
|
|
@@ -5080,7 +5133,7 @@
|
|
|
5080
5133
|
key: 0,
|
|
5081
5134
|
placement: tooltip.value.placement
|
|
5082
5135
|
}, {
|
|
5083
|
-
content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$
|
|
5136
|
+
content: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", { innerHTML: tooltip.value.text }, null, 8, _hoisted_5$4)]),
|
|
5084
5137
|
default: (0, vue.withCtx)(() => [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.resolveDynamicComponent)(tagName.value), (0, vue.mergeProps)(fieldsProps.value, {
|
|
5085
5138
|
model: __props.model,
|
|
5086
5139
|
"last-values": __props.lastValues,
|
|
@@ -6478,7 +6531,7 @@
|
|
|
6478
6531
|
var _hoisted_2$7 = ["innerHTML"];
|
|
6479
6532
|
var _hoisted_3$6 = { key: 1 };
|
|
6480
6533
|
var _hoisted_4$5 = ["innerHTML"];
|
|
6481
|
-
var _hoisted_5$
|
|
6534
|
+
var _hoisted_5$3 = ["innerHTML"];
|
|
6482
6535
|
var _hoisted_6$2 = {
|
|
6483
6536
|
key: 2,
|
|
6484
6537
|
style: { "display": "flex" }
|
|
@@ -6569,7 +6622,7 @@
|
|
|
6569
6622
|
key: 0,
|
|
6570
6623
|
innerHTML: __props.config.extra,
|
|
6571
6624
|
class: "m-form-tip"
|
|
6572
|
-
}, null, 8, _hoisted_5$
|
|
6625
|
+
}, null, 8, _hoisted_5$3)) : (0, vue.createCommentVNode)("v-if", true)])), __props.config.schematic && show.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_6$2, [(0, vue.createElementVNode)("div", _hoisted_7$1, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.config.items, (item, index) => {
|
|
6573
6626
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
6574
6627
|
key: key(item, index),
|
|
6575
6628
|
model: name.value ? __props.model[name.value] : __props.model,
|
|
@@ -6707,7 +6760,7 @@
|
|
|
6707
6760
|
style: { "display": "flex" }
|
|
6708
6761
|
};
|
|
6709
6762
|
var _hoisted_4$4 = { style: { "flex": "1" } };
|
|
6710
|
-
var _hoisted_5$
|
|
6763
|
+
var _hoisted_5$2 = ["src"];
|
|
6711
6764
|
//#endregion
|
|
6712
6765
|
//#region packages/form/src/containers/Panel.vue
|
|
6713
6766
|
var Panel_default = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
@@ -6800,7 +6853,7 @@
|
|
|
6800
6853
|
}), 128))]), (0, vue.createElementVNode)("img", {
|
|
6801
6854
|
class: "m-form-schematic",
|
|
6802
6855
|
src: __props.config.schematic
|
|
6803
|
-
}, null, 8, _hoisted_5$
|
|
6856
|
+
}, null, 8, _hoisted_5$2)])) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, (0, vue.renderList)(items.value, (item, index) => {
|
|
6804
6857
|
return (0, vue.openBlock)(), (0, vue.createBlock)(Container_default, {
|
|
6805
6858
|
key: item[(0, vue.unref)(mForm)?.keyProp || "__key"] ?? index,
|
|
6806
6859
|
config: item,
|
|
@@ -7158,7 +7211,7 @@
|
|
|
7158
7211
|
var _hoisted_2$5 = { class: "m-fields-group-list-item-title" };
|
|
7159
7212
|
var _hoisted_3$4 = ["innerHTML"];
|
|
7160
7213
|
var _hoisted_4$3 = { class: "m-fields-group-list-item-actions" };
|
|
7161
|
-
var _hoisted_5$
|
|
7214
|
+
var _hoisted_5$1 = { style: {
|
|
7162
7215
|
"text-align": "right",
|
|
7163
7216
|
"margin-top": "20px"
|
|
7164
7217
|
} };
|
|
@@ -7323,7 +7376,7 @@
|
|
|
7323
7376
|
disabled: __props.disabled
|
|
7324
7377
|
}, null, 8, ["modelValue", "disabled"]),
|
|
7325
7378
|
_cache[11] || (_cache[11] = (0, vue.createTextVNode)("行 ", -1))
|
|
7326
|
-
]), (0, vue.createElementVNode)("div", _hoisted_5$
|
|
7379
|
+
]), (0, vue.createElementVNode)("div", _hoisted_5$1, [(0, vue.createVNode)((0, vue.unref)(_tmagic_design.TMagicButton), {
|
|
7327
7380
|
size: "small",
|
|
7328
7381
|
text: "",
|
|
7329
7382
|
onClick: _cache[4] || (_cache[4] = ($event) => moveSpecifyLocationVisible.value = false)
|
|
@@ -7393,14 +7446,13 @@
|
|
|
7393
7446
|
});
|
|
7394
7447
|
//#endregion
|
|
7395
7448
|
//#region packages/form/src/containers/GroupList.vue?vue&type=script&setup=true&lang.ts
|
|
7396
|
-
var _hoisted_1$8 =
|
|
7397
|
-
var _hoisted_2$4 =
|
|
7398
|
-
var _hoisted_3$3 = {
|
|
7449
|
+
var _hoisted_1$8 = ["innerHTML"];
|
|
7450
|
+
var _hoisted_2$4 = {
|
|
7399
7451
|
key: 1,
|
|
7400
7452
|
class: "el-table__empty-block"
|
|
7401
7453
|
};
|
|
7402
|
-
var
|
|
7403
|
-
var
|
|
7454
|
+
var _hoisted_3$3 = { class: "el-table__empty-text t-table__empty" };
|
|
7455
|
+
var _hoisted_4$2 = { style: {
|
|
7404
7456
|
"display": "flex",
|
|
7405
7457
|
"justify-content": "flex-end",
|
|
7406
7458
|
"flex": "1"
|
|
@@ -7447,6 +7499,14 @@
|
|
|
7447
7499
|
};
|
|
7448
7500
|
const onAddDiffCount = () => emit("addDiffCount");
|
|
7449
7501
|
const asList = (value) => Array.isArray(value) ? value : [];
|
|
7502
|
+
const headerVars = (0, vue.computed)(() => getGroupListHeaderVars(props.config.header));
|
|
7503
|
+
/**
|
|
7504
|
+
* 取 `$slots` 而不是 `useSlots()`:宿主切换 `addable` 时插槽会增删,
|
|
7505
|
+
* computed 缓存不随插槽变化失效,只有在渲染期读才拿得到最新的。
|
|
7506
|
+
*/
|
|
7507
|
+
const hasFooter = (slots) => !props.isCompare && Boolean(slots["toggle-button"] || slots["add-button"]);
|
|
7508
|
+
/** 只有真的渲染出吸底 footer,内层列表才需要为它让位 */
|
|
7509
|
+
const isFooterSticky = (slots) => hasFooter(slots) && Boolean(props.config.addButtonConfig?.sticky);
|
|
7450
7510
|
const currentList = (0, vue.computed)(() => asList(props.model[props.name]));
|
|
7451
7511
|
/** 对比时按当前/历史较长一侧对齐,已删除的项也能渲染出来 */
|
|
7452
7512
|
const displayItems = (0, vue.computed)(() => {
|
|
@@ -7464,13 +7524,19 @@
|
|
|
7464
7524
|
}));
|
|
7465
7525
|
});
|
|
7466
7526
|
return (_ctx, _cache) => {
|
|
7467
|
-
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
7527
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7528
|
+
class: (0, vue.normalizeClass)(["m-fields-group-list", {
|
|
7529
|
+
"is-header-sticky": Boolean(__props.config.header?.sticky),
|
|
7530
|
+
"is-footer-sticky": isFooterSticky(_ctx.$slots)
|
|
7531
|
+
}]),
|
|
7532
|
+
style: (0, vue.normalizeStyle)(headerVars.value)
|
|
7533
|
+
}, [
|
|
7468
7534
|
__props.config.extra ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7469
7535
|
key: 0,
|
|
7470
7536
|
innerHTML: __props.config.extra,
|
|
7471
7537
|
style: { "color": "rgba(0, 0, 0, 0.45)" }
|
|
7472
|
-
}, null, 8,
|
|
7473
|
-
!displayItems.value.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div",
|
|
7538
|
+
}, null, 8, _hoisted_1$8)) : (0, vue.createCommentVNode)("v-if", true),
|
|
7539
|
+
!displayItems.value.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2$4, [(0, vue.createElementVNode)("span", _hoisted_3$3, "暂无" + (0, vue.toDisplayString)(__props.config.titlePrefix || "") + "数据", 1)])) : ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, { key: 2 }, (0, vue.renderList)(displayItems.value, (entry) => {
|
|
7474
7540
|
return (0, vue.openBlock)(), (0, vue.createBlock)(GroupListItem_default, {
|
|
7475
7541
|
key: entry.index,
|
|
7476
7542
|
model: entry.item,
|
|
@@ -7507,11 +7573,11 @@
|
|
|
7507
7573
|
"group-model"
|
|
7508
7574
|
]);
|
|
7509
7575
|
}), 128)),
|
|
7510
|
-
|
|
7576
|
+
hasFooter(_ctx.$slots) ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
|
|
7511
7577
|
key: 3,
|
|
7512
7578
|
class: (0, vue.normalizeClass)(["m-fields-group-list-footer", { "is-sticky-full": Boolean(__props.config.addButtonConfig?.sticky) }])
|
|
7513
|
-
}, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div",
|
|
7514
|
-
]);
|
|
7579
|
+
}, [(0, vue.renderSlot)(_ctx.$slots, "toggle-button"), (0, vue.createElementVNode)("div", _hoisted_4$2, [(0, vue.renderSlot)(_ctx.$slots, "add-button")])], 2)) : (0, vue.createCommentVNode)("v-if", true)
|
|
7580
|
+
], 6);
|
|
7515
7581
|
};
|
|
7516
7582
|
}
|
|
7517
7583
|
});
|
|
@@ -8590,14 +8656,17 @@
|
|
|
8590
8656
|
const ctrl = navigator.platform.match("Mac") ? $event.metaKey : $event.ctrlKey;
|
|
8591
8657
|
const shift = $event.shiftKey;
|
|
8592
8658
|
const alt = $event.altKey;
|
|
8593
|
-
if (arrowUp)
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
else if (
|
|
8599
|
-
|
|
8600
|
-
|
|
8659
|
+
if (arrowUp) {
|
|
8660
|
+
if (ctrl) num += 100;
|
|
8661
|
+
else if (alt) num = (num * 1e4 + 1e3) / 1e4;
|
|
8662
|
+
else if (shift) num = num + 10;
|
|
8663
|
+
else num += 1;
|
|
8664
|
+
} else if (arrowDown) {
|
|
8665
|
+
if (ctrl) num -= 100;
|
|
8666
|
+
else if (alt) num = (num * 1e4 - 1e3) / 1e4;
|
|
8667
|
+
else if (shift) num -= 10;
|
|
8668
|
+
else num -= 1;
|
|
8669
|
+
}
|
|
8601
8670
|
props.model[props.name] = `${num}${unit || ""}`;
|
|
8602
8671
|
emit("change", props.model[props.name]);
|
|
8603
8672
|
};
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.29",
|
|
3
3
|
"name": "@tmagic/form",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -46,21 +46,21 @@
|
|
|
46
46
|
"@element-plus/icons-vue": "^2.3.2",
|
|
47
47
|
"@popperjs/core": "^2.11.8",
|
|
48
48
|
"async-validator": "^4.2.5",
|
|
49
|
-
"dayjs": "^1.11.
|
|
49
|
+
"dayjs": "^1.11.23",
|
|
50
50
|
"lodash-es": "^4.18.1",
|
|
51
51
|
"sortablejs": "^1.15.7"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/lodash-es": "^4.17.12",
|
|
55
55
|
"@types/sortablejs": "^1.15.9",
|
|
56
|
-
"@vue/test-utils": "^2.
|
|
56
|
+
"@vue/test-utils": "^2.5.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"typescript": "^6.0.3",
|
|
60
|
-
"vue": "^3.5.
|
|
61
|
-
"@tmagic/design": "1.8.0-beta.
|
|
62
|
-
"@tmagic/
|
|
63
|
-
"@tmagic/
|
|
60
|
+
"vue": "^3.5.43",
|
|
61
|
+
"@tmagic/design": "1.8.0-beta.29",
|
|
62
|
+
"@tmagic/utils": "1.8.0-beta.29",
|
|
63
|
+
"@tmagic/form-schema": "1.8.0-beta.29"
|
|
64
64
|
},
|
|
65
65
|
"peerDependenciesMeta": {
|
|
66
66
|
"typescript": {
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="m-fields-group-list"
|
|
4
|
+
:class="{
|
|
5
|
+
'is-header-sticky': Boolean(config.header?.sticky),
|
|
6
|
+
'is-footer-sticky': isFooterSticky($slots),
|
|
7
|
+
}"
|
|
8
|
+
:style="headerVars"
|
|
9
|
+
>
|
|
3
10
|
<div v-if="config.extra" v-html="config.extra" style="color: rgba(0, 0, 0, 0.45)"></div>
|
|
4
11
|
<div v-if="!displayItems.length" class="el-table__empty-block">
|
|
5
12
|
<span class="el-table__empty-text t-table__empty">暂无{{ config.titlePrefix || '' }}数据</span>
|
|
@@ -34,7 +41,7 @@
|
|
|
34
41
|
<div
|
|
35
42
|
class="m-fields-group-list-footer"
|
|
36
43
|
:class="{ 'is-sticky-full': Boolean(config.addButtonConfig?.sticky) }"
|
|
37
|
-
v-if="
|
|
44
|
+
v-if="hasFooter($slots)"
|
|
38
45
|
>
|
|
39
46
|
<slot name="toggle-button"></slot>
|
|
40
47
|
<div style="display: flex; justify-content: flex-end; flex: 1">
|
|
@@ -49,6 +56,7 @@ import { computed } from 'vue';
|
|
|
49
56
|
import { cloneDeep } from 'lodash-es';
|
|
50
57
|
|
|
51
58
|
import type { ContainerChangeEventData, GroupListConfig } from '../schema';
|
|
59
|
+
import { getGroupListHeaderVars } from '../utils/tableGroupList';
|
|
52
60
|
|
|
53
61
|
import MFieldsGroupListItem from './GroupListItem.vue';
|
|
54
62
|
|
|
@@ -104,6 +112,19 @@ const onAddDiffCount = () => emit('addDiffCount');
|
|
|
104
112
|
|
|
105
113
|
const asList = (value: unknown): any[] => (Array.isArray(value) ? value : []);
|
|
106
114
|
|
|
115
|
+
const headerVars = computed(() => getGroupListHeaderVars(props.config.header));
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 取 `$slots` 而不是 `useSlots()`:宿主切换 `addable` 时插槽会增删,
|
|
119
|
+
* computed 缓存不随插槽变化失效,只有在渲染期读才拿得到最新的。
|
|
120
|
+
*/
|
|
121
|
+
const hasFooter = (slots: Record<string, unknown>) =>
|
|
122
|
+
!props.isCompare && Boolean(slots['toggle-button'] || slots['add-button']);
|
|
123
|
+
|
|
124
|
+
/** 只有真的渲染出吸底 footer,内层列表才需要为它让位 */
|
|
125
|
+
const isFooterSticky = (slots: Record<string, unknown>) =>
|
|
126
|
+
hasFooter(slots) && Boolean(props.config.addButtonConfig?.sticky);
|
|
127
|
+
|
|
107
128
|
const currentList = computed(() => asList(props.model[props.name]));
|
|
108
129
|
|
|
109
130
|
/** 对比时按当前/历史较长一侧对齐,已删除的项也能渲染出来 */
|