@tmagic/form 1.8.0-beta.28 → 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/fields/Text.vue_vue_type_script_setup_true_lang.js +11 -8
- package/dist/es/utils/form.js +14 -10
- package/dist/es/utils/typeMatch.js +53 -24
- package/dist/tmagic-form-headless.umd.cjs +71 -36
- package/dist/tmagic-form.umd.cjs +82 -44
- package/package.json +7 -7
- package/src/utils/form.ts +4 -1
- package/src/utils/typeMatch.ts +48 -17
- package/types/headless.d.ts +54 -54
- package/types/index.d.ts +57 -57
|
@@ -120,14 +120,17 @@ var Text_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
|
|
|
120
120
|
const ctrl = navigator.platform.match("Mac") ? $event.metaKey : $event.ctrlKey;
|
|
121
121
|
const shift = $event.shiftKey;
|
|
122
122
|
const alt = $event.altKey;
|
|
123
|
-
if (arrowUp)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
else if (
|
|
129
|
-
|
|
130
|
-
|
|
123
|
+
if (arrowUp) {
|
|
124
|
+
if (ctrl) num += 100;
|
|
125
|
+
else if (alt) num = (num * 1e4 + 1e3) / 1e4;
|
|
126
|
+
else if (shift) num = num + 10;
|
|
127
|
+
else num += 1;
|
|
128
|
+
} else if (arrowDown) {
|
|
129
|
+
if (ctrl) num -= 100;
|
|
130
|
+
else if (alt) num = (num * 1e4 - 1e3) / 1e4;
|
|
131
|
+
else if (shift) num -= 10;
|
|
132
|
+
else num -= 1;
|
|
133
|
+
}
|
|
131
134
|
props.model[props.name] = `${num}${unit || ""}`;
|
|
132
135
|
emit("change", props.model[props.name]);
|
|
133
136
|
};
|
package/dist/es/utils/form.js
CHANGED
|
@@ -192,16 +192,20 @@ var resolveItemType = (mForm, config, props) => {
|
|
|
192
192
|
return type?.replace(/([A-Z])/g, "-$1").toLowerCase() || (config?.items ? "" : "text");
|
|
193
193
|
};
|
|
194
194
|
var filterFunction = (mForm, config, props) => {
|
|
195
|
-
if (typeof config === "function")
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
if (typeof config === "function") {
|
|
196
|
+
const formValue = readonly(mForm?.values || props.model);
|
|
197
|
+
return config(mForm, {
|
|
198
|
+
values: readonly(mForm?.initValues || {}),
|
|
199
|
+
model: readonly(props.model),
|
|
200
|
+
parent: readonly(mForm?.parentValues || {}),
|
|
201
|
+
formValue,
|
|
202
|
+
formValues: formValue,
|
|
203
|
+
prop: props.prop,
|
|
204
|
+
config: props.config,
|
|
205
|
+
index: props.index,
|
|
206
|
+
getFormValue: (prop) => getValueByKeyPath(prop, mForm?.values || props.model)
|
|
207
|
+
});
|
|
208
|
+
}
|
|
205
209
|
return config;
|
|
206
210
|
};
|
|
207
211
|
var display = function(mForm, config, props) {
|
|
@@ -8,6 +8,14 @@ dayjs.extend(customParseFormat);
|
|
|
8
8
|
var extraTypeMatchRules = /* @__PURE__ */ new Map();
|
|
9
9
|
var builtInTypeMatchRules = /* @__PURE__ */ new Map();
|
|
10
10
|
var isPromise = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
|
|
11
|
+
/**
|
|
12
|
+
* 同步校验无法等待 Promise。调用方会丢掉返回值,这里挂上空 handler,避免变成未捕获 rejection。
|
|
13
|
+
*/
|
|
14
|
+
var ignorePromise = (value) => {
|
|
15
|
+
if (!isPromise(value)) return false;
|
|
16
|
+
value.then(() => {}, () => {});
|
|
17
|
+
return true;
|
|
18
|
+
};
|
|
11
19
|
/** 注册或覆盖某个字段 type 的 typeMatch 校验规则。`builtIn` 登记不受 `clearTypeMatchRules` / `deleteTypeMatchRule` 影响。 */
|
|
12
20
|
var registerTypeMatchRule = (type, validator, builtIn = false) => {
|
|
13
21
|
(builtIn ? builtInTypeMatchRules : extraTypeMatchRules).set(toLine(type), validator);
|
|
@@ -25,16 +33,20 @@ var clearTypeMatchRules = () => {
|
|
|
25
33
|
};
|
|
26
34
|
/** 本地解析配置函数,避免与 form.ts 循环依赖 */
|
|
27
35
|
var resolveConfig = (mForm, config, props) => {
|
|
28
|
-
if (typeof config === "function")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
if (typeof config === "function") {
|
|
37
|
+
const formValue = readonly(mForm?.values || props.model);
|
|
38
|
+
return config(mForm, {
|
|
39
|
+
values: readonly(mForm?.initValues || {}),
|
|
40
|
+
model: readonly(props.model),
|
|
41
|
+
parent: readonly(mForm?.parentValues || {}),
|
|
42
|
+
formValue,
|
|
43
|
+
formValues: formValue,
|
|
44
|
+
prop: props.prop,
|
|
45
|
+
config: props.config,
|
|
46
|
+
index: props.index,
|
|
47
|
+
getFormValue: (prop) => getValueByKeyPath(prop, mForm?.values || props.model)
|
|
48
|
+
});
|
|
49
|
+
}
|
|
38
50
|
return config;
|
|
39
51
|
};
|
|
40
52
|
var SKIP_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -126,7 +138,7 @@ var resolveFieldDefaultValue = (mForm, props) => {
|
|
|
126
138
|
const { defaultValue } = props.config || {};
|
|
127
139
|
if (typeof defaultValue === "undefined" || defaultValue === "undefined") return void 0;
|
|
128
140
|
const resolvedDefaultValue = resolveConfig(mForm, defaultValue, props);
|
|
129
|
-
if (
|
|
141
|
+
if (ignorePromise(resolvedDefaultValue)) return;
|
|
130
142
|
return resolvedDefaultValue;
|
|
131
143
|
};
|
|
132
144
|
var isNumberValue = (value) => typeof value === "number" && !Number.isNaN(value);
|
|
@@ -203,9 +215,21 @@ var flattenSelectOptions = (options) => {
|
|
|
203
215
|
});
|
|
204
216
|
return values;
|
|
205
217
|
};
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
218
|
+
/**
|
|
219
|
+
* 解析字段 options:静态数组原样返回;函数型与 `display` / `type` 一样当场求值。
|
|
220
|
+
*
|
|
221
|
+
* 函数返回 Promise、非数组或抛错时当作「还没有可选项」,交由调用方按空 options 跳过枚举。
|
|
222
|
+
* `remote` / `allowCreate` 仍由 `validateSelectValue` 单独放行,不在这里区分。
|
|
223
|
+
*/
|
|
224
|
+
var resolveOptions = (mForm, props) => {
|
|
225
|
+
let resolved;
|
|
226
|
+
try {
|
|
227
|
+
resolved = resolveConfig(mForm, props.config?.options, props);
|
|
228
|
+
} catch {
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
if (ignorePromise(resolved) || !Array.isArray(resolved)) return [];
|
|
232
|
+
return resolved;
|
|
209
233
|
};
|
|
210
234
|
var includesOptionValue = (optionValues, value) => optionValues.some((item) => Object.is(item, value));
|
|
211
235
|
var collectCascaderLeafValues = (options, result = []) => {
|
|
@@ -267,19 +291,18 @@ var validateSelectValue = (value, config, optionValues, message) => {
|
|
|
267
291
|
if (typeof value === "object") return defaultMessage(message, `${value} 类型不合法`, optionExampleSuggestion(optionValues, "\"文本内容\" 或 123", false));
|
|
268
292
|
return;
|
|
269
293
|
}
|
|
270
|
-
const isStaticOptions = Array.isArray(config.options);
|
|
271
294
|
if (config.multiple) {
|
|
272
295
|
if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
|
|
273
|
-
if (
|
|
296
|
+
if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
274
297
|
return;
|
|
275
298
|
}
|
|
276
|
-
if (
|
|
299
|
+
if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
277
300
|
};
|
|
278
301
|
var validateCascaderValue = (value, config, props, mForm, message) => {
|
|
279
|
-
const options = resolveOptions(props);
|
|
302
|
+
const options = resolveOptions(mForm, props);
|
|
280
303
|
if (!options.length) return;
|
|
281
304
|
const valueSeparator = resolveConfig(mForm, config.valueSeparator, props);
|
|
282
|
-
if (
|
|
305
|
+
if (ignorePromise(valueSeparator)) return;
|
|
283
306
|
const emitPath = config.emitPath !== false;
|
|
284
307
|
const multiple = Boolean(config.multiple);
|
|
285
308
|
const cascaderExample = (fallbackExample) => cascaderExampleSuggestion(options, config, valueSeparator, fallbackExample);
|
|
@@ -336,15 +359,15 @@ var validateBuiltinTypeMatch = (value, fieldType, mForm, props, message) => {
|
|
|
336
359
|
if (!Object.is(value, activeValue) && !Object.is(value, inactiveValue)) return defaultMessage(message, `${value} 不在合法开关值中`, toggleSuggestion(activeValue, inactiveValue));
|
|
337
360
|
return;
|
|
338
361
|
}
|
|
339
|
-
if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(props)), message);
|
|
362
|
+
if (fieldType === "select") return validateSelectValue(value, config, flattenSelectOptions(resolveOptions(mForm, props)), message);
|
|
340
363
|
if (fieldType === "radio-group") {
|
|
341
|
-
const optionValues = flattenSelectOptions(resolveOptions(props));
|
|
364
|
+
const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
|
|
342
365
|
if (optionValues.length === 0) return;
|
|
343
366
|
if (!includesOptionValue(optionValues, value)) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
344
367
|
return;
|
|
345
368
|
}
|
|
346
369
|
if (fieldType === "checkbox-group") {
|
|
347
|
-
const optionValues = flattenSelectOptions(resolveOptions(props));
|
|
370
|
+
const optionValues = flattenSelectOptions(resolveOptions(mForm, props));
|
|
348
371
|
if (optionValues.length === 0) return;
|
|
349
372
|
if (!Array.isArray(value)) return defaultMessage(message, `${value} 类型应为数组`, optionExampleSuggestion(optionValues, "[\"选项1\", \"选项2\"]", true));
|
|
350
373
|
if (value.some((item) => !includesOptionValue(optionValues, item))) return defaultMessage(message, `${value} 不在可选项中`, optionSuggestion(optionValues));
|
|
@@ -371,8 +394,14 @@ var validateTypeMatch = (value, mForm, props, message) => {
|
|
|
371
394
|
if (isEmptyValue(value) || isEmptyArray(value)) return;
|
|
372
395
|
if (!props.config?.name) return;
|
|
373
396
|
const rawFieldType = "type" in (props.config || {}) ? props.config.type : "";
|
|
374
|
-
|
|
375
|
-
|
|
397
|
+
let resolvedType;
|
|
398
|
+
try {
|
|
399
|
+
resolvedType = resolveConfig(mForm, rawFieldType, props);
|
|
400
|
+
} catch {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (ignorePromise(resolvedType) || typeof resolvedType !== "string" || !resolvedType) return;
|
|
404
|
+
const fieldType = toLine(resolvedType);
|
|
376
405
|
const customValidator = getTypeMatchRule(fieldType);
|
|
377
406
|
if (customValidator) return customValidator(value, {
|
|
378
407
|
fieldType,
|
|
@@ -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) {
|
|
@@ -8621,14 +8656,17 @@
|
|
|
8621
8656
|
const ctrl = navigator.platform.match("Mac") ? $event.metaKey : $event.ctrlKey;
|
|
8622
8657
|
const shift = $event.shiftKey;
|
|
8623
8658
|
const alt = $event.altKey;
|
|
8624
|
-
if (arrowUp)
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
else if (
|
|
8630
|
-
|
|
8631
|
-
|
|
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
|
+
}
|
|
8632
8670
|
props.model[props.name] = `${num}${unit || ""}`;
|
|
8633
8671
|
emit("change", props.model[props.name]);
|
|
8634
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/utils": "1.8.0-beta.
|
|
63
|
-
"@tmagic/form-schema": "1.8.0-beta.
|
|
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": {
|
package/src/utils/form.ts
CHANGED
|
@@ -368,11 +368,14 @@ export const filterFunction = <T = any>(
|
|
|
368
368
|
props: any,
|
|
369
369
|
) => {
|
|
370
370
|
if (typeof config === 'function') {
|
|
371
|
+
const formValue = readonly(mForm?.values || props.model);
|
|
371
372
|
return (config as FilterFunction<T>)(mForm, {
|
|
372
373
|
values: readonly(mForm?.initValues || {}),
|
|
373
374
|
model: readonly(props.model),
|
|
374
375
|
parent: readonly(mForm?.parentValues || {}),
|
|
375
|
-
formValue
|
|
376
|
+
formValue,
|
|
377
|
+
// Select.vue / SelectOptionFunction 使用 formValues 别名
|
|
378
|
+
formValues: formValue,
|
|
376
379
|
prop: props.prop,
|
|
377
380
|
config: props.config,
|
|
378
381
|
index: props.index,
|