UNPKG

@conform-to/dom

Version:

A set of opinionated helpers built on top of the Constraint Validation API

161 lines (160 loc) 6.6 kB
import { getFormAction, getFormEncType, getFormMethod } from './dom'; import { type Intent, type Submission, type SubmissionResult } from './submission'; type BaseCombine<T, K extends PropertyKey = T extends unknown ? keyof T : never> = T extends unknown ? T & Partial<Record<Exclude<K, keyof T>, never>> : never; export type Combine<T> = { [K in keyof BaseCombine<T>]: BaseCombine<T>[K]; }; export type DefaultValue<Schema> = Schema extends string | number | boolean | Date | bigint | null | undefined ? Schema | string | null | undefined : Schema extends File ? null | undefined : Schema extends Array<infer Item> ? Array<DefaultValue<Item>> | null | undefined : Schema extends Record<string, any> ? { [Key in keyof Schema]?: DefaultValue<Schema[Key]>; } | null | undefined : string | null | undefined; export type FormValue<Schema> = Schema extends string | number | boolean | Date | bigint | null | undefined ? string | undefined : Schema extends File ? File | undefined : Schema extends File[] ? File | Array<File> | undefined : Schema extends Array<infer Item> ? string | Array<FormValue<Item>> | undefined : Schema extends Record<string, any> ? { [Key in keyof Schema]?: FormValue<Schema[Key]>; } | undefined : unknown; declare const error: unique symbol; declare const field: unique symbol; declare const form: unique symbol; export type FormId<Schema extends Record<string, unknown> = Record<string, unknown>, Error = string[]> = string & { [error]?: Error; [form]?: Schema; }; export type FieldName<FieldSchema, FormSchema extends Record<string, unknown> = Record<string, unknown>, Error = string[]> = string & { [field]?: FieldSchema; [error]?: Error; [form]?: FormSchema; }; export type Constraint = { required?: boolean; minLength?: number; maxLength?: number; min?: string | number; max?: string | number; step?: string | number; multiple?: boolean; pattern?: string; }; export type FormMeta<FormError> = { formId: string; isValueUpdated: boolean; pendingIntents: Intent[]; submissionStatus?: 'error' | 'success'; defaultValue: Record<string, unknown>; initialValue: Record<string, unknown>; value: Record<string, unknown>; error: Record<string, FormError>; constraint: Record<string, Constraint>; key: Record<string, string | undefined>; validated: Record<string, boolean>; }; export type FormState<FormError> = Omit<FormMeta<FormError>, 'formId' | 'isValueUpdated'> & { valid: Record<string, boolean>; dirty: Record<string, boolean>; }; export type FormOptions<Schema, FormError = string[], FormValue = Schema> = { /** * The id of the form. */ formId: string; /** * An object representing the initial value of the form. */ defaultValue?: DefaultValue<Schema>; /** * An object describing the constraint of each field */ constraint?: Record<string, Constraint>; /** * An object describing the result of the last submission */ lastResult?: SubmissionResult<FormError> | null | undefined; /** * Define when conform should start validation. * Support "onSubmit", "onInput", "onBlur". * * @default "onSubmit" */ shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput'; /** * Define when conform should revalidate again. * Support "onSubmit", "onInput", "onBlur". * * @default Same as shouldValidate, or "onSubmit" if shouldValidate is not provided. */ shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput'; /** * Define if conform should consider the field for dirty state. * e.g. Excluding form fields that are not managed by Conform, such as CSRF token */ shouldDirtyConsider?: (name: string) => boolean; /** * A function to be called when the form should be (re)validated. */ onValidate?: (context: { form: HTMLFormElement; submitter: HTMLInputElement | HTMLButtonElement | null; formData: FormData; }) => Submission<Schema, FormError, FormValue>; }; export type SubscriptionSubject = { [key in 'error' | 'initialValue' | 'value' | 'key' | 'valid' | 'dirty']?: SubscriptionScope; } & { formId?: boolean; status?: boolean; pendingIntents?: boolean; }; export type SubscriptionScope = { prefix?: string[]; name?: string[]; }; export type ControlButtonProps = { name: string; value: string; form: string; formNoValidate: boolean; }; export type FormContext<Schema extends Record<string, any> = any, FormError = string[], FormValue = Schema> = { getFormId(): string; submit(event: SubmitEvent): { formData: FormData; action: ReturnType<typeof getFormAction>; encType: ReturnType<typeof getFormEncType>; method: ReturnType<typeof getFormMethod>; submission?: Submission<Schema, FormError, FormValue>; }; onReset(event: Event): void; onInput(event: Event): void; onBlur(event: Event): void; onUpdate(options: Partial<FormOptions<Schema, FormError, FormValue>>): void; observe(): () => void; runSideEffect(intents: Intent[]): void; subscribe(callback: () => void, getSubject?: () => SubscriptionSubject | undefined): () => void; getState(): FormState<FormError>; getSerializedState(): string; } & { [Type in Intent['type']]: {} extends Extract<Intent, { type: Type; }>['payload'] ? (<FieldSchema = Schema>(payload?: Extract<Intent<FieldSchema>, { type: Type; }>['payload']) => void) & { getButtonProps<FieldSchema = Schema>(payload?: Extract<Intent<FieldSchema>, { type: Type; }>['payload']): ControlButtonProps; } : (<FieldSchema = Schema>(payload: Extract<Intent<FieldSchema>, { type: Type; }>['payload']) => void) & { getButtonProps<FieldSchema = Schema>(payload: Extract<Intent<FieldSchema>, { type: Type; }>['payload']): ControlButtonProps; }; }; export declare function createFormContext<Schema extends Record<string, any>, FormError = string[], FormValue = Schema>(options: FormOptions<Schema, FormError, FormValue>): FormContext<Schema, FormError, FormValue>; /** * Updates the DOM element with the provided value. * * @param element The form element to update * @param options The options to update the form element */ export declare function updateFieldValue(element: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, options: { value?: string | string[]; defaultValue?: string | string[]; }): void; export {};