@formality-ui/react 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -149,6 +149,7 @@ function Form({
149
149
  record,
150
150
  autoSave = false,
151
151
  debounce: debounceMs = 1e3,
152
+ mode,
152
153
  validate
153
154
  }) {
154
155
  const providerConfig = useConfigContext();
@@ -163,12 +164,18 @@ function Form({
163
164
  return result;
164
165
  }, [providerConfig.inputs, formConfig.inputs]);
165
166
  const defaultValues = react.useMemo(() => {
166
- return core.resolveAllInitialValues(config, mergedInputs, record ?? {});
167
+ const resolved = core.resolveAllInitialValues(config, mergedInputs, record ?? {});
168
+ const baseline = { ...record ?? {}, ...resolved };
169
+ for (const fieldName of Object.keys(config)) {
170
+ if (!(fieldName in baseline)) baseline[fieldName] = void 0;
171
+ }
172
+ return baseline;
167
173
  }, [config, mergedInputs, record]);
168
174
  const methods = reactHookForm.useForm({
169
- mode: "onChange",
175
+ mode: mode ?? "onChange",
170
176
  defaultValues,
171
- values: record
177
+ values: defaultValues
178
+ // was: `record as any` — see baseline comment above
172
179
  });
173
180
  const fieldRegistry = react.useRef(/* @__PURE__ */ new Set());
174
181
  const [registeredFields, setRegisteredFields] = react.useState(
@@ -334,8 +341,10 @@ function Form({
334
341
  }, [methods, config, record, defaultValues]);
335
342
  const handleSubmit = react.useCallback(
336
343
  async (values, overrideOnSubmit) => {
337
- for (const [, isValidating] of validatingFields.current) {
338
- if (isValidating) return;
344
+ for (const [fieldName, isValidating] of validatingFields.current) {
345
+ if (!isValidating) continue;
346
+ const subscribers = invertedSubscriptions.current.get(fieldName);
347
+ if (subscribers && subscribers.size > 0) return;
339
348
  }
340
349
  if (validate) {
341
350
  const errors = await validate(values);
@@ -406,9 +415,20 @@ function Form({
406
415
  if (!validationsComplete || executionVersionRef.current !== executionVersion) {
407
416
  return;
408
417
  }
409
- for (const fieldName of changedFields) {
410
- const fieldState = methods.getFieldState(fieldName);
411
- if (fieldState.error) {
418
+ const changedArray = [...changedFields];
419
+ if (changedArray.length > 0) {
420
+ const changedValid = await methods.trigger(changedArray);
421
+ if (executionVersionRef.current !== executionVersion) {
422
+ return;
423
+ }
424
+ if (!changedValid) {
425
+ return;
426
+ }
427
+ const changedValidationsComplete = await waitForFieldValidation(
428
+ changedArray,
429
+ executionVersion
430
+ );
431
+ if (!changedValidationsComplete || executionVersionRef.current !== executionVersion) {
412
432
  return;
413
433
  }
414
434
  }
@@ -922,13 +942,12 @@ function useSubscriptions(fieldName, subscriptions) {
922
942
  };
923
943
  }, [fieldName, subscriptions, addSubscription, removeSubscription]);
924
944
  }
925
- function Field({
945
+ function useField({
926
946
  name,
927
947
  type: typeProp,
928
948
  disabled: disabledProp,
929
949
  hidden: hiddenProp,
930
950
  children,
931
- shouldRegister = true,
932
951
  inputConfig: inputConfigProp,
933
952
  ...restProps
934
953
  }) {
@@ -936,8 +955,6 @@ function Field({
936
955
  config,
937
956
  formConfig,
938
957
  methods,
939
- registerField,
940
- unregisterField,
941
958
  registerWatcherSetter,
942
959
  unregisterWatcherSetter,
943
960
  changeField,
@@ -966,12 +983,6 @@ function Field({
966
983
  };
967
984
  return inputConfigProp ? { ...baseInputConfig, ...inputConfigProp } : baseInputConfig;
968
985
  }, [type, providerConfig.inputs, formConfig.inputs, inputConfigProp]);
969
- react.useEffect(() => {
970
- if (shouldRegister) {
971
- registerField(name);
972
- return () => unregisterField(name);
973
- }
974
- }, [name, shouldRegister, registerField, unregisterField]);
975
986
  const [watchers, setWatchers] = react.useState({});
976
987
  react.useEffect(() => {
977
988
  registerWatcherSetter(name, setWatchers);
@@ -1184,10 +1195,14 @@ function Field({
1184
1195
  inputConfig
1185
1196
  ]
1186
1197
  );
1187
- if (!isVisible) {
1188
- return null;
1189
- }
1190
- return /* @__PURE__ */ jsxRuntime.jsx(
1198
+ const fieldStateRef = react.useRef(
1199
+ {}
1200
+ );
1201
+ const formStateRef = react.useRef(
1202
+ {}
1203
+ );
1204
+ const fieldPropsRef = react.useRef({});
1205
+ const renderedField = isVisible ? /* @__PURE__ */ jsxRuntime.jsx(
1191
1206
  reactHookForm.Controller,
1192
1207
  {
1193
1208
  control: methods.control,
@@ -1238,13 +1253,16 @@ function Field({
1238
1253
  ...stateInjection
1239
1254
  }
1240
1255
  });
1256
+ fieldStateRef.current = fieldState;
1257
+ formStateRef.current = formState;
1258
+ fieldPropsRef.current = finalProps;
1241
1259
  const Component = inputConfig.component;
1242
1260
  const isHostComponent = typeof inputConfig.component === "string";
1243
1261
  const template = inputConfig.template ?? providerConfig.inputTemplates[type] ?? providerConfig.defaultInputTemplate;
1244
1262
  const TemplateComponent = template;
1245
- let renderedField;
1263
+ let renderedFieldEl;
1246
1264
  if (TemplateComponent) {
1247
- renderedField = /* @__PURE__ */ jsxRuntime.jsx(
1265
+ renderedFieldEl = /* @__PURE__ */ jsxRuntime.jsx(
1248
1266
  TemplateComponent,
1249
1267
  {
1250
1268
  Field: Component,
@@ -1267,27 +1285,64 @@ function Field({
1267
1285
  strippedHostProps[key] = value;
1268
1286
  }
1269
1287
  }
1270
- renderedField = react.createElement(inputConfig.component, {
1288
+ renderedFieldEl = react.createElement(inputConfig.component, {
1271
1289
  ...strippedHostProps,
1272
1290
  ref: finalProps.forwardRef
1273
1291
  });
1274
1292
  } else {
1275
- renderedField = /* @__PURE__ */ jsxRuntime.jsx(Component, { ...finalProps });
1293
+ renderedFieldEl = /* @__PURE__ */ jsxRuntime.jsx(Component, { ...finalProps });
1276
1294
  }
1277
1295
  if (typeof children === "function") {
1278
1296
  const result = children({
1279
1297
  fieldState,
1280
- renderedField,
1298
+ renderedField: renderedFieldEl,
1281
1299
  fieldProps: finalProps,
1282
1300
  watchers,
1283
1301
  formState
1284
1302
  });
1285
1303
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: result });
1286
1304
  }
1287
- return renderedField;
1305
+ return renderedFieldEl;
1288
1306
  }
1289
1307
  }
1290
- );
1308
+ ) : null;
1309
+ return {
1310
+ fieldState: fieldStateRef.current,
1311
+ renderedField,
1312
+ fieldProps: fieldPropsRef.current,
1313
+ watchers,
1314
+ formState: formStateRef.current
1315
+ };
1316
+ }
1317
+
1318
+ // src/components/Field.tsx
1319
+ function Field({
1320
+ name,
1321
+ type: typeProp,
1322
+ disabled: disabledProp,
1323
+ hidden: hiddenProp,
1324
+ children,
1325
+ shouldRegister = true,
1326
+ inputConfig: inputConfigProp,
1327
+ ...restProps
1328
+ }) {
1329
+ const { registerField, unregisterField } = useFormContext();
1330
+ react.useEffect(() => {
1331
+ if (shouldRegister) {
1332
+ registerField(name);
1333
+ return () => unregisterField(name);
1334
+ }
1335
+ }, [name, shouldRegister, registerField, unregisterField]);
1336
+ const { renderedField } = useField({
1337
+ name,
1338
+ type: typeProp,
1339
+ disabled: disabledProp,
1340
+ hidden: hiddenProp,
1341
+ children,
1342
+ inputConfig: inputConfigProp,
1343
+ ...restProps
1344
+ });
1345
+ return renderedField;
1291
1346
  }
1292
1347
  function FieldGroup({ name, children }) {
1293
1348
  const { formConfig } = useFormContext();
@@ -1444,6 +1499,7 @@ exports.makeDeepProxyState = makeDeepProxyState;
1444
1499
  exports.makeProxyState = makeProxyState;
1445
1500
  exports.useConditions = useConditions;
1446
1501
  exports.useConfigContext = useConfigContext;
1502
+ exports.useField = useField;
1447
1503
  exports.useFormContext = useFormContext;
1448
1504
  exports.useFormState = useFormState;
1449
1505
  exports.useGroupContext = useGroupContext;