@schemx/vue 0.1.20
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/README.md +136 -0
- package/dist/components/FormGroup/index.d.ts +17 -0
- package/dist/components/FormGroup/index.d.ts.map +1 -0
- package/dist/components/FormItem/index.d.ts +17 -0
- package/dist/components/FormItem/index.d.ts.map +1 -0
- package/dist/form.d.ts +34 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/hocs/index.d.ts +10 -0
- package/dist/hocs/index.d.ts.map +1 -0
- package/dist/hocs/withRemoteOptions.d.ts +74 -0
- package/dist/hocs/withRemoteOptions.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +24 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/useContext.d.ts +40 -0
- package/dist/hooks/useContext.d.ts.map +1 -0
- package/dist/hooks/useDictionary.d.ts +63 -0
- package/dist/hooks/useDictionary.d.ts.map +1 -0
- package/dist/hooks/useEffect.d.ts +34 -0
- package/dist/hooks/useEffect.d.ts.map +1 -0
- package/dist/hooks/useField.d.ts +38 -0
- package/dist/hooks/useField.d.ts.map +1 -0
- package/dist/hooks/useFieldContext.d.ts +23 -0
- package/dist/hooks/useFieldContext.d.ts.map +1 -0
- package/dist/hooks/useForm.d.ts +59 -0
- package/dist/hooks/useForm.d.ts.map +1 -0
- package/dist/hooks/useStableRef.d.ts +28 -0
- package/dist/hooks/useStableRef.d.ts.map +1 -0
- package/dist/hooks/useViewSchemas.d.ts +6 -0
- package/dist/hooks/useViewSchemas.d.ts.map +1 -0
- package/dist/hooks/useWatch.d.ts +65 -0
- package/dist/hooks/useWatch.d.ts.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +686 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/types/field.d.ts +23 -0
- package/dist/types/field.d.ts.map +1 -0
- package/dist/types/form.d.ts +18 -0
- package/dist/types/form.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/diff.d.ts +33 -0
- package/dist/utils/diff.d.ts.map +1 -0
- package/dist/utils/dynamic.d.ts +99 -0
- package/dist/utils/dynamic.d.ts.map +1 -0
- package/dist/utils/equal.d.ts +22 -0
- package/dist/utils/equal.d.ts.map +1 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/rendererProvider.d.ts +17 -0
- package/dist/utils/rendererProvider.d.ts.map +1 -0
- package/dist/utils/rulesProvider.d.ts +17 -0
- package/dist/utils/rulesProvider.d.ts.map +1 -0
- package/dist/utils/slot.d.ts +49 -0
- package/dist/utils/slot.d.ts.map +1 -0
- package/dist/utils/validation.d.ts +43 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/package.json +64 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
import { computed, provide, onUnmounted, inject, shallowRef, ref, onMounted, watchEffect, onScopeDispose, defineComponent, createVNode, toRef, h, createTextVNode, watch, openBlock, createElementBlock, normalizeClass, Fragment, renderList, unref, createBlock, createSlots, withCtx, renderSlot, mergeProps } from "vue";
|
|
2
|
+
import classnames from "classnames";
|
|
3
|
+
import { omit } from "es-toolkit";
|
|
4
|
+
import { createRendererRegistry, createValidatorsRegistry, createForm, createField, createWatch, createEffect } from "@schemx/core";
|
|
5
|
+
export * from "@schemx/core";
|
|
6
|
+
const rendererRegistry = createRendererRegistry("input");
|
|
7
|
+
const validatorRegistry = createValidatorsRegistry();
|
|
8
|
+
const SCHEMX_INSTANCE_KEY = Symbol("SCHEMX_INSTANCE");
|
|
9
|
+
function useForm(options) {
|
|
10
|
+
const { ...formOptions } = options;
|
|
11
|
+
const mergedOptions = {
|
|
12
|
+
...formOptions,
|
|
13
|
+
rendererRegistry: formOptions.rendererRegistry ?? rendererRegistry,
|
|
14
|
+
validatorRegistry: formOptions.validatorRegistry ?? validatorRegistry
|
|
15
|
+
};
|
|
16
|
+
const instance = computed(() => createForm(mergedOptions));
|
|
17
|
+
provide(SCHEMX_INSTANCE_KEY, instance.value);
|
|
18
|
+
onUnmounted(() => {
|
|
19
|
+
instance.value.destroy();
|
|
20
|
+
});
|
|
21
|
+
return instance.value;
|
|
22
|
+
}
|
|
23
|
+
function useFormInstance() {
|
|
24
|
+
const instance = inject(SCHEMX_INSTANCE_KEY);
|
|
25
|
+
if (!instance) {
|
|
26
|
+
throw new Error("useFormInstance must be used within a Form");
|
|
27
|
+
}
|
|
28
|
+
return instance;
|
|
29
|
+
}
|
|
30
|
+
const fieldHookCache = /* @__PURE__ */ new WeakMap();
|
|
31
|
+
function createFieldHook(form, name) {
|
|
32
|
+
const field = createField(form, name);
|
|
33
|
+
const fieldValue = shallowRef(field.getValue());
|
|
34
|
+
const fieldError = shallowRef(field.getError());
|
|
35
|
+
const fieldPending = shallowRef(field.isPending());
|
|
36
|
+
const dispose = field.effect(() => {
|
|
37
|
+
fieldValue.value = field.getValue();
|
|
38
|
+
fieldError.value = field.getError();
|
|
39
|
+
fieldPending.value = field.isPending();
|
|
40
|
+
});
|
|
41
|
+
const error = computed(() => fieldError.value);
|
|
42
|
+
const dirty = computed(() => {
|
|
43
|
+
void fieldValue.value;
|
|
44
|
+
return field.isTouched();
|
|
45
|
+
});
|
|
46
|
+
const pending = computed(() => fieldPending.value);
|
|
47
|
+
const result = {
|
|
48
|
+
value: fieldValue,
|
|
49
|
+
error,
|
|
50
|
+
dirty,
|
|
51
|
+
pending,
|
|
52
|
+
...field,
|
|
53
|
+
getValue: () => fieldValue.value
|
|
54
|
+
};
|
|
55
|
+
return { result, dispose };
|
|
56
|
+
}
|
|
57
|
+
const useField = (name) => {
|
|
58
|
+
const form = useFormInstance();
|
|
59
|
+
const key = name;
|
|
60
|
+
let formCache = fieldHookCache.get(form);
|
|
61
|
+
if (!formCache) {
|
|
62
|
+
formCache = /* @__PURE__ */ new Map();
|
|
63
|
+
fieldHookCache.set(form, formCache);
|
|
64
|
+
}
|
|
65
|
+
const cachedEntry = formCache.get(key);
|
|
66
|
+
let activeEntry;
|
|
67
|
+
if (cachedEntry) {
|
|
68
|
+
cachedEntry.refCount++;
|
|
69
|
+
activeEntry = cachedEntry;
|
|
70
|
+
} else {
|
|
71
|
+
const { result, dispose } = createFieldHook(form, name);
|
|
72
|
+
activeEntry = {
|
|
73
|
+
refCount: 1,
|
|
74
|
+
result,
|
|
75
|
+
dispose
|
|
76
|
+
};
|
|
77
|
+
formCache.set(key, activeEntry);
|
|
78
|
+
}
|
|
79
|
+
onUnmounted(() => {
|
|
80
|
+
if (--activeEntry.refCount <= 0) {
|
|
81
|
+
activeEntry.dispose();
|
|
82
|
+
formCache.delete(key);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return activeEntry.result;
|
|
86
|
+
};
|
|
87
|
+
function useWatch(nameOrNamesOrCallback, callbackOrOptions, maybeOptions) {
|
|
88
|
+
const form = useFormInstance();
|
|
89
|
+
const dispose = createWatch(
|
|
90
|
+
form,
|
|
91
|
+
nameOrNamesOrCallback,
|
|
92
|
+
callbackOrOptions,
|
|
93
|
+
maybeOptions
|
|
94
|
+
);
|
|
95
|
+
onUnmounted(dispose);
|
|
96
|
+
return dispose;
|
|
97
|
+
}
|
|
98
|
+
function useWatchField(name, callback, options) {
|
|
99
|
+
return useWatch(name, callback, options);
|
|
100
|
+
}
|
|
101
|
+
function useWatchFields(names, callback, options) {
|
|
102
|
+
return useWatch(names, callback, options);
|
|
103
|
+
}
|
|
104
|
+
function useWatchAll(callback, options) {
|
|
105
|
+
return useWatch(callback, options);
|
|
106
|
+
}
|
|
107
|
+
function useEffect(callback) {
|
|
108
|
+
const dispose = createEffect(callback);
|
|
109
|
+
onUnmounted(dispose);
|
|
110
|
+
return dispose;
|
|
111
|
+
}
|
|
112
|
+
function normalizeError(err) {
|
|
113
|
+
if (err instanceof Error) return err;
|
|
114
|
+
return new Error(String(err));
|
|
115
|
+
}
|
|
116
|
+
const useDictionary = (options, fieldName) => {
|
|
117
|
+
var _a;
|
|
118
|
+
const instance = useFormInstance();
|
|
119
|
+
const list = ref([]);
|
|
120
|
+
const loading = ref(false);
|
|
121
|
+
const error = ref(void 0);
|
|
122
|
+
let requestCount = 0;
|
|
123
|
+
const format = async (res) => {
|
|
124
|
+
if (typeof (options == null ? void 0 : options.formatter) === "function") {
|
|
125
|
+
return await options.formatter(res, instance);
|
|
126
|
+
}
|
|
127
|
+
return res;
|
|
128
|
+
};
|
|
129
|
+
const executeWithRetry = async (formValues) => {
|
|
130
|
+
const maxRetries = options.retryCount ?? 0;
|
|
131
|
+
const retryDelay = options.retryInterval ?? 1e3;
|
|
132
|
+
let lastError = new Error("Unknown error");
|
|
133
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
134
|
+
try {
|
|
135
|
+
return await options.api(formValues, instance);
|
|
136
|
+
} catch (err) {
|
|
137
|
+
lastError = normalizeError(err);
|
|
138
|
+
if (attempt < maxRetries) {
|
|
139
|
+
await new Promise((r) => setTimeout(r, retryDelay));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
throw lastError;
|
|
144
|
+
};
|
|
145
|
+
const loadDict = async () => {
|
|
146
|
+
try {
|
|
147
|
+
const formValues = instance.getFieldsValue();
|
|
148
|
+
if (typeof options.shouldFetch === "function" && !options.shouldFetch(formValues)) {
|
|
149
|
+
list.value = [];
|
|
150
|
+
loading.value = false;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
loading.value = true;
|
|
154
|
+
error.value = void 0;
|
|
155
|
+
const currentCount = ++requestCount;
|
|
156
|
+
const res = await executeWithRetry(formValues);
|
|
157
|
+
if (currentCount !== requestCount) return;
|
|
158
|
+
const formatted = await format(res);
|
|
159
|
+
if (currentCount !== requestCount) return;
|
|
160
|
+
list.value = formatted;
|
|
161
|
+
error.value = void 0;
|
|
162
|
+
if (typeof options.onSuccess === "function") {
|
|
163
|
+
options.onSuccess(formatted, instance);
|
|
164
|
+
}
|
|
165
|
+
loading.value = false;
|
|
166
|
+
} catch (err) {
|
|
167
|
+
const normalized = normalizeError(err);
|
|
168
|
+
error.value = normalized;
|
|
169
|
+
list.value = [];
|
|
170
|
+
loading.value = false;
|
|
171
|
+
if (typeof options.onError === "function") {
|
|
172
|
+
options.onError(normalized, instance);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const refresh = () => loadDict();
|
|
177
|
+
const mutate = (data) => {
|
|
178
|
+
list.value = data;
|
|
179
|
+
};
|
|
180
|
+
if ((_a = options.dependsOn) == null ? void 0 : _a.length) {
|
|
181
|
+
useWatchFields(options.dependsOn, (_payload, latestSnapshot) => {
|
|
182
|
+
if (typeof options.onDepsChange === "function") {
|
|
183
|
+
options.onDepsChange(latestSnapshot, instance);
|
|
184
|
+
}
|
|
185
|
+
if (options.resetOnDepsChange && fieldName) {
|
|
186
|
+
instance.setFieldValue(fieldName, void 0);
|
|
187
|
+
}
|
|
188
|
+
void loadDict();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const immediate = options.immediate ?? true;
|
|
192
|
+
onMounted(() => {
|
|
193
|
+
if (immediate) {
|
|
194
|
+
void loadDict();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return { list, loading, error, loadDict, refresh, mutate };
|
|
198
|
+
};
|
|
199
|
+
const FORM_CONTEXT_KEY = Symbol("FormContext");
|
|
200
|
+
const createContext = (props) => {
|
|
201
|
+
provide(FORM_CONTEXT_KEY, props);
|
|
202
|
+
};
|
|
203
|
+
function useContext() {
|
|
204
|
+
const context = inject(FORM_CONTEXT_KEY);
|
|
205
|
+
if (!context) {
|
|
206
|
+
throw new Error("useContext must be used within a Form");
|
|
207
|
+
}
|
|
208
|
+
return context;
|
|
209
|
+
}
|
|
210
|
+
const isShallowEqual = (a, b) => {
|
|
211
|
+
const keysA = Object.keys(a);
|
|
212
|
+
const keysB = Object.keys(b);
|
|
213
|
+
if (keysA.length !== keysB.length) return false;
|
|
214
|
+
return keysA.every((key) => a[key] === b[key]);
|
|
215
|
+
};
|
|
216
|
+
function useStableRef(factory) {
|
|
217
|
+
const stableRef = shallowRef({});
|
|
218
|
+
watchEffect(() => {
|
|
219
|
+
const next = factory();
|
|
220
|
+
if (!isShallowEqual(stableRef.value, next)) {
|
|
221
|
+
stableRef.value = next;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return stableRef;
|
|
225
|
+
}
|
|
226
|
+
function useViewSchemas(form) {
|
|
227
|
+
const viewSchemas = shallowRef(form.getViewSchemas());
|
|
228
|
+
const unsubscribe = form.subscribeViewSchemas((nextSchemas) => {
|
|
229
|
+
viewSchemas.value = nextSchemas;
|
|
230
|
+
});
|
|
231
|
+
onScopeDispose(unsubscribe);
|
|
232
|
+
return viewSchemas;
|
|
233
|
+
}
|
|
234
|
+
const FIELD_CONTEXT_KEY = Symbol("schemx:field");
|
|
235
|
+
function provideFieldContext(field) {
|
|
236
|
+
provide(FIELD_CONTEXT_KEY, field);
|
|
237
|
+
}
|
|
238
|
+
function useFieldContext() {
|
|
239
|
+
const field = inject(FIELD_CONTEXT_KEY);
|
|
240
|
+
if (!field) {
|
|
241
|
+
throw new Error("[schemx] useFieldContext() must be used inside a FormItem tree");
|
|
242
|
+
}
|
|
243
|
+
return field;
|
|
244
|
+
}
|
|
245
|
+
function isValidTrigger(v) {
|
|
246
|
+
if (v === void 0) return false;
|
|
247
|
+
if (Array.isArray(v) && v.length === 0) return false;
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
function mergeTrigger(columnTrigger, contextTrigger, defaultTrigger) {
|
|
251
|
+
if (isValidTrigger(columnTrigger)) return columnTrigger;
|
|
252
|
+
if (isValidTrigger(contextTrigger)) return contextTrigger;
|
|
253
|
+
return defaultTrigger;
|
|
254
|
+
}
|
|
255
|
+
function normalizeTrigger(t) {
|
|
256
|
+
const map = {
|
|
257
|
+
onBlur: "blur",
|
|
258
|
+
onChange: "change",
|
|
259
|
+
onSubmit: "submit",
|
|
260
|
+
blur: "blur",
|
|
261
|
+
change: "change",
|
|
262
|
+
submit: "submit"
|
|
263
|
+
};
|
|
264
|
+
return map[t] ?? "submit";
|
|
265
|
+
}
|
|
266
|
+
function shouldValidateOn(event, trigger) {
|
|
267
|
+
if (!trigger) return false;
|
|
268
|
+
const triggers = Array.isArray(trigger) ? trigger : [trigger];
|
|
269
|
+
return triggers.some((t) => normalizeTrigger(t) === event);
|
|
270
|
+
}
|
|
271
|
+
const isCamelCase = (str) => /[A-Z]/.test(str);
|
|
272
|
+
const isKebabCase = (str) => str.includes("-");
|
|
273
|
+
const camelToKebab = (str) => {
|
|
274
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
275
|
+
};
|
|
276
|
+
const kebabToCamel = (str) => {
|
|
277
|
+
return str.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
|
|
278
|
+
};
|
|
279
|
+
const normalizeToKebab = (str) => {
|
|
280
|
+
if (isCamelCase(str)) return camelToKebab(str);
|
|
281
|
+
return str;
|
|
282
|
+
};
|
|
283
|
+
const normalizeToCamel = (str) => {
|
|
284
|
+
if (isKebabCase(str)) return kebabToCamel(str);
|
|
285
|
+
return str;
|
|
286
|
+
};
|
|
287
|
+
const resolveSlot = (slots, name) => {
|
|
288
|
+
if (slots[name]) return slots[name];
|
|
289
|
+
const alt = isCamelCase(name) ? camelToKebab(name) : isKebabCase(name) ? kebabToCamel(name) : void 0;
|
|
290
|
+
if (alt && slots[alt]) return slots[alt];
|
|
291
|
+
return void 0;
|
|
292
|
+
};
|
|
293
|
+
const extractChildSlots = (fieldName, allSlots) => {
|
|
294
|
+
const result = {};
|
|
295
|
+
const camelPrefix = normalizeToCamel(String(fieldName)) + ":";
|
|
296
|
+
const kebabPrefix = normalizeToKebab(String(fieldName)) + ":";
|
|
297
|
+
for (const [key, value] of Object.entries(allSlots)) {
|
|
298
|
+
if (key.startsWith(camelPrefix)) {
|
|
299
|
+
result[key.slice(camelPrefix.length)] = value;
|
|
300
|
+
} else if (key.startsWith(kebabPrefix) && kebabPrefix !== camelPrefix) {
|
|
301
|
+
result[key.slice(kebabPrefix.length)] = value;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
};
|
|
306
|
+
const FormGroup = /* @__PURE__ */ defineComponent((props, {
|
|
307
|
+
slots
|
|
308
|
+
}) => {
|
|
309
|
+
const collapsed = ref(Boolean(props.schema.defaultCollapsed));
|
|
310
|
+
const toggle = () => {
|
|
311
|
+
if (props.schema.collapsible) {
|
|
312
|
+
collapsed.value = !collapsed.value;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
return () => {
|
|
316
|
+
const schema = props.schema;
|
|
317
|
+
const collapsible = Boolean(schema.collapsible);
|
|
318
|
+
return createVNode("div", {
|
|
319
|
+
"class": classnames("schemx-group", {
|
|
320
|
+
"schemx-group--collapsed": collapsed.value
|
|
321
|
+
}, schema.class),
|
|
322
|
+
"data-key": schema.key
|
|
323
|
+
}, [schema.label && createVNode("div", {
|
|
324
|
+
"role": collapsible ? "button" : void 0,
|
|
325
|
+
"tabindex": collapsible ? 0 : void 0,
|
|
326
|
+
"class": classnames("schemx-group__header", {
|
|
327
|
+
"schemx-group__header--clickable": collapsible
|
|
328
|
+
}),
|
|
329
|
+
"onClick": toggle,
|
|
330
|
+
"onKeydown": (e) => {
|
|
331
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
332
|
+
e.preventDefault();
|
|
333
|
+
toggle();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}, [createVNode("span", {
|
|
337
|
+
"class": "schemx-group__title"
|
|
338
|
+
}, [schema.label]), collapsible && createVNode("span", {
|
|
339
|
+
"class": classnames("schemx-group__arrow", {
|
|
340
|
+
"schemx-group__arrow--down": !collapsed.value
|
|
341
|
+
})
|
|
342
|
+
}, null)]), !collapsed.value && createVNode("div", {
|
|
343
|
+
"class": "schemx-group__body"
|
|
344
|
+
}, [schema.children.map((child) => createVNode(FormItem, {
|
|
345
|
+
"key": child.key,
|
|
346
|
+
"schema": child
|
|
347
|
+
}, slots))])]);
|
|
348
|
+
};
|
|
349
|
+
}, {
|
|
350
|
+
name: "SchemxGroup",
|
|
351
|
+
props: {
|
|
352
|
+
schema: {
|
|
353
|
+
type: Object,
|
|
354
|
+
required: true
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
const FormItem = /* @__PURE__ */ defineComponent((props, {
|
|
359
|
+
slots
|
|
360
|
+
}) => {
|
|
361
|
+
const schemaRef = toRef(props, "schema");
|
|
362
|
+
if (isViewGroupSchema(schemaRef.value)) {
|
|
363
|
+
return () => {
|
|
364
|
+
return h(FormGroup, {
|
|
365
|
+
schema: schemaRef.value
|
|
366
|
+
}, slots);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const form = useFormInstance();
|
|
370
|
+
const formContext = useContext();
|
|
371
|
+
const schema = () => schemaRef.value;
|
|
372
|
+
const field = useField(schema().name);
|
|
373
|
+
provideFieldContext(field);
|
|
374
|
+
const trigger = computed(() => mergeTrigger(schema().validationTrigger, formContext.validationTrigger, "onChange"));
|
|
375
|
+
const canVerified = computed(() => {
|
|
376
|
+
const isOperate = schema().visible && !schema().readonly && !schema().disabled;
|
|
377
|
+
const rules = schema().rules;
|
|
378
|
+
const hasRules = Array.isArray(rules) ? (rules == null ? void 0 : rules.length) > 0 : !!schema().rules;
|
|
379
|
+
return isOperate && hasRules;
|
|
380
|
+
});
|
|
381
|
+
const handleChange = (v) => {
|
|
382
|
+
var _a, _b;
|
|
383
|
+
field.setValue(v);
|
|
384
|
+
(_b = (_a = schema().componentProps) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a, v);
|
|
385
|
+
if (canVerified.value && shouldValidateOn("change", trigger.value)) {
|
|
386
|
+
field.validate();
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
const handleBlur = () => {
|
|
390
|
+
if (canVerified.value && shouldValidateOn("blur", trigger.value)) {
|
|
391
|
+
field.validate();
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
const formItemProps = computed(() => {
|
|
395
|
+
return {
|
|
396
|
+
...omit(schema(), ["componentProps"]),
|
|
397
|
+
name: schema().name,
|
|
398
|
+
componentType: schema().componentType,
|
|
399
|
+
class: classnames("schemx-item", schema().class),
|
|
400
|
+
required: schema().required,
|
|
401
|
+
readonly: schema().readonly,
|
|
402
|
+
disabled: schema().disabled,
|
|
403
|
+
visible: schema().visible,
|
|
404
|
+
placeholder: schema().placeholder,
|
|
405
|
+
validationTrigger: trigger.value
|
|
406
|
+
};
|
|
407
|
+
});
|
|
408
|
+
const componentProps = useStableRef(() => ({
|
|
409
|
+
...schema().componentProps,
|
|
410
|
+
formItemProps: formItemProps.value,
|
|
411
|
+
value: field.getValue(),
|
|
412
|
+
readonly: schema().readonly,
|
|
413
|
+
disabled: schema().disabled,
|
|
414
|
+
placeholder: schema().placeholder,
|
|
415
|
+
onChange: handleChange,
|
|
416
|
+
onBlur: handleBlur,
|
|
417
|
+
"onUpdate:value": (v) => field.setValue(v)
|
|
418
|
+
}));
|
|
419
|
+
const renderRequired = () => {
|
|
420
|
+
if (!schema().required || schema().disabled || schema().readonly) {
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
return createVNode("span", {
|
|
424
|
+
"class": "schemx-item__required"
|
|
425
|
+
}, [createTextVNode("*")]);
|
|
426
|
+
};
|
|
427
|
+
const renderLabel = () => {
|
|
428
|
+
const labelSlot = resolveSlot(slots, `${schema().name}Label`);
|
|
429
|
+
if (labelSlot) {
|
|
430
|
+
return labelSlot(formItemProps.value);
|
|
431
|
+
}
|
|
432
|
+
const labelAlign = schema().labelAlign || formContext.labelAlign;
|
|
433
|
+
const labelWidth = schema().labelWidth || formContext.labelWidth;
|
|
434
|
+
const colon = schema().colon ?? formContext.colon;
|
|
435
|
+
return createVNode("label", {
|
|
436
|
+
"class": "schemx-item__label",
|
|
437
|
+
"style": {
|
|
438
|
+
width: labelWidth,
|
|
439
|
+
textAlign: labelAlign
|
|
440
|
+
}
|
|
441
|
+
}, [renderRequired(), createVNode("span", {
|
|
442
|
+
"class": "schemx-item__label-text"
|
|
443
|
+
}, [schema().label, colon ? ":" : ""])]);
|
|
444
|
+
};
|
|
445
|
+
const renderContent = () => {
|
|
446
|
+
const component = form.getRenderer(schema().componentType);
|
|
447
|
+
if (!component) {
|
|
448
|
+
throw new Error(`[schemx] Can not find component renderer of "${schema().componentType}".`);
|
|
449
|
+
}
|
|
450
|
+
const childSlots = extractChildSlots(normalizeNameKey(schema().name), slots);
|
|
451
|
+
const columnElement = h(component, componentProps.value, childSlots);
|
|
452
|
+
const contentSlot = resolveSlot(slots, `${schema().name}Content`);
|
|
453
|
+
if (contentSlot) {
|
|
454
|
+
return contentSlot({
|
|
455
|
+
...formItemProps.value,
|
|
456
|
+
columnElement
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
return createVNode("div", {
|
|
460
|
+
"class": "schemx-item__control"
|
|
461
|
+
}, [columnElement]);
|
|
462
|
+
};
|
|
463
|
+
const renderError = () => {
|
|
464
|
+
const errorSlot = resolveSlot(slots, `${schema().name}Error`);
|
|
465
|
+
if (errorSlot) {
|
|
466
|
+
return errorSlot({
|
|
467
|
+
...formItemProps.value,
|
|
468
|
+
errors: field.error.value
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
if (!Array.isArray(field.error.value) || field.error.value.length === 0) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
return createVNode("div", {
|
|
475
|
+
"class": "schemx-item__error"
|
|
476
|
+
}, [field.error.value[0]]);
|
|
477
|
+
};
|
|
478
|
+
return () => {
|
|
479
|
+
if (!schema().visible) {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
const itemSlot = resolveSlot(slots, normalizeNameKey(schema().name));
|
|
483
|
+
if (itemSlot) {
|
|
484
|
+
return itemSlot(formItemProps.value);
|
|
485
|
+
}
|
|
486
|
+
const labelPosition = schema().labelPosition || formContext.labelPosition;
|
|
487
|
+
return createVNode("div", {
|
|
488
|
+
"class": classnames("schemx-item-wrapper", {
|
|
489
|
+
"is-readonly": schema().readonly,
|
|
490
|
+
"is-disabled": schema().disabled
|
|
491
|
+
})
|
|
492
|
+
}, [createVNode("div", {
|
|
493
|
+
"class": classnames("schemx-item", `schemx-item--label-${labelPosition}`, schema().class),
|
|
494
|
+
"style": {
|
|
495
|
+
...schema().style ?? {}
|
|
496
|
+
}
|
|
497
|
+
}, [renderLabel(), createVNode("div", {
|
|
498
|
+
"class": "schemx-item__content"
|
|
499
|
+
}, [renderContent(), renderError()])])]);
|
|
500
|
+
};
|
|
501
|
+
}, {
|
|
502
|
+
name: "SchemxItem",
|
|
503
|
+
props: {
|
|
504
|
+
schema: {
|
|
505
|
+
type: Object,
|
|
506
|
+
required: true
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
const isViewGroupSchema = (schema) => {
|
|
511
|
+
return schema.componentType === "group";
|
|
512
|
+
};
|
|
513
|
+
const normalizeNameKey = (name) => {
|
|
514
|
+
if (Array.isArray(name)) {
|
|
515
|
+
return name.map((part) => String(part)).join(".");
|
|
516
|
+
}
|
|
517
|
+
return String(name);
|
|
518
|
+
};
|
|
519
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
520
|
+
...{ name: "SchemxForm" },
|
|
521
|
+
__name: "form",
|
|
522
|
+
props: {
|
|
523
|
+
class: { default: "" },
|
|
524
|
+
style: { default: () => ({}) },
|
|
525
|
+
required: { type: Boolean },
|
|
526
|
+
readonly: { type: Boolean },
|
|
527
|
+
disabled: { type: Boolean },
|
|
528
|
+
visible: { type: Boolean },
|
|
529
|
+
labelIcon: {},
|
|
530
|
+
labelAlign: {},
|
|
531
|
+
labelPosition: {},
|
|
532
|
+
labelWidth: {},
|
|
533
|
+
contentAlign: {},
|
|
534
|
+
validationTrigger: {},
|
|
535
|
+
colon: { type: Boolean },
|
|
536
|
+
modelValue: { default: () => ({}) },
|
|
537
|
+
initialValues: { default: () => ({}) },
|
|
538
|
+
schemas: { default: () => [] },
|
|
539
|
+
form: { default: void 0 },
|
|
540
|
+
rendererRegistry: { default: void 0 },
|
|
541
|
+
defaultRendererType: {},
|
|
542
|
+
validatorRegistry: { default: void 0 },
|
|
543
|
+
onFinish: { type: Function, default: void 0 },
|
|
544
|
+
onFinishFailed: { type: Function, default: void 0 },
|
|
545
|
+
onValuesChange: { type: Function, default: void 0 },
|
|
546
|
+
onFieldsChange: { type: Function, default: void 0 }
|
|
547
|
+
},
|
|
548
|
+
emits: ["update:modelValue"],
|
|
549
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
550
|
+
const props = __props;
|
|
551
|
+
const emit = __emit;
|
|
552
|
+
createContext(
|
|
553
|
+
omit(props, [
|
|
554
|
+
"form",
|
|
555
|
+
"modelValue",
|
|
556
|
+
"rendererRegistry",
|
|
557
|
+
"defaultRendererType",
|
|
558
|
+
"validatorRegistry",
|
|
559
|
+
"onFinish",
|
|
560
|
+
"onFinishFailed",
|
|
561
|
+
"onValuesChange",
|
|
562
|
+
"onFieldsChange"
|
|
563
|
+
])
|
|
564
|
+
);
|
|
565
|
+
const form = props.form ? props.form : useForm({
|
|
566
|
+
schemas: props.schemas,
|
|
567
|
+
initialValues: props.initialValues,
|
|
568
|
+
rendererRegistry: props.rendererRegistry,
|
|
569
|
+
defaultRendererType: props.defaultRendererType,
|
|
570
|
+
validatorRegistry: props.validatorRegistry,
|
|
571
|
+
readonly: props.readonly,
|
|
572
|
+
disabled: props.disabled,
|
|
573
|
+
onFinish: async (values) => {
|
|
574
|
+
var _a;
|
|
575
|
+
(_a = props.onFinish) == null ? void 0 : _a.call(props, values);
|
|
576
|
+
},
|
|
577
|
+
onFinishFailed: async (errors) => {
|
|
578
|
+
var _a;
|
|
579
|
+
(_a = props.onFinishFailed) == null ? void 0 : _a.call(props, errors);
|
|
580
|
+
},
|
|
581
|
+
onValuesChange: (changedValues, latestSnapshot) => {
|
|
582
|
+
var _a;
|
|
583
|
+
emit("update:modelValue", latestSnapshot);
|
|
584
|
+
(_a = props.onValuesChange) == null ? void 0 : _a.call(props, changedValues, latestSnapshot);
|
|
585
|
+
},
|
|
586
|
+
onFieldsChange: (changedPaths, allPaths) => {
|
|
587
|
+
var _a;
|
|
588
|
+
(_a = props.onFieldsChange) == null ? void 0 : _a.call(props, changedPaths, allPaths);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
watch(
|
|
592
|
+
() => props.schemas,
|
|
593
|
+
(schemas) => {
|
|
594
|
+
form.setSchemas(schemas);
|
|
595
|
+
},
|
|
596
|
+
{ deep: false, immediate: !!props.form }
|
|
597
|
+
);
|
|
598
|
+
const viewSchemas = useViewSchemas(form);
|
|
599
|
+
watchEffect(() => {
|
|
600
|
+
form.updateDefaultProps(props);
|
|
601
|
+
});
|
|
602
|
+
__expose({
|
|
603
|
+
...form
|
|
604
|
+
});
|
|
605
|
+
return (_ctx, _cache) => {
|
|
606
|
+
return openBlock(), createElementBlock("div", {
|
|
607
|
+
class: normalizeClass(["schemx", props.class])
|
|
608
|
+
}, [
|
|
609
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(viewSchemas), (schema) => {
|
|
610
|
+
return openBlock(), createBlock(unref(FormItem), {
|
|
611
|
+
key: schema.key,
|
|
612
|
+
schema
|
|
613
|
+
}, createSlots({ _: 2 }, [
|
|
614
|
+
renderList(_ctx.$slots, (_, slotName) => {
|
|
615
|
+
return {
|
|
616
|
+
name: slotName,
|
|
617
|
+
fn: withCtx((slotProps) => [
|
|
618
|
+
renderSlot(_ctx.$slots, slotName, mergeProps({ ref_for: true }, slotProps ?? {}))
|
|
619
|
+
])
|
|
620
|
+
};
|
|
621
|
+
})
|
|
622
|
+
]), 1032, ["schema"]);
|
|
623
|
+
}), 128))
|
|
624
|
+
], 2);
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
function withInstall(comp, extra) {
|
|
629
|
+
return Object.assign(comp, extra);
|
|
630
|
+
}
|
|
631
|
+
const SchemxFormExport = withInstall(_sfc_main, {
|
|
632
|
+
/** Vue 插件安装方法 */
|
|
633
|
+
install(app, _options) {
|
|
634
|
+
app.component("SchemxForm", _sfc_main);
|
|
635
|
+
},
|
|
636
|
+
/** FormItem 子组件引用 */
|
|
637
|
+
FormItem
|
|
638
|
+
});
|
|
639
|
+
function WithRemoteOptions(WrappedComponent) {
|
|
640
|
+
return defineComponent({
|
|
641
|
+
name: `WithRemoteOptions(${WrappedComponent.name || "Anonymous"})`,
|
|
642
|
+
inheritAttrs: false,
|
|
643
|
+
props: {
|
|
644
|
+
dict: {
|
|
645
|
+
type: Object,
|
|
646
|
+
default: void 0
|
|
647
|
+
},
|
|
648
|
+
fieldName: {
|
|
649
|
+
type: [String, Array],
|
|
650
|
+
default: void 0
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
setup(props, { attrs, slots }) {
|
|
654
|
+
const dictResult = props.dict ? useDictionary(props.dict, props.fieldName) : null;
|
|
655
|
+
const childrenProps = computed(() => {
|
|
656
|
+
return {
|
|
657
|
+
...attrs,
|
|
658
|
+
dict: props.dict,
|
|
659
|
+
options: props.dict ? dictResult == null ? void 0 : dictResult.list.value : attrs.options,
|
|
660
|
+
loading: props.dict ? dictResult == null ? void 0 : dictResult.loading.value : attrs.loading
|
|
661
|
+
};
|
|
662
|
+
});
|
|
663
|
+
return () => h(WrappedComponent, childrenProps.value, slots);
|
|
664
|
+
}
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
export {
|
|
668
|
+
FormGroup,
|
|
669
|
+
FormItem,
|
|
670
|
+
WithRemoteOptions,
|
|
671
|
+
SchemxFormExport as default,
|
|
672
|
+
rendererRegistry,
|
|
673
|
+
SchemxFormExport as schemxForm,
|
|
674
|
+
useContext,
|
|
675
|
+
useDictionary,
|
|
676
|
+
useEffect,
|
|
677
|
+
useField,
|
|
678
|
+
useFieldContext,
|
|
679
|
+
useForm,
|
|
680
|
+
useWatch,
|
|
681
|
+
useWatchAll,
|
|
682
|
+
useWatchField,
|
|
683
|
+
useWatchFields,
|
|
684
|
+
validatorRegistry
|
|
685
|
+
};
|
|
686
|
+
//# sourceMappingURL=index.mjs.map
|