UNPKG

el-form-react-hooks

Version:

React Hook Form alternative - TypeScript-first useForm hook with enterprise-grade state management. Schema-agnostic validation (Zod, Yup, Valibot), minimal re-renders, advanced form controls.

198 lines (188 loc) 8.22 kB
import { ValidatorConfig } from 'el-form-core'; export * from 'el-form-core'; import * as react_jsx_runtime from 'react/jsx-runtime'; import React$1 from 'react'; interface FileInfo { name: string; size: number; type: string; lastModified: number; formattedSize: string; isImage: boolean; extension: string; } interface FileValidationOptions { maxSize?: number; minSize?: number; maxFiles?: number; minFiles?: number; acceptedTypes?: string[]; acceptedExtensions?: string[]; } type Primitive = string | number | boolean | symbol | null | undefined | Date | bigint | Function; type ArrayElem<T> = T extends readonly (infer E)[] ? E : T extends (infer E)[] ? E : never; type ArrayPaths<K extends string, V> = K | `${K}.${number}` | `${K}[${number}]` | (V extends object ? `${K}.${number}.${Path<V>}` | `${K}[${number}].${Path<V>}` : never); type Path<T, Prev extends string = never> = T extends Primitive ? never : { [K in Extract<keyof T, string>]: T[K] extends Primitive ? K | Prev : T[K] extends readonly any[] | any[] ? ArrayPaths<K, ArrayElem<T[K]>> | Prev : K | `${K}.${Path<T[K], Prev>}` | Prev; }[Extract<keyof T, string>]; type PathValue<T, P extends string> = P extends `${infer K}.${infer Rest}` ? K extends `${infer Key}[${number}]` ? Key extends keyof T ? T[Key] extends readonly any[] | any[] ? PathValue<ArrayElem<T[Key]>, Rest> : never : never : K extends `${number}` ? T extends readonly any[] | any[] ? PathValue<ArrayElem<T>, Rest> : never : K extends keyof T ? PathValue<T[K], Rest> : never : P extends `${infer K}[${number}]` ? K extends keyof T ? T[K] extends readonly any[] | any[] ? ArrayElem<T[K]> : never : never : P extends `${number}` ? T extends readonly any[] | any[] ? ArrayElem<T> : never : P extends keyof T ? T[P] : unknown; type RegisterReturn<Value> = { name: string; onChange: (e: React.ChangeEvent<any>) => void; onBlur: (e: React.FocusEvent<any>) => void; } & (Value extends boolean ? { checked: boolean; value?: never; files?: never; } : Value extends File | FileList | (File | null)[] | File[] | null | undefined ? { files: FileList | File | File[] | null; value?: never; checked?: never; } : { value: Value; checked?: never; files?: never; }); interface FormContextValue<T extends Record<string, any>> { form: UseFormReturn<T>; formId?: string; } interface FormState<T extends Record<string, any>> { values: Partial<T>; errors: Partial<Record<keyof T, string>>; touched: Partial<Record<keyof T, boolean>>; isSubmitting: boolean; isValid: boolean; isDirty: boolean; } interface FormSnapshot<T extends Record<string, any>> { values: Partial<T>; errors: Partial<Record<keyof T, string>>; touched: Partial<Record<keyof T, boolean>>; timestamp: number; isDirty: boolean; } interface UseFormOptions<T extends Record<string, any>> { defaultValues?: Partial<T>; validators?: ValidatorConfig; onSubmit?: (values: T) => void | Promise<void>; fieldValidators?: Partial<Record<keyof T, ValidatorConfig>>; fileValidators?: Partial<Record<keyof T, FileValidationOptions>>; mode?: "onChange" | "onBlur" | "onSubmit" | "all"; validateOn?: "onChange" | "onBlur" | "onSubmit" | "manual"; schema?: any; } interface FieldState { isDirty: boolean; isTouched: boolean; error?: string; } interface ResetOptions<T> { values?: Partial<T>; keepErrors?: boolean; keepDirty?: boolean; keepTouched?: boolean; } interface SetFocusOptions { shouldSelect?: boolean; } interface UseFormReturn<T extends Record<string, any>> { register<Name extends Path<T>>(name: Name): RegisterReturn<PathValue<T, Name>>; handleSubmit: (onValid: (data: T) => void, onError?: (errors: Record<keyof T, string>) => void) => (e: React.FormEvent) => void; formState: FormState<T>; reset: (options?: ResetOptions<T>) => void; setValue: <Name extends Path<T>>(path: Name, value: PathValue<T, Name>) => void; setValues: (values: Partial<T>) => void; watch: { (): Partial<T>; <Name extends Path<T>>(name: Name): PathValue<T, Name>; <Names extends Path<T>>(names: Names[]): { [K in Names]: PathValue<T, K>; }; }; resetValues: (values?: Partial<T>) => void; getFieldState: <Name extends keyof T>(name: Name) => FieldState; isDirty: <Name extends keyof T>(name?: Name) => boolean; getDirtyFields: () => Partial<Record<keyof T, boolean>>; getTouchedFields: () => Partial<Record<keyof T, boolean>>; isFieldDirty: (name: string) => boolean; isFieldTouched: (name: string) => boolean; isFieldValid: (name: string) => boolean; hasErrors: () => boolean; getErrorCount: () => number; markAllTouched: () => void; markFieldTouched: (name: string) => void; markFieldUntouched: (name: string) => void; trigger: { (): Promise<boolean>; <Name extends keyof T>(name: Name): Promise<boolean>; <Names extends keyof T>(names: Names[]): Promise<boolean>; }; clearErrors: (name?: keyof T) => void; setError: <Name extends keyof T>(name: Name, error: string) => void; setFocus: <Name extends keyof T>(name: Name, options?: SetFocusOptions) => void; addArrayItem: (path: string, item: any) => void; removeArrayItem: (path: string, index: number) => void; resetField: <Name extends Path<T>>(name: Name) => void; submit: () => Promise<void>; submitAsync: () => Promise<{ success: true; data: T; } | { success: false; errors: Partial<Record<keyof T, string>>; }>; canSubmit: boolean; getSnapshot: () => FormSnapshot<T>; restoreSnapshot: (snapshot: FormSnapshot<T>) => void; hasChanges: () => boolean; getChanges: () => Partial<T>; addFile: (name: string, file: File) => void; removeFile: (name: string, index?: number) => void; clearFiles: (name: string) => void; getFileInfo: (file: File) => FileInfo; getFilePreview: (file: File) => Promise<string | null>; filePreview: Partial<Record<keyof T, string | null>>; } declare function useForm<T extends Record<string, any>>(options: UseFormOptions<T>): UseFormReturn<T>; interface DiscriminatedUnionContextValue { schema?: any; unionMetadata?: { discriminatorField: string; options: Array<{ value: string; label: string; }>; unionOptions: Record<string, any[]>; }; } declare function FormProvider<T extends Record<string, any>>({ children, form, formId, schema, }: { children: React$1.ReactNode; form: UseFormReturn<T>; formId?: string; schema?: any; }): react_jsx_runtime.JSX.Element; declare function useFormContext<T extends Record<string, any> = any>(): FormContextValue<T>; declare function useFormState<T extends Record<string, any> = any>(): UseFormReturn<T>; declare function useDiscriminatedUnionContext(): DiscriminatedUnionContextValue | undefined; /** * Select a slice of the form state and subscribe to changes in that slice. * Default equality uses Object.is. Pass a custom equality for arrays/objects * (e.g., shallowEqual) to avoid unnecessary notifications. */ declare function useFormSelector<TSelected>(selector: (s: FormState<any>) => TSelected, equalityFn?: (a: TSelected, b: TSelected) => boolean): TSelected; type FieldSlice<T, Name extends Path<T>> = { value: PathValue<T, Name>; error: any; touched: any; }; declare function useField<T extends Record<string, any>, Name extends Path<T>>(name: Name): FieldSlice<T, Name>; /** * Efficient equality comparison utilities for form state management */ /** * Shallow equality comparison for objects * Much faster than JSON.stringify for simple comparisons */ declare function shallowEqual(obj1: any, obj2: any): boolean; export { type FieldState, type FormContextValue, FormProvider, type FormState, type Path, type PathValue, type RegisterReturn, type ResetOptions, type SetFocusOptions, type UseFormOptions, type UseFormReturn, shallowEqual, useDiscriminatedUnionContext, useField, useForm, useFormContext, useFormSelector, useFormState };