@formality-ui/react 0.2.5 → 0.3.1

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
@@ -164,12 +164,25 @@ function Form({
164
164
  return result;
165
165
  }, [providerConfig.inputs, formConfig.inputs]);
166
166
  const defaultValues = react.useMemo(() => {
167
- return core.resolveAllInitialValues(config, mergedInputs, record ?? {});
167
+ const resolved = core.resolveAllInitialValues(
168
+ config,
169
+ mergedInputs,
170
+ record ?? {}
171
+ );
172
+ const baseline = {
173
+ ...record ?? {},
174
+ ...resolved
175
+ };
176
+ for (const fieldName of Object.keys(config)) {
177
+ if (!(fieldName in baseline)) baseline[fieldName] = void 0;
178
+ }
179
+ return baseline;
168
180
  }, [config, mergedInputs, record]);
169
181
  const methods = reactHookForm.useForm({
170
182
  mode: mode ?? "onChange",
171
183
  defaultValues,
172
- values: record
184
+ values: defaultValues
185
+ // was: `record as any` — see baseline comment above
173
186
  });
174
187
  const fieldRegistry = react.useRef(/* @__PURE__ */ new Set());
175
188
  const [registeredFields, setRegisteredFields] = react.useState(
@@ -197,11 +210,6 @@ function Form({
197
210
  invertedSubscriptions.current.set(target, /* @__PURE__ */ new Set());
198
211
  }
199
212
  invertedSubscriptions.current.get(target).add(subscriber);
200
- if (process.env.NODE_ENV !== "production") {
201
- console.warn(
202
- `[Formality Subscription] "${subscriber}" added to watch "${target}"`
203
- );
204
- }
205
213
  const setter = watcherSetters.current.get(target);
206
214
  if (setter) {
207
215
  setter((prev) => ({ ...prev, [subscriber]: true }));
@@ -214,20 +222,7 @@ function Form({
214
222
  }, []);
215
223
  const removeSubscription = react.useCallback(
216
224
  (target, subscriber) => {
217
- const subscribers = invertedSubscriptions.current.get(target);
218
- const subscriptionExists = subscribers?.has(subscriber) ?? false;
219
225
  invertedSubscriptions.current.get(target)?.delete(subscriber);
220
- if (process.env.NODE_ENV !== "production") {
221
- if (subscriptionExists) {
222
- console.warn(
223
- `[Formality Subscription] "${subscriber}" removed from watching "${target}"`
224
- );
225
- } else {
226
- console.warn(
227
- `[Formality Subscription] WARNING: Double-cleanup attempt - "${subscriber}" was not watching "${target}"`
228
- );
229
- }
230
- }
231
226
  const setter = watcherSetters.current.get(target);
232
227
  if (setter) {
233
228
  setter((prev) => {
@@ -335,8 +330,10 @@ function Form({
335
330
  }, [methods, config, record, defaultValues]);
336
331
  const handleSubmit = react.useCallback(
337
332
  async (values, overrideOnSubmit) => {
338
- for (const [, isValidating] of validatingFields.current) {
339
- if (isValidating) return;
333
+ for (const [fieldName, isValidating] of validatingFields.current) {
334
+ if (!isValidating) continue;
335
+ const subscribers = invertedSubscriptions.current.get(fieldName);
336
+ if (subscribers && subscribers.size > 0) return;
340
337
  }
341
338
  if (validate) {
342
339
  const errors = await validate(values);
@@ -912,20 +909,10 @@ function useSubscriptions(fieldName, subscriptions) {
912
909
  runSubscriptionsRef.current.set(currentRunId, [...subscriptions]);
913
910
  subscriptions.forEach((target) => {
914
911
  addSubscription(target, fieldName);
915
- if (process.env.NODE_ENV !== "production") {
916
- console.warn(
917
- `[Formality Subscription] Run ${currentRunId}: "${fieldName}" subscribing to "${target}"`
918
- );
919
- }
920
912
  });
921
913
  return () => {
922
914
  const thisRunSubscriptions = runSubscriptionsRef.current.get(currentRunId);
923
915
  if (thisRunSubscriptions) {
924
- if (process.env.NODE_ENV !== "production") {
925
- console.warn(
926
- `[Formality Subscription] Run ${currentRunId}: "${fieldName}" cleaning up [${thisRunSubscriptions.join(", ")}]`
927
- );
928
- }
929
916
  [...thisRunSubscriptions].reverse().forEach((target) => {
930
917
  removeSubscription(target, fieldName);
931
918
  });
@@ -934,13 +921,12 @@ function useSubscriptions(fieldName, subscriptions) {
934
921
  };
935
922
  }, [fieldName, subscriptions, addSubscription, removeSubscription]);
936
923
  }
937
- function Field({
924
+ function useField({
938
925
  name,
939
926
  type: typeProp,
940
927
  disabled: disabledProp,
941
928
  hidden: hiddenProp,
942
929
  children,
943
- shouldRegister = true,
944
930
  inputConfig: inputConfigProp,
945
931
  ...restProps
946
932
  }) {
@@ -948,8 +934,6 @@ function Field({
948
934
  config,
949
935
  formConfig,
950
936
  methods,
951
- registerField,
952
- unregisterField,
953
937
  registerWatcherSetter,
954
938
  unregisterWatcherSetter,
955
939
  changeField,
@@ -978,12 +962,6 @@ function Field({
978
962
  };
979
963
  return inputConfigProp ? { ...baseInputConfig, ...inputConfigProp } : baseInputConfig;
980
964
  }, [type, providerConfig.inputs, formConfig.inputs, inputConfigProp]);
981
- react.useEffect(() => {
982
- if (shouldRegister) {
983
- registerField(name);
984
- return () => unregisterField(name);
985
- }
986
- }, [name, shouldRegister, registerField, unregisterField]);
987
965
  const [watchers, setWatchers] = react.useState({});
988
966
  react.useEffect(() => {
989
967
  registerWatcherSetter(name, setWatchers);
@@ -1196,10 +1174,14 @@ function Field({
1196
1174
  inputConfig
1197
1175
  ]
1198
1176
  );
1199
- if (!isVisible) {
1200
- return null;
1201
- }
1202
- return /* @__PURE__ */ jsxRuntime.jsx(
1177
+ const fieldStateRef = react.useRef(
1178
+ {}
1179
+ );
1180
+ const formStateRef = react.useRef(
1181
+ {}
1182
+ );
1183
+ const fieldPropsRef = react.useRef({});
1184
+ const renderedField = isVisible ? /* @__PURE__ */ jsxRuntime.jsx(
1203
1185
  reactHookForm.Controller,
1204
1186
  {
1205
1187
  control: methods.control,
@@ -1250,13 +1232,16 @@ function Field({
1250
1232
  ...stateInjection
1251
1233
  }
1252
1234
  });
1235
+ fieldStateRef.current = fieldState;
1236
+ formStateRef.current = formState;
1237
+ fieldPropsRef.current = finalProps;
1253
1238
  const Component = inputConfig.component;
1254
1239
  const isHostComponent = typeof inputConfig.component === "string";
1255
1240
  const template = inputConfig.template ?? providerConfig.inputTemplates[type] ?? providerConfig.defaultInputTemplate;
1256
1241
  const TemplateComponent = template;
1257
- let renderedField;
1242
+ let renderedFieldEl;
1258
1243
  if (TemplateComponent) {
1259
- renderedField = /* @__PURE__ */ jsxRuntime.jsx(
1244
+ renderedFieldEl = /* @__PURE__ */ jsxRuntime.jsx(
1260
1245
  TemplateComponent,
1261
1246
  {
1262
1247
  Field: Component,
@@ -1279,27 +1264,64 @@ function Field({
1279
1264
  strippedHostProps[key] = value;
1280
1265
  }
1281
1266
  }
1282
- renderedField = react.createElement(inputConfig.component, {
1267
+ renderedFieldEl = react.createElement(inputConfig.component, {
1283
1268
  ...strippedHostProps,
1284
1269
  ref: finalProps.forwardRef
1285
1270
  });
1286
1271
  } else {
1287
- renderedField = /* @__PURE__ */ jsxRuntime.jsx(Component, { ...finalProps });
1272
+ renderedFieldEl = /* @__PURE__ */ jsxRuntime.jsx(Component, { ...finalProps });
1288
1273
  }
1289
1274
  if (typeof children === "function") {
1290
1275
  const result = children({
1291
1276
  fieldState,
1292
- renderedField,
1277
+ renderedField: renderedFieldEl,
1293
1278
  fieldProps: finalProps,
1294
1279
  watchers,
1295
1280
  formState
1296
1281
  });
1297
1282
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: result });
1298
1283
  }
1299
- return renderedField;
1284
+ return renderedFieldEl;
1300
1285
  }
1301
1286
  }
1302
- );
1287
+ ) : null;
1288
+ return {
1289
+ fieldState: fieldStateRef.current,
1290
+ renderedField,
1291
+ fieldProps: fieldPropsRef.current,
1292
+ watchers,
1293
+ formState: formStateRef.current
1294
+ };
1295
+ }
1296
+
1297
+ // src/components/Field.tsx
1298
+ function Field({
1299
+ name,
1300
+ type: typeProp,
1301
+ disabled: disabledProp,
1302
+ hidden: hiddenProp,
1303
+ children,
1304
+ shouldRegister = true,
1305
+ inputConfig: inputConfigProp,
1306
+ ...restProps
1307
+ }) {
1308
+ const { registerField, unregisterField } = useFormContext();
1309
+ react.useEffect(() => {
1310
+ if (shouldRegister) {
1311
+ registerField(name);
1312
+ return () => unregisterField(name);
1313
+ }
1314
+ }, [name, shouldRegister, registerField, unregisterField]);
1315
+ const { renderedField } = useField({
1316
+ name,
1317
+ type: typeProp,
1318
+ disabled: disabledProp,
1319
+ hidden: hiddenProp,
1320
+ children,
1321
+ inputConfig: inputConfigProp,
1322
+ ...restProps
1323
+ });
1324
+ return renderedField;
1303
1325
  }
1304
1326
  function FieldGroup({ name, children }) {
1305
1327
  const { formConfig } = useFormContext();
@@ -1456,6 +1478,7 @@ exports.makeDeepProxyState = makeDeepProxyState;
1456
1478
  exports.makeProxyState = makeProxyState;
1457
1479
  exports.useConditions = useConditions;
1458
1480
  exports.useConfigContext = useConfigContext;
1481
+ exports.useField = useField;
1459
1482
  exports.useFormContext = useFormContext;
1460
1483
  exports.useFormState = useFormState;
1461
1484
  exports.useGroupContext = useGroupContext;