remix-validated-form 4.4.2 → 4.5.0-beta.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.
Files changed (48) hide show
  1. package/.turbo/turbo-build.log +13 -10
  2. package/browser/ValidatedForm.js +24 -39
  3. package/browser/hooks.d.ts +1 -1
  4. package/browser/internal/hooks.d.ts +3 -2
  5. package/browser/internal/hooks.js +1 -0
  6. package/browser/internal/state/controlledFieldStore.d.ts +23 -21
  7. package/browser/internal/state/controlledFieldStore.js +32 -19
  8. package/browser/internal/state/controlledFields.d.ts +3 -3
  9. package/browser/internal/state/controlledFields.js +19 -21
  10. package/browser/internal/state/createFormStore.d.ts +16 -8
  11. package/browser/internal/state/createFormStore.js +62 -8
  12. package/browser/internal/state/storeHooks.d.ts +1 -3
  13. package/browser/internal/state/storeHooks.js +2 -8
  14. package/browser/internal/state/types.d.ts +1 -0
  15. package/browser/internal/state/types.js +1 -0
  16. package/browser/unreleased/formStateHooks.d.ts +8 -2
  17. package/browser/unreleased/formStateHooks.js +12 -2
  18. package/browser/userFacingFormContext.d.ts +8 -2
  19. package/browser/userFacingFormContext.js +15 -4
  20. package/dist/remix-validated-form.cjs.js +3 -3
  21. package/dist/remix-validated-form.cjs.js.map +1 -1
  22. package/dist/remix-validated-form.es.js +169 -113
  23. package/dist/remix-validated-form.es.js.map +1 -1
  24. package/dist/remix-validated-form.umd.js +3 -3
  25. package/dist/remix-validated-form.umd.js.map +1 -1
  26. package/dist/types/hooks.d.ts +1 -1
  27. package/dist/types/internal/hooks.d.ts +3 -2
  28. package/dist/types/internal/state/controlledFieldStore.d.ts +23 -21
  29. package/dist/types/internal/state/controlledFields.d.ts +3 -3
  30. package/dist/types/internal/state/createFormStore.d.ts +16 -8
  31. package/dist/types/internal/state/storeHooks.d.ts +1 -3
  32. package/dist/types/internal/state/types.d.ts +1 -0
  33. package/dist/types/unreleased/formStateHooks.d.ts +8 -2
  34. package/dist/types/userFacingFormContext.d.ts +8 -2
  35. package/package.json +4 -4
  36. package/src/ValidatedForm.tsx +41 -56
  37. package/src/internal/hooks.ts +4 -1
  38. package/src/internal/state/controlledFieldStore.ts +95 -74
  39. package/src/internal/state/controlledFields.ts +38 -26
  40. package/src/internal/state/createFormStore.ts +199 -115
  41. package/src/internal/state/storeHooks.ts +3 -16
  42. package/src/internal/state/types.ts +1 -0
  43. package/src/unreleased/formStateHooks.ts +24 -3
  44. package/src/userFacingFormContext.ts +38 -13
  45. package/dist/types/internal/state/cleanup.d.ts +0 -2
  46. package/dist/types/internal/state/storeFamily.d.ts +0 -9
  47. package/src/internal/state/cleanup.ts +0 -8
  48. package/src/internal/state/storeFamily.ts +0 -24
@@ -1377,14 +1377,18 @@ const createGetInputProps = ({
1377
1377
  return omitBy_1(inputProps, (value) => value === void 0);
1378
1378
  };
1379
1379
  };
1380
+ var isProduction = true;
1380
1381
  var prefix = "Invariant failed";
1381
1382
  function invariant(condition, message) {
1382
1383
  if (condition) {
1383
1384
  return;
1384
1385
  }
1385
- {
1386
+ if (isProduction) {
1386
1387
  throw new Error(prefix);
1387
1388
  }
1389
+ var provided = typeof message === "function" ? message() : message;
1390
+ var value = provided ? prefix + ": " + provided : prefix;
1391
+ throw new Error(value);
1388
1392
  }
1389
1393
  const FORM_ID_FIELD = "__rvfInternalFormId";
1390
1394
  const FORM_DEFAULTS_FIELD = "__rvfInternalFormDefaults";
@@ -1903,27 +1907,16 @@ const immerImpl = (initializer) => (set2, get2, store) => {
1903
1907
  return initializer(store.setState, get2, store);
1904
1908
  };
1905
1909
  const immer = immerImpl;
1906
- const storeFamily = (create2) => {
1907
- const stores = /* @__PURE__ */ new Map();
1908
- const family = (formId) => {
1909
- if (stores.has(formId))
1910
- return stores.get(formId);
1911
- const store = create2(formId);
1912
- stores.set(formId, store);
1913
- return store;
1914
- };
1915
- family.remove = (formId) => {
1916
- stores.delete(formId);
1917
- };
1918
- return family;
1919
- };
1920
- const controlledFieldStore = storeFamily(() => create$1()(immer((set2, get2, api) => ({
1921
- fields: {},
1922
- register: (field) => set2((state) => {
1923
- if (state.fields[field]) {
1924
- state.fields[field].refCount++;
1910
+ const useControlledFieldStore = create$1()(immer((set2, get2) => ({
1911
+ forms: {},
1912
+ register: (formId, field) => set2((state) => {
1913
+ if (!state.forms[formId]) {
1914
+ state.forms[formId] = {};
1915
+ }
1916
+ if (state.forms[formId][field]) {
1917
+ state.forms[formId][field].refCount++;
1925
1918
  } else {
1926
- state.fields[field] = {
1919
+ state.forms[formId][field] = {
1927
1920
  refCount: 1,
1928
1921
  value: void 0,
1929
1922
  hydrated: false,
@@ -1932,16 +1925,23 @@ const controlledFieldStore = storeFamily(() => create$1()(immer((set2, get2, api
1932
1925
  };
1933
1926
  }
1934
1927
  }),
1935
- unregister: (field) => set2((state) => {
1936
- const fieldState = state.fields[field];
1928
+ unregister: (formId, field) => set2((state) => {
1929
+ var _a;
1930
+ const formState = (_a = state.forms) == null ? void 0 : _a[formId];
1931
+ const fieldState = formState == null ? void 0 : formState[field];
1937
1932
  if (!fieldState)
1938
1933
  return;
1939
1934
  fieldState.refCount--;
1940
1935
  if (fieldState.refCount === 0)
1941
- delete state.fields[field];
1936
+ delete formState[field];
1942
1937
  }),
1943
- setValue: (field, value) => set2((state) => {
1944
- const fieldState = state.fields[field];
1938
+ getField: (formId, field) => {
1939
+ var _a, _b;
1940
+ return (_b = (_a = get2().forms) == null ? void 0 : _a[formId]) == null ? void 0 : _b[field];
1941
+ },
1942
+ setValue: (formId, field, value) => set2((state) => {
1943
+ var _a, _b;
1944
+ const fieldState = (_b = (_a = state.forms) == null ? void 0 : _a[formId]) == null ? void 0 : _b[field];
1945
1945
  if (!fieldState)
1946
1946
  return;
1947
1947
  fieldState.value = value;
@@ -1950,27 +1950,60 @@ const controlledFieldStore = storeFamily(() => create$1()(immer((set2, get2, api
1950
1950
  });
1951
1951
  fieldState.valueUpdatePromise = promise;
1952
1952
  }),
1953
- hydrateWithDefault: (field, defaultValue) => set2((state) => {
1954
- const fieldState = state.fields[field];
1953
+ hydrateWithDefault: (formId, field, defaultValue) => set2((state) => {
1954
+ var _a;
1955
+ const fieldState = (_a = state.forms[formId]) == null ? void 0 : _a[field];
1955
1956
  if (!fieldState)
1956
1957
  return;
1957
1958
  fieldState.value = defaultValue;
1958
1959
  fieldState.defaultValue = defaultValue;
1959
1960
  fieldState.hydrated = true;
1960
1961
  }),
1961
- awaitValueUpdate: async (field) => {
1962
+ awaitValueUpdate: async (formId, field) => {
1962
1963
  var _a;
1963
- await ((_a = get2().fields[field]) == null ? void 0 : _a.valueUpdatePromise);
1964
+ await ((_a = get2().getField(formId, field)) == null ? void 0 : _a.valueUpdatePromise);
1964
1965
  },
1965
- reset: () => set2((state) => {
1966
- Object.values(state.fields).forEach((field) => {
1966
+ reset: (formId) => set2((state) => {
1967
+ const formState = state.forms[formId];
1968
+ if (!formState)
1969
+ return;
1970
+ Object.values(formState).forEach((field) => {
1967
1971
  if (!field)
1968
1972
  return;
1969
1973
  field.value = field.defaultValue;
1970
1974
  });
1971
1975
  })
1972
- }))));
1973
- const formStore = storeFamily((formId) => create$1()(immer((set2, get2, api) => ({
1976
+ })));
1977
+ const noOp = () => {
1978
+ };
1979
+ const defaultFormState = {
1980
+ isHydrated: false,
1981
+ isSubmitting: false,
1982
+ hasBeenSubmitted: false,
1983
+ touchedFields: {},
1984
+ fieldErrors: {},
1985
+ formElement: null,
1986
+ isValid: () => true,
1987
+ startSubmit: noOp,
1988
+ endSubmit: noOp,
1989
+ setTouched: noOp,
1990
+ setFieldError: noOp,
1991
+ setFieldErrors: noOp,
1992
+ clearFieldError: noOp,
1993
+ reset: () => noOp,
1994
+ syncFormProps: noOp,
1995
+ setHydrated: noOp,
1996
+ setFormElement: noOp,
1997
+ validateField: async () => null,
1998
+ validate: async () => {
1999
+ throw new Error("Validate called before form was initialized.");
2000
+ },
2001
+ submit: async () => {
2002
+ throw new Error("Submit called before form was initialized.");
2003
+ },
2004
+ resetFormElement: noOp
2005
+ };
2006
+ const createFormState = (formId, set2, get2) => ({
1974
2007
  isHydrated: false,
1975
2008
  isSubmitting: false,
1976
2009
  hasBeenSubmitted: false,
@@ -2004,6 +2037,7 @@ const formStore = storeFamily((formId) => create$1()(immer((set2, get2, api) =>
2004
2037
  }),
2005
2038
  syncFormProps: (props) => set2((state) => {
2006
2039
  state.formProps = props;
2040
+ state.isHydrated = true;
2007
2041
  }),
2008
2042
  setHydrated: () => set2((state) => {
2009
2043
  state.isHydrated = true;
@@ -2018,10 +2052,10 @@ const formStore = storeFamily((formId) => create$1()(immer((set2, get2, api) =>
2018
2052
  validateField: async (field) => {
2019
2053
  var _a, _b, _c;
2020
2054
  const formElement = get2().formElement;
2021
- invariant(formElement);
2055
+ invariant(formElement, "Cannot find reference to form. This is probably a bug in remix-validated-form.");
2022
2056
  const validator = (_a = get2().formProps) == null ? void 0 : _a.validator;
2023
- invariant(validator);
2024
- await ((_c = (_b = controlledFieldStore(formId).getState()).awaitValueUpdate) == null ? void 0 : _c.call(_b, field));
2057
+ invariant(validator, "Cannot validator. This is probably a bug in remix-validated-form.");
2058
+ await ((_c = (_b = useControlledFieldStore.getState()).awaitValueUpdate) == null ? void 0 : _c.call(_b, formId, field));
2025
2059
  const { error } = await validator.validateField(new FormData(formElement), field);
2026
2060
  if (error) {
2027
2061
  get2().setFieldError(field, error);
@@ -2034,25 +2068,45 @@ const formStore = storeFamily((formId) => create$1()(immer((set2, get2, api) =>
2034
2068
  validate: async () => {
2035
2069
  var _a;
2036
2070
  const formElement = get2().formElement;
2037
- invariant(formElement);
2071
+ invariant(formElement, "Cannot find reference to form. This is probably a bug in remix-validated-form.");
2038
2072
  const validator = (_a = get2().formProps) == null ? void 0 : _a.validator;
2039
- invariant(validator);
2040
- const { error } = await validator.validate(new FormData(formElement));
2041
- if (error)
2042
- get2().setFieldErrors(error.fieldErrors);
2073
+ invariant(validator, "Cannot validator. This is probably a bug in remix-validated-form.");
2074
+ const result = await validator.validate(new FormData(formElement));
2075
+ if (result.error)
2076
+ get2().setFieldErrors(result.error.fieldErrors);
2077
+ return result;
2078
+ },
2079
+ submit: () => {
2080
+ const formElement = get2().formElement;
2081
+ invariant(formElement, "Cannot find reference to form. This is probably a bug in remix-validated-form.");
2082
+ formElement.submit();
2043
2083
  },
2044
2084
  resetFormElement: () => {
2045
2085
  var _a;
2046
2086
  return (_a = get2().formElement) == null ? void 0 : _a.reset();
2047
2087
  }
2048
- }))));
2088
+ });
2089
+ const useRootFormStore = create$1()(immer((set2, get2) => ({
2090
+ forms: {},
2091
+ form: (formId) => {
2092
+ var _a;
2093
+ return (_a = get2().forms[formId]) != null ? _a : defaultFormState;
2094
+ },
2095
+ cleanupForm: (formId) => {
2096
+ set2((state) => {
2097
+ delete state.forms[formId];
2098
+ });
2099
+ },
2100
+ registerForm: (formId) => {
2101
+ if (get2().forms[formId])
2102
+ return;
2103
+ set2((state) => {
2104
+ state.forms[formId] = createFormState(formId, (setter) => set2((state2) => setter(state2.forms[formId])), () => get2().forms[formId]);
2105
+ });
2106
+ }
2107
+ })));
2049
2108
  const useFormStore = (formId, selector) => {
2050
- const useStore2 = formStore(formId);
2051
- return useStore2(selector);
2052
- };
2053
- const useControlledFieldStore = (formId, selector) => {
2054
- const useStore2 = controlledFieldStore(formId);
2055
- return useStore2(selector);
2109
+ return useRootFormStore((state) => selector(state.form(formId)));
2056
2110
  };
2057
2111
  const useInternalFormContext = (formId, hookName) => {
2058
2112
  const formContext = useContext(InternalFormContext);
@@ -2106,7 +2160,7 @@ const useDefaultValuesForForm = (context) => {
2106
2160
  if (hydrated)
2107
2161
  return hydratable.hydratedData();
2108
2162
  if (errorResponse == null ? void 0 : errorResponse.repopulateFields) {
2109
- invariant(typeof errorResponse.repopulateFields === "object");
2163
+ invariant(typeof errorResponse.repopulateFields === "object", "repopulateFields returned something other than an object");
2110
2164
  return hydratable.serverData(errorResponse.repopulateFields);
2111
2165
  }
2112
2166
  if (defaultValuesProp)
@@ -2161,6 +2215,7 @@ const useTouchedFields = (formId) => useFormStore(formId, (state) => state.touch
2161
2215
  const useFieldErrors = (formId) => useFormStore(formId, (state) => state.fieldErrors);
2162
2216
  const useSetFieldErrors = (formId) => useFormStore(formId, (state) => state.setFieldErrors);
2163
2217
  const useResetFormElement = (formId) => useFormStore(formId, (state) => state.resetFormElement);
2218
+ const useSubmitForm = (formId) => useFormStore(formId, (state) => state.submit);
2164
2219
  const useFormActionProp = (formId) => useFormStore(formId, (state) => {
2165
2220
  var _a;
2166
2221
  return (_a = state.formProps) == null ? void 0 : _a.action;
@@ -2170,24 +2225,23 @@ const useFormSubactionProp = (formId) => useFormStore(formId, (state) => {
2170
2225
  return (_a = state.formProps) == null ? void 0 : _a.subaction;
2171
2226
  });
2172
2227
  const useControlledFieldValue = (context, field) => {
2173
- const useValueStore = controlledFieldStore(context.formId);
2174
- const value = useValueStore((state) => {
2228
+ const value = useControlledFieldStore((state) => {
2175
2229
  var _a;
2176
- return (_a = state.fields[field]) == null ? void 0 : _a.value;
2230
+ return (_a = state.getField(context.formId, field)) == null ? void 0 : _a.value;
2177
2231
  });
2178
- const useFormStore2 = formStore(context.formId);
2179
- const isFormHydrated = useFormStore2((state) => state.isHydrated);
2232
+ const isFormHydrated = useFormStore(context.formId, (state) => state.isHydrated);
2180
2233
  const defaultValue = useFieldDefaultValue(field, context);
2181
- const isFieldHydrated = useValueStore((state) => {
2234
+ const isFieldHydrated = useControlledFieldStore((state) => {
2182
2235
  var _a, _b;
2183
- return (_b = (_a = state.fields[field]) == null ? void 0 : _a.hydrated) != null ? _b : false;
2236
+ return (_b = (_a = state.getField(context.formId, field)) == null ? void 0 : _a.hydrated) != null ? _b : false;
2184
2237
  });
2185
- const hydrateWithDefault = useValueStore((state) => state.hydrateWithDefault);
2238
+ const hydrateWithDefault = useControlledFieldStore((state) => state.hydrateWithDefault);
2186
2239
  useEffect(() => {
2187
2240
  if (isFormHydrated && !isFieldHydrated) {
2188
- hydrateWithDefault(field, defaultValue);
2241
+ hydrateWithDefault(context.formId, field, defaultValue);
2189
2242
  }
2190
2243
  }, [
2244
+ context.formId,
2191
2245
  defaultValue,
2192
2246
  field,
2193
2247
  hydrateWithDefault,
@@ -2197,28 +2251,27 @@ const useControlledFieldValue = (context, field) => {
2197
2251
  return isFieldHydrated ? value : defaultValue;
2198
2252
  };
2199
2253
  const useControllableValue = (context, field) => {
2200
- const useValueStore = controlledFieldStore(context.formId);
2201
- const resolveUpdate = useValueStore((state) => {
2254
+ const resolveUpdate = useControlledFieldStore((state) => {
2202
2255
  var _a;
2203
- return (_a = state.fields[field]) == null ? void 0 : _a.resolveValueUpdate;
2256
+ return (_a = state.getField(context.formId, field)) == null ? void 0 : _a.resolveValueUpdate;
2204
2257
  });
2205
2258
  useEffect(() => {
2206
2259
  resolveUpdate == null ? void 0 : resolveUpdate();
2207
2260
  }, [resolveUpdate]);
2208
- const register = useValueStore((state) => state.register);
2209
- const unregister = useValueStore((state) => state.unregister);
2261
+ const register = useControlledFieldStore((state) => state.register);
2262
+ const unregister = useControlledFieldStore((state) => state.unregister);
2210
2263
  useEffect(() => {
2211
- register(field);
2212
- return () => unregister(field);
2264
+ register(context.formId, field);
2265
+ return () => unregister(context.formId, field);
2213
2266
  }, [context.formId, field, register, unregister]);
2214
- const setControlledFieldValue = useValueStore((state) => state.setValue);
2215
- const setValue = useCallback((value2) => setControlledFieldValue(field, value2), [field, setControlledFieldValue]);
2267
+ const setControlledFieldValue = useControlledFieldStore((state) => state.setValue);
2268
+ const setValue = useCallback((value2) => setControlledFieldValue(context.formId, field, value2), [context.formId, field, setControlledFieldValue]);
2216
2269
  const value = useControlledFieldValue(context, field);
2217
2270
  return [value, setValue];
2218
2271
  };
2219
2272
  const useUpdateControllableValue = (formId) => {
2220
- const useValueStore = controlledFieldStore(formId);
2221
- return useValueStore((state) => state.setValue);
2273
+ const setValue = useControlledFieldStore((state) => state.setValue);
2274
+ return useCallback((field, value) => setValue(formId, field, value), [formId, setValue]);
2222
2275
  };
2223
2276
  const useIsSubmitting = (formId) => {
2224
2277
  const formContext = useInternalFormContext(formId, "useIsSubmitting");
@@ -2437,10 +2490,6 @@ const useMultiValueMap = () => {
2437
2490
  return ref.current;
2438
2491
  }, []);
2439
2492
  };
2440
- const cleanupFormState = (formId) => {
2441
- formStore.remove(formId);
2442
- controlledFieldStore.remove(formId);
2443
- };
2444
2493
  function useSubmitComplete(isSubmitting, callback) {
2445
2494
  const isPending = useRef(false);
2446
2495
  useEffect(() => {
@@ -2604,16 +2653,13 @@ function ValidatedForm(_a) {
2604
2653
  const setFieldErrors = useSetFieldErrors(formId);
2605
2654
  const setFieldError = useFormStore(formId, (state) => state.setFieldError);
2606
2655
  const reset = useFormStore(formId, (state) => state.reset);
2607
- const resetControlledFields = useControlledFieldStore(formId, (state) => state.reset);
2656
+ const resetControlledFields = useControlledFieldStore((state) => state.reset);
2608
2657
  const startSubmit = useFormStore(formId, (state) => state.startSubmit);
2609
2658
  const endSubmit = useFormStore(formId, (state) => state.endSubmit);
2610
2659
  const syncFormProps = useFormStore(formId, (state) => state.syncFormProps);
2611
- const setHydrated = useFormStore(formId, (state) => state.setHydrated);
2612
2660
  const setFormElementInState = useFormStore(formId, (state) => state.setFormElement);
2613
- useEffect(() => {
2614
- setHydrated();
2615
- return () => cleanupFormState(formId);
2616
- }, [formId, setHydrated]);
2661
+ const cleanupForm = useRootFormStore((state) => state.cleanupForm);
2662
+ const registerForm = useRootFormStore((state) => state.registerForm);
2617
2663
  const customFocusHandlers = useMultiValueMap();
2618
2664
  const registerReceiveFocus = useCallback((fieldName, handler) => {
2619
2665
  customFocusHandlers().add(fieldName, handler);
@@ -2621,6 +2667,10 @@ function ValidatedForm(_a) {
2621
2667
  customFocusHandlers().remove(fieldName, handler);
2622
2668
  };
2623
2669
  }, [customFocusHandlers]);
2670
+ useIsomorphicLayoutEffect(() => {
2671
+ registerForm(formId);
2672
+ return () => cleanupForm(formId);
2673
+ }, [cleanupForm, formId, registerForm]);
2624
2674
  useIsomorphicLayoutEffect(() => {
2625
2675
  var _a3;
2626
2676
  syncFormProps({
@@ -2639,6 +2689,9 @@ function ValidatedForm(_a) {
2639
2689
  backendDefaultValues,
2640
2690
  validator
2641
2691
  ]);
2692
+ useIsomorphicLayoutEffect(() => {
2693
+ setFormElementInState(formRef.current);
2694
+ }, [setFormElementInState]);
2642
2695
  useEffect(() => {
2643
2696
  var _a3;
2644
2697
  setFieldErrors((_a3 = backendError == null ? void 0 : backendError.fieldErrors) != null ? _a3 : {});
@@ -2646,25 +2699,7 @@ function ValidatedForm(_a) {
2646
2699
  useSubmitComplete(hasActiveSubmission, () => {
2647
2700
  endSubmit();
2648
2701
  });
2649
- let clickedButtonRef = React.useRef();
2650
- useEffect(() => {
2651
- let form = formRef.current;
2652
- if (!form)
2653
- return;
2654
- function handleClick(event) {
2655
- if (!(event.target instanceof HTMLElement))
2656
- return;
2657
- let submitButton = event.target.closest("button,input[type=submit]");
2658
- if (submitButton && submitButton.form === form && submitButton.type === "submit") {
2659
- clickedButtonRef.current = submitButton;
2660
- }
2661
- }
2662
- window.addEventListener("click", handleClick, { capture: true });
2663
- return () => {
2664
- window.removeEventListener("click", handleClick, { capture: true });
2665
- };
2666
- }, []);
2667
- const handleSubmit = async (e2) => {
2702
+ const handleSubmit = async (e2, target, nativeEvent) => {
2668
2703
  startSubmit();
2669
2704
  const result = await validator.validate(getDataFromForm(e2.currentTarget));
2670
2705
  if (result.error) {
@@ -2680,16 +2715,15 @@ function ValidatedForm(_a) {
2680
2715
  endSubmit();
2681
2716
  return;
2682
2717
  }
2683
- const submitter = e2.nativeEvent.submitter;
2718
+ const submitter = nativeEvent.submitter;
2684
2719
  if (fetcher)
2685
2720
  fetcher.submit(submitter || e2.currentTarget);
2686
2721
  else
2687
- submit(submitter || e2.currentTarget, { method, replace });
2688
- clickedButtonRef.current = null;
2722
+ submit(submitter || target, { method, replace });
2689
2723
  }
2690
2724
  };
2691
2725
  return /* @__PURE__ */ React.createElement(Form$1, __spreadProps(__spreadValues({
2692
- ref: mergeRefs([formRef, formRefProp, setFormElementInState])
2726
+ ref: mergeRefs([formRef, formRefProp])
2693
2727
  }, rest), {
2694
2728
  id,
2695
2729
  action,
@@ -2697,18 +2731,18 @@ function ValidatedForm(_a) {
2697
2731
  replace,
2698
2732
  onSubmit: (e2) => {
2699
2733
  e2.preventDefault();
2700
- handleSubmit(e2);
2734
+ handleSubmit(e2, e2.currentTarget, e2.nativeEvent);
2701
2735
  },
2702
2736
  onReset: (event) => {
2703
2737
  onReset == null ? void 0 : onReset(event);
2704
2738
  if (event.defaultPrevented)
2705
2739
  return;
2706
2740
  reset();
2707
- resetControlledFields();
2741
+ resetControlledFields(formId);
2708
2742
  }
2709
2743
  }), /* @__PURE__ */ React.createElement(InternalFormContext.Provider, {
2710
2744
  value: contextValue
2711
- }, /* @__PURE__ */ React.createElement(FormResetter, {
2745
+ }, /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormResetter, {
2712
2746
  formRef,
2713
2747
  resetAfterSubmit
2714
2748
  }), subaction && /* @__PURE__ */ React.createElement("input", {
@@ -2719,7 +2753,7 @@ function ValidatedForm(_a) {
2719
2753
  type: "hidden",
2720
2754
  value: id,
2721
2755
  name: FORM_ID_FIELD
2722
- }), children));
2756
+ }), children)));
2723
2757
  }
2724
2758
  var baseSet = _baseSet;
2725
2759
  function set(object, path, value) {
@@ -2805,14 +2839,24 @@ const useFormHelpers = (formId) => {
2805
2839
  const clearError = useClearError(formContext);
2806
2840
  const setFieldErrors = useSetFieldErrors(formContext.formId);
2807
2841
  const reset = useResetFormElement(formContext.formId);
2842
+ const submit = useSubmitForm(formContext.formId);
2808
2843
  return useMemo(() => ({
2809
2844
  setTouched,
2810
2845
  validateField,
2811
2846
  clearError,
2812
2847
  validate,
2813
2848
  clearAllErrors: () => setFieldErrors({}),
2814
- reset
2815
- }), [clearError, reset, setFieldErrors, setTouched, validate, validateField]);
2849
+ reset,
2850
+ submit
2851
+ }), [
2852
+ clearError,
2853
+ reset,
2854
+ setFieldErrors,
2855
+ setTouched,
2856
+ submit,
2857
+ validate,
2858
+ validateField
2859
+ ]);
2816
2860
  };
2817
2861
  const useFormContext = (formId) => {
2818
2862
  const context = useInternalFormContext(formId, "useFormContext");
@@ -2823,7 +2867,8 @@ const useFormContext = (formId) => {
2823
2867
  validateField,
2824
2868
  clearAllErrors,
2825
2869
  validate,
2826
- reset
2870
+ reset,
2871
+ submit
2827
2872
  } = useFormHelpers(formId);
2828
2873
  const registerReceiveFocus = useRegisterReceiveFocus(context.formId);
2829
2874
  const clearError = useCallback((...names) => {
@@ -2831,15 +2876,26 @@ const useFormContext = (formId) => {
2831
2876
  internalClearError(name);
2832
2877
  });
2833
2878
  }, [internalClearError]);
2834
- return __spreadProps(__spreadValues({}, state), {
2879
+ return useMemo(() => __spreadProps(__spreadValues({}, state), {
2835
2880
  setFieldTouched: setTouched,
2836
2881
  validateField,
2837
2882
  clearError,
2838
2883
  registerReceiveFocus,
2839
2884
  clearAllErrors,
2840
2885
  validate,
2841
- reset
2842
- });
2886
+ reset,
2887
+ submit
2888
+ }), [
2889
+ clearAllErrors,
2890
+ clearError,
2891
+ registerReceiveFocus,
2892
+ reset,
2893
+ setTouched,
2894
+ state,
2895
+ submit,
2896
+ validate,
2897
+ validateField
2898
+ ]);
2843
2899
  };
2844
2900
  export { ValidatedForm, createValidator, setFormDefaults, useControlField, useField, useFormContext, useIsSubmitting, useIsValid, useUpdateControlledField, validationError };
2845
2901
  //# sourceMappingURL=remix-validated-form.es.js.map