UNPKG

react-jsonschema-form-validation

Version:
253 lines (249 loc) 11.6 kB
import Ajv from 'ajv'; import { JSONSchema7Definition } from 'json-schema'; import React$1 from 'react'; /** * An AJV `ErrorObject` enriched with a `field` property — a normalized, * dot-separated path to the offending field (e.g. `'user.email'` or * `'items.0.label'`). Used everywhere internally to locate the input * associated with an error. */ export type FormattedError = Ajv.ErrorObject & { field: string; }; /** * Minimal shape required by the library on an input target. Structurally * compatible with `HTMLInputElement`, `HTMLTextAreaElement`, `HTMLSelectElement` * and any custom object that mimics them (e.g. when an integration like * `react-select` synthesizes its own events). Only the properties actually * read by the library appear here. */ export type FormInputTarget = { name: string; value: string; type?: string; checked?: boolean; files?: FileList | null; multiple?: boolean; }; /** * Lightweight change event accepted by the form. Any DOM `ChangeEvent` * or `InputEvent` is structurally compatible with this shape, so users can * forward native React events without casting. */ export type FormChangeEvent = { target: FormInputTarget; }; /** * Internal `Omit` variant that keeps typed keys strict even when `T` has an * index signature (like `[key: string]: any` — reactstrap and a few other * libraries expose these). Standard `Omit<T, K>` on such a type collapses * the typed keys back into `any` through the index, which effectively kills * the polymorphic type-checking on `<Field component={X} .../>` etc. * * This variant: * 1. Strips the index signature so `Omit` can operate on named keys only, * keeping their precise types. * 2. Only re-attaches the original index signature (with its original * value type) *if T actually had one to begin with*. The `string * extends keyof T` guard prevents accidentally re-injecting an index * signature on plain "record-like" types whose values happen to share * a common supertype (e.g. `{ label: string; flavor: 'a' | 'b' }` * structurally extends `{ [k: string]: string }` but does not really * accept arbitrary keys). */ export type SafePropsOmit<T, K extends PropertyKey> = (Omit<{ [P in keyof T as string extends P ? never : P]: T[P]; }, K> & (string extends keyof T ? (T extends { [k: string]: infer V; } ? { [k: string]: V; } : {}) : {})); /** * Built-in AJV validation keywords. Listed here so consumers writing * `errorMessages` get IDE autocomplete on the well-known keys while still * being free to add custom keywords (any other string is accepted via the * `(string & {})` intersection in `ErrorMessagesMap`). */ export type AjvKeyword = ("type" | "required" | "enum" | "const" | "minimum" | "maximum" | "exclusiveMinimum" | "exclusiveMaximum" | "multipleOf" | "minLength" | "maxLength" | "pattern" | "format" | "minItems" | "maxItems" | "uniqueItems" | "minProperties" | "maxProperties" | "additionalProperties" | "dependencies" | "patternProperties" | "properties" | "oneOf" | "anyOf" | "allOf" | "not" | "if" | "then" | "else"); /** * Builds a single error message string from an AJV error. */ export type ErrorMessageFn = (error: FormattedError) => string; /** * Map of error messages. `defaultMessage` is the catch-all used by * `<FieldError>` when no entry matches the error's keyword. The known * keywords (see {@link AjvKeyword}) are typed for autocomplete; any other * string key (e.g. a custom AJV keyword) is still allowed. * * The `(string & {})` in the key union is the standard TypeScript trick to * accept arbitrary strings *without* collapsing the literal union — plain * `string` would erase the autocomplete on the known keywords. */ export type ErrorMessagesMap = Partial<Record<AjvKeyword | "defaultMessage" | (string & {}), ErrorMessageFn>>; /** * The complete value of the form context, supplied by `<Form>` to all its * descendants. The actual context type is `FormContextValue | undefined` * (it is `undefined` for any consumer rendered outside a `<Form>`), but * `useFormContext()` and `withFormContext()` perform the runtime check * so downstream code receives a guaranteed non-`undefined` value. */ export type FormContextValue = { errors: FormattedError[]; isSubmitted: boolean; touchedFields: string[]; valid: boolean; errorMessages?: ErrorMessagesMap; getFieldErrors: (names: string | string[]) => FormattedError[]; handleFieldChange: (event: FormChangeEvent | string, value?: unknown) => void; isFieldTouched: (names: string | string[]) => boolean; isFieldInvalid: (names: string | string[]) => boolean; isTouched: () => boolean; touch: (names: string | string[]) => void; }; declare const _default: <C extends React$1.ElementType = "input">(props: FieldProps<C> & { ref?: React$1.ComponentPropsWithRef<C>["ref"]; }) => JSX.Element | null; /** * Signature of the user-supplied `onChange` handler. It receives the event * and the form's internal handler so the user can decide whether to apply, * transform or skip the update. */ export type FieldChangeHandler = (event: FormChangeEvent, formHandleFieldChange: FormContextValue["handleFieldChange"]) => void; /** * Base props of `<Field>` — the validation-specific props handled by the * component itself. The public, polymorphic `FieldProps<C>` extends this * with the props of the underlying component `C`. * * `forwardedRef` is an implementation detail (injected by the outer * `React.forwardRef` wrapper) and is omitted from the public polymorphic * type below. */ export type FieldBaseProps = { name: string; children?: React$1.ReactNode; className?: string; component?: React$1.ElementType; forwardedRef?: React$1.Ref<unknown> | null; onBlur?: ((event: React$1.FocusEvent) => void) | null; onChange?: FieldChangeHandler | null; }; /** * Polymorphic props of `<Field>`. When `component={X}` is supplied, every * prop accepted by `X` is also accepted here (with autocomplete and typo * detection). The default `C = 'input'` matches the runtime default. * * - `name` — path within the form data this field reads/writes. * - `component` — host element or component (default `'input'`). * - `onChange` — user override; receives the raw event plus the form's * internal change handler so the user can decide whether * to apply, transform or skip the update. * - `onBlur` — user override; always fires *after* `form.touch(name)`. */ export type FieldProps<C extends React$1.ElementType = "input"> = (Omit<FieldBaseProps, "component" | "forwardedRef"> & { component?: C; } & SafePropsOmit<React$1.ComponentProps<C>, keyof FieldBaseProps | "ref">); declare const _default$1: <C extends React$1.ElementType = "div">(props: FieldErrorProps<C>) => JSX.Element | null; /** * Base props of `<FieldError>` — the validation-specific props handled by * the component itself. The public, polymorphic `FieldErrorProps<C>` extends * this with the props of the underlying component `C`. */ export type FieldErrorBaseProps = { children?: React$1.ReactNode; className?: string; component?: React$1.ElementType; errorMessages?: ErrorMessagesMap | null; name: string; }; /** * Polymorphic props of `<FieldError>`. When `component={X}` is supplied, * every prop accepted by `X` is also accepted here (with autocomplete and * typo detection). The default `C = 'div'` matches the runtime default. * * - `name` — path of the form field whose first error should be shown. * - `errorMessages` — optional per-field overrides; they take priority over the * map declared at the `<Form>` level (see `ErrorMessagesMap`). * - `component` — element rendered when an error is present (default `'div'`). * - `children` — replaces the auto-generated message when provided. */ export type FieldErrorProps<C extends React$1.ElementType = "div"> = (Omit<FieldErrorBaseProps, "component"> & { component?: C; } & SafePropsOmit<React$1.ComponentProps<C>, keyof FieldErrorBaseProps | "ref">); declare const _default$2: <T = Record<string, unknown>, C extends React$1.ElementType = "form">(props: FormProps<T, C>) => JSX.Element | null; /** * Options controlling how the form scrolls to the first invalid field on * a failed submit. */ export type JfvScrollOptions = { offset?: number; align?: "top" | "middle" | "bottom" | (string & {}); duration?: number; ease?: string; }; /** * Base props of `<Form>` — the validation-specific props the component * handles itself. The public, polymorphic `FormProps<T, C>` extends this * with the props of the underlying component `C` and typed data `T`. */ export type FormBaseProps = { ajv?: Ajv.Ajv; children?: React$1.ReactNode; className?: string; component?: React$1.ElementType; data?: Record<string, unknown>; throttleDuration?: number; errorMessages?: ErrorMessagesMap; onChange?: ((data: Record<string, unknown>, event?: FormChangeEvent) => void) | null; onSubmit: (event: React$1.FormEvent) => void; schema: JSONSchema7Definition; scrollToError?: boolean; scrollOptions?: JfvScrollOptions; }; /** * Polymorphic props of `<Form>`. Two type parameters: * - `T` — shape of the form data. Inferred from `data` / `onChange`, or * you can pass it explicitly via `<Form<UserData> …>`. Default * `Record<string, unknown>`. Note that `T` is a *promise* by the * caller: nothing at compile time ensures the JSON Schema actually * validates `T`. * - `C` — element type used for the form wrapper (the `component` prop). * Default `'form'`. When supplied, every prop accepted by `C` is * also accepted on `<Form>` (autocomplete + typo detection). * * Field reference: * - `schema` — JSON-Schema used to validate `data`. * - `data` — current form values, fully controlled by the parent. * - `onChange` — called with the updated data on every field change. * - `onSubmit` — called only when validation passes at submit time. * - `errorMessages` — map of error messages shared by every `<FieldError>` * descendant (see `ErrorMessagesMap`). * - `ajv` — optional pre-configured AJV instance, useful to plug * in custom keywords/formats. * - `component` — element rendered for the form wrapper (default `<form noValidate>`). */ export type FormProps<T = Record<string, unknown>, C extends React$1.ElementType = "form"> = (Omit<FormBaseProps, "component" | "data" | "onChange"> & { component?: C; data?: T; onChange?: ((data: T, event?: FormChangeEvent) => void) | null; } & SafePropsOmit<React$1.ComponentProps<C>, keyof FormBaseProps | "ref">); export function useFormContext(): FormContextValue; export function withFormContext<T>(cb: (ctx: FormContextValue) => T): React$1.ReactElement; /** * @import { ReactElement } from 'react' * @import { FormContextValue } from './Context.types' */ /** * React context that carries the `<Form>` state down to descendant * `<Field>` and `<FieldError>` components. Not intended for direct use — * consume it through `useFormContext()` (or the legacy `withFormContext()` * render-prop helper), which handles the "outside a Form" case with a * descriptive error instead of returning `undefined`. */ export declare const FormContext: React$1.Context<FormContextValue | undefined>; export { _default as Field, _default$1 as FieldError, _default$2 as Form, _default$2 as default, }; export {};