@schemx/vue 1.0.0-next.2 → 1.0.0-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +292 -293
  2. package/dist/analyze.html +1 -1
  3. package/dist/bridge/fieldBridge.d.ts +10 -0
  4. package/dist/bridge/fieldBridge.d.ts.map +1 -0
  5. package/dist/bridge/formBridge.d.ts +13 -0
  6. package/dist/bridge/formBridge.d.ts.map +1 -0
  7. package/dist/bridge/formInstance.d.ts +18 -0
  8. package/dist/bridge/formInstance.d.ts.map +1 -0
  9. package/dist/bridge/helpers.d.ts +39 -0
  10. package/dist/bridge/helpers.d.ts.map +1 -0
  11. package/dist/bridge/index.d.ts +13 -0
  12. package/dist/bridge/index.d.ts.map +1 -0
  13. package/dist/bridge/types.d.ts +69 -0
  14. package/dist/bridge/types.d.ts.map +1 -0
  15. package/dist/bridge/viewSchemaBridge.d.ts +5 -0
  16. package/dist/bridge/viewSchemaBridge.d.ts.map +1 -0
  17. package/dist/components/Button/index.vue.d.ts +30 -0
  18. package/dist/components/Button/index.vue.d.ts.map +1 -0
  19. package/dist/components/Button/types.d.ts.map +1 -1
  20. package/dist/components/ConfigProvider/index.d.ts +68 -0
  21. package/dist/components/ConfigProvider/index.d.ts.map +1 -0
  22. package/dist/components/Dynamic/index.d.ts +30 -0
  23. package/dist/components/Dynamic/index.d.ts.map +1 -0
  24. package/dist/components/Field/index.d.ts +47 -0
  25. package/dist/components/Field/index.d.ts.map +1 -0
  26. package/dist/components/Field/slot.d.ts +40 -0
  27. package/dist/components/Field/slot.d.ts.map +1 -0
  28. package/dist/components/Group/index.d.ts +46 -0
  29. package/dist/components/Group/index.d.ts.map +1 -0
  30. package/dist/components/Group/slot.d.ts +34 -0
  31. package/dist/components/Group/slot.d.ts.map +1 -0
  32. package/dist/config/index.d.ts +2 -0
  33. package/dist/config/index.d.ts.map +1 -1
  34. package/dist/config/providerConfig.d.ts +15 -0
  35. package/dist/config/providerConfig.d.ts.map +1 -0
  36. package/dist/config/vueConfig.d.ts +12 -0
  37. package/dist/config/vueConfig.d.ts.map +1 -0
  38. package/dist/form.d.ts +2 -2
  39. package/dist/form.d.ts.map +1 -1
  40. package/dist/hocs/withRemoteOptions.d.ts.map +1 -1
  41. package/dist/hooks/index.d.ts +3 -3
  42. package/dist/hooks/index.d.ts.map +1 -1
  43. package/dist/hooks/provideFieldContext.d.ts +2 -2
  44. package/dist/hooks/provideFormContext.d.ts +13 -46
  45. package/dist/hooks/provideFormContext.d.ts.map +1 -1
  46. package/dist/hooks/useDictionary.d.ts.map +1 -1
  47. package/dist/hooks/useField.d.ts +1 -1
  48. package/dist/hooks/useField.d.ts.map +1 -1
  49. package/dist/hooks/useForm.d.ts +3 -3
  50. package/dist/hooks/useForm.d.ts.map +1 -1
  51. package/dist/hooks/useFormSelector.d.ts +4 -0
  52. package/dist/hooks/useFormSelector.d.ts.map +1 -1
  53. package/dist/hooks/useViewSchemas.d.ts +2 -34
  54. package/dist/hooks/useViewSchemas.d.ts.map +1 -1
  55. package/dist/hooks/useWatch.d.ts.map +1 -1
  56. package/dist/index.cjs +1 -1
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.d.ts +5 -6
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.mjs +923 -557
  61. package/dist/index.mjs.map +1 -1
  62. package/dist/style.css +1 -1
  63. package/dist/types/dictionary.d.ts +1 -1
  64. package/dist/types/dictionary.d.ts.map +1 -1
  65. package/dist/types/field.d.ts +38 -2
  66. package/dist/types/field.d.ts.map +1 -1
  67. package/dist/types/form.d.ts +11 -7
  68. package/dist/types/form.d.ts.map +1 -1
  69. package/dist/types/index.d.ts +4 -4
  70. package/dist/types/index.d.ts.map +1 -1
  71. package/dist/utils/helpers.d.ts +4 -0
  72. package/dist/utils/helpers.d.ts.map +1 -1
  73. package/dist/utils/index.d.ts +2 -0
  74. package/dist/utils/index.d.ts.map +1 -1
  75. package/dist/utils/presetRuleProvider.d.ts +16 -0
  76. package/dist/utils/presetRuleProvider.d.ts.map +1 -0
  77. package/dist/utils/rendererProvider.d.ts.map +1 -1
  78. package/package.json +3 -3
  79. package/dist/components/FormGroup/index.d.ts +0 -16
  80. package/dist/components/FormGroup/index.d.ts.map +0 -1
  81. package/dist/components/FormItem/index.d.ts +0 -22
  82. package/dist/components/FormItem/index.d.ts.map +0 -1
  83. package/dist/components/FormItem/slot.d.ts +0 -48
  84. package/dist/components/FormItem/slot.d.ts.map +0 -1
  85. package/dist/formBridge.d.ts +0 -188
  86. package/dist/formBridge.d.ts.map +0 -1
  87. package/dist/utils/rulesProvider.d.ts +0 -16
  88. package/dist/utils/rulesProvider.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,110 +1,38 @@
1
1
  import "./style.css";
2
- import { getCurrentInstance, inject, shallowRef, onScopeDispose, provide, computed, onUnmounted, ref, onMounted, watchEffect, watch, readonly, defineComponent, createVNode, h, createTextVNode, mergeProps, useAttrs, openBlock, createElementBlock, unref, renderSlot, createCommentVNode, createStaticVNode, Fragment, toDisplayString, useSlots, reactive, normalizeClass, normalizeStyle, renderList, createBlock, createSlots, withCtx } from "vue";
3
- import { createValidationRuleRegistry, mergeSchemxConfig, createForm, createField, createWatch, isViewGroupSchema, isSchemxViewFieldSchema, isSchemxSchemas, defaultSchemxConfigKeys } from "@schemx/core";
2
+ import { shallowRef, computed, getCurrentInstance, inject, provide, onScopeDispose, onUnmounted, ref, onMounted, watchEffect, watch, readonly, createVNode, h, createTextVNode, defineComponent, mergeProps, useAttrs, openBlock, createElementBlock, unref, renderSlot, createCommentVNode, createStaticVNode, Fragment, toDisplayString, useSlots, reactive, toRaw, normalizeClass, normalizeStyle, renderList, createBlock, createSlots, withCtx, nextTick } from "vue";
3
+ import { isViewGroupSchema, isViewDynamicSchema, mergeSchemxConfig, createPresetRuleRegistry, createForm, createField, createWatch, isSchemxViewFieldSchema, isSchemxSchemas, defaultSchemxConfigKeys } from "@schemx/core";
4
4
  export * from "@schemx/core";
5
5
  import classnames from "classnames";
6
- import { createFormExternalStore, createRendererRegistry } from "@schemx/core/adapter";
6
+ import { createFormStateAdapter, createRendererRegistry } from "@schemx/core/adapter";
7
7
  import { pick } from "es-toolkit";
8
- const SCHEMX_APP_CONFIG_KEY = Symbol("schemx:app-config");
9
- const EMPTY_SCHEMX_CONFIG = Object.freeze({
10
- schemaConfig: Object.freeze({}),
11
- validatorAdapters: Object.freeze([])
12
- });
13
- function normalizeSchemxAppConfig(config) {
14
- const schemaConfig = Object.freeze({ ...config.schemaConfig ?? {} });
15
- const validatorAdapters = Object.freeze([...config.validatorAdapters ?? []]);
16
- return Object.freeze({
17
- schemaConfig,
18
- rendererProps: normalizeRendererProps(config.rendererProps),
19
- validatorAdapters,
20
- defaultRendererType: config.defaultRendererType,
21
- rendererRegistry: config.rendererRegistry,
22
- validationRuleRegistry: config.validationRuleRegistry
23
- });
24
- }
25
- function normalizeRendererProps(source) {
26
- if (source === void 0) {
27
- return void 0;
28
- }
29
- const entries = Object.entries(source).map(([type, props]) => {
30
- return [type, props === void 0 ? void 0 : Object.freeze({ ...props })];
31
- });
32
- return Object.freeze(Object.fromEntries(entries));
33
- }
34
- function provideSchemxAppConfig(app, config = {}) {
35
- const normalizedConfig = normalizeSchemxAppConfig(config);
36
- app.provide(SCHEMX_APP_CONFIG_KEY, normalizedConfig);
37
- }
38
- function getSchemxAppConfig() {
39
- if (getCurrentInstance() === null) {
40
- return EMPTY_SCHEMX_CONFIG;
41
- }
42
- return inject(SCHEMX_APP_CONFIG_KEY, EMPTY_SCHEMX_CONFIG);
43
- }
44
- const formBridgeCache = /* @__PURE__ */ new WeakMap();
45
- const formFacadeCache = /* @__PURE__ */ new WeakMap();
46
- const facadeCoreFormCache = /* @__PURE__ */ new WeakMap();
47
8
  function createVueShallowRef(value) {
48
9
  return shallowRef(value);
49
10
  }
50
- function getCoreForm(form) {
51
- const coreForm = facadeCoreFormCache.get(form);
52
- return coreForm ?? form;
53
- }
54
- function getVueFormBridge(form) {
55
- const coreForm = getCoreForm(form);
56
- const cachedBridge = formBridgeCache.get(coreForm);
57
- if (cachedBridge) {
58
- return cachedBridge;
59
- }
60
- const bridge = createVueFormBridge(coreForm);
61
- formBridgeCache.set(coreForm, bridge);
62
- return bridge;
63
- }
64
- function getVueFormFacade(form) {
65
- const coreForm = getCoreForm(form);
66
- const cachedFacade = formFacadeCache.get(coreForm);
67
- if (cachedFacade) {
68
- return cachedFacade;
69
- }
70
- const facade = createVueFormFacade(coreForm);
71
- formFacadeCache.set(coreForm, facade);
72
- facadeCoreFormCache.set(facade, coreForm);
73
- return facade;
11
+ function bindSnapshotSource(source) {
12
+ const value = createVueShallowRef(source.getSnapshot());
13
+ source.subscribe(() => {
14
+ value.value = source.getSnapshot();
15
+ });
16
+ return value;
74
17
  }
75
- function retainVueFormBridge(bridge) {
76
- if (bridge.destroyed) {
77
- return () => {
78
- };
79
- }
80
- bridge.refCount++;
81
- let released = false;
82
- return () => {
83
- if (released || bridge.destroyed) {
84
- return;
85
- }
86
- released = true;
87
- bridge.refCount--;
88
- if (bridge.refCount === 0) {
89
- disposeVueFormBridge(bridge);
90
- }
91
- };
18
+ function areStringListsEqual(previous, next) {
19
+ return previous.length === next.length && previous.every((value, index) => value === next[index]);
92
20
  }
93
- function getVueFieldBridge(bridge, name) {
94
- const store = bridge.externalStore.field(name);
95
- const cachedBridge = bridge.fieldBridges.get(store);
96
- if (cachedBridge) {
97
- return cachedBridge;
21
+ function getVueFieldState(resources, name) {
22
+ const source = resources.stateAdapter.field(name);
23
+ const cachedState = resources.fieldStates.get(source);
24
+ if (cachedState) {
25
+ return cachedState;
98
26
  }
99
- const snapshot = store.getSnapshot();
27
+ const snapshot = source.getSnapshot();
100
28
  const value = createVueShallowRef(
101
29
  snapshot.value
102
30
  );
103
31
  const errors = createVueShallowRef(snapshot.errors);
104
32
  const touched = createVueShallowRef(snapshot.touched);
105
33
  const pending = createVueShallowRef(snapshot.pending);
106
- const updateFieldRefs = () => {
107
- const nextSnapshot = store.getSnapshot();
34
+ const updateFieldState = () => {
35
+ const nextSnapshot = source.getSnapshot();
108
36
  if (!Object.is(value.value, nextSnapshot.value)) {
109
37
  value.value = nextSnapshot.value;
110
38
  }
@@ -118,145 +46,63 @@ function getVueFieldBridge(bridge, name) {
118
46
  pending.value = nextSnapshot.pending;
119
47
  }
120
48
  };
121
- const unsubscribe = store.subscribe(updateFieldRefs);
122
- const dispose = () => {
123
- unsubscribe();
124
- };
125
- const fieldBridge = {
126
- store,
49
+ source.subscribe(updateFieldState);
50
+ const fieldState = {
127
51
  value,
128
52
  errors,
129
53
  touched,
130
- pending,
131
- dispose
132
- };
133
- bridge.fieldBridges.set(store, fieldBridge);
134
- return fieldBridge;
135
- }
136
- function disposeVueFormBridge(bridge) {
137
- if (bridge.destroyed) {
138
- return;
139
- }
140
- bridge.destroyed = true;
141
- bridge.refCount = 0;
142
- bridge.unsubscribe();
143
- for (const fieldBridge of bridge.fieldBridges.values()) {
144
- fieldBridge.dispose();
145
- }
146
- bridge.fieldBridges.clear();
147
- bridge.externalStore.dispose();
148
- formBridgeCache.delete(bridge.form);
149
- }
150
- function createVueFormBridge(form) {
151
- const externalStore = createFormExternalStore(form);
152
- const values = createVueShallowRef(externalStore.values.getSnapshot());
153
- const touchedFields = createVueShallowRef(
154
- externalStore.touchedFields.getSnapshot()
155
- );
156
- const pendingFields = createVueShallowRef(
157
- externalStore.pendingFields.getSnapshot()
158
- );
159
- const loading = createVueShallowRef(externalStore.loading.getSnapshot());
160
- const fieldBridges = /* @__PURE__ */ new Map();
161
- const syncValues = () => {
162
- values.value = externalStore.values.getSnapshot();
163
- };
164
- const syncTouchedFields = () => {
165
- touchedFields.value = externalStore.touchedFields.getSnapshot();
166
- };
167
- const syncPendingFields = () => {
168
- pendingFields.value = externalStore.pendingFields.getSnapshot();
169
- };
170
- const syncLoading = () => {
171
- loading.value = externalStore.loading.getSnapshot();
172
- };
173
- const unsubscribeValues = externalStore.values.subscribe(syncValues);
174
- const unsubscribeTouchedFields = externalStore.touchedFields.subscribe(syncTouchedFields);
175
- const unsubscribePendingFields = externalStore.pendingFields.subscribe(syncPendingFields);
176
- const unsubscribeLoading = externalStore.loading.subscribe(syncLoading);
177
- const unsubscribe = () => {
178
- unsubscribeValues();
179
- unsubscribeTouchedFields();
180
- unsubscribePendingFields();
181
- unsubscribeLoading();
182
- };
183
- const facade = getVueFormFacade(form);
184
- const bridge = {
185
- form,
186
- externalStore,
187
- values,
188
- touchedFields,
189
- pendingFields,
190
- loading,
191
- fieldBridges,
192
- refCount: 0,
193
- destroyed: false,
194
- unsubscribe,
195
- facade
54
+ pending
196
55
  };
197
- return bridge;
56
+ resources.fieldStates.set(source, fieldState);
57
+ return fieldState;
198
58
  }
199
- function createVueFormFacade(form) {
59
+ function createVueFormInstance(form, dependencies) {
200
60
  let destroyed = false;
201
61
  const getFieldValue = (name) => {
202
62
  if (!destroyed) {
203
- const bridge = getVueFormBridge(form);
204
- void getVueFieldBridge(bridge, name).value.value;
63
+ dependencies.trackField(name, "value");
205
64
  }
206
65
  return form.getFieldValue(name);
207
66
  };
208
67
  const getFieldErrors = (name) => {
209
68
  if (!destroyed) {
210
- const bridge = getVueFormBridge(form);
211
- void getVueFieldBridge(bridge, name).errors.value;
69
+ dependencies.trackField(name, "errors");
212
70
  }
213
71
  return form.getFieldErrors(name);
214
72
  };
215
73
  const isFieldTouched = (name) => {
216
74
  if (!destroyed) {
217
- const bridge = getVueFormBridge(form);
218
- void getVueFieldBridge(bridge, name).touched.value;
75
+ dependencies.trackField(name, "touched");
219
76
  }
220
77
  return form.isFieldTouched(name);
221
78
  };
222
79
  const isFieldPending = (name) => {
223
80
  if (!destroyed) {
224
- const bridge = getVueFormBridge(form);
225
- void getVueFieldBridge(bridge, name).pending.value;
81
+ dependencies.trackField(name, "pending");
226
82
  }
227
83
  return form.isFieldPending(name);
228
84
  };
229
85
  const getFieldsValue = (names) => {
230
86
  if (!destroyed) {
231
- const bridge = getVueFormBridge(form);
232
- if (names === void 0) {
233
- void bridge.values.value;
234
- } else {
235
- for (const name of names) {
236
- void getVueFieldBridge(bridge, name).value.value;
237
- }
238
- }
87
+ dependencies.trackFieldsValue(names);
239
88
  }
240
89
  return form.getFieldsValue(names);
241
90
  };
242
91
  const getTouchedFields = () => {
243
92
  if (!destroyed) {
244
- const bridge = getVueFormBridge(form);
245
- void bridge.touchedFields.value;
93
+ dependencies.trackForm("touchedFields");
246
94
  }
247
95
  return form.getTouchedFields();
248
96
  };
249
97
  const getPendingFields = () => {
250
98
  if (!destroyed) {
251
- const bridge = getVueFormBridge(form);
252
- void bridge.pendingFields.value;
99
+ dependencies.trackForm("pendingFields");
253
100
  }
254
101
  return form.getPendingFields();
255
102
  };
256
103
  const isLoading = () => {
257
104
  if (!destroyed) {
258
- const bridge = getVueFormBridge(form);
259
- void bridge.loading.value;
105
+ dependencies.trackForm("loading");
260
106
  }
261
107
  return form.isLoading();
262
108
  };
@@ -265,10 +111,7 @@ function createVueFormFacade(form) {
265
111
  return;
266
112
  }
267
113
  destroyed = true;
268
- const bridge = formBridgeCache.get(form);
269
- if (bridge) {
270
- disposeVueFormBridge(bridge);
271
- }
114
+ dependencies.destroy();
272
115
  form.destroy();
273
116
  };
274
117
  return {
@@ -284,30 +127,293 @@ function createVueFormFacade(form) {
284
127
  destroy
285
128
  };
286
129
  }
287
- function areStringListsEqual(previous, next) {
288
- return previous.length === next.length && previous.every((value, index) => value === next[index]);
130
+ function createVueViewSchemaState(form) {
131
+ const viewSchemas = shallowRef(
132
+ form.getViewSchemas()
133
+ );
134
+ const schemasByKey = computed(() => {
135
+ return createViewSchemaIndex(viewSchemas.value);
136
+ });
137
+ const unsubscribe = form.subscribeViewSchemas((nextSchemas) => {
138
+ viewSchemas.value = nextSchemas;
139
+ });
140
+ let disposed = false;
141
+ const dispose = () => {
142
+ if (disposed) {
143
+ return;
144
+ }
145
+ disposed = true;
146
+ unsubscribe();
147
+ };
148
+ return {
149
+ schemasByKey,
150
+ viewSchemas,
151
+ dispose
152
+ };
153
+ }
154
+ function createViewSchemaIndex(viewSchemas) {
155
+ const schemasByKey = /* @__PURE__ */ new Map();
156
+ const appendSchemas = (schemas) => {
157
+ for (const schema of schemas) {
158
+ schemasByKey.set(schema.key, schema);
159
+ if (isViewGroupSchema(schema)) {
160
+ appendSchemas(schema.children);
161
+ } else if (isViewDynamicSchema(schema)) {
162
+ for (const item of schema.items) {
163
+ appendSchemas(item.children);
164
+ }
165
+ }
166
+ }
167
+ };
168
+ appendSchemas(viewSchemas);
169
+ return schemasByKey;
289
170
  }
171
+ const runtimeCache = /* @__PURE__ */ new WeakMap();
172
+ const instanceRuntimeCache = /* @__PURE__ */ new WeakMap();
173
+ function acquireVueFormRuntime(form) {
174
+ const runtime = getOrCreateVueFormRuntime(form);
175
+ const release = runtime.retain();
176
+ return {
177
+ runtime,
178
+ release
179
+ };
180
+ }
181
+ function getOrCreateVueFormRuntime(form) {
182
+ const cachedByInstance = instanceRuntimeCache.get(form);
183
+ if (cachedByInstance) {
184
+ return cachedByInstance;
185
+ }
186
+ const cachedByCore = runtimeCache.get(form);
187
+ if (cachedByCore) {
188
+ return cachedByCore;
189
+ }
190
+ const runtime = createVueFormRuntime(form);
191
+ runtimeCache.set(form, runtime);
192
+ instanceRuntimeCache.set(runtime.instance, runtime);
193
+ return runtime;
194
+ }
195
+ function createVueFormRuntime(core) {
196
+ let resources;
197
+ let ownerCount = 0;
198
+ let destroyed = false;
199
+ const createResources = () => {
200
+ const stateAdapter = createFormStateAdapter(core);
201
+ const values = bindSnapshotSource(stateAdapter.values);
202
+ const touchedFields = bindSnapshotSource(stateAdapter.touchedFields);
203
+ const pendingFields = bindSnapshotSource(stateAdapter.pendingFields);
204
+ const loading = bindSnapshotSource(stateAdapter.loading);
205
+ const fieldStates = /* @__PURE__ */ new Map();
206
+ let viewSchemaState;
207
+ let disposed = false;
208
+ const dispose = () => {
209
+ if (disposed) {
210
+ return;
211
+ }
212
+ disposed = true;
213
+ fieldStates.clear();
214
+ stateAdapter.dispose();
215
+ };
216
+ return {
217
+ stateAdapter,
218
+ values,
219
+ touchedFields,
220
+ pendingFields,
221
+ loading,
222
+ fieldStates,
223
+ viewSchemaState,
224
+ dispose
225
+ };
226
+ };
227
+ const ensureResources = () => {
228
+ if (destroyed) {
229
+ throw new Error("[schemx] Vue Form Runtime has been destroyed.");
230
+ }
231
+ resources ?? (resources = createResources());
232
+ return resources;
233
+ };
234
+ const disposeResources = () => {
235
+ const currentResources = resources;
236
+ if (!currentResources) {
237
+ return;
238
+ }
239
+ resources = void 0;
240
+ currentResources.dispose();
241
+ };
242
+ const retain = () => {
243
+ if (destroyed) {
244
+ return () => {
245
+ };
246
+ }
247
+ ensureResources();
248
+ ownerCount++;
249
+ let released = false;
250
+ return () => {
251
+ if (released || destroyed) {
252
+ return;
253
+ }
254
+ released = true;
255
+ ownerCount--;
256
+ if (ownerCount === 0) {
257
+ disposeResources();
258
+ }
259
+ };
260
+ };
261
+ const trackField = (name, dependency) => {
262
+ if (!resources) {
263
+ return;
264
+ }
265
+ const fieldState = getVueFieldState(resources, name);
266
+ void fieldState[dependency].value;
267
+ };
268
+ const trackFieldsValue = (names) => {
269
+ if (!resources) {
270
+ return;
271
+ }
272
+ if (names === void 0) {
273
+ void resources.values.value;
274
+ return;
275
+ }
276
+ for (const name of names) {
277
+ void getVueFieldState(resources, name).value.value;
278
+ }
279
+ };
280
+ const trackForm = (dependency) => {
281
+ if (!resources) {
282
+ return;
283
+ }
284
+ switch (dependency) {
285
+ case "values":
286
+ void resources.values.value;
287
+ break;
288
+ case "touchedFields":
289
+ void resources.touchedFields.value;
290
+ break;
291
+ case "pendingFields":
292
+ void resources.pendingFields.value;
293
+ break;
294
+ case "loading":
295
+ void resources.loading.value;
296
+ break;
297
+ }
298
+ };
299
+ const getValuesRef = () => {
300
+ return ensureResources().values;
301
+ };
302
+ const getFieldState = (name) => {
303
+ return getVueFieldState(ensureResources(), name);
304
+ };
305
+ const getViewSchemaState = () => {
306
+ const currentResources = ensureResources();
307
+ const viewSchemaState = currentResources.viewSchemaState ?? (currentResources.viewSchemaState = createVueViewSchemaState(core));
308
+ return viewSchemaState;
309
+ };
310
+ const destroy = () => {
311
+ if (destroyed) {
312
+ return;
313
+ }
314
+ destroyed = true;
315
+ ownerCount = 0;
316
+ disposeResources();
317
+ };
318
+ const instance = createVueFormInstance(core, {
319
+ trackField,
320
+ trackFieldsValue,
321
+ trackForm,
322
+ destroy
323
+ });
324
+ const runtime = {
325
+ core,
326
+ instance,
327
+ retain,
328
+ trackField,
329
+ trackFieldsValue,
330
+ trackForm,
331
+ getValuesRef,
332
+ getFieldState,
333
+ getViewSchemaState,
334
+ destroy
335
+ };
336
+ return runtime;
337
+ }
338
+ const SCHEMX_APP_CONFIG_KEY = Symbol("schemx:app-config");
339
+ const EMPTY_SCHEMX_CONFIG = Object.freeze({
340
+ schemaConfig: Object.freeze({}),
341
+ validatorAdapters: Object.freeze([])
342
+ });
343
+ function normalizeSchemxAppConfig(config) {
344
+ const schemaConfig = Object.freeze({ ...config.schemaConfig ?? {} });
345
+ const validatorAdapters = Object.freeze([...config.validatorAdapters ?? []]);
346
+ return Object.freeze({
347
+ schemaConfig,
348
+ rendererProps: normalizeRendererProps(config.rendererProps),
349
+ validatorAdapters,
350
+ defaultRendererType: config.defaultRendererType,
351
+ rendererRegistry: config.rendererRegistry,
352
+ presetRuleRegistry: config.presetRuleRegistry
353
+ });
354
+ }
355
+ function normalizeRendererProps(source) {
356
+ if (source === void 0) {
357
+ return void 0;
358
+ }
359
+ const entries = Object.entries(source).map(([type, props]) => {
360
+ return [type, props === void 0 ? void 0 : Object.freeze({ ...props })];
361
+ });
362
+ return Object.freeze(Object.fromEntries(entries));
363
+ }
364
+ function provideSchemxAppConfig(app, config = {}) {
365
+ const normalizedConfig = normalizeSchemxAppConfig(config);
366
+ app.provide(SCHEMX_APP_CONFIG_KEY, normalizedConfig);
367
+ }
368
+ function getSchemxAppConfig() {
369
+ if (getCurrentInstance() === null) {
370
+ return EMPTY_SCHEMX_CONFIG;
371
+ }
372
+ return inject(SCHEMX_APP_CONFIG_KEY, EMPTY_SCHEMX_CONFIG);
373
+ }
374
+ const SCHEMX_CONFIG_PROVIDER_KEY = Symbol(
375
+ "schemx:config-provider"
376
+ );
377
+ function provideSchemxConfigProvider(config) {
378
+ const parentConfig = inject(SCHEMX_CONFIG_PROVIDER_KEY, void 0);
379
+ const mergedConfig = computed(
380
+ () => mergeSchemxConfig(config.value, (parentConfig == null ? void 0 : parentConfig.value) ?? {})
381
+ );
382
+ provide(SCHEMX_CONFIG_PROVIDER_KEY, mergedConfig);
383
+ }
384
+ function getSchemxConfigProvider() {
385
+ var _a;
386
+ if (getCurrentInstance() === null) {
387
+ return void 0;
388
+ }
389
+ return (_a = inject(SCHEMX_CONFIG_PROVIDER_KEY, void 0)) == null ? void 0 : _a.value;
390
+ }
391
+ const presetRuleRegistry = createPresetRuleRegistry();
290
392
  const rendererRegistry = createRendererRegistry("input");
291
- const validationRuleRegistry = createValidationRuleRegistry();
292
- function useForm(options = {}) {
293
- const configuredOptions = mergeSchemxConfig(
294
- getUseFormSchemxConfig(options),
295
- // App 安装配置以 Values 存储;在 useForm 边界关联到当前 TValues。
393
+ function mergeVueSchemxConfig(localConfig, fallbackConfig = {}) {
394
+ const providerConfig = getSchemxConfigProvider();
395
+ return mergeSchemxConfig(
396
+ localConfig,
397
+ providerConfig ?? {},
296
398
  getSchemxAppConfig(),
399
+ fallbackConfig,
297
400
  {
298
401
  rendererRegistry,
299
- validationRuleRegistry
402
+ presetRuleRegistry
300
403
  }
301
404
  );
405
+ }
406
+ function useForm(options = {}) {
407
+ const configuredOptions = mergeVueSchemxConfig(getUseFormSchemxConfig(options));
302
408
  const mergedOptions = {
303
409
  ...options,
304
410
  ...configuredOptions
305
411
  };
306
412
  const instance = createForm(mergedOptions);
307
- const form = getVueFormFacade(instance);
308
- const releaseBridge = retainVueFormBridge(getVueFormBridge(instance));
413
+ const acquired = acquireVueFormRuntime(instance);
414
+ const form = acquired.runtime.instance;
309
415
  onScopeDispose(() => {
310
- releaseBridge();
416
+ acquired.release();
311
417
  form.destroy();
312
418
  });
313
419
  return form;
@@ -319,24 +425,32 @@ function getUseFormSchemxConfig(options) {
319
425
  validatorAdapters = [],
320
426
  defaultRendererType = void 0,
321
427
  rendererRegistry: rendererRegistry2 = void 0,
322
- validationRuleRegistry: validationRuleRegistry2 = void 0
428
+ presetRuleRegistry: presetRuleRegistry2 = void 0
323
429
  } = options;
324
430
  return {
325
431
  schemaConfig,
326
432
  rendererProps,
327
433
  defaultRendererType,
328
434
  rendererRegistry: rendererRegistry2,
329
- validationRuleRegistry: validationRuleRegistry2,
435
+ presetRuleRegistry: presetRuleRegistry2,
330
436
  validatorAdapters
331
437
  };
332
438
  }
333
- const SCHEMX_FORM_INSTANCE_KEY = Symbol("schemx:instance");
439
+ const SCHEMX_FORM_INSTANCE_KEY = Symbol(
440
+ "schemx:instance"
441
+ );
442
+ const SCHEMX_FORM_RUNTIME_KEY = Symbol(
443
+ "schemx:runtime"
444
+ );
334
445
  function createFormContext(instance) {
335
- const form = getVueFormFacade(instance);
336
- const releaseBridge = retainVueFormBridge(getVueFormBridge(form));
337
- provide(SCHEMX_FORM_INSTANCE_KEY, form);
338
- onScopeDispose(releaseBridge);
339
- return form;
446
+ const { runtime, release } = acquireVueFormRuntime(instance);
447
+ provide(
448
+ SCHEMX_FORM_INSTANCE_KEY,
449
+ runtime.instance
450
+ );
451
+ provide(SCHEMX_FORM_RUNTIME_KEY, runtime);
452
+ onScopeDispose(release);
453
+ return runtime.instance;
340
454
  }
341
455
  function useFormContext() {
342
456
  const instance = inject(SCHEMX_FORM_INSTANCE_KEY, null);
@@ -347,21 +461,30 @@ function useFormContext() {
347
461
  }
348
462
  return instance;
349
463
  }
350
- function createFieldHook(form, name, fieldBridge) {
351
- const coreForm = getCoreForm(form);
464
+ function useFormRuntimeContext() {
465
+ const providedRuntime = inject(SCHEMX_FORM_RUNTIME_KEY, null);
466
+ if (providedRuntime) {
467
+ return providedRuntime;
468
+ }
469
+ const instance = useFormContext();
470
+ const acquired = acquireVueFormRuntime(instance);
471
+ onScopeDispose(acquired.release);
472
+ return acquired.runtime;
473
+ }
474
+ function createFieldHook(form, coreForm, name, fieldState) {
352
475
  const coreField = createField(coreForm, name);
353
- const errors = computed(() => fieldBridge.errors.value);
354
- const dirty = computed(() => fieldBridge.touched.value);
355
- const pending = computed(() => fieldBridge.pending.value);
356
- const getValue = () => fieldBridge.value.value;
357
- const getErrors = () => fieldBridge.errors.value;
358
- const isTouched = () => fieldBridge.touched.value;
359
- const isPending = () => fieldBridge.pending.value;
476
+ const errors = computed(() => fieldState.errors.value);
477
+ const dirty = computed(() => fieldState.touched.value);
478
+ const pending = computed(() => fieldState.pending.value);
479
+ const getValue = () => fieldState.value.value;
480
+ const getErrors = () => fieldState.errors.value;
481
+ const isTouched = () => fieldState.touched.value;
482
+ const isPending = () => fieldState.pending.value;
360
483
  const getValues = () => form.getFieldsValue();
361
484
  return {
362
485
  ...coreField,
363
486
  name,
364
- value: fieldBridge.value,
487
+ value: fieldState.value,
365
488
  errors,
366
489
  dirty,
367
490
  pending,
@@ -374,10 +497,9 @@ function createFieldHook(form, name, fieldBridge) {
374
497
  }
375
498
  const useField = (name) => {
376
499
  const form = useFormContext();
377
- const coreForm = getCoreForm(form);
378
- const formBridge = getVueFormBridge(coreForm);
379
- const fieldBridge = getVueFieldBridge(formBridge, name);
380
- return createFieldHook(form, name, fieldBridge);
500
+ const runtime = useFormRuntimeContext();
501
+ const fieldState = runtime.getFieldState(name);
502
+ return createFieldHook(form, runtime.core, name, fieldState);
381
503
  };
382
504
  const SCHEMX_FORM_FIELD_KEY = Symbol(
383
505
  "schemx:field"
@@ -395,9 +517,9 @@ function useFieldContext() {
395
517
  return field;
396
518
  }
397
519
  function useWatch(nameOrNamesOrCallback, callbackOrOptions, maybeOptions) {
398
- const form = useFormContext();
520
+ const runtime = useFormRuntimeContext();
399
521
  const dispose = createWatch(
400
- getCoreForm(form),
522
+ runtime.core,
401
523
  nameOrNamesOrCallback,
402
524
  callbackOrOptions,
403
525
  maybeOptions
@@ -426,6 +548,7 @@ const useDictionary = (options, fieldName) => {
426
548
  const loading = ref(false);
427
549
  const error = ref(void 0);
428
550
  let requestCount = 0;
551
+ let activeController = null;
429
552
  const format = async (res) => {
430
553
  if (typeof (options == null ? void 0 : options.formatter) === "function") {
431
554
  return await options.formatter(res, instance);
@@ -437,25 +560,32 @@ const useDictionary = (options, fieldName) => {
437
560
  }
438
561
  return res;
439
562
  };
440
- const executeWithRetry = async (formValues) => {
563
+ const executeWithRetry = async (formValues, signal) => {
441
564
  const maxRetries = options.retryCount ?? 0;
442
565
  const retryDelay = options.retryInterval ?? 1e3;
443
566
  let lastError = new Error("Unknown error");
444
567
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
445
568
  try {
446
- return await options.api(formValues, instance);
569
+ if (signal.aborted) {
570
+ throw new Error("Dictionary request aborted");
571
+ }
572
+ return await callDictionaryApi(formValues, instance, options.api, signal);
447
573
  } catch (err) {
448
574
  lastError = normalizeError(err);
449
575
  if (attempt < maxRetries) {
450
- await new Promise((r) => setTimeout(r, retryDelay));
576
+ await waitForRetry(retryDelay, signal);
451
577
  }
452
578
  }
453
579
  }
454
580
  throw lastError;
455
581
  };
456
582
  const loadDict = async () => {
583
+ const currentCount = ++requestCount;
584
+ activeController == null ? void 0 : activeController.abort();
585
+ const controller = new AbortController();
586
+ activeController = controller;
457
587
  try {
458
- const formValues = instance.getFieldsValue();
588
+ const formValues = instance.getFieldsSnapshot();
459
589
  if (typeof options.shouldFetch === "function" && !options.shouldFetch(formValues)) {
460
590
  list.value = [];
461
591
  loading.value = false;
@@ -463,12 +593,11 @@ const useDictionary = (options, fieldName) => {
463
593
  }
464
594
  loading.value = true;
465
595
  error.value = void 0;
466
- const currentCount = ++requestCount;
467
- const res = await executeWithRetry(formValues);
468
- if (currentCount !== requestCount)
596
+ const res = await executeWithRetry(formValues, controller.signal);
597
+ if (currentCount !== requestCount || controller.signal.aborted)
469
598
  return;
470
599
  const formatted = await format(res);
471
- if (currentCount !== requestCount)
600
+ if (currentCount !== requestCount || controller.signal.aborted)
472
601
  return;
473
602
  list.value = formatted;
474
603
  error.value = void 0;
@@ -477,6 +606,9 @@ const useDictionary = (options, fieldName) => {
477
606
  }
478
607
  loading.value = false;
479
608
  } catch (err) {
609
+ if (controller.signal.aborted || currentCount !== requestCount) {
610
+ return;
611
+ }
480
612
  const normalized = normalizeError(err);
481
613
  error.value = normalized;
482
614
  list.value = [];
@@ -484,6 +616,10 @@ const useDictionary = (options, fieldName) => {
484
616
  if (typeof options.onError === "function") {
485
617
  options.onError(normalized, instance);
486
618
  }
619
+ } finally {
620
+ if (activeController === controller) {
621
+ activeController = null;
622
+ }
487
623
  }
488
624
  };
489
625
  const refresh = () => loadDict();
@@ -491,15 +627,19 @@ const useDictionary = (options, fieldName) => {
491
627
  list.value = data;
492
628
  };
493
629
  if ((_a = options.dependsOn) == null ? void 0 : _a.length) {
494
- useWatchFields(options.dependsOn, (latestSnapshot, _payload) => {
495
- if (typeof options.onDepsChange === "function") {
496
- options.onDepsChange(latestSnapshot, instance);
497
- }
498
- if (options.resetOnDepsChange && fieldName) {
499
- instance.setFieldValue(fieldName, void 0);
500
- }
501
- void loadDict();
502
- });
630
+ useWatchFields(
631
+ options.dependsOn,
632
+ (latestSnapshot, _payload) => {
633
+ if (typeof options.onDepsChange === "function") {
634
+ options.onDepsChange(latestSnapshot, instance);
635
+ }
636
+ if (options.resetOnDepsChange && fieldName) {
637
+ instance.setFieldValue(fieldName, void 0);
638
+ }
639
+ void loadDict();
640
+ },
641
+ { inequality: true }
642
+ );
503
643
  }
504
644
  const immediate = options.immediate ?? true;
505
645
  onMounted(() => {
@@ -507,8 +647,43 @@ const useDictionary = (options, fieldName) => {
507
647
  void loadDict();
508
648
  }
509
649
  });
650
+ onScopeDispose(() => {
651
+ requestCount += 1;
652
+ activeController == null ? void 0 : activeController.abort();
653
+ activeController = null;
654
+ });
510
655
  return { list, loading, error, loadDict, refresh, mutate };
511
656
  };
657
+ function waitForRetry(delay, signal) {
658
+ return new Promise((resolve, reject) => {
659
+ let abort = () => {
660
+ };
661
+ const cleanup = () => {
662
+ clearTimeout(timeoutId);
663
+ signal.removeEventListener("abort", abort);
664
+ };
665
+ const complete = () => {
666
+ cleanup();
667
+ resolve();
668
+ };
669
+ const timeoutId = setTimeout(complete, delay);
670
+ abort = () => {
671
+ cleanup();
672
+ reject(new Error("Dictionary request aborted"));
673
+ };
674
+ if (signal.aborted) {
675
+ abort();
676
+ return;
677
+ }
678
+ signal.addEventListener("abort", abort, { once: true });
679
+ });
680
+ }
681
+ function callDictionaryApi(values, form, api, signal) {
682
+ if (api.length >= 3) {
683
+ return api(values, form, signal);
684
+ }
685
+ return api(values, form);
686
+ }
512
687
  const SCHEMX_FORM_CONFIG_KEY = Symbol(
513
688
  "schemx:form-config"
514
689
  );
@@ -541,87 +716,37 @@ function useStableRef(factory) {
541
716
  });
542
717
  return stableRef;
543
718
  }
544
- const viewSchemaBridgeCache = /* @__PURE__ */ new WeakMap();
545
- function useViewSchemas(form) {
546
- const bridge = acquireViewSchemaBridge(getCoreForm(form));
547
- return bridge.viewSchemas;
548
- }
549
- function useViewSchema(form, getKey) {
550
- const bridge = acquireViewSchemaBridge(getCoreForm(form));
551
- return computed(() => bridge.schemasByKey.value.get(getKey()));
552
- }
553
- function createViewSchemaBridge(form) {
554
- const viewSchemas = shallowRef(
555
- form.getViewSchemas()
556
- );
557
- const schemasByKey = computed(() => {
558
- return createViewSchemaIndex(viewSchemas.value);
559
- });
560
- const unsubscribe = form.subscribeViewSchemas(
561
- /**
562
- * 接收 Core 发布的完整列表并替换共享引用,以保留更新边界。
563
- *
564
- * @param nextSchemas - Core 计算出的最新 ViewSchema 列表。
565
- */
566
- (nextSchemas) => {
567
- viewSchemas.value = nextSchemas;
568
- }
569
- );
570
- return {
571
- refCount: 0,
572
- schemasByKey,
573
- unsubscribe,
574
- viewSchemas
575
- };
576
- }
577
- function acquireViewSchemaBridge(form) {
578
- const cachedBridge = viewSchemaBridgeCache.get(form);
579
- const bridge = cachedBridge ?? createViewSchemaBridge(form);
580
- if (!cachedBridge) {
581
- viewSchemaBridgeCache.set(form, bridge);
582
- }
583
- bridge.refCount++;
584
- onScopeDispose(() => {
585
- bridge.refCount--;
586
- if (bridge.refCount > 0) {
587
- return;
588
- }
589
- bridge.unsubscribe();
590
- viewSchemaBridgeCache.delete(form);
591
- });
592
- return bridge;
593
- }
594
- function createViewSchemaIndex(viewSchemas) {
595
- const schemasByKey = /* @__PURE__ */ new Map();
596
- const appendSchemas = (schemas) => {
597
- for (const schema of schemas) {
598
- schemasByKey.set(schema.key, schema);
599
- if (isViewGroupSchema(schema)) {
600
- appendSchemas(schema.children);
601
- }
602
- }
603
- };
604
- appendSchemas(viewSchemas);
605
- return schemasByKey;
606
- }
719
+ function useViewSchemas(form) {
720
+ const acquired = acquireVueFormRuntime(form);
721
+ const state = acquired.runtime.getViewSchemaState();
722
+ onScopeDispose(acquired.release);
723
+ return state.viewSchemas;
724
+ }
725
+ function useViewSchema(form, getKey) {
726
+ const acquired = acquireVueFormRuntime(form);
727
+ const state = acquired.runtime.getViewSchemaState();
728
+ const schema = computed(() => state.schemasByKey.value.get(getKey()));
729
+ onScopeDispose(acquired.release);
730
+ return schema;
731
+ }
607
732
  function useFormSelector(form, selector, options = {}) {
608
- const bridge = getVueFormBridge(getCoreForm(form));
609
- const releaseBridge = retainVueFormBridge(bridge);
610
- const selected = shallowRef(selector(bridge.values.value));
733
+ const acquired = acquireVueFormRuntime(form);
734
+ const values = acquired.runtime.getValuesRef();
735
+ const selected = shallowRef(selector(values.value));
611
736
  const equals = options.equals ?? Object.is;
612
737
  const stop = watch(
613
- bridge.values,
614
- (values) => {
615
- const next = selector(values);
738
+ values,
739
+ (values2) => {
740
+ const next = selector(values2);
616
741
  if (!equals(selected.value, next)) {
617
742
  selected.value = next;
618
743
  }
619
744
  },
620
- { flush: "sync" }
745
+ { flush: options.flush ?? "sync" }
621
746
  );
622
747
  onScopeDispose(() => {
623
748
  stop();
624
- releaseBridge();
749
+ acquired.release();
625
750
  });
626
751
  return readonly(selected);
627
752
  }
@@ -695,105 +820,57 @@ const extractChildSlots = (fieldName, allSlots) => {
695
820
  }
696
821
  return result;
697
822
  };
698
- const FormGroup = /* @__PURE__ */ defineComponent((props, {
699
- slots
700
- }) => {
701
- var _a;
702
- const internalCollapsed = ref(Boolean(props.schema.defaultCollapsed));
703
- const collapsed = computed(() => props.schema.collapsed ?? internalCollapsed.value);
704
- const componentId = ((_a = getCurrentInstance()) == null ? void 0 : _a.uid) ?? 0;
705
- watch(() => props.schema.collapsed, (nextCollapsed, previousCollapsed) => {
706
- if (nextCollapsed !== void 0) {
707
- internalCollapsed.value = nextCollapsed;
708
- } else if (previousCollapsed !== void 0) {
709
- internalCollapsed.value = previousCollapsed;
710
- }
711
- });
712
- const toggle = () => {
713
- var _a2, _b;
714
- if (!props.schema.collapsible || props.schema.disabled) {
715
- return;
716
- }
717
- const nextCollapsed = !collapsed.value;
718
- if (props.schema.collapsed === void 0) {
719
- internalCollapsed.value = nextCollapsed;
720
- }
721
- (_b = (_a2 = props.schema).onCollapsedChange) == null ? void 0 : _b.call(_a2, nextCollapsed);
823
+ function getSectionPosition(list, currentKey) {
824
+ const currentIndex = list.findIndex((item) => item.key === currentKey);
825
+ if (currentIndex === -1) {
826
+ return {
827
+ found: false,
828
+ isFirst: false,
829
+ isLast: false
830
+ };
831
+ }
832
+ const currentItem = list[currentIndex];
833
+ if (!isPositionItem(currentItem)) {
834
+ return {
835
+ found: true,
836
+ isFirst: false,
837
+ isLast: false
838
+ };
839
+ }
840
+ return {
841
+ found: true,
842
+ isFirst: !hasPositionItemInSection(list, currentIndex, -1),
843
+ isLast: !hasPositionItemInSection(list, currentIndex, 1)
722
844
  };
723
- return () => {
724
- var _a2;
725
- const schema = props.schema;
726
- if (schema.visible === false) {
727
- return null;
845
+ }
846
+ function normalizeNameKey(name) {
847
+ if (Array.isArray(name)) {
848
+ return name.map((part) => String(part)).join(".");
849
+ }
850
+ return String(name);
851
+ }
852
+ function normalizeId(key) {
853
+ return String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
854
+ }
855
+ function isPositionItem(item) {
856
+ return !!item && !isViewGroupSchema(item) && item.visible !== false;
857
+ }
858
+ function hasPositionItemInSection(list, startIndex, step) {
859
+ for (let index = startIndex + step; index >= 0 && index < list.length; index += step) {
860
+ const item = list[index];
861
+ if (item.visible === false) {
862
+ continue;
728
863
  }
729
- const collapsible = Boolean(schema.collapsible);
730
- const isCollapsed = collapsed.value;
731
- const destroyOnCollapse = schema.destroyOnCollapse ?? true;
732
- const uniqueId = ((_a2 = schema.debug) == null ? void 0 : _a2.runtimeNodeId) ?? `local-${componentId}`;
733
- const idBase = `schemx-group-${uniqueId}-${normalizeId(schema.key)}`;
734
- const headerId = `${idBase}-header`;
735
- const bodyId = `${idBase}-body`;
736
- const body = createVNode("div", {
737
- "id": bodyId,
738
- "role": "group",
739
- "aria-labelledby": schema.label ? headerId : void 0,
740
- "aria-hidden": isCollapsed || void 0,
741
- "class": "schemx-group__body",
742
- "style": !destroyOnCollapse && isCollapsed ? {
743
- display: "none"
744
- } : void 0
745
- }, [schema.children.map((child) => createVNode(FormItem$1, {
746
- "key": child.key,
747
- "schema": child
748
- }, slots))]);
749
- return createVNode("div", {
750
- "class": classnames("schemx-group", {
751
- "schemx-group--collapsed": isCollapsed,
752
- "is-readonly": schema.readonly,
753
- "is-disabled": schema.disabled
754
- }, schema.class),
755
- "style": schema.style,
756
- "data-key": schema.key,
757
- "aria-disabled": schema.disabled || void 0
758
- }, [schema.label && createVNode("div", {
759
- "id": headerId,
760
- "role": collapsible ? "button" : void 0,
761
- "tabindex": collapsible ? schema.disabled ? -1 : 0 : void 0,
762
- "aria-expanded": collapsible ? !isCollapsed : void 0,
763
- "aria-controls": collapsible ? bodyId : void 0,
764
- "aria-disabled": collapsible ? schema.disabled || void 0 : void 0,
765
- "class": classnames("schemx-group__header", {
766
- "schemx-group__header--clickable": collapsible && !schema.disabled
767
- }),
768
- "onClick": toggle,
769
- "onKeydown": (e) => {
770
- if (!schema.disabled && (e.key === "Enter" || e.key === " ")) {
771
- e.preventDefault();
772
- toggle();
773
- }
774
- }
775
- }, [createVNode("span", {
776
- "class": "schemx-group__title"
777
- }, [schema.label]), collapsible && createVNode("span", {
778
- "class": classnames("schemx-group__arrow", {
779
- "schemx-group__arrow--down": !isCollapsed
780
- })
781
- }, null)]), destroyOnCollapse ? !isCollapsed && body : body]);
782
- };
783
- }, {
784
- name: "SchemxGroup",
785
- props: {
786
- schema: {
787
- type: Object,
788
- required: true
864
+ if (isViewGroupSchema(item)) {
865
+ return false;
866
+ }
867
+ if (isPositionItem(item)) {
868
+ return true;
789
869
  }
790
870
  }
791
- });
792
- const FormGroup$1 = FormGroup;
793
- const normalizeId = (key) => {
794
- return String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
795
- };
796
- function createFormItemSlotRenderers(options) {
871
+ return false;
872
+ }
873
+ function createFieldSlotRenderers(options) {
797
874
  const {
798
875
  schemaRef,
799
876
  field,
@@ -808,36 +885,39 @@ function createFormItemSlotRenderers(options) {
808
885
  return null;
809
886
  }
810
887
  return createVNode("span", {
811
- "class": "schemx-item__required"
888
+ "class": "schemx-field__required"
812
889
  }, [createTextVNode("*")]);
813
890
  };
814
891
  const createSlotProps = (additionalProps = {}) => {
815
892
  return {
816
- ...componentProps.value,
893
+ schema: schemaRef.value,
894
+ componentProps: componentProps.value,
817
895
  value: field.value.value,
896
+ field,
897
+ form,
818
898
  ...additionalProps
819
899
  };
820
900
  };
821
901
  const renderFieldSlot = (suffix) => {
822
- const slot = resolveSlot(slots, `${schemaRef.value.name}${suffix}`);
902
+ const slot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}${suffix}`);
823
903
  return (slot == null ? void 0 : slot(createSlotProps())) ?? null;
824
904
  };
825
905
  const renderLabel = () => {
826
- const labelSlot = resolveSlot(slots, `${schemaRef.value.name}Label`);
906
+ const labelSlot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}Label`);
827
907
  if (labelSlot) {
828
- return labelSlot(schemaRef.value);
908
+ return labelSlot(createSlotProps());
829
909
  }
830
910
  const labelAlign = schemaRef.value.labelAlign || formContext.schemaConfig.labelAlign;
831
911
  const labelWidth = schemaRef.value.labelWidth || formContext.schemaConfig.labelWidth;
832
912
  const colon = schemaRef.value.colon ?? formContext.schemaConfig.colon;
833
913
  return createVNode("label", {
834
- "class": "schemx-item__label",
914
+ "class": "schemx-field__label",
835
915
  "style": {
836
916
  width: labelWidth,
837
917
  textAlign: labelAlign
838
918
  }
839
919
  }, [renderRequired(), createVNode("span", {
840
- "class": "schemx-item__label-text"
920
+ "class": "schemx-field__label-text"
841
921
  }, [schemaRef.value.label, colon ? ":" : ""])]);
842
922
  };
843
923
  const renderBefore = () => renderFieldSlot("Before");
@@ -848,19 +928,19 @@ function createFormItemSlotRenderers(options) {
848
928
  }
849
929
  const childSlots = extractChildSlots(normalizeNameKey(schemaRef.value.name), slots);
850
930
  const columnElement = h(component, componentProps.value, childSlots);
851
- const contentSlot = resolveSlot(slots, `${schemaRef.value.name}Content`);
931
+ const contentSlot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}Content`);
852
932
  if (contentSlot) {
853
933
  return contentSlot(createSlotProps({
854
934
  columnElement
855
935
  }));
856
936
  }
857
937
  return createVNode("div", {
858
- "class": "schemx-item__control"
938
+ "class": "schemx-field__control"
859
939
  }, [columnElement]);
860
940
  };
861
941
  const renderAfter = () => renderFieldSlot("After");
862
942
  const renderError = () => {
863
- const errorSlot = resolveSlot(slots, `${schemaRef.value.name}Error`);
943
+ const errorSlot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}Error`);
864
944
  if (errorSlot) {
865
945
  return errorSlot(createSlotProps({
866
946
  errors: field.errors.value
@@ -870,7 +950,7 @@ function createFormItemSlotRenderers(options) {
870
950
  return null;
871
951
  }
872
952
  return createVNode("div", {
873
- "class": "schemx-item__error"
953
+ "class": "schemx-field__error"
874
954
  }, [field.errors.value[0]]);
875
955
  };
876
956
  return {
@@ -882,49 +962,23 @@ function createFormItemSlotRenderers(options) {
882
962
  renderLabel
883
963
  };
884
964
  }
885
- function normalizeNameKey(name) {
886
- if (Array.isArray(name)) {
887
- return name.map((part) => String(part)).join(".");
888
- }
889
- return String(name);
890
- }
891
- const FormItem = /* @__PURE__ */ defineComponent({
892
- name: "SchemxItem",
893
- props: {
894
- schema: {
895
- type: Object,
896
- required: true
897
- }
898
- },
899
- /**
900
- * 根据 schema 类型分发字段组或字段项渲染。
901
- *
902
- * @param props - 当前组件的 schema 属性。
903
- * @param slots - Vue setup 上下文提供的插槽集合。
904
- */
905
- setup(props, {
906
- slots
907
- }) {
908
- return () => {
909
- const schema = props.schema;
910
- if (isViewGroupSchema(schema)) {
911
- return h(FormGroup$1, {
912
- schema
913
- }, slots);
914
- }
915
- return h(FieldFormItem, {
916
- schema
917
- }, slots);
918
- };
919
- }
920
- });
921
- const FieldFormItem = /* @__PURE__ */ defineComponent({
922
- name: "SchemxFieldItem",
965
+ const Field = /* @__PURE__ */ defineComponent({
966
+ name: "SchemxField",
923
967
  inheritAttrs: false,
924
968
  props: {
925
969
  schema: {
926
970
  type: Object,
927
971
  required: true
972
+ },
973
+ class: {
974
+ type: [String, Object, Array, Boolean],
975
+ required: false,
976
+ default: void 0
977
+ },
978
+ style: {
979
+ type: [String, Object, Array],
980
+ required: false,
981
+ default: void 0
928
982
  }
929
983
  },
930
984
  /**
@@ -949,7 +1003,7 @@ const FieldFormItem = /* @__PURE__ */ defineComponent({
949
1003
  createFieldContext(field);
950
1004
  const trigger = computed(() => mergeTrigger(schemaRef.value.validationTrigger, formContext.schemaConfig.validationTrigger, "onChange"));
951
1005
  const canVerified = computed(() => {
952
- const isOperate = schemaRef.value.visible && !schemaRef.value.readonly && !schemaRef.value.disabled;
1006
+ const isOperate = schemaRef.value.visible !== false && !schemaRef.value.readonly && !schemaRef.value.disabled;
953
1007
  const rules = schemaRef.value.rules;
954
1008
  const hasRules = Array.isArray(rules) ? (rules == null ? void 0 : rules.length) > 0 : !!schemaRef.value.rules;
955
1009
  return isOperate && (Boolean(schemaRef.value.required) || hasRules);
@@ -989,7 +1043,7 @@ const FieldFormItem = /* @__PURE__ */ defineComponent({
989
1043
  renderContent,
990
1044
  renderError,
991
1045
  renderLabel
992
- } = createFormItemSlotRenderers({
1046
+ } = createFieldSlotRenderers({
993
1047
  schemaRef,
994
1048
  field,
995
1049
  form,
@@ -998,32 +1052,27 @@ const FieldFormItem = /* @__PURE__ */ defineComponent({
998
1052
  slots
999
1053
  });
1000
1054
  return () => {
1001
- if (!schemaRef.value.visible) {
1055
+ if (schemaRef.value.visible === false) {
1002
1056
  return null;
1003
1057
  }
1004
- const itemSlot = resolveSlot(slots, normalizeNameKey(schemaRef.value.name));
1005
- if (itemSlot) {
1006
- return itemSlot(createSlotProps());
1007
- }
1058
+ const fieldSlot = resolveSlot(slots, normalizeNameKey(schemaRef.value.name));
1008
1059
  const labelPosition = schemaRef.value.labelPosition || formContext.schemaConfig.labelPosition;
1009
- return createVNode("div", mergeProps(attrs, {
1010
- "class": classnames("schemx-item-wrapper", attrs.class),
1011
- "style": [attrs.style, schemaRef.value.style]
1012
- }), [createVNode("div", {
1013
- "class": classnames("schemx-item", `schemx-item--label-${labelPosition}`, schemaRef.value.class, {
1060
+ const fieldContent = fieldSlot ? fieldSlot(createSlotProps()) : createVNode("div", {
1061
+ "class": classnames("schemx-field", `schemx-field--label-${labelPosition}`, {
1014
1062
  "is-readonly": schemaRef.value.readonly,
1015
1063
  "is-disabled": schemaRef.value.disabled
1016
- }),
1017
- "style": {
1018
- ...schemaRef.value.style ?? {}
1019
- }
1064
+ })
1020
1065
  }, [renderLabel(), createVNode("div", {
1021
- "class": "schemx-item__content"
1022
- }, [renderBefore(), renderContent(), renderAfter(), renderError()])])]);
1066
+ "class": "schemx-field__content"
1067
+ }, [renderBefore(), renderContent(), renderAfter(), renderError()])]);
1068
+ return createVNode("div", mergeProps(attrs, {
1069
+ "class": classnames("schemx-field-wrapper", props.class, attrs.class, schemaRef.value.class),
1070
+ "style": [attrs.style, props.style, schemaRef.value.style]
1071
+ }), [fieldContent]);
1023
1072
  };
1024
1073
  }
1025
1074
  });
1026
- const FormItem$1 = FormItem;
1075
+ const Field$1 = Field;
1027
1076
  const _hoisted_1$1 = ["aria-busy", "data-loading", "disabled"];
1028
1077
  const _hoisted_2 = {
1029
1078
  key: 0,
@@ -1083,47 +1132,250 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1083
1132
  };
1084
1133
  }
1085
1134
  });
1086
- function getSectionPosition(list, currentKey) {
1087
- const currentIndex = list.findIndex((item) => item.key === currentKey);
1088
- if (currentIndex === -1) {
1089
- return {
1090
- found: false,
1091
- isFirst: false,
1092
- isLast: false
1093
- };
1094
- }
1095
- const currentItem = list[currentIndex];
1096
- if (!isPositionItem(currentItem)) {
1097
- return {
1098
- found: true,
1099
- isFirst: false,
1100
- isLast: false
1101
- };
1102
- }
1135
+ function createGroupSlotRenderers(options) {
1136
+ const {
1137
+ schema,
1138
+ collapsed,
1139
+ collapsible,
1140
+ disabled,
1141
+ readonly: readonly2,
1142
+ toggle,
1143
+ slots,
1144
+ renderChildren
1145
+ } = options;
1146
+ const slotKey = String(schema.key);
1147
+ const headerSlot = resolveSlot(slots, `${slotKey}Header`);
1148
+ const labelSlot = resolveSlot(slots, `${slotKey}Label`);
1149
+ const contentSlot = resolveSlot(slots, `${slotKey}Content`);
1150
+ const slotProps = {
1151
+ schema,
1152
+ collapsed,
1153
+ collapsible,
1154
+ disabled,
1155
+ readonly: readonly2,
1156
+ toggle
1157
+ };
1158
+ const renderHeaderContent = () => {
1159
+ if (headerSlot) {
1160
+ return headerSlot(slotProps);
1161
+ }
1162
+ const label = labelSlot ? labelSlot(slotProps) : createVNode("span", {
1163
+ "class": "schemx-group__title"
1164
+ }, [schema.label]);
1165
+ if (!collapsible) {
1166
+ return label;
1167
+ }
1168
+ return createVNode(Fragment, null, [label, createVNode("span", {
1169
+ "class": classnames("schemx-group__arrow", {
1170
+ "schemx-group__arrow--down": !collapsed
1171
+ })
1172
+ }, null)]);
1173
+ };
1174
+ const renderBodyContent = () => {
1175
+ if (contentSlot) {
1176
+ return contentSlot(slotProps);
1177
+ }
1178
+ return renderChildren();
1179
+ };
1103
1180
  return {
1104
- found: true,
1105
- isFirst: !hasPositionItemInSection(list, currentIndex, -1),
1106
- isLast: !hasPositionItemInSection(list, currentIndex, 1)
1181
+ hasHeader: Boolean(schema.label || headerSlot || labelSlot),
1182
+ renderBodyContent,
1183
+ renderHeaderContent
1107
1184
  };
1108
1185
  }
1109
- function isPositionItem(item) {
1110
- return !!item && !isViewGroupSchema(item) && item.visible !== false;
1111
- }
1112
- function hasPositionItemInSection(list, startIndex, step) {
1113
- for (let index = startIndex + step; index >= 0 && index < list.length; index += step) {
1114
- const item = list[index];
1115
- if (item.visible === false) {
1116
- continue;
1117
- }
1118
- if (isViewGroupSchema(item)) {
1119
- return false;
1186
+ const Group = /* @__PURE__ */ defineComponent({
1187
+ name: "SchemxGroup",
1188
+ inheritAttrs: false,
1189
+ props: {
1190
+ schema: {
1191
+ type: Object,
1192
+ required: true
1193
+ },
1194
+ class: {
1195
+ type: [String, Object, Array, Boolean],
1196
+ required: false,
1197
+ default: void 0
1198
+ },
1199
+ style: {
1200
+ type: [String, Object, Array],
1201
+ required: false,
1202
+ default: void 0
1120
1203
  }
1121
- if (isPositionItem(item)) {
1122
- return true;
1204
+ },
1205
+ setup(props, {
1206
+ attrs,
1207
+ slots
1208
+ }) {
1209
+ var _a;
1210
+ const internalCollapsed = ref(Boolean(props.schema.defaultCollapsed));
1211
+ const collapsed = computed(() => props.schema.collapsed ?? internalCollapsed.value);
1212
+ const componentId = ((_a = getCurrentInstance()) == null ? void 0 : _a.uid) ?? 0;
1213
+ watch(() => props.schema.collapsed, (nextCollapsed, previousCollapsed) => {
1214
+ if (nextCollapsed !== void 0) {
1215
+ internalCollapsed.value = nextCollapsed;
1216
+ } else if (previousCollapsed !== void 0) {
1217
+ internalCollapsed.value = previousCollapsed;
1218
+ }
1219
+ });
1220
+ const toggle = () => {
1221
+ var _a2, _b;
1222
+ if (!props.schema.collapsible || props.schema.disabled) {
1223
+ return;
1224
+ }
1225
+ const nextCollapsed = !collapsed.value;
1226
+ if (props.schema.collapsed === void 0) {
1227
+ internalCollapsed.value = nextCollapsed;
1228
+ }
1229
+ (_b = (_a2 = props.schema).onCollapsedChange) == null ? void 0 : _b.call(_a2, nextCollapsed);
1230
+ };
1231
+ return () => {
1232
+ var _a2;
1233
+ const schema = props.schema;
1234
+ if (schema.visible === false) {
1235
+ return null;
1236
+ }
1237
+ const collapsible = Boolean(schema.collapsible);
1238
+ const isCollapsed = collapsed.value;
1239
+ const destroyOnCollapse = schema.destroyOnCollapse ?? true;
1240
+ const uniqueId = ((_a2 = schema.debug) == null ? void 0 : _a2.runtimeNodeId) ?? `local-${componentId}`;
1241
+ const idBase = `schemx-group-${uniqueId}-${normalizeId(schema.key)}`;
1242
+ const headerId = `${idBase}-header`;
1243
+ const bodyId = `${idBase}-body`;
1244
+ const renderChild = (child) => {
1245
+ if (isViewDynamicSchema(child)) {
1246
+ if (child.visible === false) {
1247
+ return null;
1248
+ }
1249
+ return child.items.map((item) => item.children.map((itemChild) => renderChild(itemChild)));
1250
+ }
1251
+ if (isViewGroupSchema(child)) {
1252
+ return createVNode(Group, {
1253
+ "key": child.key,
1254
+ "schema": child,
1255
+ "class": props.class,
1256
+ "style": props.style
1257
+ }, slots);
1258
+ }
1259
+ return createVNode(Field$1, {
1260
+ "key": `${child.key}:${normalizeNameKey(child.name)}`,
1261
+ "schema": child
1262
+ }, slots);
1263
+ };
1264
+ const {
1265
+ hasHeader,
1266
+ renderBodyContent,
1267
+ renderHeaderContent
1268
+ } = createGroupSlotRenderers({
1269
+ schema,
1270
+ collapsed: isCollapsed,
1271
+ collapsible,
1272
+ disabled: Boolean(schema.disabled),
1273
+ readonly: Boolean(schema.readonly),
1274
+ toggle,
1275
+ slots,
1276
+ renderChildren: () => schema.children.map(renderChild)
1277
+ });
1278
+ const body = createVNode("div", {
1279
+ "id": bodyId,
1280
+ "role": "group",
1281
+ "aria-labelledby": schema.label ? headerId : void 0,
1282
+ "aria-hidden": isCollapsed || void 0,
1283
+ "class": "schemx-group__body",
1284
+ "style": !destroyOnCollapse && isCollapsed ? {
1285
+ display: "none"
1286
+ } : void 0
1287
+ }, [renderBodyContent()]);
1288
+ return createVNode("div", mergeProps(attrs, {
1289
+ "class": classnames("schemx-group-wrapper", props.class, attrs.class, schema.class),
1290
+ "data-key": schema.key,
1291
+ "aria-disabled": schema.disabled || void 0,
1292
+ "style": [attrs.style, props.style, schema.style]
1293
+ }), [createVNode("div", {
1294
+ "class": classnames("schemx-group", {
1295
+ "schemx-group--collapsed": isCollapsed,
1296
+ "is-readonly": schema.readonly,
1297
+ "is-disabled": schema.disabled
1298
+ })
1299
+ }, [hasHeader && createVNode("div", {
1300
+ "id": headerId,
1301
+ "role": collapsible ? "button" : void 0,
1302
+ "tabindex": collapsible ? schema.disabled ? -1 : 0 : void 0,
1303
+ "aria-expanded": collapsible ? !isCollapsed : void 0,
1304
+ "aria-controls": collapsible ? bodyId : void 0,
1305
+ "aria-disabled": collapsible ? schema.disabled || void 0 : void 0,
1306
+ "class": classnames("schemx-group__header", {
1307
+ "schemx-group__header--clickable": collapsible && !schema.disabled
1308
+ }),
1309
+ "onClick": toggle,
1310
+ "onKeydown": (e) => {
1311
+ if (!schema.disabled && (e.key === "Enter" || e.key === " ")) {
1312
+ e.preventDefault();
1313
+ toggle();
1314
+ }
1315
+ }
1316
+ }, [renderHeaderContent()]), destroyOnCollapse ? !isCollapsed && body : body])]);
1317
+ };
1318
+ }
1319
+ });
1320
+ const Group$1 = Group;
1321
+ const Dynamic = /* @__PURE__ */ defineComponent({
1322
+ name: "SchemxDynamic",
1323
+ inheritAttrs: false,
1324
+ props: {
1325
+ schema: {
1326
+ type: Object,
1327
+ required: true
1328
+ },
1329
+ viewSchemas: {
1330
+ type: Array,
1331
+ required: true
1123
1332
  }
1333
+ },
1334
+ /**
1335
+ * 初始化 Dynamic 的行模板渲染器。
1336
+ *
1337
+ * @param props - 当前 Dynamic ViewSchema 与 Form 根级 ViewSchema。
1338
+ * @param slots - 父级透传的字段插槽。
1339
+ */
1340
+ setup(props, {
1341
+ slots
1342
+ }) {
1343
+ const getFieldRenderKey = (schema) => `${schema.key}:${normalizeNameKey(schema.name)}`;
1344
+ const getFieldClass = (schema) => {
1345
+ const {
1346
+ isFirst,
1347
+ isLast
1348
+ } = getSectionPosition(props.viewSchemas, schema.key);
1349
+ return {
1350
+ "schemx-field-wrapper--first": isFirst,
1351
+ "schemx-field-wrapper--last": isLast
1352
+ };
1353
+ };
1354
+ const renderItemSchema = (schema) => {
1355
+ if (isViewGroupSchema(schema)) {
1356
+ return createVNode(Group$1, {
1357
+ "key": schema.key,
1358
+ "schema": schema
1359
+ }, slots);
1360
+ }
1361
+ const field = schema;
1362
+ return createVNode(Field$1, {
1363
+ "key": getFieldRenderKey(field),
1364
+ "schema": field,
1365
+ "class": getFieldClass(field)
1366
+ }, slots);
1367
+ };
1368
+ return () => {
1369
+ if (props.schema.visible === false) {
1370
+ return null;
1371
+ }
1372
+ return props.schema.items.map((item) => createVNode(Fragment, {
1373
+ "key": item.key
1374
+ }, [item.children.map(renderItemSchema)]));
1375
+ };
1124
1376
  }
1125
- return false;
1126
- }
1377
+ });
1378
+ const Dynamic$1 = Dynamic;
1127
1379
  const _hoisted_1 = {
1128
1380
  key: 0,
1129
1381
  class: "schemx-actions"
@@ -1133,19 +1385,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1133
1385
  __name: "form",
1134
1386
  props: {
1135
1387
  schemas: { default: () => [] },
1388
+ fieldRules: { default: void 0 },
1136
1389
  initialValues: { default: () => ({}) },
1137
1390
  modelValue: { default: () => ({}) },
1138
1391
  form: { default: void 0 },
1139
1392
  loading: { type: Boolean, default: void 0 },
1140
1393
  submitter: { type: [Boolean, Object], default: true },
1141
1394
  resetter: { type: [Boolean, Object], default: true },
1142
- class: { default: "" },
1395
+ class: { type: [Boolean, null, String, Object, Array], default: "" },
1143
1396
  style: { type: [Boolean, null, String, Object, Array], default: () => ({}) },
1144
1397
  rendererProps: { default: void 0 },
1145
1398
  validatorAdapters: {},
1146
1399
  defaultRendererType: {},
1147
1400
  rendererRegistry: { default: void 0 },
1148
- validationRuleRegistry: { default: void 0 },
1401
+ presetRuleRegistry: { default: void 0 },
1149
1402
  onRuleError: {},
1150
1403
  onFinish: { type: Function, default: void 0 },
1151
1404
  onFinishFailed: { type: Function, default: void 0 },
@@ -1154,18 +1407,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1154
1407
  onValuesChange: { type: Function, default: void 0 },
1155
1408
  onFieldsChange: { type: Function, default: void 0 },
1156
1409
  lifecycleHooks: {},
1410
+ schedulerOptions: { default: void 0 },
1411
+ validationConcurrency: { default: void 0 },
1157
1412
  required: { type: [Boolean, Object] },
1158
- readonly: { type: Boolean },
1159
- disabled: { type: Boolean },
1160
- visible: { type: Boolean, default: true },
1413
+ readonly: { type: Boolean, default: void 0 },
1414
+ disabled: { type: Boolean, default: void 0 },
1415
+ visible: { type: Boolean, default: void 0 },
1161
1416
  labelIcon: {},
1162
1417
  labelAlign: {},
1163
1418
  labelPosition: {},
1164
1419
  labelWidth: {},
1165
1420
  contentAlign: {},
1166
- validationTrigger: {},
1167
- colon: { type: Boolean },
1168
- showRequiredMark: { type: Boolean }
1421
+ validationTrigger: { default: void 0 },
1422
+ colon: { type: Boolean, default: void 0 },
1423
+ showRequiredMark: { type: Boolean, default: void 0 }
1169
1424
  },
1170
1425
  emits: ["update:modelValue"],
1171
1426
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -1173,19 +1428,36 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1173
1428
  const emit = __emit;
1174
1429
  const slots = useSlots();
1175
1430
  const pickSchemaConfig = () => {
1176
- return pick(props, defaultSchemxConfigKeys);
1431
+ const schemaConfig = pick(
1432
+ props,
1433
+ defaultSchemxConfigKeys
1434
+ );
1435
+ return Object.fromEntries(
1436
+ Object.entries(schemaConfig).filter(([, value]) => value !== void 0)
1437
+ );
1438
+ };
1439
+ const isExternalForm = props.form !== void 0;
1440
+ const formFallbackConfig = {
1441
+ schemaConfig: {
1442
+ visible: true,
1443
+ validationTrigger: ["blur", "change"]
1444
+ }
1177
1445
  };
1178
- const formSchemaConfig = reactive(pickSchemaConfig());
1446
+ const initialSchemaConfig = (isExternalForm ? mergeSchemxConfig({ schemaConfig: pickSchemaConfig() }, formFallbackConfig).schemaConfig : mergeVueSchemxConfig({ schemaConfig: pickSchemaConfig() }, formFallbackConfig).schemaConfig) ?? {};
1447
+ const formSchemaConfig = reactive(initialSchemaConfig);
1179
1448
  createFormConfigContext({ schemaConfig: formSchemaConfig });
1180
1449
  const providedForm = props.form ? props.form : useForm({
1181
1450
  schemas: props.schemas,
1182
- schemaConfig: pickSchemaConfig(),
1451
+ schemaConfig: initialSchemaConfig,
1183
1452
  initialValues: Object.keys(props.modelValue).length > 0 ? props.modelValue : props.initialValues,
1184
1453
  rendererProps: props.rendererProps,
1185
1454
  rendererRegistry: props.rendererRegistry,
1186
1455
  defaultRendererType: props.defaultRendererType,
1187
- validationRuleRegistry: props.validationRuleRegistry,
1456
+ presetRuleRegistry: props.presetRuleRegistry,
1457
+ fieldRules: props.fieldRules,
1188
1458
  validatorAdapters: props.validatorAdapters,
1459
+ schedulerOptions: props.schedulerOptions,
1460
+ validationConcurrency: props.validationConcurrency,
1189
1461
  /**
1190
1462
  * 转发提交成功回调。
1191
1463
  *
@@ -1243,9 +1515,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1243
1515
  (_a = props.onFieldsChange) == null ? void 0 : _a.call(props, changedPaths, allPaths);
1244
1516
  }
1245
1517
  });
1246
- const isExternalForm = props.form !== void 0;
1247
1518
  const formInstance = createFormContext(providedForm);
1248
1519
  const effectiveLoading = computed(() => props.loading ?? formInstance.isLoading());
1520
+ const formRootClass = computed(() => ["schemx", props.class]);
1521
+ const formRootStyle = computed(() => props.style);
1249
1522
  const normalizeActionConfig = (action) => action === true ? {} : action || {};
1250
1523
  const submitterConfig = computed(() => normalizeActionConfig(props.submitter));
1251
1524
  const resetterConfig = computed(() => normalizeActionConfig(props.resetter));
@@ -1282,12 +1555,27 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1282
1555
  () => effectiveLoading.value || Boolean(resetterButtonProps.value.disabled)
1283
1556
  );
1284
1557
  let syncingFromModel = false;
1558
+ const internalModelEchoes = /* @__PURE__ */ new Set();
1559
+ const emitModelValue = (values) => {
1560
+ const rawValues = toRaw(values);
1561
+ internalModelEchoes.add(rawValues);
1562
+ emit("update:modelValue", values);
1563
+ void nextTick(() => {
1564
+ internalModelEchoes.delete(rawValues);
1565
+ });
1566
+ };
1285
1567
  watch(
1286
1568
  () => props.modelValue,
1287
1569
  (values) => {
1570
+ if (internalModelEchoes.delete(toRaw(values))) {
1571
+ return;
1572
+ }
1288
1573
  syncingFromModel = true;
1289
- formInstance.setFieldsValue(values);
1290
- syncingFromModel = false;
1574
+ try {
1575
+ formInstance.setFieldsValue(values);
1576
+ } finally {
1577
+ syncingFromModel = false;
1578
+ }
1291
1579
  },
1292
1580
  { deep: true }
1293
1581
  );
@@ -1301,7 +1589,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1301
1589
  (latestSnapshot) => {
1302
1590
  if (syncingFromModel)
1303
1591
  return;
1304
- emit("update:modelValue", latestSnapshot);
1592
+ emitModelValue(latestSnapshot);
1305
1593
  },
1306
1594
  { flush: "sync" }
1307
1595
  );
@@ -1315,14 +1603,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1315
1603
  { deep: false, immediate: !!props.form }
1316
1604
  );
1317
1605
  const viewSchemas = useViewSchemas(formInstance);
1318
- const getFormItemClass = (schema) => {
1606
+ const getFieldRenderKey = (schema) => `${schema.key}:${normalizeNameKey(schema.name)}`;
1607
+ const getFieldClass = (schema) => {
1319
1608
  const { isFirst, isLast } = getSectionPosition(
1320
1609
  viewSchemas.value,
1321
1610
  schema.key
1322
1611
  );
1323
1612
  return {
1324
- "schemx-item-wrapper--first": isFirst,
1325
- "schemx-item-wrapper--last": isLast
1613
+ "schemx-field-wrapper--first": isFirst,
1614
+ "schemx-field-wrapper--last": isLast
1326
1615
  };
1327
1616
  };
1328
1617
  watch(
@@ -1333,31 +1622,61 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1333
1622
  },
1334
1623
  { deep: false, immediate: isExternalForm }
1335
1624
  );
1336
- __expose({
1625
+ const exposed = {
1337
1626
  ...formInstance,
1338
1627
  submit: handleSubmit,
1339
1628
  reset: handleReset
1340
- });
1629
+ };
1630
+ __expose(exposed);
1341
1631
  return (_ctx, _cache) => {
1342
1632
  return openBlock(), createElementBlock("div", {
1343
- class: normalizeClass(["schemx", props.class]),
1344
- style: normalizeStyle(props.style)
1633
+ class: normalizeClass(formRootClass.value),
1634
+ style: normalizeStyle(formRootStyle.value)
1345
1635
  }, [
1346
1636
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(viewSchemas), (schema) => {
1347
- return openBlock(), createBlock(unref(FormItem$1), {
1348
- key: schema.key,
1349
- schema,
1350
- class: normalizeClass(getFormItemClass(schema))
1351
- }, createSlots({ _: 2 }, [
1352
- renderList(fieldSlots.value, (_, slotName) => {
1353
- return {
1354
- name: slotName,
1355
- fn: withCtx((slotProps) => [
1356
- renderSlot(_ctx.$slots, slotName, mergeProps({ ref_for: true }, slotProps ?? {}))
1357
- ])
1358
- };
1359
- })
1360
- ]), 1032, ["schema", "class"]);
1637
+ return openBlock(), createElementBlock(Fragment, {
1638
+ key: schema.key
1639
+ }, [
1640
+ unref(isViewGroupSchema)(schema) ? (openBlock(), createBlock(unref(Group$1), {
1641
+ key: 0,
1642
+ schema
1643
+ }, createSlots({ _: 2 }, [
1644
+ renderList(fieldSlots.value, (_, slotName) => {
1645
+ return {
1646
+ name: slotName,
1647
+ fn: withCtx((slotProps) => [
1648
+ renderSlot(_ctx.$slots, slotName, mergeProps({ ref_for: true }, slotProps ?? {}))
1649
+ ])
1650
+ };
1651
+ })
1652
+ ]), 1032, ["schema"])) : unref(isViewDynamicSchema)(schema) ? (openBlock(), createBlock(unref(Dynamic$1), {
1653
+ key: 1,
1654
+ schema,
1655
+ "view-schemas": unref(viewSchemas)
1656
+ }, createSlots({ _: 2 }, [
1657
+ renderList(fieldSlots.value, (_, slotName) => {
1658
+ return {
1659
+ name: slotName,
1660
+ fn: withCtx((slotProps) => [
1661
+ renderSlot(_ctx.$slots, slotName, mergeProps({ ref_for: true }, slotProps ?? {}))
1662
+ ])
1663
+ };
1664
+ })
1665
+ ]), 1032, ["schema", "view-schemas"])) : (openBlock(), createBlock(unref(Field$1), {
1666
+ key: getFieldRenderKey(schema),
1667
+ schema,
1668
+ class: normalizeClass(getFieldClass(schema))
1669
+ }, createSlots({ _: 2 }, [
1670
+ renderList(fieldSlots.value, (_, slotName) => {
1671
+ return {
1672
+ name: slotName,
1673
+ fn: withCtx((slotProps) => [
1674
+ renderSlot(_ctx.$slots, slotName, mergeProps({ ref_for: true }, slotProps ?? {}))
1675
+ ])
1676
+ };
1677
+ })
1678
+ ]), 1032, ["schema", "class"]))
1679
+ ], 64);
1361
1680
  }), 128)),
1362
1681
  isActionsVisible.value ? (openBlock(), createElementBlock("div", _hoisted_1, [
1363
1682
  isResetterVisible.value && unref(slots).resetter ? renderSlot(_ctx.$slots, "resetter", {
@@ -1407,8 +1726,8 @@ const SchemxFormExport = withInstall(_sfc_main, {
1407
1726
  provideSchemxAppConfig(app, options);
1408
1727
  app.component("SchemxForm", _sfc_main);
1409
1728
  },
1410
- /** FormItem 子组件引用 */
1411
- FormItem: FormItem$1
1729
+ /** Field 子组件引用 */
1730
+ Field: Field$1
1412
1731
  });
1413
1732
  const SchemxFormExport$1 = SchemxFormExport;
1414
1733
  function normalizeDictionary(dictionary) {
@@ -1443,16 +1762,64 @@ function WithRemoteOptions(WrappedComponent) {
1443
1762
  }
1444
1763
  });
1445
1764
  }
1765
+ const ConfigProvider = /* @__PURE__ */ defineComponent({
1766
+ name: "SchemxConfigProvider",
1767
+ inheritAttrs: false,
1768
+ props: {
1769
+ schemaConfig: {
1770
+ type: Object,
1771
+ default: void 0
1772
+ },
1773
+ rendererProps: {
1774
+ type: Object,
1775
+ default: void 0
1776
+ },
1777
+ validatorAdapters: {
1778
+ type: Array,
1779
+ default: void 0
1780
+ },
1781
+ defaultRendererType: {
1782
+ type: String,
1783
+ default: void 0
1784
+ },
1785
+ rendererRegistry: {
1786
+ type: Object,
1787
+ default: void 0
1788
+ },
1789
+ presetRuleRegistry: {
1790
+ type: Object,
1791
+ default: void 0
1792
+ }
1793
+ },
1794
+ setup(props, {
1795
+ slots
1796
+ }) {
1797
+ const config = computed(() => ({
1798
+ schemaConfig: props.schemaConfig,
1799
+ rendererProps: props.rendererProps,
1800
+ validatorAdapters: props.validatorAdapters,
1801
+ defaultRendererType: props.defaultRendererType,
1802
+ rendererRegistry: props.rendererRegistry,
1803
+ presetRuleRegistry: props.presetRuleRegistry
1804
+ }));
1805
+ provideSchemxConfigProvider(config);
1806
+ return () => {
1807
+ var _a;
1808
+ return (_a = slots.default) == null ? void 0 : _a.call(slots);
1809
+ };
1810
+ }
1811
+ });
1812
+ const ConfigProvider$1 = ConfigProvider;
1446
1813
  export {
1447
- _sfc_main$1 as Button,
1448
- FormGroup$1 as FormGroup,
1449
- FormItem$1 as FormItem,
1814
+ ConfigProvider$1 as ConfigProvider,
1815
+ Field$1 as Field,
1816
+ Group$1 as Group,
1450
1817
  WithRemoteOptions,
1451
1818
  createFieldContext,
1452
1819
  createFormConfigContext,
1453
1820
  createFormContext,
1454
1821
  SchemxFormExport$1 as default,
1455
- getCoreForm,
1822
+ presetRuleRegistry,
1456
1823
  rendererRegistry,
1457
1824
  SchemxFormExport$1 as schemxForm,
1458
1825
  useDictionary,
@@ -1467,7 +1834,6 @@ export {
1467
1834
  useWatch,
1468
1835
  useWatchAll,
1469
1836
  useWatchField,
1470
- useWatchFields,
1471
- validationRuleRegistry
1837
+ useWatchFields
1472
1838
  };
1473
1839
  //# sourceMappingURL=index.mjs.map