diff --git a/src/atomWithFormControls.ts b/src/atomWithFormControls.ts index 4cc9827..128414d 100644 --- a/src/atomWithFormControls.ts +++ b/src/atomWithFormControls.ts @@ -1,5 +1,9 @@ -import { atom } from 'jotai/vanilla'; -import type { Validator } from './validateAtoms'; +import { WritableAtom, atom } from 'jotai/vanilla'; +import type { + ExtractTypeOfValidatorValue, + Validator, + ValidatorState, +} from './validateAtoms'; import { AtomWithValidation, validateAtoms } from './validateAtoms'; type Options = { @@ -12,6 +16,24 @@ export type ActionableNext = { value: any; }; +export type FormControls = { + isValid: boolean; + fieldErrors: { + [k: string]: any; + }; + touched: Record; + focused: Record; + setValue(key: Keys, value: Vals): void; + setTouched(key: Keys, val: boolean): void; + setFocused(key: Keys, val: boolean): void; + handleOnChange(key: Keys): (val: any) => void; + handleOnFocus(key: Keys): () => unknown; + handleOnBlur(key: Keys): () => void; + values: Record>; + error: unknown; + isValidating: boolean | undefined; +}; + const getDefaultOptions = () => >{ validate: (v) => v, @@ -19,7 +41,7 @@ const getDefaultOptions = () => export function atomWithFormControls< AtomGroup extends Record>, - Keys extends keyof AtomGroup, + Keys extends Extract, Vals extends AtomGroup[Keys], >(labeledAtoms: AtomGroup, options?: Options) { const { validate } = Object.assign( @@ -155,5 +177,15 @@ export function atomWithFormControls< ); // Return read only atom to avoid direct modifications to the atom - return atom((get) => get(formControlAtom)); + const forceCastedAtom = formControlAtom as unknown as WritableAtom< + FormControls, + [next: ActionableNext], + | void + | ({ + values: Record>; + } & ValidatorState & + FormControls) + >; + + return atom((get) => get(forceCastedAtom)); }