fielder
Version:
A field-first form library for React and React Native
138 lines (121 loc) • 4.21 kB
text/typescript
import { SetFieldValueArgs } from './actions/setFieldValue';
import { ValidateFieldArgs } from './actions/validateField';
import { MountFieldArgs } from './actions/mountField';
import { BlurFieldArgs } from './actions/blurField';
import { UnmountFieldArgs } from './actions/unmountField';
import { SetFieldStateArgs } from './actions/setFieldState';
import { SetFieldValidationArgs } from './actions/setFieldValidation';
export type FormValue = string | boolean | number | string[];
export type FormSchemaType = Record<string, FormValue>;
export type FieldsState<T extends FormSchemaType = FormSchemaType> = {
[K in keyof T]: FieldState<T, K>;
};
export interface FormState<T extends FormSchemaType = FormSchemaType> {
fields: FieldsState<T>;
/** All mounted fields are valid. */
isValid: boolean;
/** Async validation currently active on a mounted fields. */
isValidating: boolean;
/** Set value for a field. */
setFieldValue: <K extends keyof T>(a: SetFieldValueArgs<T, K>) => void;
/** Trigger blur event for a mounted field. */
blurField: (a: BlurFieldArgs<T>) => void;
/** Force trigger validation on a mounted field. */
validateField: (a: ValidateFieldArgs<T>) => void;
/** Internal: Premount field during render */
premountField: <K extends keyof T & string>(
a: MountFieldArgs<T, K>
) => FieldState<T, K>;
/** Internal: Manually mount field. */
mountField: <K extends keyof T & string>(
a: MountFieldArgs<T, K>
) => FieldState<T, K>;
/** Internal: Manually unmount field. */
unmountField: (a: UnmountFieldArgs<T>) => void;
/** Internal: Manually set field state. */
setFieldState: <K extends keyof T>(a: SetFieldStateArgs<T, K>) => void;
/** Internal: Set new field validation function */
setFieldValidation: <K extends keyof T>(
a: SetFieldValidationArgs<T, K>
) => void;
/** Trigger submission validation.
*
* Throws on synchronous validation errors.
* Returns promise if form contains async validation.
*/
validateSubmission: () => MaybePromise<{
state: FieldsState;
errors: Record<string, string>;
}>;
}
export interface FieldState<
T extends FormSchemaType | FormValue = FormValue,
K extends keyof T = any,
// Resolve value and schema form generics
V extends FormValue = T extends FormSchemaType ? T[K] : T,
S extends FormSchemaType = T extends FormSchemaType ? T : FormSchemaType
> {
/** The field is currently mounted. */
readonly _isActive: boolean;
/** Validation function. */
readonly _validate?: ValidationFn<V, S> | ObjectValidation<V, S>;
// Props
/** Field name */
readonly name: K;
/** Field value */
readonly value: V;
// Meta
/** Field error */
readonly error?: string;
/** Field is currently valid. */
readonly isValid: boolean;
/** Field is currently being validated (async). */
readonly isValidating: boolean;
/** Field has been blurred since mount. */
readonly hasBlurred: boolean;
/** Field has been changed since mount. */
readonly hasChanged: boolean;
}
/**
* Events which trigger validation
*
* `mount`: Field has been mounted.
*
* `blur`: Field has had 'onBlur' event.
*
* `change`: Field has had 'onChange' event.
*
* `update`: The value of another field in the form has changed.
*
* `submit`: Submission has begun.
*/
export type ValidationTrigger =
| 'mount'
| 'blur'
| 'change'
| 'update'
| 'submit';
/** Arguments passed to a validation function */
export type ValidationArgs<
T extends FormValue = FormValue,
S extends FormSchemaType = FormSchemaType
> = {
trigger: ValidationTrigger;
value: T;
form: FieldsState<S>;
};
/** Handler for validation event */
export type ValidationFn<
T extends FormValue = FormValue,
S extends FormSchemaType = FormSchemaType
> = (args: ValidationArgs<T, S>) => void | Promise<void>;
/** A map of validation events corresponding to a function. */
export type ObjectValidation<
T extends FormValue = FormValue,
S extends FormSchemaType = FormSchemaType
> = {
[k in ValidationTrigger]?: ValidationFn<T, S>;
};
type MaybePromise<T> = T | Promise<T>;
export type Dispatch<T> = (a: T) => void;
export type SetStateAction<T> = T | ((a: T) => T);