remix-validated-form 4.6.12 → 5.0.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.
@@ -7,12 +7,12 @@
7
7
  CLI Cleaning output folder
8
8
  ESM Build start
9
9
  CJS Build start
10
- ESM dist/index.esm.js 56.25 KB
11
- ESM dist/index.esm.js.map 121.08 KB
12
- ESM ⚡️ Build success in 27ms
13
- CJS dist/index.cjs.js 58.87 KB
14
- CJS dist/index.cjs.js.map 121.22 KB
15
- CJS ⚡️ Build success in 26ms
10
+ ESM dist/index.esm.js 60.30 KB
11
+ ESM dist/index.esm.js.map 130.77 KB
12
+ ESM ⚡️ Build success in 23ms
13
+ CJS dist/index.cjs.js 63.04 KB
14
+ CJS dist/index.cjs.js.map 130.88 KB
15
+ CJS ⚡️ Build success in 25ms
16
16
  DTS Build start
17
- DTS ⚡️ Build success in 1588ms
18
- DTS dist/index.d.ts 11.67 KB
17
+ DTS ⚡️ Build success in 1569ms
18
+ DTS dist/index.d.ts 12.81 KB
package/dist/index.cjs.js CHANGED
@@ -309,7 +309,9 @@ function sparseSplice(array, start, deleteCount, item) {
309
309
  }
310
310
  if (arguments.length === 4)
311
311
  return array.splice(start, deleteCount, item);
312
- return array.splice(start, deleteCount);
312
+ else if (arguments.length === 3)
313
+ return array.splice(start, deleteCount);
314
+ return array.splice(start);
313
315
  }
314
316
  var move = (array, from2, to) => {
315
317
  const [item] = sparseSplice(array, from2, 1);
@@ -318,6 +320,12 @@ var move = (array, from2, to) => {
318
320
  var insert = (array, index, value) => {
319
321
  sparseSplice(array, index, 0, value);
320
322
  };
323
+ var insertEmpty = (array, index) => {
324
+ const tail = sparseSplice(array, index);
325
+ tail.forEach((item, i) => {
326
+ sparseSplice(array, index + i + 1, 0, item);
327
+ });
328
+ };
321
329
  var remove = (array, index) => {
322
330
  sparseSplice(array, index, 1);
323
331
  };
@@ -447,6 +455,29 @@ if (void 0) {
447
455
  expect(array).toEqual([true, void 0, void 0, true]);
448
456
  });
449
457
  });
458
+ describe("insertEmpty", () => {
459
+ it("should insert an empty item at a given index", () => {
460
+ const array = [1, 2, 3];
461
+ insertEmpty(array, 1);
462
+ expect(array).toStrictEqual([1, , 2, 3]);
463
+ expect(array).not.toStrictEqual([1, void 0, 2, 3]);
464
+ });
465
+ it("should work with already sparse arrays", () => {
466
+ const array = [, , 1, , 2, , 3];
467
+ insertEmpty(array, 3);
468
+ expect(array).toStrictEqual([, , 1, , , 2, , 3]);
469
+ expect(array).not.toStrictEqual([
470
+ void 0,
471
+ void 0,
472
+ 1,
473
+ void 0,
474
+ void 0,
475
+ 2,
476
+ void 0,
477
+ 3
478
+ ]);
479
+ });
480
+ });
450
481
  describe("remove", () => {
451
482
  it("should remove an item at a given index", () => {
452
483
  const array = [1, 2, 3];
@@ -628,10 +659,12 @@ var defaultFormState = {
628
659
  reset: () => noOp,
629
660
  syncFormProps: noOp,
630
661
  setFormElement: noOp,
631
- validateField: async () => null,
632
662
  validate: async () => {
633
663
  throw new Error("Validate called before form was initialized.");
634
664
  },
665
+ smartValidate: async () => {
666
+ throw new Error("Validate called before form was initialized.");
667
+ },
635
668
  submit: async () => {
636
669
  throw new Error("Submit called before form was initialized.");
637
670
  },
@@ -714,8 +747,8 @@ var createFormState = (set, get2) => ({
714
747
  state.formElement = formElement;
715
748
  });
716
749
  },
717
- validateField: async (field) => {
718
- var _a, _b, _c;
750
+ validate: async () => {
751
+ var _a;
719
752
  const formElement = get2().formElement;
720
753
  (0, import_tiny_invariant2.default)(
721
754
  formElement,
@@ -724,22 +757,14 @@ var createFormState = (set, get2) => ({
724
757
  const validator = (_a = get2().formProps) == null ? void 0 : _a.validator;
725
758
  (0, import_tiny_invariant2.default)(
726
759
  validator,
727
- "Cannot validator. This is probably a bug in remix-validated-form."
728
- );
729
- await ((_c = (_b = get2().controlledFields).awaitValueUpdate) == null ? void 0 : _c.call(_b, field));
730
- const { error } = await validator.validateField(
731
- new FormData(formElement),
732
- field
760
+ "Cannot find validator. This is probably a bug in remix-validated-form."
733
761
  );
734
- if (error) {
735
- get2().setFieldError(field, error);
736
- return error;
737
- } else {
738
- get2().clearFieldError(field);
739
- return null;
740
- }
762
+ const result = await validator.validate(new FormData(formElement));
763
+ if (result.error)
764
+ get2().setFieldErrors(result.error.fieldErrors);
765
+ return result;
741
766
  },
742
- validate: async () => {
767
+ smartValidate: async ({ alwaysIncludeErrorsFromFields = [] } = {}) => {
743
768
  var _a;
744
769
  const formElement = get2().formElement;
745
770
  (0, import_tiny_invariant2.default)(
@@ -749,12 +774,75 @@ var createFormState = (set, get2) => ({
749
774
  const validator = (_a = get2().formProps) == null ? void 0 : _a.validator;
750
775
  (0, import_tiny_invariant2.default)(
751
776
  validator,
752
- "Cannot validator. This is probably a bug in remix-validated-form."
777
+ "Cannot find validator. This is probably a bug in remix-validated-form."
753
778
  );
754
- const result = await validator.validate(new FormData(formElement));
755
- if (result.error)
756
- get2().setFieldErrors(result.error.fieldErrors);
757
- return result;
779
+ await Promise.all(
780
+ alwaysIncludeErrorsFromFields.map(
781
+ (field) => {
782
+ var _a2, _b;
783
+ return (_b = (_a2 = get2().controlledFields).awaitValueUpdate) == null ? void 0 : _b.call(_a2, field);
784
+ }
785
+ )
786
+ );
787
+ const validationResult = await validator.validate(
788
+ new FormData(formElement)
789
+ );
790
+ if (!validationResult.error) {
791
+ const hadErrors = Object.keys(get2().fieldErrors).length > 0;
792
+ if (hadErrors)
793
+ get2().setFieldErrors({});
794
+ return validationResult;
795
+ }
796
+ const {
797
+ error: { fieldErrors }
798
+ } = validationResult;
799
+ const errorFields = /* @__PURE__ */ new Set();
800
+ const incomingErrors = /* @__PURE__ */ new Set();
801
+ const prevErrors = /* @__PURE__ */ new Set();
802
+ Object.keys(fieldErrors).forEach((field) => {
803
+ errorFields.add(field);
804
+ incomingErrors.add(field);
805
+ });
806
+ Object.keys(get2().fieldErrors).forEach((field) => {
807
+ errorFields.add(field);
808
+ prevErrors.add(field);
809
+ });
810
+ const fieldsToUpdate = /* @__PURE__ */ new Set();
811
+ const fieldsToDelete = /* @__PURE__ */ new Set();
812
+ errorFields.forEach((field) => {
813
+ if (!incomingErrors.has(field)) {
814
+ fieldsToDelete.add(field);
815
+ return;
816
+ }
817
+ if (prevErrors.has(field) && incomingErrors.has(field)) {
818
+ if (fieldErrors[field] !== get2().fieldErrors[field])
819
+ fieldsToUpdate.add(field);
820
+ return;
821
+ }
822
+ if (alwaysIncludeErrorsFromFields.includes(field)) {
823
+ fieldsToUpdate.add(field);
824
+ return;
825
+ }
826
+ if (!prevErrors.has(field)) {
827
+ const fieldTouched = get2().touchedFields[field];
828
+ const formHasBeenSubmitted = get2().hasBeenSubmitted;
829
+ if (fieldTouched || formHasBeenSubmitted)
830
+ fieldsToUpdate.add(field);
831
+ return;
832
+ }
833
+ });
834
+ if (fieldsToDelete.size === 0 && fieldsToUpdate.size === 0) {
835
+ return { ...validationResult, error: { fieldErrors: get2().fieldErrors } };
836
+ }
837
+ set((state) => {
838
+ fieldsToDelete.forEach((field) => {
839
+ delete state.fieldErrors[field];
840
+ });
841
+ fieldsToUpdate.forEach((field) => {
842
+ state.fieldErrors[field] = fieldErrors[field];
843
+ });
844
+ });
845
+ return { ...validationResult, error: { fieldErrors: get2().fieldErrors } };
758
846
  },
759
847
  submit: () => {
760
848
  const formElement = get2().formElement;
@@ -907,12 +995,12 @@ var createFormState = (set, get2) => ({
907
995
  mutateAsArray(
908
996
  fieldName,
909
997
  state.touchedFields,
910
- (array) => insert(array, index, false)
998
+ (array) => insertEmpty(array, index)
911
999
  );
912
1000
  mutateAsArray(
913
1001
  fieldName,
914
1002
  state.fieldErrors,
915
- (array) => insert(array, index, void 0)
1003
+ (array) => insertEmpty(array, index)
916
1004
  );
917
1005
  });
918
1006
  get2().controlledFields.kickoffValueUpdate(fieldName);
@@ -964,12 +1052,12 @@ var createFormState = (set, get2) => ({
964
1052
  mutateAsArray(
965
1053
  fieldName,
966
1054
  state.touchedFields,
967
- (array) => array.unshift(false)
1055
+ (array) => insertEmpty(array, 0)
968
1056
  );
969
1057
  mutateAsArray(
970
1058
  fieldName,
971
1059
  state.fieldErrors,
972
- (array) => array.unshift(void 0)
1060
+ (array) => insertEmpty(array, 0)
973
1061
  );
974
1062
  });
975
1063
  },
@@ -1101,8 +1189,8 @@ var useDefaultValuesForForm = (context) => {
1101
1189
  var useHasActiveFormSubmit = ({
1102
1190
  fetcher
1103
1191
  }) => {
1104
- const transition = (0, import_react2.useTransition)();
1105
- const hasActiveSubmission = fetcher ? fetcher.state === "submitting" : !!transition.submission;
1192
+ let navigation = (0, import_react2.useNavigation)();
1193
+ const hasActiveSubmission = fetcher ? fetcher.state === "submitting" : navigation.state === "submitting";
1106
1194
  return hasActiveSubmission;
1107
1195
  };
1108
1196
  var useFieldTouched = (field, { formId }) => {
@@ -1135,7 +1223,7 @@ var useFieldDefaultValue = (name, context) => {
1135
1223
  var useInternalIsSubmitting = (formId) => useFormStore(formId, (state) => state.isSubmitting);
1136
1224
  var useInternalIsValid = (formId) => useFormStore(formId, (state) => state.isValid());
1137
1225
  var useInternalHasBeenSubmitted = (formId) => useFormStore(formId, (state) => state.hasBeenSubmitted);
1138
- var useValidateField = (formId) => useFormStore(formId, (state) => state.validateField);
1226
+ var useSmartValidate = (formId) => useFormStore(formId, (state) => state.smartValidate);
1139
1227
  var useValidate = (formId) => useFormStore(formId, (state) => state.validate);
1140
1228
  var noOpReceiver = () => () => {
1141
1229
  };
@@ -1246,7 +1334,7 @@ var useField = (name, options) => {
1246
1334
  const error = useFieldError(name, formContext);
1247
1335
  const clearError = useClearError(formContext);
1248
1336
  const hasBeenSubmitted = useInternalHasBeenSubmitted(formContext.formId);
1249
- const validateField = useValidateField(formContext.formId);
1337
+ const smartValidate = useSmartValidate(formContext.formId);
1250
1338
  const registerReceiveFocus = useRegisterReceiveFocus(formContext.formId);
1251
1339
  (0, import_react5.useEffect)(() => {
1252
1340
  if (handleReceiveFocus)
@@ -1256,9 +1344,7 @@ var useField = (name, options) => {
1256
1344
  const helpers = {
1257
1345
  error,
1258
1346
  clearError: () => clearError(name),
1259
- validate: () => {
1260
- validateField(name);
1261
- },
1347
+ validate: () => smartValidate({ alwaysIncludeErrorsFromFields: [name] }),
1262
1348
  defaultValue,
1263
1349
  touched,
1264
1350
  setTouched
@@ -1282,7 +1368,7 @@ var useField = (name, options) => {
1282
1368
  name,
1283
1369
  hasBeenSubmitted,
1284
1370
  options == null ? void 0 : options.validationBehavior,
1285
- validateField
1371
+ smartValidate
1286
1372
  ]);
1287
1373
  return field;
1288
1374
  };
@@ -1495,6 +1581,9 @@ function ValidatedForm({
1495
1581
  method,
1496
1582
  replace: replace2,
1497
1583
  id,
1584
+ preventScrollReset,
1585
+ relative,
1586
+ encType,
1498
1587
  ...rest
1499
1588
  }) {
1500
1589
  var _a;
@@ -1587,11 +1676,11 @@ function ValidatedForm({
1587
1676
  startSubmit();
1588
1677
  const submitter = nativeEvent.submitter;
1589
1678
  const formMethod = (submitter == null ? void 0 : submitter.formMethod) || method;
1590
- const formDataToValidate = getDataFromForm(target);
1679
+ const formData = getDataFromForm(target);
1591
1680
  if (submitter == null ? void 0 : submitter.name) {
1592
- formDataToValidate.append(submitter.name, submitter.value);
1681
+ formData.append(submitter.name, submitter.value);
1593
1682
  }
1594
- const result = await validator.validate(formDataToValidate);
1683
+ const result = await validator.validate(formData);
1595
1684
  if (result.error) {
1596
1685
  setFieldErrors(result.error.fieldErrors);
1597
1686
  endSubmit();
@@ -1610,13 +1699,18 @@ function ValidatedForm({
1610
1699
  endSubmit();
1611
1700
  return;
1612
1701
  }
1702
+ const opts = {
1703
+ method: formMethod,
1704
+ replace: replace2,
1705
+ preventScrollReset,
1706
+ relative,
1707
+ action,
1708
+ encType
1709
+ };
1613
1710
  if (fetcher)
1614
- fetcher.submit(submitter || target, { method: formMethod });
1711
+ fetcher.submit(formData, opts);
1615
1712
  else
1616
- submit(submitter || target, {
1617
- replace: replace2,
1618
- method: formMethod
1619
- });
1713
+ submit(formData, opts);
1620
1714
  }
1621
1715
  };
1622
1716
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1627,7 +1721,10 @@ function ValidatedForm({
1627
1721
  id,
1628
1722
  action,
1629
1723
  method,
1724
+ encType,
1630
1725
  replace: replace2,
1726
+ preventScrollReset,
1727
+ relative,
1631
1728
  onSubmit: (e) => {
1632
1729
  e.preventDefault();
1633
1730
  handleSubmit(
@@ -1745,7 +1842,7 @@ var useFormState = (formId) => {
1745
1842
  var useFormHelpers = (formId) => {
1746
1843
  const formContext = useInternalFormContext(formId, "useFormHelpers");
1747
1844
  const setTouched = useSetTouched(formContext);
1748
- const validateField = useValidateField(formContext.formId);
1845
+ const validateField = useSmartValidate(formContext.formId);
1749
1846
  const validate = useValidate(formContext.formId);
1750
1847
  const clearError = useClearError(formContext);
1751
1848
  const setFieldErrors = useSetFieldErrors(formContext.formId);
@@ -1755,7 +1852,13 @@ var useFormHelpers = (formId) => {
1755
1852
  return (0, import_react11.useMemo)(
1756
1853
  () => ({
1757
1854
  setTouched,
1758
- validateField,
1855
+ validateField: async (fieldName) => {
1856
+ var _a, _b;
1857
+ const res = await validateField({
1858
+ alwaysIncludeErrorsFromFields: [fieldName]
1859
+ });
1860
+ return (_b = (_a = res.error) == null ? void 0 : _a.fieldErrors[fieldName]) != null ? _b : null;
1861
+ },
1759
1862
  clearError,
1760
1863
  validate,
1761
1864
  clearAllErrors: () => setFieldErrors({}),
@@ -1828,6 +1931,7 @@ var useFormContext = (formId) => {
1828
1931
  };
1829
1932
 
1830
1933
  // src/internal/state/fieldArray.tsx
1934
+ var import_nanoid = require("nanoid");
1831
1935
  var import_react13 = require("react");
1832
1936
  var import_react14 = require("react");
1833
1937
  var import_tiny_invariant4 = __toESM(require("tiny-invariant"));
@@ -1836,7 +1940,7 @@ var useInternalFieldArray = (context, field, validationBehavior) => {
1836
1940
  const value = useFieldDefaultValue(field, context);
1837
1941
  useRegisterControlledField(context, field);
1838
1942
  const hasBeenSubmitted = useInternalHasBeenSubmitted(context.formId);
1839
- const validateField = useValidateField(context.formId);
1943
+ const validateField = useSmartValidate(context.formId);
1840
1944
  const error = useFieldError(field, context);
1841
1945
  const resolvedValidationBehavior = {
1842
1946
  initial: "onSubmit",
@@ -1846,7 +1950,7 @@ var useInternalFieldArray = (context, field, validationBehavior) => {
1846
1950
  const behavior = hasBeenSubmitted ? resolvedValidationBehavior.whenSubmitted : resolvedValidationBehavior.initial;
1847
1951
  const maybeValidate = (0, import_react14.useCallback)(() => {
1848
1952
  if (behavior === "onChange") {
1849
- validateField(field);
1953
+ validateField({ alwaysIncludeErrorsFromFields: [field] });
1850
1954
  }
1851
1955
  }, [behavior, field, validateField]);
1852
1956
  (0, import_tiny_invariant4.default)(
@@ -1857,56 +1961,78 @@ var useInternalFieldArray = (context, field, validationBehavior) => {
1857
1961
  context.formId,
1858
1962
  (state) => state.controlledFields.array
1859
1963
  );
1964
+ const arrayValue = (0, import_react13.useMemo)(() => value != null ? value : [], [value]);
1965
+ const keyRef = (0, import_react13.useRef)([]);
1966
+ if (keyRef.current.length !== arrayValue.length) {
1967
+ keyRef.current = arrayValue.map(() => (0, import_nanoid.nanoid)());
1968
+ }
1860
1969
  const helpers = (0, import_react13.useMemo)(
1861
1970
  () => ({
1862
1971
  push: (item) => {
1863
1972
  arr.push(field, item);
1973
+ keyRef.current.push((0, import_nanoid.nanoid)());
1864
1974
  maybeValidate();
1865
1975
  },
1866
1976
  swap: (indexA, indexB) => {
1867
1977
  arr.swap(field, indexA, indexB);
1978
+ swap(keyRef.current, indexA, indexB);
1868
1979
  maybeValidate();
1869
1980
  },
1870
1981
  move: (from2, to) => {
1871
1982
  arr.move(field, from2, to);
1983
+ move(keyRef.current, from2, to);
1872
1984
  maybeValidate();
1873
1985
  },
1874
1986
  insert: (index, value2) => {
1875
1987
  arr.insert(field, index, value2);
1988
+ insert(keyRef.current, index, (0, import_nanoid.nanoid)());
1876
1989
  maybeValidate();
1877
1990
  },
1878
1991
  unshift: (value2) => {
1879
1992
  arr.unshift(field, value2);
1993
+ keyRef.current.unshift((0, import_nanoid.nanoid)());
1880
1994
  maybeValidate();
1881
1995
  },
1882
1996
  remove: (index) => {
1883
1997
  arr.remove(field, index);
1998
+ remove(keyRef.current, index);
1884
1999
  maybeValidate();
1885
2000
  },
1886
2001
  pop: () => {
1887
2002
  arr.pop(field);
2003
+ keyRef.current.pop();
1888
2004
  maybeValidate();
1889
2005
  },
1890
2006
  replace: (index, value2) => {
1891
2007
  arr.replace(field, index, value2);
2008
+ keyRef.current[index] = (0, import_nanoid.nanoid)();
1892
2009
  maybeValidate();
1893
2010
  }
1894
2011
  }),
1895
2012
  [arr, field, maybeValidate]
1896
2013
  );
1897
- const arrayValue = (0, import_react13.useMemo)(() => value != null ? value : [], [value]);
1898
- return [arrayValue, helpers, error];
2014
+ const valueWithKeys = (0, import_react13.useMemo)(() => {
2015
+ const result = [];
2016
+ arrayValue.forEach((item, index) => {
2017
+ result[index] = {
2018
+ key: keyRef.current[index],
2019
+ defaultValue: item
2020
+ };
2021
+ });
2022
+ return result;
2023
+ }, [arrayValue]);
2024
+ return [valueWithKeys, helpers, error];
1899
2025
  };
1900
2026
  function useFieldArray(name, { formId, validationBehavior } = {}) {
1901
2027
  const context = useInternalFormContext(formId, "FieldArray");
1902
2028
  return useInternalFieldArray(context, name, validationBehavior);
1903
2029
  }
1904
- var FieldArray = ({
2030
+ function FieldArray({
1905
2031
  name,
1906
2032
  children,
1907
2033
  formId,
1908
2034
  validationBehavior
1909
- }) => {
2035
+ }) {
1910
2036
  const context = useInternalFormContext(formId, "FieldArray");
1911
2037
  const [value, helpers, error] = useInternalFieldArray(
1912
2038
  context,
@@ -1914,7 +2040,7 @@ var FieldArray = ({
1914
2040
  validationBehavior
1915
2041
  );
1916
2042
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: children(value, helpers, error) });
1917
- };
2043
+ }
1918
2044
  // Annotate the CommonJS export names for ESM import in node:
1919
2045
  0 && (module.exports = {
1920
2046
  FieldArray,