@schemx/vue 1.0.0-next.3 → 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 (87) hide show
  1. package/README.md +282 -281
  2. package/dist/analyze.html +1 -1
  3. package/dist/bridge/fieldBridge.d.ts +5 -18
  4. package/dist/bridge/fieldBridge.d.ts.map +1 -1
  5. package/dist/bridge/formBridge.d.ts +8 -76
  6. package/dist/bridge/formBridge.d.ts.map +1 -1
  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 +9 -1
  10. package/dist/bridge/helpers.d.ts.map +1 -1
  11. package/dist/bridge/index.d.ts +7 -5
  12. package/dist/bridge/index.d.ts.map +1 -1
  13. package/dist/bridge/types.d.ts +37 -77
  14. package/dist/bridge/types.d.ts.map +1 -1
  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 +1 -1
  18. package/dist/components/Button/index.vue.d.ts.map +1 -1
  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.map +1 -1
  48. package/dist/hooks/useForm.d.ts +2 -2
  49. package/dist/hooks/useForm.d.ts.map +1 -1
  50. package/dist/hooks/useFormSelector.d.ts +4 -0
  51. package/dist/hooks/useFormSelector.d.ts.map +1 -1
  52. package/dist/hooks/useViewSchemas.d.ts +2 -34
  53. package/dist/hooks/useViewSchemas.d.ts.map +1 -1
  54. package/dist/hooks/useWatch.d.ts.map +1 -1
  55. package/dist/index.cjs +1 -1
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.ts +5 -4
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.mjs +863 -505
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/style.css +1 -1
  62. package/dist/types/dictionary.d.ts +1 -1
  63. package/dist/types/dictionary.d.ts.map +1 -1
  64. package/dist/types/field.d.ts +38 -2
  65. package/dist/types/field.d.ts.map +1 -1
  66. package/dist/types/form.d.ts +11 -7
  67. package/dist/types/form.d.ts.map +1 -1
  68. package/dist/types/index.d.ts +4 -4
  69. package/dist/types/index.d.ts.map +1 -1
  70. package/dist/utils/helpers.d.ts +4 -0
  71. package/dist/utils/helpers.d.ts.map +1 -1
  72. package/dist/utils/index.d.ts +2 -0
  73. package/dist/utils/index.d.ts.map +1 -1
  74. package/dist/utils/presetRuleProvider.d.ts +16 -0
  75. package/dist/utils/presetRuleProvider.d.ts.map +1 -0
  76. package/dist/utils/rendererProvider.d.ts.map +1 -1
  77. package/package.json +3 -3
  78. package/dist/bridge/formFacade.d.ts +0 -65
  79. package/dist/bridge/formFacade.d.ts.map +0 -1
  80. package/dist/components/FormGroup/index.d.ts +0 -16
  81. package/dist/components/FormGroup/index.d.ts.map +0 -1
  82. package/dist/components/FormItem/index.d.ts +0 -22
  83. package/dist/components/FormItem/index.d.ts.map +0 -1
  84. package/dist/components/FormItem/slot.d.ts +0 -48
  85. package/dist/components/FormItem/slot.d.ts.map +0 -1
  86. package/dist/utils/rulesProvider.d.ts +0 -16
  87. package/dist/utils/rulesProvider.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./style.css";
2
- import { shallowRef, getCurrentInstance, inject, 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
6
  import { createFormStateAdapter, createRendererRegistry } from "@schemx/core/adapter";
@@ -8,14 +8,21 @@ import { pick } from "es-toolkit";
8
8
  function createVueShallowRef(value) {
9
9
  return shallowRef(value);
10
10
  }
11
+ function bindSnapshotSource(source) {
12
+ const value = createVueShallowRef(source.getSnapshot());
13
+ source.subscribe(() => {
14
+ value.value = source.getSnapshot();
15
+ });
16
+ return value;
17
+ }
11
18
  function areStringListsEqual(previous, next) {
12
19
  return previous.length === next.length && previous.every((value, index) => value === next[index]);
13
20
  }
14
- function getVueFieldBridge(bridge, name) {
15
- const source = bridge.stateAdapter.field(name);
16
- const cachedBridge = bridge.fieldBridges.get(source);
17
- if (cachedBridge) {
18
- 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;
19
26
  }
20
27
  const snapshot = source.getSnapshot();
21
28
  const value = createVueShallowRef(
@@ -24,7 +31,7 @@ function getVueFieldBridge(bridge, name) {
24
31
  const errors = createVueShallowRef(snapshot.errors);
25
32
  const touched = createVueShallowRef(snapshot.touched);
26
33
  const pending = createVueShallowRef(snapshot.pending);
27
- const updateFieldRefs = () => {
34
+ const updateFieldState = () => {
28
35
  const nextSnapshot = source.getSnapshot();
29
36
  if (!Object.is(value.value, nextSnapshot.value)) {
30
37
  value.value = nextSnapshot.value;
@@ -39,82 +46,63 @@ function getVueFieldBridge(bridge, name) {
39
46
  pending.value = nextSnapshot.pending;
40
47
  }
41
48
  };
42
- const unsubscribe = source.subscribe(updateFieldRefs);
43
- const dispose = () => {
44
- unsubscribe();
45
- };
46
- const fieldBridge = {
47
- source,
49
+ source.subscribe(updateFieldState);
50
+ const fieldState = {
48
51
  value,
49
52
  errors,
50
53
  touched,
51
- pending,
52
- dispose
54
+ pending
53
55
  };
54
- bridge.fieldBridges.set(source, fieldBridge);
55
- return fieldBridge;
56
+ resources.fieldStates.set(source, fieldState);
57
+ return fieldState;
56
58
  }
57
- function createVueFormFacade(form, dependencies) {
59
+ function createVueFormInstance(form, dependencies) {
58
60
  let destroyed = false;
59
61
  const getFieldValue = (name) => {
60
62
  if (!destroyed) {
61
- const bridge = dependencies.getFormBridge(form);
62
- void dependencies.getFieldBridge(bridge, name).value.value;
63
+ dependencies.trackField(name, "value");
63
64
  }
64
65
  return form.getFieldValue(name);
65
66
  };
66
67
  const getFieldErrors = (name) => {
67
68
  if (!destroyed) {
68
- const bridge = dependencies.getFormBridge(form);
69
- void dependencies.getFieldBridge(bridge, name).errors.value;
69
+ dependencies.trackField(name, "errors");
70
70
  }
71
71
  return form.getFieldErrors(name);
72
72
  };
73
73
  const isFieldTouched = (name) => {
74
74
  if (!destroyed) {
75
- const bridge = dependencies.getFormBridge(form);
76
- void dependencies.getFieldBridge(bridge, name).touched.value;
75
+ dependencies.trackField(name, "touched");
77
76
  }
78
77
  return form.isFieldTouched(name);
79
78
  };
80
79
  const isFieldPending = (name) => {
81
80
  if (!destroyed) {
82
- const bridge = dependencies.getFormBridge(form);
83
- void dependencies.getFieldBridge(bridge, name).pending.value;
81
+ dependencies.trackField(name, "pending");
84
82
  }
85
83
  return form.isFieldPending(name);
86
84
  };
87
85
  const getFieldsValue = (names) => {
88
86
  if (!destroyed) {
89
- const bridge = dependencies.getFormBridge(form);
90
- if (names === void 0) {
91
- void bridge.values.value;
92
- } else {
93
- for (const name of names) {
94
- void dependencies.getFieldBridge(bridge, name).value.value;
95
- }
96
- }
87
+ dependencies.trackFieldsValue(names);
97
88
  }
98
89
  return form.getFieldsValue(names);
99
90
  };
100
91
  const getTouchedFields = () => {
101
92
  if (!destroyed) {
102
- const bridge = dependencies.getFormBridge(form);
103
- void bridge.touchedFields.value;
93
+ dependencies.trackForm("touchedFields");
104
94
  }
105
95
  return form.getTouchedFields();
106
96
  };
107
97
  const getPendingFields = () => {
108
98
  if (!destroyed) {
109
- const bridge = dependencies.getFormBridge(form);
110
- void bridge.pendingFields.value;
99
+ dependencies.trackForm("pendingFields");
111
100
  }
112
101
  return form.getPendingFields();
113
102
  };
114
103
  const isLoading = () => {
115
104
  if (!destroyed) {
116
- const bridge = dependencies.getFormBridge(form);
117
- void bridge.loading.value;
105
+ dependencies.trackForm("loading");
118
106
  }
119
107
  return form.isLoading();
120
108
  };
@@ -123,10 +111,7 @@ function createVueFormFacade(form, dependencies) {
123
111
  return;
124
112
  }
125
113
  destroyed = true;
126
- const bridge = dependencies.getCachedFormBridge(form);
127
- if (bridge) {
128
- dependencies.disposeFormBridge(bridge);
129
- }
114
+ dependencies.destroy();
130
115
  form.destroy();
131
116
  };
132
117
  return {
@@ -142,122 +127,213 @@ function createVueFormFacade(form, dependencies) {
142
127
  destroy
143
128
  };
144
129
  }
145
- const formBridgeCache = /* @__PURE__ */ new WeakMap();
146
- const formFacadeCache = /* @__PURE__ */ new WeakMap();
147
- const facadeCoreFormCache = /* @__PURE__ */ new WeakMap();
148
- function getCoreForm(form) {
149
- const coreForm = facadeCoreFormCache.get(form);
150
- return coreForm ?? form;
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;
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
+ };
151
180
  }
152
- function getVueFormBridge(form) {
153
- const coreForm = getCoreForm(form);
154
- const cachedBridge = formBridgeCache.get(coreForm);
155
- if (cachedBridge) {
156
- return cachedBridge;
181
+ function getOrCreateVueFormRuntime(form) {
182
+ const cachedByInstance = instanceRuntimeCache.get(form);
183
+ if (cachedByInstance) {
184
+ return cachedByInstance;
157
185
  }
158
- const bridge = createVueFormBridge(coreForm);
159
- formBridgeCache.set(coreForm, bridge);
160
- return bridge;
161
- }
162
- function getVueFormFacade(form) {
163
- const coreForm = getCoreForm(form);
164
- const cachedFacade = formFacadeCache.get(coreForm);
165
- if (cachedFacade) {
166
- return cachedFacade;
186
+ const cachedByCore = runtimeCache.get(form);
187
+ if (cachedByCore) {
188
+ return cachedByCore;
167
189
  }
168
- const facade = createVueFormFacade(coreForm, {
169
- getFormBridge: (bridgeForm) => getVueFormBridge(bridgeForm),
170
- getFieldBridge: (bridge, name) => getVueFieldBridge(bridge, name),
171
- getCachedFormBridge: (bridgeForm) => {
172
- const bridge = formBridgeCache.get(bridgeForm);
173
- return bridge;
174
- },
175
- disposeFormBridge: (bridge) => disposeVueFormBridge(bridge)
176
- });
177
- formFacadeCache.set(coreForm, facade);
178
- facadeCoreFormCache.set(facade, coreForm);
179
- return facade;
190
+ const runtime = createVueFormRuntime(form);
191
+ runtimeCache.set(form, runtime);
192
+ instanceRuntimeCache.set(runtime.instance, runtime);
193
+ return runtime;
180
194
  }
181
- function retainVueFormBridge(bridge) {
182
- if (bridge.destroyed) {
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;
183
250
  return () => {
251
+ if (released || destroyed) {
252
+ return;
253
+ }
254
+ released = true;
255
+ ownerCount--;
256
+ if (ownerCount === 0) {
257
+ disposeResources();
258
+ }
184
259
  };
185
- }
186
- bridge.refCount++;
187
- let released = false;
188
- return () => {
189
- if (released || bridge.destroyed) {
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;
190
274
  return;
191
275
  }
192
- released = true;
193
- bridge.refCount--;
194
- if (bridge.refCount === 0) {
195
- disposeVueFormBridge(bridge);
276
+ for (const name of names) {
277
+ void getVueFieldState(resources, name).value.value;
196
278
  }
197
279
  };
198
- }
199
- function disposeVueFormBridge(bridge) {
200
- if (bridge.destroyed) {
201
- return;
202
- }
203
- bridge.destroyed = true;
204
- bridge.refCount = 0;
205
- bridge.unsubscribe();
206
- for (const fieldBridge of bridge.fieldBridges.values()) {
207
- fieldBridge.dispose();
208
- }
209
- bridge.fieldBridges.clear();
210
- bridge.stateAdapter.dispose();
211
- formBridgeCache.delete(bridge.form);
212
- }
213
- function createVueFormBridge(form) {
214
- const stateAdapter = createFormStateAdapter(form);
215
- const values = createVueShallowRef(stateAdapter.values.getSnapshot());
216
- const touchedFields = createVueShallowRef(
217
- stateAdapter.touchedFields.getSnapshot()
218
- );
219
- const pendingFields = createVueShallowRef(
220
- stateAdapter.pendingFields.getSnapshot()
221
- );
222
- const loading = createVueShallowRef(stateAdapter.loading.getSnapshot());
223
- const fieldBridges = /* @__PURE__ */ new Map();
224
- const syncValues = () => {
225
- values.value = stateAdapter.values.getSnapshot();
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
+ }
226
298
  };
227
- const syncTouchedFields = () => {
228
- touchedFields.value = stateAdapter.touchedFields.getSnapshot();
299
+ const getValuesRef = () => {
300
+ return ensureResources().values;
229
301
  };
230
- const syncPendingFields = () => {
231
- pendingFields.value = stateAdapter.pendingFields.getSnapshot();
302
+ const getFieldState = (name) => {
303
+ return getVueFieldState(ensureResources(), name);
232
304
  };
233
- const syncLoading = () => {
234
- loading.value = stateAdapter.loading.getSnapshot();
305
+ const getViewSchemaState = () => {
306
+ const currentResources = ensureResources();
307
+ const viewSchemaState = currentResources.viewSchemaState ?? (currentResources.viewSchemaState = createVueViewSchemaState(core));
308
+ return viewSchemaState;
235
309
  };
236
- const unsubscribeValues = stateAdapter.values.subscribe(syncValues);
237
- const unsubscribeTouchedFields = stateAdapter.touchedFields.subscribe(syncTouchedFields);
238
- const unsubscribePendingFields = stateAdapter.pendingFields.subscribe(syncPendingFields);
239
- const unsubscribeLoading = stateAdapter.loading.subscribe(syncLoading);
240
- const unsubscribe = () => {
241
- unsubscribeValues();
242
- unsubscribeTouchedFields();
243
- unsubscribePendingFields();
244
- unsubscribeLoading();
310
+ const destroy = () => {
311
+ if (destroyed) {
312
+ return;
313
+ }
314
+ destroyed = true;
315
+ ownerCount = 0;
316
+ disposeResources();
245
317
  };
246
- const facade = getVueFormFacade(form);
247
- const bridge = {
248
- form,
249
- stateAdapter,
250
- values,
251
- touchedFields,
252
- pendingFields,
253
- loading,
254
- fieldBridges,
255
- refCount: 0,
256
- destroyed: false,
257
- unsubscribe,
258
- facade
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
259
335
  };
260
- return bridge;
336
+ return runtime;
261
337
  }
262
338
  const SCHEMX_APP_CONFIG_KEY = Symbol("schemx:app-config");
263
339
  const EMPTY_SCHEMX_CONFIG = Object.freeze({
@@ -273,7 +349,7 @@ function normalizeSchemxAppConfig(config) {
273
349
  validatorAdapters,
274
350
  defaultRendererType: config.defaultRendererType,
275
351
  rendererRegistry: config.rendererRegistry,
276
- validationRuleRegistry: config.validationRuleRegistry
352
+ presetRuleRegistry: config.presetRuleRegistry
277
353
  });
278
354
  }
279
355
  function normalizeRendererProps(source) {
@@ -295,27 +371,49 @@ function getSchemxAppConfig() {
295
371
  }
296
372
  return inject(SCHEMX_APP_CONFIG_KEY, EMPTY_SCHEMX_CONFIG);
297
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();
298
392
  const rendererRegistry = createRendererRegistry("input");
299
- const validationRuleRegistry = createValidationRuleRegistry();
300
- function useForm(options = {}) {
301
- const configuredOptions = mergeSchemxConfig(
302
- getUseFormSchemxConfig(options),
303
- // App 安装配置以 Values 存储;在 useForm 边界关联到当前 TValues。
393
+ function mergeVueSchemxConfig(localConfig, fallbackConfig = {}) {
394
+ const providerConfig = getSchemxConfigProvider();
395
+ return mergeSchemxConfig(
396
+ localConfig,
397
+ providerConfig ?? {},
304
398
  getSchemxAppConfig(),
399
+ fallbackConfig,
305
400
  {
306
401
  rendererRegistry,
307
- validationRuleRegistry
402
+ presetRuleRegistry
308
403
  }
309
404
  );
405
+ }
406
+ function useForm(options = {}) {
407
+ const configuredOptions = mergeVueSchemxConfig(getUseFormSchemxConfig(options));
310
408
  const mergedOptions = {
311
409
  ...options,
312
410
  ...configuredOptions
313
411
  };
314
412
  const instance = createForm(mergedOptions);
315
- const form = getVueFormFacade(instance);
316
- const releaseBridge = retainVueFormBridge(getVueFormBridge(instance));
413
+ const acquired = acquireVueFormRuntime(instance);
414
+ const form = acquired.runtime.instance;
317
415
  onScopeDispose(() => {
318
- releaseBridge();
416
+ acquired.release();
319
417
  form.destroy();
320
418
  });
321
419
  return form;
@@ -327,24 +425,32 @@ function getUseFormSchemxConfig(options) {
327
425
  validatorAdapters = [],
328
426
  defaultRendererType = void 0,
329
427
  rendererRegistry: rendererRegistry2 = void 0,
330
- validationRuleRegistry: validationRuleRegistry2 = void 0
428
+ presetRuleRegistry: presetRuleRegistry2 = void 0
331
429
  } = options;
332
430
  return {
333
431
  schemaConfig,
334
432
  rendererProps,
335
433
  defaultRendererType,
336
434
  rendererRegistry: rendererRegistry2,
337
- validationRuleRegistry: validationRuleRegistry2,
435
+ presetRuleRegistry: presetRuleRegistry2,
338
436
  validatorAdapters
339
437
  };
340
438
  }
341
- 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
+ );
342
445
  function createFormContext(instance) {
343
- const form = getVueFormFacade(instance);
344
- const releaseBridge = retainVueFormBridge(getVueFormBridge(form));
345
- provide(SCHEMX_FORM_INSTANCE_KEY, form);
346
- onScopeDispose(releaseBridge);
347
- 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;
348
454
  }
349
455
  function useFormContext() {
350
456
  const instance = inject(SCHEMX_FORM_INSTANCE_KEY, null);
@@ -355,21 +461,30 @@ function useFormContext() {
355
461
  }
356
462
  return instance;
357
463
  }
358
- function createFieldHook(form, name, fieldBridge) {
359
- 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) {
360
475
  const coreField = createField(coreForm, name);
361
- const errors = computed(() => fieldBridge.errors.value);
362
- const dirty = computed(() => fieldBridge.touched.value);
363
- const pending = computed(() => fieldBridge.pending.value);
364
- const getValue = () => fieldBridge.value.value;
365
- const getErrors = () => fieldBridge.errors.value;
366
- const isTouched = () => fieldBridge.touched.value;
367
- 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;
368
483
  const getValues = () => form.getFieldsValue();
369
484
  return {
370
485
  ...coreField,
371
486
  name,
372
- value: fieldBridge.value,
487
+ value: fieldState.value,
373
488
  errors,
374
489
  dirty,
375
490
  pending,
@@ -382,10 +497,9 @@ function createFieldHook(form, name, fieldBridge) {
382
497
  }
383
498
  const useField = (name) => {
384
499
  const form = useFormContext();
385
- const coreForm = getCoreForm(form);
386
- const formBridge = getVueFormBridge(coreForm);
387
- const fieldBridge = getVueFieldBridge(formBridge, name);
388
- return createFieldHook(form, name, fieldBridge);
500
+ const runtime = useFormRuntimeContext();
501
+ const fieldState = runtime.getFieldState(name);
502
+ return createFieldHook(form, runtime.core, name, fieldState);
389
503
  };
390
504
  const SCHEMX_FORM_FIELD_KEY = Symbol(
391
505
  "schemx:field"
@@ -403,9 +517,9 @@ function useFieldContext() {
403
517
  return field;
404
518
  }
405
519
  function useWatch(nameOrNamesOrCallback, callbackOrOptions, maybeOptions) {
406
- const form = useFormContext();
520
+ const runtime = useFormRuntimeContext();
407
521
  const dispose = createWatch(
408
- getCoreForm(form),
522
+ runtime.core,
409
523
  nameOrNamesOrCallback,
410
524
  callbackOrOptions,
411
525
  maybeOptions
@@ -434,6 +548,7 @@ const useDictionary = (options, fieldName) => {
434
548
  const loading = ref(false);
435
549
  const error = ref(void 0);
436
550
  let requestCount = 0;
551
+ let activeController = null;
437
552
  const format = async (res) => {
438
553
  if (typeof (options == null ? void 0 : options.formatter) === "function") {
439
554
  return await options.formatter(res, instance);
@@ -445,25 +560,32 @@ const useDictionary = (options, fieldName) => {
445
560
  }
446
561
  return res;
447
562
  };
448
- const executeWithRetry = async (formValues) => {
563
+ const executeWithRetry = async (formValues, signal) => {
449
564
  const maxRetries = options.retryCount ?? 0;
450
565
  const retryDelay = options.retryInterval ?? 1e3;
451
566
  let lastError = new Error("Unknown error");
452
567
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
453
568
  try {
454
- 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);
455
573
  } catch (err) {
456
574
  lastError = normalizeError(err);
457
575
  if (attempt < maxRetries) {
458
- await new Promise((r) => setTimeout(r, retryDelay));
576
+ await waitForRetry(retryDelay, signal);
459
577
  }
460
578
  }
461
579
  }
462
580
  throw lastError;
463
581
  };
464
582
  const loadDict = async () => {
583
+ const currentCount = ++requestCount;
584
+ activeController == null ? void 0 : activeController.abort();
585
+ const controller = new AbortController();
586
+ activeController = controller;
465
587
  try {
466
- const formValues = instance.getFieldsValue();
588
+ const formValues = instance.getFieldsSnapshot();
467
589
  if (typeof options.shouldFetch === "function" && !options.shouldFetch(formValues)) {
468
590
  list.value = [];
469
591
  loading.value = false;
@@ -471,12 +593,11 @@ const useDictionary = (options, fieldName) => {
471
593
  }
472
594
  loading.value = true;
473
595
  error.value = void 0;
474
- const currentCount = ++requestCount;
475
- const res = await executeWithRetry(formValues);
476
- if (currentCount !== requestCount)
596
+ const res = await executeWithRetry(formValues, controller.signal);
597
+ if (currentCount !== requestCount || controller.signal.aborted)
477
598
  return;
478
599
  const formatted = await format(res);
479
- if (currentCount !== requestCount)
600
+ if (currentCount !== requestCount || controller.signal.aborted)
480
601
  return;
481
602
  list.value = formatted;
482
603
  error.value = void 0;
@@ -485,6 +606,9 @@ const useDictionary = (options, fieldName) => {
485
606
  }
486
607
  loading.value = false;
487
608
  } catch (err) {
609
+ if (controller.signal.aborted || currentCount !== requestCount) {
610
+ return;
611
+ }
488
612
  const normalized = normalizeError(err);
489
613
  error.value = normalized;
490
614
  list.value = [];
@@ -492,6 +616,10 @@ const useDictionary = (options, fieldName) => {
492
616
  if (typeof options.onError === "function") {
493
617
  options.onError(normalized, instance);
494
618
  }
619
+ } finally {
620
+ if (activeController === controller) {
621
+ activeController = null;
622
+ }
495
623
  }
496
624
  };
497
625
  const refresh = () => loadDict();
@@ -499,15 +627,19 @@ const useDictionary = (options, fieldName) => {
499
627
  list.value = data;
500
628
  };
501
629
  if ((_a = options.dependsOn) == null ? void 0 : _a.length) {
502
- useWatchFields(options.dependsOn, (latestSnapshot, _payload) => {
503
- if (typeof options.onDepsChange === "function") {
504
- options.onDepsChange(latestSnapshot, instance);
505
- }
506
- if (options.resetOnDepsChange && fieldName) {
507
- instance.setFieldValue(fieldName, void 0);
508
- }
509
- void loadDict();
510
- });
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
+ );
511
643
  }
512
644
  const immediate = options.immediate ?? true;
513
645
  onMounted(() => {
@@ -515,8 +647,43 @@ const useDictionary = (options, fieldName) => {
515
647
  void loadDict();
516
648
  }
517
649
  });
650
+ onScopeDispose(() => {
651
+ requestCount += 1;
652
+ activeController == null ? void 0 : activeController.abort();
653
+ activeController = null;
654
+ });
518
655
  return { list, loading, error, loadDict, refresh, mutate };
519
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
+ }
520
687
  const SCHEMX_FORM_CONFIG_KEY = Symbol(
521
688
  "schemx:form-config"
522
689
  );
@@ -549,87 +716,37 @@ function useStableRef(factory) {
549
716
  });
550
717
  return stableRef;
551
718
  }
552
- const viewSchemaBridgeCache = /* @__PURE__ */ new WeakMap();
553
719
  function useViewSchemas(form) {
554
- const bridge = acquireViewSchemaBridge(getCoreForm(form));
555
- return bridge.viewSchemas;
720
+ const acquired = acquireVueFormRuntime(form);
721
+ const state = acquired.runtime.getViewSchemaState();
722
+ onScopeDispose(acquired.release);
723
+ return state.viewSchemas;
556
724
  }
557
725
  function useViewSchema(form, getKey) {
558
- const bridge = acquireViewSchemaBridge(getCoreForm(form));
559
- return computed(() => bridge.schemasByKey.value.get(getKey()));
560
- }
561
- function createViewSchemaBridge(form) {
562
- const viewSchemas = shallowRef(
563
- form.getViewSchemas()
564
- );
565
- const schemasByKey = computed(() => {
566
- return createViewSchemaIndex(viewSchemas.value);
567
- });
568
- const unsubscribe = form.subscribeViewSchemas(
569
- /**
570
- * 接收 Core 发布的完整列表并替换共享引用,以保留更新边界。
571
- *
572
- * @param nextSchemas - Core 计算出的最新 ViewSchema 列表。
573
- */
574
- (nextSchemas) => {
575
- viewSchemas.value = nextSchemas;
576
- }
577
- );
578
- return {
579
- refCount: 0,
580
- schemasByKey,
581
- unsubscribe,
582
- viewSchemas
583
- };
584
- }
585
- function acquireViewSchemaBridge(form) {
586
- const cachedBridge = viewSchemaBridgeCache.get(form);
587
- const bridge = cachedBridge ?? createViewSchemaBridge(form);
588
- if (!cachedBridge) {
589
- viewSchemaBridgeCache.set(form, bridge);
590
- }
591
- bridge.refCount++;
592
- onScopeDispose(() => {
593
- bridge.refCount--;
594
- if (bridge.refCount > 0) {
595
- return;
596
- }
597
- bridge.unsubscribe();
598
- viewSchemaBridgeCache.delete(form);
599
- });
600
- return bridge;
601
- }
602
- function createViewSchemaIndex(viewSchemas) {
603
- const schemasByKey = /* @__PURE__ */ new Map();
604
- const appendSchemas = (schemas) => {
605
- for (const schema of schemas) {
606
- schemasByKey.set(schema.key, schema);
607
- if (isViewGroupSchema(schema)) {
608
- appendSchemas(schema.children);
609
- }
610
- }
611
- };
612
- appendSchemas(viewSchemas);
613
- return schemasByKey;
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;
614
731
  }
615
732
  function useFormSelector(form, selector, options = {}) {
616
- const bridge = getVueFormBridge(getCoreForm(form));
617
- const releaseBridge = retainVueFormBridge(bridge);
618
- 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));
619
736
  const equals = options.equals ?? Object.is;
620
737
  const stop = watch(
621
- bridge.values,
622
- (values) => {
623
- const next = selector(values);
738
+ values,
739
+ (values2) => {
740
+ const next = selector(values2);
624
741
  if (!equals(selected.value, next)) {
625
742
  selected.value = next;
626
743
  }
627
744
  },
628
- { flush: "sync" }
745
+ { flush: options.flush ?? "sync" }
629
746
  );
630
747
  onScopeDispose(() => {
631
748
  stop();
632
- releaseBridge();
749
+ acquired.release();
633
750
  });
634
751
  return readonly(selected);
635
752
  }
@@ -703,105 +820,57 @@ const extractChildSlots = (fieldName, allSlots) => {
703
820
  }
704
821
  return result;
705
822
  };
706
- const FormGroup = /* @__PURE__ */ defineComponent((props, {
707
- slots
708
- }) => {
709
- var _a;
710
- const internalCollapsed = ref(Boolean(props.schema.defaultCollapsed));
711
- const collapsed = computed(() => props.schema.collapsed ?? internalCollapsed.value);
712
- const componentId = ((_a = getCurrentInstance()) == null ? void 0 : _a.uid) ?? 0;
713
- watch(() => props.schema.collapsed, (nextCollapsed, previousCollapsed) => {
714
- if (nextCollapsed !== void 0) {
715
- internalCollapsed.value = nextCollapsed;
716
- } else if (previousCollapsed !== void 0) {
717
- internalCollapsed.value = previousCollapsed;
718
- }
719
- });
720
- const toggle = () => {
721
- var _a2, _b;
722
- if (!props.schema.collapsible || props.schema.disabled) {
723
- return;
724
- }
725
- const nextCollapsed = !collapsed.value;
726
- if (props.schema.collapsed === void 0) {
727
- internalCollapsed.value = nextCollapsed;
728
- }
729
- (_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)
730
844
  };
731
- return () => {
732
- var _a2;
733
- const schema = props.schema;
734
- if (schema.visible === false) {
735
- 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;
736
863
  }
737
- const collapsible = Boolean(schema.collapsible);
738
- const isCollapsed = collapsed.value;
739
- const destroyOnCollapse = schema.destroyOnCollapse ?? true;
740
- const uniqueId = ((_a2 = schema.debug) == null ? void 0 : _a2.runtimeNodeId) ?? `local-${componentId}`;
741
- const idBase = `schemx-group-${uniqueId}-${normalizeId(schema.key)}`;
742
- const headerId = `${idBase}-header`;
743
- const bodyId = `${idBase}-body`;
744
- const body = createVNode("div", {
745
- "id": bodyId,
746
- "role": "group",
747
- "aria-labelledby": schema.label ? headerId : void 0,
748
- "aria-hidden": isCollapsed || void 0,
749
- "class": "schemx-group__body",
750
- "style": !destroyOnCollapse && isCollapsed ? {
751
- display: "none"
752
- } : void 0
753
- }, [schema.children.map((child) => createVNode(FormItem$1, {
754
- "key": child.key,
755
- "schema": child
756
- }, slots))]);
757
- return createVNode("div", {
758
- "class": classnames("schemx-group", {
759
- "schemx-group--collapsed": isCollapsed,
760
- "is-readonly": schema.readonly,
761
- "is-disabled": schema.disabled
762
- }, schema.class),
763
- "style": schema.style,
764
- "data-key": schema.key,
765
- "aria-disabled": schema.disabled || void 0
766
- }, [schema.label && createVNode("div", {
767
- "id": headerId,
768
- "role": collapsible ? "button" : void 0,
769
- "tabindex": collapsible ? schema.disabled ? -1 : 0 : void 0,
770
- "aria-expanded": collapsible ? !isCollapsed : void 0,
771
- "aria-controls": collapsible ? bodyId : void 0,
772
- "aria-disabled": collapsible ? schema.disabled || void 0 : void 0,
773
- "class": classnames("schemx-group__header", {
774
- "schemx-group__header--clickable": collapsible && !schema.disabled
775
- }),
776
- "onClick": toggle,
777
- "onKeydown": (e) => {
778
- if (!schema.disabled && (e.key === "Enter" || e.key === " ")) {
779
- e.preventDefault();
780
- toggle();
781
- }
782
- }
783
- }, [createVNode("span", {
784
- "class": "schemx-group__title"
785
- }, [schema.label]), collapsible && createVNode("span", {
786
- "class": classnames("schemx-group__arrow", {
787
- "schemx-group__arrow--down": !isCollapsed
788
- })
789
- }, null)]), destroyOnCollapse ? !isCollapsed && body : body]);
790
- };
791
- }, {
792
- name: "SchemxGroup",
793
- props: {
794
- schema: {
795
- type: Object,
796
- required: true
864
+ if (isViewGroupSchema(item)) {
865
+ return false;
866
+ }
867
+ if (isPositionItem(item)) {
868
+ return true;
797
869
  }
798
870
  }
799
- });
800
- const FormGroup$1 = FormGroup;
801
- const normalizeId = (key) => {
802
- return String(key).replace(/[^a-zA-Z0-9_-]/g, "-");
803
- };
804
- function createFormItemSlotRenderers(options) {
871
+ return false;
872
+ }
873
+ function createFieldSlotRenderers(options) {
805
874
  const {
806
875
  schemaRef,
807
876
  field,
@@ -816,36 +885,39 @@ function createFormItemSlotRenderers(options) {
816
885
  return null;
817
886
  }
818
887
  return createVNode("span", {
819
- "class": "schemx-item__required"
888
+ "class": "schemx-field__required"
820
889
  }, [createTextVNode("*")]);
821
890
  };
822
891
  const createSlotProps = (additionalProps = {}) => {
823
892
  return {
824
- ...componentProps.value,
893
+ schema: schemaRef.value,
894
+ componentProps: componentProps.value,
825
895
  value: field.value.value,
896
+ field,
897
+ form,
826
898
  ...additionalProps
827
899
  };
828
900
  };
829
901
  const renderFieldSlot = (suffix) => {
830
- const slot = resolveSlot(slots, `${schemaRef.value.name}${suffix}`);
902
+ const slot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}${suffix}`);
831
903
  return (slot == null ? void 0 : slot(createSlotProps())) ?? null;
832
904
  };
833
905
  const renderLabel = () => {
834
- const labelSlot = resolveSlot(slots, `${schemaRef.value.name}Label`);
906
+ const labelSlot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}Label`);
835
907
  if (labelSlot) {
836
- return labelSlot(schemaRef.value);
908
+ return labelSlot(createSlotProps());
837
909
  }
838
910
  const labelAlign = schemaRef.value.labelAlign || formContext.schemaConfig.labelAlign;
839
911
  const labelWidth = schemaRef.value.labelWidth || formContext.schemaConfig.labelWidth;
840
912
  const colon = schemaRef.value.colon ?? formContext.schemaConfig.colon;
841
913
  return createVNode("label", {
842
- "class": "schemx-item__label",
914
+ "class": "schemx-field__label",
843
915
  "style": {
844
916
  width: labelWidth,
845
917
  textAlign: labelAlign
846
918
  }
847
919
  }, [renderRequired(), createVNode("span", {
848
- "class": "schemx-item__label-text"
920
+ "class": "schemx-field__label-text"
849
921
  }, [schemaRef.value.label, colon ? ":" : ""])]);
850
922
  };
851
923
  const renderBefore = () => renderFieldSlot("Before");
@@ -856,19 +928,19 @@ function createFormItemSlotRenderers(options) {
856
928
  }
857
929
  const childSlots = extractChildSlots(normalizeNameKey(schemaRef.value.name), slots);
858
930
  const columnElement = h(component, componentProps.value, childSlots);
859
- const contentSlot = resolveSlot(slots, `${schemaRef.value.name}Content`);
931
+ const contentSlot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}Content`);
860
932
  if (contentSlot) {
861
933
  return contentSlot(createSlotProps({
862
934
  columnElement
863
935
  }));
864
936
  }
865
937
  return createVNode("div", {
866
- "class": "schemx-item__control"
938
+ "class": "schemx-field__control"
867
939
  }, [columnElement]);
868
940
  };
869
941
  const renderAfter = () => renderFieldSlot("After");
870
942
  const renderError = () => {
871
- const errorSlot = resolveSlot(slots, `${schemaRef.value.name}Error`);
943
+ const errorSlot = resolveSlot(slots, `${normalizeNameKey(schemaRef.value.name)}Error`);
872
944
  if (errorSlot) {
873
945
  return errorSlot(createSlotProps({
874
946
  errors: field.errors.value
@@ -878,7 +950,7 @@ function createFormItemSlotRenderers(options) {
878
950
  return null;
879
951
  }
880
952
  return createVNode("div", {
881
- "class": "schemx-item__error"
953
+ "class": "schemx-field__error"
882
954
  }, [field.errors.value[0]]);
883
955
  };
884
956
  return {
@@ -890,49 +962,23 @@ function createFormItemSlotRenderers(options) {
890
962
  renderLabel
891
963
  };
892
964
  }
893
- function normalizeNameKey(name) {
894
- if (Array.isArray(name)) {
895
- return name.map((part) => String(part)).join(".");
896
- }
897
- return String(name);
898
- }
899
- const FormItem = /* @__PURE__ */ defineComponent({
900
- name: "SchemxItem",
901
- props: {
902
- schema: {
903
- type: Object,
904
- required: true
905
- }
906
- },
907
- /**
908
- * 根据 schema 类型分发字段组或字段项渲染。
909
- *
910
- * @param props - 当前组件的 schema 属性。
911
- * @param slots - Vue setup 上下文提供的插槽集合。
912
- */
913
- setup(props, {
914
- slots
915
- }) {
916
- return () => {
917
- const schema = props.schema;
918
- if (isViewGroupSchema(schema)) {
919
- return h(FormGroup$1, {
920
- schema
921
- }, slots);
922
- }
923
- return h(FieldFormItem, {
924
- schema
925
- }, slots);
926
- };
927
- }
928
- });
929
- const FieldFormItem = /* @__PURE__ */ defineComponent({
930
- name: "SchemxFieldItem",
965
+ const Field = /* @__PURE__ */ defineComponent({
966
+ name: "SchemxField",
931
967
  inheritAttrs: false,
932
968
  props: {
933
969
  schema: {
934
970
  type: Object,
935
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
936
982
  }
937
983
  },
938
984
  /**
@@ -957,7 +1003,7 @@ const FieldFormItem = /* @__PURE__ */ defineComponent({
957
1003
  createFieldContext(field);
958
1004
  const trigger = computed(() => mergeTrigger(schemaRef.value.validationTrigger, formContext.schemaConfig.validationTrigger, "onChange"));
959
1005
  const canVerified = computed(() => {
960
- const isOperate = schemaRef.value.visible && !schemaRef.value.readonly && !schemaRef.value.disabled;
1006
+ const isOperate = schemaRef.value.visible !== false && !schemaRef.value.readonly && !schemaRef.value.disabled;
961
1007
  const rules = schemaRef.value.rules;
962
1008
  const hasRules = Array.isArray(rules) ? (rules == null ? void 0 : rules.length) > 0 : !!schemaRef.value.rules;
963
1009
  return isOperate && (Boolean(schemaRef.value.required) || hasRules);
@@ -997,7 +1043,7 @@ const FieldFormItem = /* @__PURE__ */ defineComponent({
997
1043
  renderContent,
998
1044
  renderError,
999
1045
  renderLabel
1000
- } = createFormItemSlotRenderers({
1046
+ } = createFieldSlotRenderers({
1001
1047
  schemaRef,
1002
1048
  field,
1003
1049
  form,
@@ -1006,32 +1052,27 @@ const FieldFormItem = /* @__PURE__ */ defineComponent({
1006
1052
  slots
1007
1053
  });
1008
1054
  return () => {
1009
- if (!schemaRef.value.visible) {
1055
+ if (schemaRef.value.visible === false) {
1010
1056
  return null;
1011
1057
  }
1012
- const itemSlot = resolveSlot(slots, normalizeNameKey(schemaRef.value.name));
1013
- if (itemSlot) {
1014
- return itemSlot(createSlotProps());
1015
- }
1058
+ const fieldSlot = resolveSlot(slots, normalizeNameKey(schemaRef.value.name));
1016
1059
  const labelPosition = schemaRef.value.labelPosition || formContext.schemaConfig.labelPosition;
1017
- return createVNode("div", mergeProps(attrs, {
1018
- "class": classnames("schemx-item-wrapper", attrs.class),
1019
- "style": [attrs.style, schemaRef.value.style]
1020
- }), [createVNode("div", {
1021
- "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}`, {
1022
1062
  "is-readonly": schemaRef.value.readonly,
1023
1063
  "is-disabled": schemaRef.value.disabled
1024
- }),
1025
- "style": {
1026
- ...schemaRef.value.style ?? {}
1027
- }
1064
+ })
1028
1065
  }, [renderLabel(), createVNode("div", {
1029
- "class": "schemx-item__content"
1030
- }, [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]);
1031
1072
  };
1032
1073
  }
1033
1074
  });
1034
- const FormItem$1 = FormItem;
1075
+ const Field$1 = Field;
1035
1076
  const _hoisted_1$1 = ["aria-busy", "data-loading", "disabled"];
1036
1077
  const _hoisted_2 = {
1037
1078
  key: 0,
@@ -1091,47 +1132,250 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1091
1132
  };
1092
1133
  }
1093
1134
  });
1094
- function getSectionPosition(list, currentKey) {
1095
- const currentIndex = list.findIndex((item) => item.key === currentKey);
1096
- if (currentIndex === -1) {
1097
- return {
1098
- found: false,
1099
- isFirst: false,
1100
- isLast: false
1101
- };
1102
- }
1103
- const currentItem = list[currentIndex];
1104
- if (!isPositionItem(currentItem)) {
1105
- return {
1106
- found: true,
1107
- isFirst: false,
1108
- isLast: false
1109
- };
1110
- }
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
+ };
1111
1180
  return {
1112
- found: true,
1113
- isFirst: !hasPositionItemInSection(list, currentIndex, -1),
1114
- isLast: !hasPositionItemInSection(list, currentIndex, 1)
1181
+ hasHeader: Boolean(schema.label || headerSlot || labelSlot),
1182
+ renderBodyContent,
1183
+ renderHeaderContent
1115
1184
  };
1116
1185
  }
1117
- function isPositionItem(item) {
1118
- return !!item && !isViewGroupSchema(item) && item.visible !== false;
1119
- }
1120
- function hasPositionItemInSection(list, startIndex, step) {
1121
- for (let index = startIndex + step; index >= 0 && index < list.length; index += step) {
1122
- const item = list[index];
1123
- if (item.visible === false) {
1124
- continue;
1125
- }
1126
- if (isViewGroupSchema(item)) {
1127
- 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
1128
1203
  }
1129
- if (isPositionItem(item)) {
1130
- 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
1131
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
+ };
1132
1376
  }
1133
- return false;
1134
- }
1377
+ });
1378
+ const Dynamic$1 = Dynamic;
1135
1379
  const _hoisted_1 = {
1136
1380
  key: 0,
1137
1381
  class: "schemx-actions"
@@ -1141,19 +1385,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1141
1385
  __name: "form",
1142
1386
  props: {
1143
1387
  schemas: { default: () => [] },
1388
+ fieldRules: { default: void 0 },
1144
1389
  initialValues: { default: () => ({}) },
1145
1390
  modelValue: { default: () => ({}) },
1146
1391
  form: { default: void 0 },
1147
1392
  loading: { type: Boolean, default: void 0 },
1148
- submitter: { type: [Boolean, Object], default: void 0 },
1149
- resetter: { type: [Boolean, Object], default: void 0 },
1150
- class: { default: "" },
1393
+ submitter: { type: [Boolean, Object], default: true },
1394
+ resetter: { type: [Boolean, Object], default: true },
1395
+ class: { type: [Boolean, null, String, Object, Array], default: "" },
1151
1396
  style: { type: [Boolean, null, String, Object, Array], default: () => ({}) },
1152
1397
  rendererProps: { default: void 0 },
1153
1398
  validatorAdapters: {},
1154
1399
  defaultRendererType: {},
1155
1400
  rendererRegistry: { default: void 0 },
1156
- validationRuleRegistry: { default: void 0 },
1401
+ presetRuleRegistry: { default: void 0 },
1157
1402
  onRuleError: {},
1158
1403
  onFinish: { type: Function, default: void 0 },
1159
1404
  onFinishFailed: { type: Function, default: void 0 },
@@ -1162,18 +1407,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1162
1407
  onValuesChange: { type: Function, default: void 0 },
1163
1408
  onFieldsChange: { type: Function, default: void 0 },
1164
1409
  lifecycleHooks: {},
1410
+ schedulerOptions: { default: void 0 },
1411
+ validationConcurrency: { default: void 0 },
1165
1412
  required: { type: [Boolean, Object] },
1166
- readonly: { type: Boolean },
1167
- disabled: { type: Boolean },
1168
- 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 },
1169
1416
  labelIcon: {},
1170
1417
  labelAlign: {},
1171
1418
  labelPosition: {},
1172
1419
  labelWidth: {},
1173
1420
  contentAlign: {},
1174
- validationTrigger: {},
1175
- colon: { type: Boolean },
1176
- showRequiredMark: { type: Boolean }
1421
+ validationTrigger: { default: void 0 },
1422
+ colon: { type: Boolean, default: void 0 },
1423
+ showRequiredMark: { type: Boolean, default: void 0 }
1177
1424
  },
1178
1425
  emits: ["update:modelValue"],
1179
1426
  setup(__props, { expose: __expose, emit: __emit }) {
@@ -1181,19 +1428,36 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1181
1428
  const emit = __emit;
1182
1429
  const slots = useSlots();
1183
1430
  const pickSchemaConfig = () => {
1184
- 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
+ );
1185
1438
  };
1186
- const formSchemaConfig = reactive(pickSchemaConfig());
1439
+ const isExternalForm = props.form !== void 0;
1440
+ const formFallbackConfig = {
1441
+ schemaConfig: {
1442
+ visible: true,
1443
+ validationTrigger: ["blur", "change"]
1444
+ }
1445
+ };
1446
+ const initialSchemaConfig = (isExternalForm ? mergeSchemxConfig({ schemaConfig: pickSchemaConfig() }, formFallbackConfig).schemaConfig : mergeVueSchemxConfig({ schemaConfig: pickSchemaConfig() }, formFallbackConfig).schemaConfig) ?? {};
1447
+ const formSchemaConfig = reactive(initialSchemaConfig);
1187
1448
  createFormConfigContext({ schemaConfig: formSchemaConfig });
1188
1449
  const providedForm = props.form ? props.form : useForm({
1189
1450
  schemas: props.schemas,
1190
- schemaConfig: pickSchemaConfig(),
1451
+ schemaConfig: initialSchemaConfig,
1191
1452
  initialValues: Object.keys(props.modelValue).length > 0 ? props.modelValue : props.initialValues,
1192
1453
  rendererProps: props.rendererProps,
1193
1454
  rendererRegistry: props.rendererRegistry,
1194
1455
  defaultRendererType: props.defaultRendererType,
1195
- validationRuleRegistry: props.validationRuleRegistry,
1456
+ presetRuleRegistry: props.presetRuleRegistry,
1457
+ fieldRules: props.fieldRules,
1196
1458
  validatorAdapters: props.validatorAdapters,
1459
+ schedulerOptions: props.schedulerOptions,
1460
+ validationConcurrency: props.validationConcurrency,
1197
1461
  /**
1198
1462
  * 转发提交成功回调。
1199
1463
  *
@@ -1251,9 +1515,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1251
1515
  (_a = props.onFieldsChange) == null ? void 0 : _a.call(props, changedPaths, allPaths);
1252
1516
  }
1253
1517
  });
1254
- const isExternalForm = props.form !== void 0;
1255
1518
  const formInstance = createFormContext(providedForm);
1256
1519
  const effectiveLoading = computed(() => props.loading ?? formInstance.isLoading());
1520
+ const formRootClass = computed(() => ["schemx", props.class]);
1521
+ const formRootStyle = computed(() => props.style);
1257
1522
  const normalizeActionConfig = (action) => action === true ? {} : action || {};
1258
1523
  const submitterConfig = computed(() => normalizeActionConfig(props.submitter));
1259
1524
  const resetterConfig = computed(() => normalizeActionConfig(props.resetter));
@@ -1290,12 +1555,27 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1290
1555
  () => effectiveLoading.value || Boolean(resetterButtonProps.value.disabled)
1291
1556
  );
1292
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
+ };
1293
1567
  watch(
1294
1568
  () => props.modelValue,
1295
1569
  (values) => {
1570
+ if (internalModelEchoes.delete(toRaw(values))) {
1571
+ return;
1572
+ }
1296
1573
  syncingFromModel = true;
1297
- formInstance.setFieldsValue(values);
1298
- syncingFromModel = false;
1574
+ try {
1575
+ formInstance.setFieldsValue(values);
1576
+ } finally {
1577
+ syncingFromModel = false;
1578
+ }
1299
1579
  },
1300
1580
  { deep: true }
1301
1581
  );
@@ -1309,7 +1589,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1309
1589
  (latestSnapshot) => {
1310
1590
  if (syncingFromModel)
1311
1591
  return;
1312
- emit("update:modelValue", latestSnapshot);
1592
+ emitModelValue(latestSnapshot);
1313
1593
  },
1314
1594
  { flush: "sync" }
1315
1595
  );
@@ -1323,14 +1603,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1323
1603
  { deep: false, immediate: !!props.form }
1324
1604
  );
1325
1605
  const viewSchemas = useViewSchemas(formInstance);
1326
- const getFormItemClass = (schema) => {
1606
+ const getFieldRenderKey = (schema) => `${schema.key}:${normalizeNameKey(schema.name)}`;
1607
+ const getFieldClass = (schema) => {
1327
1608
  const { isFirst, isLast } = getSectionPosition(
1328
1609
  viewSchemas.value,
1329
1610
  schema.key
1330
1611
  );
1331
1612
  return {
1332
- "schemx-item-wrapper--first": isFirst,
1333
- "schemx-item-wrapper--last": isLast
1613
+ "schemx-field-wrapper--first": isFirst,
1614
+ "schemx-field-wrapper--last": isLast
1334
1615
  };
1335
1616
  };
1336
1617
  watch(
@@ -1349,24 +1630,53 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1349
1630
  __expose(exposed);
1350
1631
  return (_ctx, _cache) => {
1351
1632
  return openBlock(), createElementBlock("div", {
1352
- class: normalizeClass(["schemx", props.class]),
1353
- style: normalizeStyle(props.style)
1633
+ class: normalizeClass(formRootClass.value),
1634
+ style: normalizeStyle(formRootStyle.value)
1354
1635
  }, [
1355
1636
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(viewSchemas), (schema) => {
1356
- return openBlock(), createBlock(unref(FormItem$1), {
1357
- key: schema.key,
1358
- schema,
1359
- class: normalizeClass(getFormItemClass(schema))
1360
- }, createSlots({ _: 2 }, [
1361
- renderList(fieldSlots.value, (_, slotName) => {
1362
- return {
1363
- name: slotName,
1364
- fn: withCtx((slotProps) => [
1365
- renderSlot(_ctx.$slots, slotName, mergeProps({ ref_for: true }, slotProps ?? {}))
1366
- ])
1367
- };
1368
- })
1369
- ]), 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);
1370
1680
  }), 128)),
1371
1681
  isActionsVisible.value ? (openBlock(), createElementBlock("div", _hoisted_1, [
1372
1682
  isResetterVisible.value && unref(slots).resetter ? renderSlot(_ctx.$slots, "resetter", {
@@ -1416,8 +1726,8 @@ const SchemxFormExport = withInstall(_sfc_main, {
1416
1726
  provideSchemxAppConfig(app, options);
1417
1727
  app.component("SchemxForm", _sfc_main);
1418
1728
  },
1419
- /** FormItem 子组件引用 */
1420
- FormItem: FormItem$1
1729
+ /** Field 子组件引用 */
1730
+ Field: Field$1
1421
1731
  });
1422
1732
  const SchemxFormExport$1 = SchemxFormExport;
1423
1733
  function normalizeDictionary(dictionary) {
@@ -1452,15 +1762,64 @@ function WithRemoteOptions(WrappedComponent) {
1452
1762
  }
1453
1763
  });
1454
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;
1455
1813
  export {
1456
- FormGroup$1 as FormGroup,
1457
- FormItem$1 as FormItem,
1814
+ ConfigProvider$1 as ConfigProvider,
1815
+ Field$1 as Field,
1816
+ Group$1 as Group,
1458
1817
  WithRemoteOptions,
1459
1818
  createFieldContext,
1460
1819
  createFormConfigContext,
1461
1820
  createFormContext,
1462
1821
  SchemxFormExport$1 as default,
1463
- getCoreForm,
1822
+ presetRuleRegistry,
1464
1823
  rendererRegistry,
1465
1824
  SchemxFormExport$1 as schemxForm,
1466
1825
  useDictionary,
@@ -1475,7 +1834,6 @@ export {
1475
1834
  useWatch,
1476
1835
  useWatchAll,
1477
1836
  useWatchField,
1478
- useWatchFields,
1479
- validationRuleRegistry
1837
+ useWatchFields
1480
1838
  };
1481
1839
  //# sourceMappingURL=index.mjs.map