Skip to content

Commit

Permalink
Store form ref on context and add useSubmit hook
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Oct 24, 2024
1 parent 5cc4bf3 commit 909ecdb
Show file tree
Hide file tree
Showing 8 changed files with 23 additions and 4 deletions.
1 change: 1 addition & 0 deletions lib/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type FormContext<S extends AnyObjectSchema> = FieldsContext & {
validate(): ValidationResult<InferType<S>>;
onSubmit: FormEventHandler<HTMLFormElement>;
setErrors(errors: ValidationError[]): void;
formRef: React.RefObject<HTMLFormElement>;
};

export const FormContext = createContext<FormContext<any> | undefined>(
Expand Down
3 changes: 3 additions & 0 deletions lib/create-form-context.tsx → lib/create-form-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type CreateFormContextOptions<S extends AnyObjectSchema> = {
schema: ReadonlySignal<S | undefined>;
id: string;
onSubmit?: FormEventHandler<HTMLFormElement>;
formRef: React.RefObject<HTMLFormElement>;
};

export function createFormContext<S extends AnyObjectSchema>({
Expand All @@ -25,6 +26,7 @@ export function createFormContext<S extends AnyObjectSchema>({
schema,
id,
onSubmit,
formRef,
}: CreateFormContextOptions<S>): FormContext<S> {
let result = signal(undefined);
let data = outerData || signal(submittedData || defaultData || {});
Expand Down Expand Up @@ -61,6 +63,7 @@ export function createFormContext<S extends AnyObjectSchema>({
touched,
didSubmit,
formId: id,
formRef,
validate,
onSubmit(event) {
onSubmit?.(event);
Expand Down
7 changes: 5 additions & 2 deletions lib/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FieldsContext, FormContext } from "~/context";
import { type ValidationError } from "~/utils/validate";
import { createFormContext } from "./create-form-context";
import type { DeepPartial } from "./utils/deep-partial";
import { useForwardedRef } from "~/utils/use-forwarded-ref";

export type FormProps<S extends AnyObjectSchema> = {
children?: ReactNode;
Expand All @@ -29,10 +30,11 @@ export const Form = forwardRef(
submittedErrors,
...props
}: FormProps<S>,
ref: ForwardedRef<HTMLFormElement>
forwardedRef: ForwardedRef<HTMLFormElement>
): JSX.Element => {
let formId = useId();
let schemaSignal = useSignal(schema);
let formRef = useForwardedRef(forwardedRef);

let formContext: FormContext<S> = useMemo(() => {
return createFormContext<S>({
Expand All @@ -43,6 +45,7 @@ export const Form = forwardRef(
schema: schemaSignal,
id: id || formId,
onSubmit,
formRef,
});
}, []);

Expand All @@ -56,7 +59,7 @@ export const Form = forwardRef(
id={id || formId}
{...props}
onSubmit={formContext.onSubmit}
ref={ref}
ref={formRef}
>
<FormContext.Provider value={formContext}>
<FieldsContext.Provider value={formContext}>
Expand Down
16 changes: 14 additions & 2 deletions lib/remix.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Form as RemixForm,
useActionData,
useNavigation,
useSubmit as useRemixSubmit,
} from "@remix-run/react";
import type { FormProps as RemixFormProps } from "@remix-run/react";
import type { ForwardedRef, ReactNode } from "react";
Expand All @@ -13,6 +14,7 @@ import type { ErrorActionData, ValidationErrorResult } from "~/utils/validate";
import { createFormContext } from "./create-form-context";
import type { DeepPartial } from "./utils/deep-partial";
import { json } from "@remix-run/node";
import { useForwardedRef } from "~/utils/use-forwarded-ref";

export * from "./index";

Expand All @@ -34,7 +36,7 @@ export const Form = forwardRef(
onSubmit,
...props
}: FormProps<S>,
ref: ForwardedRef<HTMLFormElement>
forwardedRef: ForwardedRef<HTMLFormElement>
): JSX.Element => {
let actionData = useActionData<ErrorActionData | undefined>();
let formId = useId();
Expand All @@ -46,6 +48,8 @@ export const Form = forwardRef(
}
}, [actionData?.errors]);

let formRef = useForwardedRef(forwardedRef);

let formContext: FormContext<S> = useMemo(() => {
return createFormContext<S>({
submittedErrors: actionData?.errors,
Expand All @@ -55,6 +59,7 @@ export const Form = forwardRef(
schema: schemaSignal,
id: id || formId,
onSubmit,
formRef,
});
}, []);

Expand All @@ -68,7 +73,7 @@ export const Form = forwardRef(
id={id || formId}
{...props}
onSubmit={formContext.onSubmit}
ref={ref}
ref={formRef}
>
<FormContext.Provider value={formContext}>
<FieldsContext.Provider value={formContext}>
Expand Down Expand Up @@ -97,3 +102,10 @@ export function useIsSubmitting() {
navigation.formData?.get("_formId") === form.formId
);
}

export function useSubmit() {
let remixSubmit = useRemixSubmit();
let context = useFormContext();

return () => remixSubmit(context.formRef.current);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 909ecdb

Please sign in to comment.