remix-validated-form 4.6.12 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ CJS dist/index.cjs.js 63.04 KB
11
+ CJS dist/index.cjs.js.map 130.86 KB
12
+ CJS ⚡️ Build success in 25ms
13
+ ESM dist/index.esm.js 60.30 KB
14
+ ESM dist/index.esm.js.map 130.76 KB
15
+ ESM ⚡️ 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 1486ms
18
+ DTS dist/index.d.ts 12.80 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,