hs-uix 1.4.0 → 1.4.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/form.mjs CHANGED
@@ -671,9 +671,10 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
671
671
  const inputDebounceRef = useRef(/* @__PURE__ */ new Map());
672
672
  const rowKeyRef = useRef(/* @__PURE__ */ new WeakMap());
673
673
  const rowKeyCounterRef = useRef(0);
674
+ const controlledBaselineLockedRef = useRef(false);
674
675
  const initialSnapshot = useRef(null);
675
676
  if (initialSnapshot.current === null) {
676
- initialSnapshot.current = deepClone(computeInitialValues());
677
+ initialSnapshot.current = deepClone(values != null ? values : computeInitialValues());
677
678
  }
678
679
  const formValues = values != null ? values : internalValues;
679
680
  const formErrors = controlledErrors != null ? controlledErrors : internalErrors;
@@ -685,6 +686,10 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
685
686
  const draftValuesRef = useRef(null);
686
687
  formValuesRef.current = formValues;
687
688
  formErrorsRef.current = formErrors;
689
+ const syncDirtyBaseline = useCallback((nextValues) => {
690
+ initialSnapshot.current = deepClone(nextValues || {});
691
+ prevAutoSaveValues.current = deepClone(nextValues || {});
692
+ }, []);
688
693
  const fieldByName = useMemo(() => {
689
694
  const map = /* @__PURE__ */ new Map();
690
695
  for (const field of fields) {
@@ -761,6 +766,11 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
761
766
  if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
762
767
  };
763
768
  }, []);
769
+ useEffect(() => {
770
+ if (values == null) return;
771
+ if (controlledBaselineLockedRef.current) return;
772
+ syncDirtyBaseline(values);
773
+ }, [values, syncDirtyBaseline]);
764
774
  const isDirty = useMemo(() => {
765
775
  return !deepEqual(formValues, initialSnapshot.current);
766
776
  }, [formValues]);
@@ -879,6 +889,50 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
879
889
  },
880
890
  [fieldTypes]
881
891
  );
892
+ const setRepeaterSubFieldError = useCallback(
893
+ (fieldName, rowIdx, subFieldName, errorMessage) => {
894
+ const key = getRepeaterErrorKey(fieldName, rowIdx, subFieldName);
895
+ const merged = { ...formErrorsRef.current };
896
+ if (errorMessage) {
897
+ merged[key] = errorMessage;
898
+ } else {
899
+ delete merged[key];
900
+ }
901
+ const subErrors = Object.keys(merged).filter((k) => k.startsWith(`${fieldName}[`)).map((k) => {
902
+ const match = k.match(/\[(\d+)\]\./);
903
+ const row = match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
904
+ return { key: k, row };
905
+ }).sort((a, b) => a.row - b.row);
906
+ if (subErrors.length > 0) {
907
+ const first = subErrors[0];
908
+ merged[fieldName] = `Row ${first.row + 1}: ${merged[first.key]}`;
909
+ } else if (!merged[fieldName] || merged[fieldName].startsWith("Row ")) {
910
+ delete merged[fieldName];
911
+ }
912
+ replaceErrors(merged);
913
+ },
914
+ [replaceErrors]
915
+ );
916
+ const expandValidationFields = useCallback(
917
+ (fieldSubset) => {
918
+ const toValidate = fieldSubset || visibleFields;
919
+ const expanded = [];
920
+ for (const field of toValidate) {
921
+ if (field.type === "fieldGroup" && field.items && field.fields) {
922
+ for (const item of field.items) {
923
+ for (const subField of field.fields(item)) {
924
+ if (subField.visible && !subField.visible(formValues)) continue;
925
+ expanded.push(subField);
926
+ }
927
+ }
928
+ continue;
929
+ }
930
+ expanded.push(field);
931
+ }
932
+ return expanded;
933
+ },
934
+ [visibleFields, formValues]
935
+ );
882
936
  const validateField = useCallback(
883
937
  (name, value) => {
884
938
  const field = fieldByName.get(name);
@@ -898,7 +952,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
898
952
  );
899
953
  const validateVisibleFields = useCallback(
900
954
  (fieldSubset) => {
901
- const toValidate = fieldSubset || visibleFields;
955
+ const toValidate = expandValidationFields(fieldSubset);
902
956
  const errors = {};
903
957
  let hasErrors = false;
904
958
  for (const field of toValidate) {
@@ -918,52 +972,54 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
918
972
  }
919
973
  return { errors, hasErrors };
920
974
  },
921
- [visibleFields, formValues, validateRepeaterField, fieldTypes, validationMessages]
975
+ [expandValidationFields, formValues, validateRepeaterField, fieldTypes, validationMessages]
922
976
  );
923
- const runAsyncValidation = useCallback(
924
- (name, value) => {
925
- const field = fieldByName.get(name);
926
- if (!field || field.type === "repeater") return null;
927
- const val = value != null ? value : formValues[name];
928
- const syncError = runValidators(val, field, formValues, fieldTypes, { includeCustomValidators: false, messages: validationMessages });
929
- const prevController = asyncAbortRef.current.get(name);
977
+ const runAsyncValidationTarget = useCallback(
978
+ (target) => {
979
+ const { validationKey, field, value, allValues, applyError } = target || {};
980
+ if (!field || !validationKey || field.type === "repeater" || field.type === "fieldGroup") return null;
981
+ const syncError = runValidators(value, field, allValues, fieldTypes, {
982
+ includeCustomValidators: false,
983
+ messages: validationMessages
984
+ });
985
+ const prevController = asyncAbortRef.current.get(validationKey);
930
986
  if (prevController) prevController.abort();
931
- asyncAbortRef.current.delete(name);
987
+ asyncAbortRef.current.delete(validationKey);
932
988
  setValidatingFields((prev) => {
933
- if (!prev[name]) return prev;
989
+ if (!prev[validationKey]) return prev;
934
990
  const next = { ...prev };
935
- delete next[name];
991
+ delete next[validationKey];
936
992
  return next;
937
993
  });
938
994
  if (syncError) return null;
939
- const version = (asyncValidationVersionRef.current.get(name) || 0) + 1;
940
- asyncValidationVersionRef.current.set(name, version);
995
+ const version = (asyncValidationVersionRef.current.get(validationKey) || 0) + 1;
996
+ asyncValidationVersionRef.current.set(validationKey, version);
941
997
  const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
942
- if (controller) asyncAbortRef.current.set(name, controller);
998
+ if (controller) asyncAbortRef.current.set(validationKey, controller);
943
999
  let asyncPromises;
944
1000
  try {
945
1001
  asyncPromises = collectAsyncValidatorPromises(
946
- val,
1002
+ value,
947
1003
  field,
948
- formValues,
1004
+ allValues,
949
1005
  controller ? { signal: controller.signal } : void 0
950
1006
  );
951
1007
  } catch (err) {
952
- updateErrors({ [name]: (err == null ? void 0 : err.message) || "Validation failed" });
1008
+ applyError((err == null ? void 0 : err.message) || "Validation failed");
953
1009
  return null;
954
1010
  }
955
1011
  if (asyncPromises.length === 0) {
956
- asyncAbortRef.current.delete(name);
1012
+ asyncAbortRef.current.delete(validationKey);
957
1013
  return null;
958
1014
  }
959
1015
  const validationPromise = Promise.all(asyncPromises).then(
960
1016
  (results) => {
961
- if (asyncValidationVersionRef.current.get(name) !== version) return;
962
- asyncValidationRef.current.delete(name);
963
- asyncAbortRef.current.delete(name);
1017
+ if (asyncValidationVersionRef.current.get(validationKey) !== version) return;
1018
+ asyncValidationRef.current.delete(validationKey);
1019
+ asyncAbortRef.current.delete(validationKey);
964
1020
  setValidatingFields((prev) => {
965
1021
  const next = { ...prev };
966
- delete next[name];
1022
+ delete next[validationKey];
967
1023
  return next;
968
1024
  });
969
1025
  let err = null;
@@ -974,50 +1030,128 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
974
1030
  break;
975
1031
  }
976
1032
  }
977
- updateErrors({ [name]: err });
1033
+ applyError(err);
978
1034
  },
979
1035
  (rejection) => {
980
- if (asyncValidationVersionRef.current.get(name) !== version) return;
981
- asyncValidationRef.current.delete(name);
982
- asyncAbortRef.current.delete(name);
1036
+ if (asyncValidationVersionRef.current.get(validationKey) !== version) return;
1037
+ asyncValidationRef.current.delete(validationKey);
1038
+ asyncAbortRef.current.delete(validationKey);
983
1039
  setValidatingFields((prev) => {
984
1040
  const next = { ...prev };
985
- delete next[name];
1041
+ delete next[validationKey];
986
1042
  return next;
987
1043
  });
988
1044
  if (rejection && rejection.name === "AbortError") return;
989
- updateErrors({ [name]: (rejection == null ? void 0 : rejection.message) || "Validation failed" });
1045
+ applyError((rejection == null ? void 0 : rejection.message) || "Validation failed");
990
1046
  }
991
1047
  );
992
- asyncValidationRef.current.set(name, validationPromise);
993
- setValidatingFields((prev) => ({ ...prev, [name]: true }));
1048
+ asyncValidationRef.current.set(validationKey, validationPromise);
1049
+ setValidatingFields((prev) => ({ ...prev, [validationKey]: true }));
994
1050
  return validationPromise;
995
1051
  },
996
- [fieldByName, formValues, fieldTypes, updateErrors]
1052
+ [fieldTypes, validationMessages]
997
1053
  );
998
- const triggerAsyncValidation = useCallback(
1054
+ const runAsyncValidation = useCallback(
999
1055
  (name, value) => {
1000
1056
  const field = fieldByName.get(name);
1001
- if (!field || field.type === "repeater") return;
1002
- const debounceMs = field.validateDebounce;
1057
+ if (!field || field.type === "repeater" || field.type === "fieldGroup") return null;
1058
+ return runAsyncValidationTarget({
1059
+ validationKey: name,
1060
+ field,
1061
+ value: value != null ? value : formValues[name],
1062
+ allValues: formValues,
1063
+ applyError: (errorMessage) => updateErrors({ [name]: errorMessage })
1064
+ });
1065
+ },
1066
+ [fieldByName, formValues, runAsyncValidationTarget, updateErrors]
1067
+ );
1068
+ const triggerAsyncValidationTarget = useCallback(
1069
+ (target) => {
1070
+ if (!(target == null ? void 0 : target.field) || !target.validationKey) return;
1071
+ const debounceMs = target.field.validateDebounce;
1003
1072
  if (debounceMs && debounceMs > 0) {
1004
- const existing = debounceTimersRef.current.get(name);
1073
+ const existing = debounceTimersRef.current.get(target.validationKey);
1005
1074
  if (existing) clearTimeout(existing);
1006
1075
  const timer = setTimeout(() => {
1007
- debounceTimersRef.current.delete(name);
1008
- runAsyncValidation(name, value);
1076
+ debounceTimersRef.current.delete(target.validationKey);
1077
+ runAsyncValidationTarget(target);
1009
1078
  }, debounceMs);
1010
- debounceTimersRef.current.set(name, timer);
1079
+ debounceTimersRef.current.set(target.validationKey, timer);
1011
1080
  } else {
1012
- runAsyncValidation(name, value);
1081
+ runAsyncValidationTarget(target);
1082
+ }
1083
+ },
1084
+ [runAsyncValidationTarget]
1085
+ );
1086
+ const triggerAsyncValidation = useCallback(
1087
+ (name, value) => {
1088
+ const field = fieldByName.get(name);
1089
+ if (!field || field.type === "repeater" || field.type === "fieldGroup") return;
1090
+ triggerAsyncValidationTarget({
1091
+ validationKey: name,
1092
+ field,
1093
+ value: value != null ? value : formValuesRef.current[name],
1094
+ allValues: formValuesRef.current,
1095
+ applyError: (errorMessage) => updateErrors({ [name]: errorMessage })
1096
+ });
1097
+ },
1098
+ [fieldByName, triggerAsyncValidationTarget, updateErrors]
1099
+ );
1100
+ const getAsyncValidationTargets = useCallback(
1101
+ (fieldSubset) => {
1102
+ const toValidate = fieldSubset || visibleFields;
1103
+ const targets = [];
1104
+ for (const field of toValidate) {
1105
+ if (field.type === "fieldGroup" && field.items && field.fields) {
1106
+ for (const item of field.items) {
1107
+ for (const subField of field.fields(item)) {
1108
+ if (subField.visible && !subField.visible(formValues)) continue;
1109
+ targets.push({
1110
+ validationKey: subField.name,
1111
+ field: subField,
1112
+ value: formValues[subField.name],
1113
+ allValues: formValues,
1114
+ applyError: (errorMessage) => updateErrors({ [subField.name]: errorMessage })
1115
+ });
1116
+ }
1117
+ }
1118
+ continue;
1119
+ }
1120
+ if (field.type === "repeater") {
1121
+ const rows = Array.isArray(formValues[field.name]) ? formValues[field.name] : [];
1122
+ const subFields = field.fields || [];
1123
+ rows.forEach((row, rowIdx) => {
1124
+ const rowValues = { ...formValues, [field.name]: rows };
1125
+ subFields.forEach((subField) => {
1126
+ if (subField.visible && !subField.visible(rowValues)) return;
1127
+ targets.push({
1128
+ validationKey: getRepeaterErrorKey(field.name, rowIdx, subField.name),
1129
+ field: subField,
1130
+ value: row == null ? void 0 : row[subField.name],
1131
+ allValues: rowValues,
1132
+ applyError: (errorMessage) => setRepeaterSubFieldError(field.name, rowIdx, subField.name, errorMessage)
1133
+ });
1134
+ });
1135
+ });
1136
+ continue;
1137
+ }
1138
+ targets.push({
1139
+ validationKey: field.name,
1140
+ field,
1141
+ value: formValues[field.name],
1142
+ allValues: formValues,
1143
+ applyError: (errorMessage) => updateErrors({ [field.name]: errorMessage })
1144
+ });
1013
1145
  }
1146
+ return targets;
1014
1147
  },
1015
- [fieldByName, runAsyncValidation]
1148
+ [visibleFields, formValues, setRepeaterSubFieldError, updateErrors]
1016
1149
  );
1017
1150
  const commitValues = useCallback(
1018
1151
  (nextValues) => {
1019
1152
  formValuesRef.current = nextValues;
1020
1153
  if (values != null) {
1154
+ controlledBaselineLockedRef.current = true;
1021
1155
  if (onChange) onChange(nextValues);
1022
1156
  } else {
1023
1157
  setInternalValues(nextValues);
@@ -1035,7 +1169,8 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1035
1169
  [commitValues]
1036
1170
  );
1037
1171
  const handleFieldChange = useCallback(
1038
- (name, value) => {
1172
+ (name, value, options = {}) => {
1173
+ const { clearNestedErrors = true } = options;
1039
1174
  const newValues = { ...formValuesRef.current, [name]: value };
1040
1175
  const queue = [name];
1041
1176
  const visited = /* @__PURE__ */ new Set();
@@ -1076,9 +1211,11 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1076
1211
  if (formErrorsRef.current[name] != null) {
1077
1212
  clearedErrors[name] = null;
1078
1213
  }
1079
- for (const key of Object.keys(formErrorsRef.current)) {
1080
- if (key.startsWith(`${name}[`)) {
1081
- clearedErrors[key] = null;
1214
+ if (clearNestedErrors) {
1215
+ for (const key of Object.keys(formErrorsRef.current)) {
1216
+ if (key.startsWith(`${name}[`)) {
1217
+ clearedErrors[key] = null;
1218
+ }
1082
1219
  }
1083
1220
  }
1084
1221
  draftValuesRef.current = newValues;
@@ -1147,7 +1284,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1147
1284
  replaceErrors(errors);
1148
1285
  return;
1149
1286
  }
1150
- const asyncSubmitValidations = allVisibleFields.map((field) => runAsyncValidation(field.name, formValues[field.name])).filter(Boolean);
1287
+ const asyncSubmitValidations = getAsyncValidationTargets(allVisibleFields).map((target) => runAsyncValidationTarget(target)).filter(Boolean);
1151
1288
  if (asyncSubmitValidations.length > 0 || asyncValidationRef.current.size > 0) {
1152
1289
  const pendingValidations = [
1153
1290
  .../* @__PURE__ */ new Set([
@@ -1162,6 +1299,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1162
1299
  const reset = () => {
1163
1300
  const fresh = computeInitialValues();
1164
1301
  if (values == null) setInternalValues(fresh);
1302
+ controlledBaselineLockedRef.current = false;
1165
1303
  replaceErrors({});
1166
1304
  initialSnapshot.current = deepClone(fresh);
1167
1305
  prevAutoSaveValues.current = deepClone(fresh);
@@ -1201,7 +1339,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1201
1339
  if (controlledLoading == null) setInternalLoading(false);
1202
1340
  }
1203
1341
  },
1204
- [validateOnSubmit, allVisibleFields, validateVisibleFields, replaceErrors, onSubmit, values, controlledLoading, transformValues, onBeforeSubmit, onSubmitSuccess, onSubmitError, resetOnSuccess, formValues, fieldByName, runAsyncValidation]
1342
+ [validateOnSubmit, allVisibleFields, validateVisibleFields, replaceErrors, onSubmit, values, controlledLoading, transformValues, onBeforeSubmit, onSubmitSuccess, onSubmitError, resetOnSuccess, formValues, fieldByName, getAsyncValidationTargets, runAsyncValidationTarget]
1205
1343
  );
1206
1344
  const handleNext = useCallback(async () => {
1207
1345
  if (!isMultiStep) return;
@@ -1213,7 +1351,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1213
1351
  replaceErrors({ ...formErrorsRef.current, ...errors });
1214
1352
  return;
1215
1353
  }
1216
- const asyncStepValidations = stepFields.map((field) => runAsyncValidation(field.name, formValues[field.name])).filter(Boolean);
1354
+ const asyncStepValidations = getAsyncValidationTargets(stepFields).map((target) => runAsyncValidationTarget(target)).filter(Boolean);
1217
1355
  if (asyncStepValidations.length > 0 || asyncValidationRef.current.size > 0) {
1218
1356
  const pendingValidations = [
1219
1357
  .../* @__PURE__ */ new Set([
@@ -1238,7 +1376,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1238
1376
  } else {
1239
1377
  setInternalStep(nextStep);
1240
1378
  }
1241
- }, [isMultiStep, validateStepOnNext, steps, currentStep, formValues, validateVisibleFields, controlledStep, onStepChange, replaceErrors, allVisibleFields, runAsyncValidation]);
1379
+ }, [isMultiStep, validateStepOnNext, steps, currentStep, formValues, validateVisibleFields, controlledStep, onStepChange, replaceErrors, allVisibleFields, getAsyncValidationTargets, runAsyncValidationTarget]);
1242
1380
  const handleBack = useCallback(() => {
1243
1381
  if (!isMultiStep) return;
1244
1382
  const prevStep = Math.max(currentStep - 1, 0);
@@ -1270,6 +1408,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1270
1408
  reset: () => {
1271
1409
  const fresh = computeInitialValues();
1272
1410
  if (values == null) setInternalValues(fresh);
1411
+ controlledBaselineLockedRef.current = false;
1273
1412
  replaceErrors({});
1274
1413
  initialSnapshot.current = deepClone(fresh);
1275
1414
  prevAutoSaveValues.current = deepClone(fresh);
@@ -1282,30 +1421,6 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1282
1421
  replaceErrors(errors);
1283
1422
  }
1284
1423
  }));
1285
- const setRepeaterSubFieldError = useCallback(
1286
- (fieldName, rowIdx, subFieldName, errorMessage) => {
1287
- const key = getRepeaterErrorKey(fieldName, rowIdx, subFieldName);
1288
- const merged = { ...formErrorsRef.current };
1289
- if (errorMessage) {
1290
- merged[key] = errorMessage;
1291
- } else {
1292
- delete merged[key];
1293
- }
1294
- const subErrors = Object.keys(merged).filter((k) => k.startsWith(`${fieldName}[`)).map((k) => {
1295
- const match = k.match(/\[(\d+)\]\./);
1296
- const row = match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
1297
- return { key: k, row };
1298
- }).sort((a, b) => a.row - b.row);
1299
- if (subErrors.length > 0) {
1300
- const first = subErrors[0];
1301
- merged[fieldName] = `Row ${first.row + 1}: ${merged[first.key]}`;
1302
- } else if (!merged[fieldName] || merged[fieldName].startsWith("Row ")) {
1303
- delete merged[fieldName];
1304
- }
1305
- replaceErrors(merged);
1306
- },
1307
- [replaceErrors]
1308
- );
1309
1424
  const renderField = (field) => {
1310
1425
  const fieldError = formErrors[field.name] || null;
1311
1426
  const rendered = renderFieldInner(field);
@@ -1785,12 +1900,13 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1785
1900
  const rowValues = { ...formValues, [field.name]: nextRows };
1786
1901
  const err = runValidators(subValue, subField, rowValues, fieldTypes, { messages: validationMessages });
1787
1902
  setRepeaterSubFieldError(field.name, rowIdx, subField.name, err);
1903
+ return err;
1788
1904
  };
1789
1905
  const handleSubFieldChange = (rowIdx, subField, subValue) => {
1790
1906
  const updated = rows.map(
1791
1907
  (row, i) => i === rowIdx ? { ...row, [subField.name]: subValue } : row
1792
1908
  );
1793
- handleFieldChange(field.name, updated);
1909
+ handleFieldChange(field.name, updated, { clearNestedErrors: false });
1794
1910
  if (validateOnChange) {
1795
1911
  validateSubField(rowIdx, subField, subValue, updated);
1796
1912
  }
@@ -1800,13 +1916,24 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1800
1916
  const nextRows = rows.map(
1801
1917
  (row, i) => i === rowIdx ? { ...row, [subField.name]: subValue } : row
1802
1918
  );
1803
- validateSubField(rowIdx, subField, subValue, nextRows);
1919
+ const err = validateSubField(rowIdx, subField, subValue, nextRows);
1920
+ if (err) return;
1921
+ const validationKey = getRepeaterErrorKey(field.name, rowIdx, subField.name);
1922
+ const rowValues = { ...formValues, [field.name]: nextRows };
1923
+ triggerAsyncValidationTarget({
1924
+ validationKey,
1925
+ field: subField,
1926
+ value: subValue,
1927
+ allValues: rowValues,
1928
+ applyError: (errorMessage) => setRepeaterSubFieldError(field.name, rowIdx, subField.name, errorMessage)
1929
+ });
1804
1930
  };
1805
1931
  return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, field.label && /* @__PURE__ */ React.createElement(Text, { format: { fontWeight: "demibold" } }, field.label, isRequired ? " *" : ""), field.description && /* @__PURE__ */ React.createElement(Text, { variant: "microcopy" }, field.description), rows.map((row, rowIdx) => /* @__PURE__ */ React.createElement(Flex, { key: getRowKey(field.name, row, rowIdx), direction: "row", gap: "xs", align: "end" }, subFields.map((sf) => {
1806
1932
  const sfValue = row[sf.name];
1807
1933
  const sfLabel = rowIdx === 0 ? sf.label : void 0;
1808
1934
  const sfOptions = resolveOptions(sf, { ...formValues, [field.name]: rows });
1809
1935
  const sfError = formErrors[getRepeaterErrorKey(field.name, rowIdx, sf.name)] || null;
1936
+ const validationKey = getRepeaterErrorKey(field.name, rowIdx, sf.name);
1810
1937
  const sfProps = {
1811
1938
  name: `${field.name}-${rowIdx}-${sf.name}`,
1812
1939
  label: sfLabel,
@@ -1815,6 +1942,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
1815
1942
  disabled: resolveDisabled(sf, formValues) || isDisabled,
1816
1943
  error: !!sfError,
1817
1944
  validationMessage: sfError || void 0,
1945
+ ...validatingFields[validationKey] ? { loading: true } : {},
1818
1946
  ...sf.fieldProps || {}
1819
1947
  };
1820
1948
  let sfElement;