Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | 'use client';
/**
* Form Context
*
* Provides a unified form context for managing form state, validation,
* and submission across the application.
*/
import { createContext, useContext, ReactNode } from 'react';
import { z } from 'zod';
/**
* Form field state
*/
export interface FieldState {
value: unknown;
error: string | null;
touched: boolean;
dirty: boolean;
}
/**
* Generic form context value type
*/
export interface FormContextValue<T extends Record<string, unknown>> {
values: T;
errors: Record<keyof T, string | null>;
touched: Record<keyof T, boolean>;
isSubmitting: boolean;
isValid: boolean;
isDirty: boolean;
setValue: (field: keyof T, value: unknown) => void;
setTouched: (field: keyof T) => void;
setError: (field: keyof T, error: string | null) => void;
validateField: (field: keyof T) => Promise<string | null>;
validateForm: () => Promise<boolean>;
resetForm: () => void;
handleSubmit: (onSubmit: (values: T) => Promise<void>) => (e: React.FormEvent) => void;
getFieldProps: (field: keyof T) => {
value: unknown;
onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => void;
onBlur: () => void;
'aria-invalid': boolean;
};
}
// Create the context with a default undefined value
const FormContext = createContext<FormContextValue<Record<string, unknown>> | undefined>(undefined);
/**
* Form Provider Props
*/
interface FormProviderProps<T extends Record<string, unknown>> {
value: FormContextValue<T>;
children: ReactNode;
}
/**
* Form Provider Component
*
* Wraps form components to provide form state and validation context.
*/
export function FormProvider<T extends Record<string, unknown>>({
value,
children
}: FormProviderProps<T>) {
return (
<FormContext.Provider value={value as FormContextValue<Record<string, unknown>>}>
{children}
</FormContext.Provider>
);
}
/**
* Hook to access form context
*
* @throws Error if used outside of FormProvider
*/
export function useFormContext<T extends Record<string, unknown>>(): FormContextValue<T> {
const context = useContext(FormContext);
if (!context) {
throw new Error('useFormContext must be used within a FormProvider');
}
return context as FormContextValue<T>;
}
/**
* Type helper for creating form schemas
*/
export type FormSchema<T> = z.ZodType<T>;
/**
* Extract form values type from a Zod schema
*/
export type FormValues<T extends z.ZodTypeAny> = z.infer<T>;
|