remix-validated-form 4.5.0-beta.0 → 4.5.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 (35) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/browser/ValidatedForm.js +10 -32
  3. package/browser/internal/hooks.d.ts +3 -1
  4. package/browser/internal/hooks.js +2 -0
  5. package/browser/internal/logic/nestedObjectToPathObject.d.ts +1 -0
  6. package/browser/internal/logic/nestedObjectToPathObject.js +47 -0
  7. package/browser/internal/state/arrayUtil.d.ts +12 -0
  8. package/browser/internal/state/arrayUtil.js +337 -0
  9. package/browser/internal/state/createFormStore.d.ts +4 -2
  10. package/browser/internal/state/createFormStore.js +21 -4
  11. package/browser/internal/state/fieldArray.d.ts +28 -0
  12. package/browser/internal/state/fieldArray.js +73 -0
  13. package/browser/internal/state/types.d.ts +0 -0
  14. package/browser/internal/state/types.js +0 -0
  15. package/browser/unreleased/formStateHooks.d.ts +12 -2
  16. package/browser/unreleased/formStateHooks.js +15 -2
  17. package/browser/userFacingFormContext.d.ts +12 -2
  18. package/browser/userFacingFormContext.js +5 -1
  19. package/dist/remix-validated-form.cjs.js +3 -3
  20. package/dist/remix-validated-form.cjs.js.map +1 -1
  21. package/dist/remix-validated-form.es.js +55 -37
  22. package/dist/remix-validated-form.es.js.map +1 -1
  23. package/dist/remix-validated-form.umd.js +3 -3
  24. package/dist/remix-validated-form.umd.js.map +1 -1
  25. package/dist/types/internal/hooks.d.ts +3 -1
  26. package/dist/types/internal/state/createFormStore.d.ts +4 -2
  27. package/dist/types/unreleased/formStateHooks.d.ts +12 -2
  28. package/dist/types/userFacingFormContext.d.ts +12 -2
  29. package/package.json +1 -1
  30. package/src/ValidatedForm.tsx +24 -42
  31. package/src/internal/hooks.ts +6 -0
  32. package/src/internal/state/createFormStore.ts +40 -6
  33. package/src/unreleased/formStateHooks.ts +32 -3
  34. package/src/userFacingFormContext.ts +22 -2
  35. package/src/validation/validation.test.ts +7 -7
@@ -1996,8 +1996,13 @@ const defaultFormState = {
1996
1996
  setFormElement: noOp,
1997
1997
  validateField: async () => null,
1998
1998
  validate: async () => {
1999
+ throw new Error("Validate called before form was initialized.");
1999
2000
  },
2000
- resetFormElement: noOp
2001
+ submit: async () => {
2002
+ throw new Error("Submit called before form was initialized.");
2003
+ },
2004
+ resetFormElement: noOp,
2005
+ getValues: () => new FormData()
2001
2006
  };
2002
2007
  const createFormState = (formId, set2, get2) => ({
2003
2008
  isHydrated: false,
@@ -2067,9 +2072,20 @@ const createFormState = (formId, set2, get2) => ({
2067
2072
  invariant(formElement, "Cannot find reference to form. This is probably a bug in remix-validated-form.");
2068
2073
  const validator = (_a = get2().formProps) == null ? void 0 : _a.validator;
2069
2074
  invariant(validator, "Cannot validator. This is probably a bug in remix-validated-form.");
2070
- const { error } = await validator.validate(new FormData(formElement));
2071
- if (error)
2072
- get2().setFieldErrors(error.fieldErrors);
2075
+ const result = await validator.validate(new FormData(formElement));
2076
+ if (result.error)
2077
+ get2().setFieldErrors(result.error.fieldErrors);
2078
+ return result;
2079
+ },
2080
+ submit: () => {
2081
+ const formElement = get2().formElement;
2082
+ invariant(formElement, "Cannot find reference to form. This is probably a bug in remix-validated-form.");
2083
+ formElement.submit();
2084
+ },
2085
+ getValues: () => {
2086
+ const formElement = get2().formElement;
2087
+ invariant(formElement, "Cannot find reference to form. This is probably a bug in remix-validated-form.");
2088
+ return new FormData(formElement);
2073
2089
  },
2074
2090
  resetFormElement: () => {
2075
2091
  var _a;
@@ -2205,6 +2221,7 @@ const useTouchedFields = (formId) => useFormStore(formId, (state) => state.touch
2205
2221
  const useFieldErrors = (formId) => useFormStore(formId, (state) => state.fieldErrors);
2206
2222
  const useSetFieldErrors = (formId) => useFormStore(formId, (state) => state.setFieldErrors);
2207
2223
  const useResetFormElement = (formId) => useFormStore(formId, (state) => state.resetFormElement);
2224
+ const useSubmitForm = (formId) => useFormStore(formId, (state) => state.submit);
2208
2225
  const useFormActionProp = (formId) => useFormStore(formId, (state) => {
2209
2226
  var _a;
2210
2227
  return (_a = state.formProps) == null ? void 0 : _a.action;
@@ -2213,6 +2230,7 @@ const useFormSubactionProp = (formId) => useFormStore(formId, (state) => {
2213
2230
  var _a;
2214
2231
  return (_a = state.formProps) == null ? void 0 : _a.subaction;
2215
2232
  });
2233
+ const useFormValues = (formId) => useFormStore(formId, (state) => state.getValues);
2216
2234
  const useControlledFieldValue = (context, field) => {
2217
2235
  const value = useControlledFieldStore((state) => {
2218
2236
  var _a;
@@ -2526,7 +2544,7 @@ const focusFirstInvalidInput = (fieldErrors, customFocusHandlers, formElement) =
2526
2544
  var _a;
2527
2545
  const namesInOrder = [...formElement.elements].map((el) => {
2528
2546
  const input = el instanceof RadioNodeList ? el[0] : el;
2529
- if (input instanceof HTMLInputElement)
2547
+ if (input instanceof HTMLElement && "name" in input)
2530
2548
  return input.name;
2531
2549
  return null;
2532
2550
  }).filter(nonNull).filter((name) => name in fieldErrors);
@@ -2548,8 +2566,8 @@ const focusFirstInvalidInput = (fieldErrors, customFocusHandlers, formElement) =
2548
2566
  break;
2549
2567
  }
2550
2568
  }
2551
- if (elem instanceof HTMLInputElement) {
2552
- if (elem.type === "hidden") {
2569
+ if (elem instanceof HTMLElement) {
2570
+ if (elem instanceof HTMLInputElement && elem.type === "hidden") {
2553
2571
  continue;
2554
2572
  }
2555
2573
  elem.focus();
@@ -2688,25 +2706,7 @@ function ValidatedForm(_a) {
2688
2706
  useSubmitComplete(hasActiveSubmission, () => {
2689
2707
  endSubmit();
2690
2708
  });
2691
- let clickedButtonRef = React.useRef();
2692
- useEffect(() => {
2693
- let form = formRef.current;
2694
- if (!form)
2695
- return;
2696
- function handleClick(event) {
2697
- if (!(event.target instanceof HTMLElement))
2698
- return;
2699
- let submitButton = event.target.closest("button,input[type=submit]");
2700
- if (submitButton && submitButton.form === form && submitButton.type === "submit") {
2701
- clickedButtonRef.current = submitButton;
2702
- }
2703
- }
2704
- window.addEventListener("click", handleClick, { capture: true });
2705
- return () => {
2706
- window.removeEventListener("click", handleClick, { capture: true });
2707
- };
2708
- }, []);
2709
- const handleSubmit = async (e2) => {
2709
+ const handleSubmit = async (e2, target, nativeEvent) => {
2710
2710
  startSubmit();
2711
2711
  const result = await validator.validate(getDataFromForm(e2.currentTarget));
2712
2712
  if (result.error) {
@@ -2722,12 +2722,11 @@ function ValidatedForm(_a) {
2722
2722
  endSubmit();
2723
2723
  return;
2724
2724
  }
2725
- const submitter = e2.nativeEvent.submitter;
2725
+ const submitter = nativeEvent.submitter;
2726
2726
  if (fetcher)
2727
2727
  fetcher.submit(submitter || e2.currentTarget);
2728
2728
  else
2729
- submit(submitter || e2.currentTarget, { method, replace });
2730
- clickedButtonRef.current = null;
2729
+ submit(submitter || target, { replace });
2731
2730
  }
2732
2731
  };
2733
2732
  return /* @__PURE__ */ React.createElement(Form$1, __spreadProps(__spreadValues({
@@ -2739,7 +2738,7 @@ function ValidatedForm(_a) {
2739
2738
  replace,
2740
2739
  onSubmit: (e2) => {
2741
2740
  e2.preventDefault();
2742
- handleSubmit(e2);
2741
+ handleSubmit(e2, e2.currentTarget, e2.nativeEvent);
2743
2742
  },
2744
2743
  onReset: (event) => {
2745
2744
  onReset == null ? void 0 : onReset(event);
@@ -2750,7 +2749,7 @@ function ValidatedForm(_a) {
2750
2749
  }
2751
2750
  }), /* @__PURE__ */ React.createElement(InternalFormContext.Provider, {
2752
2751
  value: contextValue
2753
- }, /* @__PURE__ */ React.createElement(FormResetter, {
2752
+ }, /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(FormResetter, {
2754
2753
  formRef,
2755
2754
  resetAfterSubmit
2756
2755
  }), subaction && /* @__PURE__ */ React.createElement("input", {
@@ -2761,7 +2760,7 @@ function ValidatedForm(_a) {
2761
2760
  type: "hidden",
2762
2761
  value: id,
2763
2762
  name: FORM_ID_FIELD
2764
- }), children));
2763
+ }), children)));
2765
2764
  }
2766
2765
  var baseSet = _baseSet;
2767
2766
  function set(object, path, value) {
@@ -2847,14 +2846,27 @@ const useFormHelpers = (formId) => {
2847
2846
  const clearError = useClearError(formContext);
2848
2847
  const setFieldErrors = useSetFieldErrors(formContext.formId);
2849
2848
  const reset = useResetFormElement(formContext.formId);
2849
+ const submit = useSubmitForm(formContext.formId);
2850
+ const getValues = useFormValues(formContext.formId);
2850
2851
  return useMemo(() => ({
2851
2852
  setTouched,
2852
2853
  validateField,
2853
2854
  clearError,
2854
2855
  validate,
2855
2856
  clearAllErrors: () => setFieldErrors({}),
2856
- reset
2857
- }), [clearError, reset, setFieldErrors, setTouched, validate, validateField]);
2857
+ reset,
2858
+ submit,
2859
+ getValues
2860
+ }), [
2861
+ clearError,
2862
+ reset,
2863
+ setFieldErrors,
2864
+ setTouched,
2865
+ submit,
2866
+ validate,
2867
+ validateField,
2868
+ getValues
2869
+ ]);
2858
2870
  };
2859
2871
  const useFormContext = (formId) => {
2860
2872
  const context = useInternalFormContext(formId, "useFormContext");
@@ -2865,7 +2877,9 @@ const useFormContext = (formId) => {
2865
2877
  validateField,
2866
2878
  clearAllErrors,
2867
2879
  validate,
2868
- reset
2880
+ reset,
2881
+ submit,
2882
+ getValues
2869
2883
  } = useFormHelpers(formId);
2870
2884
  const registerReceiveFocus = useRegisterReceiveFocus(context.formId);
2871
2885
  const clearError = useCallback((...names) => {
@@ -2880,7 +2894,9 @@ const useFormContext = (formId) => {
2880
2894
  registerReceiveFocus,
2881
2895
  clearAllErrors,
2882
2896
  validate,
2883
- reset
2897
+ reset,
2898
+ submit,
2899
+ getValues
2884
2900
  }), [
2885
2901
  clearAllErrors,
2886
2902
  clearError,
@@ -2888,8 +2904,10 @@ const useFormContext = (formId) => {
2888
2904
  reset,
2889
2905
  setTouched,
2890
2906
  state,
2907
+ submit,
2891
2908
  validate,
2892
- validateField
2909
+ validateField,
2910
+ getValues
2893
2911
  ]);
2894
2912
  };
2895
2913
  export { ValidatedForm, createValidator, setFormDefaults, useControlField, useField, useFormContext, useIsSubmitting, useIsValid, useUpdateControlledField, validationError };