UNPKG

@rjsf/core

Version:

A simple React component capable of building HTML forms out of a JSON schema.

511 lines 30.9 kB
import { Component, ElementType, FormEvent, ReactNode, Ref, RefObject } from 'react'; import { CustomValidator, ErrorSchema, ErrorSchemaBuilder, ErrorTransformer, FieldPathId, FieldPathList, FormContextType, PathSchema, StrictRJSFSchema, Registry, RegistryFieldsType, RegistryWidgetsType, RJSFSchema, RJSFValidationError, SchemaUtilsType, TemplatesType, UiSchema, ValidationData, ValidatorType, Experimental_DefaultFormStateBehavior, Experimental_CustomMergeAllOf, NameGeneratorFunction } from '@rjsf/utils'; /** Represents a boolean option that is deprecated. * @deprecated - In a future major release, this type will be removed */ type DeprecatedBooleanOption = boolean; /** The properties that are passed to the `Form` */ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> { /** The JSON schema object for the form */ schema: S; /** An implementation of the `ValidatorType` interface that is needed for form validation to work */ validator: ValidatorType<T, S, F>; /** The optional children for the form, if provided, it will replace the default `SubmitButton` */ children?: ReactNode; /** The uiSchema for the form */ uiSchema?: UiSchema<T, S, F>; /** The data for the form, used to load a "controlled" form with its current data. If you want an "uncontrolled" form * with initial data, then use `initialFormData` instead. */ formData?: T; /** The initial data for the form, used to fill an "uncontrolled" form with existing data on the initial render and * when `reset()` is called programmatically. */ initialFormData?: T; /** You can provide a `formContext` object to the form, which is passed down to all fields and widgets. Useful for * implementing context aware fields and widgets. * * NOTE: Setting `{readonlyAsDisabled: false}` on the formContext will make the antd theme treat readOnly fields as * disabled. */ formContext?: F; /** To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids; * Default is `root` */ idPrefix?: string; /** To avoid using a path separator that is present in field names, it is possible to change the separator used for * ids (Default is `_`) */ idSeparator?: string; /** It's possible to disable the whole form by setting the `disabled` prop. The `disabled` prop is then forwarded down * to each field of the form. If you just want to disable some fields, see the `ui:disabled` parameter in `uiSchema` */ disabled?: boolean; /** It's possible to make the whole form read-only by setting the `readonly` prop. The `readonly` prop is then * forwarded down to each field of the form. If you just want to make some fields read-only, see the `ui:readonly` * parameter in `uiSchema` */ readonly?: boolean; /** The dictionary of registered fields in the form */ fields?: RegistryFieldsType<T, S, F>; /** The dictionary of registered templates in the form; Partial allows a subset to be provided beyond the defaults */ templates?: Partial<Omit<TemplatesType<T, S, F>, 'ButtonTemplates'>> & { ButtonTemplates?: Partial<TemplatesType<T, S, F>['ButtonTemplates']>; }; /** The dictionary of registered widgets in the form */ widgets?: RegistryWidgetsType<T, S, F>; /** If you plan on being notified every time the form data are updated, you can pass an `onChange` handler, which will * receive the same args as `onSubmit` any time a value is updated in the form. Can also return the `id` of the field * that caused the change */ onChange?: (data: IChangeEvent<T, S, F>, id?: string) => void; /** To react when submitted form data are invalid, pass an `onError` handler. It will be passed the list of * encountered errors */ onError?: (errors: RJSFValidationError[]) => void; /** You can pass a function as the `onSubmit` prop of your `Form` component to listen to when the form is submitted * and its data are valid. It will be passed a result object having a `formData` attribute, which is the valid form * data you're usually after. The original event will also be passed as a second parameter */ onSubmit?: (data: IChangeEvent<T, S, F>, event: FormEvent<any>) => void; /** Sometimes you may want to trigger events or modify external state when a field has been touched, so you can pass * an `onBlur` handler, which will receive the id of the input that was blurred and the field value */ onBlur?: (id: string, data: any) => void; /** Sometimes you may want to trigger events or modify external state when a field has been focused, so you can pass * an `onFocus` handler, which will receive the id of the input that is focused and the field value */ onFocus?: (id: string, data: any) => void; /** The value of this prop will be passed to the `accept-charset` HTML attribute on the form */ acceptCharset?: string; /** The value of this prop will be passed to the `action` HTML attribute on the form * * NOTE: this just renders the `action` attribute in the HTML markup. There is no real network request being sent to * this `action` on submit. Instead, react-jsonschema-form catches the submit event with `event.preventDefault()` * and then calls the `onSubmit` function, where you could send a request programmatically with `fetch` or similar. */ action?: string; /** The value of this prop will be passed to the `autocomplete` HTML attribute on the form */ autoComplete?: string; /** The value of this prop will be passed to the `class` HTML attribute on the form */ className?: string; /** The value of this prop will be passed to the `enctype` HTML attribute on the form */ enctype?: string; /** The value of this prop will be passed to the `id` HTML attribute on the form */ id?: string; /** The value of this prop will be passed to the `name` HTML attribute on the form */ name?: string; /** The value of this prop will be passed to the `method` HTML attribute on the form */ method?: string; /** It's possible to change the default `form` tag name to a different HTML tag, which can be helpful if you are * nesting forms. However, native browser form behaviour, such as submitting when the `Enter` key is pressed, may no * longer work */ tagName?: ElementType; /** The value of this prop will be passed to the `target` HTML attribute on the form */ target?: string; /** Formerly the `validate` prop; Takes a function that specifies custom validation rules for the form */ customValidate?: CustomValidator<T, S, F>; /** This prop allows passing in custom errors that are augmented with the existing JSON Schema errors on the form; it * can be used to implement asynchronous validation. By default, these are non-blocking errors, meaning that you can * still submit the form when these are the only errors displayed to the user. */ extraErrors?: ErrorSchema<T>; /** If set to true, causes the `extraErrors` to become blocking when the form is submitted */ extraErrorsBlockSubmit?: boolean; /** If set to true, turns off HTML5 validation on the form; Set to `false` by default */ noHtml5Validate?: boolean; /** If set to true, turns off all validation. Set to `false` by default * * @deprecated - In a future release, this switch may be replaced by making `validator` prop optional */ noValidate?: boolean; /** Flag that describes when live validation will be performed. Live validation means that the form will perform * validation and show any validation errors whenever the form data is updated, rather than just on submit. * * If no value (or `false`) is provided, then live validation will not happen. If `true` or `onChange` is provided for * the flag, then live validation will be performed after processing of all pending changes has completed. If `onBlur` * is provided, then live validation will be performed when a field that was updated is blurred (as a performance * optimization). * * NOTE: In a future major release, the `boolean` options for this flag will be removed */ liveValidate?: 'onChange' | 'onBlur' | DeprecatedBooleanOption; /** Flag that describes when live omit will be performed. Live omit happens only when `omitExtraData` is also set to * to `true` and the form's data is updated by the user. * * If no value (or `false`) is provided, then live omit will not happen. If `true` or `onChange` is provided for * the flag, then live omit will be performed after processing of all pending changes has completed. If `onBlur` * is provided, then live omit will be performed when a field that was updated is blurred (as a performance * optimization). * * NOTE: In a future major release, the `boolean` options for this flag will be removed */ liveOmit?: 'onChange' | 'onBlur' | DeprecatedBooleanOption; /** If set to true, then extra form data values that are not in any form field will be removed whenever `onSubmit` is * called. Set to `false` by default. */ omitExtraData?: boolean; /** When this prop is set to `top` or 'bottom', a list of errors (or the custom error list defined in the `ErrorList`) will also * show. When set to false, only inline input validation errors will be shown. Set to `top` by default */ showErrorList?: false | 'top' | 'bottom'; /** A function can be passed to this prop in order to make modifications to the default errors resulting from JSON * Schema validation */ transformErrors?: ErrorTransformer<T, S, F>; /** If set to true, then the first field with an error will receive the focus when the form is submitted with errors */ focusOnFirstError?: boolean | ((error: RJSFValidationError) => void); /** Optional string translation function, if provided, allows users to change the translation of the RJSF internal * strings. Some strings contain replaceable parameter values as indicated by `%1`, `%2`, etc. The number after the * `%` indicates the order of the parameter. The ordering of parameters is important because some languages may choose * to put the second parameter before the first in its translation. */ translateString?: Registry['translateString']; /** Optional function to generate custom HTML `name` attributes for form fields. */ nameGenerator?: NameGeneratorFunction; /** Optional flag that, when set to true, will cause the `FallbackField` to render a type selector for unsupported * fields instead of the default UnsupportedField error UI. */ useFallbackUiForUnsupportedType?: boolean; /** Optional configuration object with flags, if provided, allows users to override default form state behavior * Currently only affecting minItems on array fields and handling of setting defaults based on the value of * `emptyObjectFields` */ experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior; /** * Controls the component update strategy used by the Form's `shouldComponentUpdate` lifecycle method. * * - `'customDeep'`: Uses RJSF's custom deep equality checks via the `deepEquals` utility function, * which treats all functions as equivalent and provides optimized performance for form data comparisons. * - `'shallow'`: Uses shallow comparison of props and state (only compares direct properties). This matches React's PureComponent behavior. * - `'always'`: Always rerenders when called. This matches React's Component behavior. * * @default 'customDeep' */ experimental_componentUpdateStrategy?: 'customDeep' | 'shallow' | 'always'; /** Optional function that allows for custom merging of `allOf` schemas */ experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>; /** * _internalFormWrapper is currently used by the semantic-ui theme to provide a custom wrapper around `<Form />` * that supports the proper rendering of those themes. To use this prop, one must pass a component that takes two * props: `children` and `as`. That component, at minimum, should render the `children` inside of a <form /> tag * unless `as` is provided, in which case, use the `as` prop in place of `<form />`. * i.e.: * ``` * export default function InternalForm({ children, as }) { * const FormTag = as || 'form'; * return <FormTag>{children}</FormTag>; * } * ``` * * Use at your own risk as this prop is private and may change at any time without notice. */ _internalFormWrapper?: ElementType; /** Support receiving a React ref to the Form */ ref?: Ref<Form<T, S, F>>; } /** The data that is contained within the state for the `Form` */ export interface FormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> { /** The JSON schema object for the form */ schema: S; /** The uiSchema for the form */ uiSchema: UiSchema<T, S, F>; /** The `FieldPathId` for the form, computed from the `schema`, the `rootFieldId`, the `idPrefix` and * `idSeparator` props. */ fieldPathId: FieldPathId; /** The schemaUtils implementation used by the `Form`, created from the `validator` and the `schema` */ schemaUtils: SchemaUtilsType<T, S, F>; /** The current data for the form, computed from the `formData` prop and the changes made by the user */ formData?: T; /** Flag indicating whether the form is in edit mode, true when `formData` is passed to the form, otherwise false */ edit: boolean; /** The current list of errors for the form, includes `extraErrors` */ errors: RJSFValidationError[]; /** The current errors, in `ErrorSchema` format, for the form, includes `extraErrors` */ errorSchema: ErrorSchema<T>; /** The current list of errors for the form directly from schema validation, does NOT include `extraErrors` */ schemaValidationErrors: RJSFValidationError[]; /** The current errors, in `ErrorSchema` format, for the form directly from schema validation, does NOT include * `extraErrors` */ schemaValidationErrorSchema: ErrorSchema<T>; /** A container used to handle custom errors provided via `onChange` */ customErrors?: ErrorSchemaBuilder<T>; /** @description result of schemaUtils.retrieveSchema(schema, formData). This a memoized value to avoid re calculate at internal functions (getStateFromProps, onChange) */ retrievedSchema: S; /** Flag indicating whether the initial form defaults have been generated */ initialDefaultsGenerated: boolean; /** The registry (re)computed only when props changed */ registry: Registry<T, S, F>; } /** The event data passed when changes have been made to the form, includes everything from the `FormState` except * the schema validation errors. An additional `status` is added when returned from `onSubmit` */ export interface IChangeEvent<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> extends Pick<FormState<T, S, F>, 'schema' | 'uiSchema' | 'fieldPathId' | 'schemaUtils' | 'formData' | 'edit' | 'errors' | 'errorSchema'> { /** The status of the form when submitted */ status?: 'submitted'; } /** The definition of a pending change that will be processed in the `onChange` handler */ interface PendingChange<T> { /** The path into the formData/errorSchema at which the `newValue`/`newErrorSchema` will be set */ path: FieldPathList; /** The new value to set into the formData */ newValue?: T; /** The new errors to be set into the errorSchema, if any */ newErrorSchema?: ErrorSchema<T>; /** The optional id of the field for which the change is being made */ id?: string; } /** The `Form` component renders the outer form and all the fields defined in the `schema` */ export default class Form<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> extends Component<FormProps<T, S, F>, FormState<T, S, F>> { /** The ref used to hold the `form` element, this needs to be `any` because `tagName` or `_internalFormWrapper` can * provide any possible type here */ formElement: RefObject<any>; /** The list of pending changes */ pendingChanges: PendingChange<T>[]; /** Flag to track when we're processing a user-initiated field change. * This prevents componentDidUpdate from reverting oneOf/anyOf option switches. */ private _isProcessingUserChange; /** Constructs the `Form` from the `props`. Will setup the initial state from the props. It will also call the * `onChange` handler if the initially provided `formData` is modified to add missing default values as part of the * state construction. * * @param props - The initial props for the `Form` */ constructor(props: FormProps<T, S, F>); /** * `getSnapshotBeforeUpdate` is a React lifecycle method that is invoked right before the most recently rendered * output is committed to the DOM. It enables your component to capture current values (e.g., scroll position) before * they are potentially changed. * * In this case, it checks if the props have changed since the last render. If they have, it computes the next state * of the component using `getStateFromProps` method and returns it along with a `shouldUpdate` flag set to `true` IF * the `nextState` and `prevState` are different, otherwise `false`. This ensures that we have the most up-to-date * state ready to be applied in `componentDidUpdate`. * * If `formData` hasn't changed, it simply returns an object with `shouldUpdate` set to `false`, indicating that a * state update is not necessary. * * @param prevProps - The previous set of props before the update. * @param prevState - The previous state before the update. * @returns Either an object containing the next state and a flag indicating that an update should occur, or an object * with a flag indicating that an update is not necessary. */ getSnapshotBeforeUpdate(prevProps: FormProps<T, S, F>, prevState: FormState<T, S, F>): { nextState: FormState<T, S, F>; shouldUpdate: true; } | { shouldUpdate: false; }; /** * `componentDidUpdate` is a React lifecycle method that is invoked immediately after updating occurs. This method is * not called for the initial render. * * Here, it checks if an update is necessary based on the `shouldUpdate` flag received from `getSnapshotBeforeUpdate`. * If an update is required, it applies the next state and, if needed, triggers the `onChange` handler to inform about * changes. * * @param _ - The previous set of props. * @param prevState - The previous state of the component before the update. * @param snapshot - The value returned from `getSnapshotBeforeUpdate`. */ componentDidUpdate(_: FormProps<T, S, F>, prevState: FormState<T, S, F>, snapshot: { nextState: FormState<T, S, F>; shouldUpdate: true; } | { shouldUpdate: false; }): void; /** Extracts the updated state from the given `props` and `inputFormData`. As part of this process, the * `inputFormData` is first processed to add any missing required defaults. After that, the data is run through the * validation process IF required by the `props`. * * @param props - The props passed to the `Form` * @param inputFormData - The new or current data for the `Form` * @param retrievedSchema - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData`. * @param isSchemaChanged - A flag indicating whether the schema has changed. * @param formDataChangedFields - The changed fields of `formData` * @param skipLiveValidate - Optional flag, if true, means that we are not running live validation * @returns - The new state for the `Form` */ getStateFromProps(props: FormProps<T, S, F>, inputFormData?: T, retrievedSchema?: S, isSchemaChanged?: boolean, formDataChangedFields?: string[], skipLiveValidate?: boolean): FormState<T, S, F>; /** React lifecycle method that is used to determine whether component should be updated. * * @param nextProps - The next version of the props * @param nextState - The next version of the state * @returns - True if the component should be updated, false otherwise */ shouldComponentUpdate(nextProps: FormProps<T, S, F>, nextState: FormState<T, S, F>): boolean; /** Validates the `formData` against the `schema` using the `altSchemaUtils` (if provided otherwise it uses the * `schemaUtils` in the state), returning the results. * * @param formData - The new form data to validate * @param schema - The schema used to validate against * @param [altSchemaUtils] - The alternate schemaUtils to use for validation * @param [retrievedSchema] - An optionally retrieved schema for per */ validate(formData: T | undefined, schema?: S, altSchemaUtils?: SchemaUtilsType<T, S, F>, retrievedSchema?: S): ValidationData<T>; /** Renders any errors contained in the `state` in using the `ErrorList`, if not disabled by `showErrorList`. */ renderErrors(registry: Registry<T, S, F>): import("react/jsx-runtime").JSX.Element | null; /** Merges any `extraErrors` or `customErrors` into the given `schemaValidation` object, returning the result * * @param schemaValidation - The `ValidationData` object into which additional errors are merged * @param [extraErrors] - The extra errors from the props * @param [customErrors] - The customErrors from custom components * @return - The `extraErrors` and `customErrors` merged into the `schemaValidation` * @private */ private mergeErrors; /** Performs live validation and then updates and returns the errors and error schemas by potentially merging in * `extraErrors` and `customErrors`. * * @param rootSchema - The `rootSchema` from the state * @param schemaUtils - The `SchemaUtilsType` from the state * @param originalErrorSchema - The original `ErrorSchema` from the state * @param [formData] - The new form data to validate * @param [extraErrors] - The extra errors from the props * @param [customErrors] - The customErrors from custom components * @param [retrievedSchema] - An expanded schema, if not provided, it will be retrieved from the `schema` and `formData` * @param [mergeIntoOriginalErrorSchema=false] - Optional flag indicating whether we merge into original schema * @returns - An object containing `errorSchema`, `errors`, `schemaValidationErrors` and `schemaValidationErrorSchema` * @private */ private liveValidate; /** Returns the `formData` with only the elements specified in the `fields` list * * @param formData - The data for the `Form` * @param fields - The fields to keep while filtering * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement */ getUsedFormData: (formData: T | undefined, fields: string[]) => T | undefined; /** Returns the list of field names from inspecting the `pathSchema` as well as using the `formData` * * @param pathSchema - The `PathSchema` object for the form * @param [formData] - The form data to use while checking for empty objects/arrays * @deprecated - To be removed as an exported `Form` function in a future release; there isn't a planned replacement */ getFieldNames: (pathSchema: PathSchema<T>, formData?: T) => string[][]; /** Returns the `formData` after filtering to remove any extra data not in a form field * * @param formData - The data for the `Form` * @returns The `formData` after omitting extra data * @deprecated - To be removed as an exported `Form` function in a future release, use `SchemaUtils.omitExtraData` * instead. */ omitExtraData: (formData?: T) => T | undefined; /** Allows a user to set a value for the provided `fieldPath`, which must be either a dotted path to the field OR a * `FieldPathList`. To set the root element, used either `''` or `[]` for the path. Passing undefined will clear the * value in the field. * * @param fieldPath - Either a dotted path to the field or the `FieldPathList` to the field * @param [newValue] - The new value for the field */ setFieldValue: (fieldPath: string | FieldPathList, newValue?: T) => void; /** Pushes the given change information into the `pendingChanges` array and then calls `processPendingChanges()` if * the array only contains a single pending change. * * @param newValue - The new form data from a change to a field * @param path - The path to the change into which to set the formData * @param [newErrorSchema] - The new `ErrorSchema` based on the field change * @param [id] - The id of the field that caused the change */ onChange: (newValue: T | undefined, path: FieldPathList, newErrorSchema?: ErrorSchema<T>, id?: string) => void; /** Function to handle changes made to a field in the `Form`. This handler gets the first change from the * `pendingChanges` list, containing the `newValue` for the `formData` and the `path` at which the `newValue` is to be * updated, along with a new, optional `ErrorSchema` for that same `path` and potentially the `id` of the field being * changed. It will first update the `formData` with any missing default fields and then, if `omitExtraData` and * `liveOmit` are turned on, the `formData` will be filtered to remove any extra data not in a form field. Then, the * resulting `formData` will be validated if required. The state will be updated with the new updated (potentially * filtered) `formData`, any errors that resulted from validation. Finally the `onChange` callback will be called, if * specified, with the updated state and the `processPendingChange()` function is called again. */ processPendingChange(): void; /** * If the retrievedSchema has changed the new retrievedSchema is returned. * Otherwise, the old retrievedSchema is returned to persist reference. * - This ensures that AJV retrieves the schema from the cache when it has not changed, * avoiding the performance cost of recompiling the schema. * * @param retrievedSchema The new retrieved schema. * @returns The new retrieved schema if it has changed, else the old retrieved schema. */ private updateRetrievedSchema; /** * Callback function to handle reset form data. * - Reset all fields with default values. * - Reset validations and errors * */ reset: () => void; /** Callback function to handle when a field on the form is blurred. Calls the `onBlur` callback for the `Form` if it * was provided. Also runs any live validation and/or live omit operations if the flags indicate they should happen * during `onBlur`. * * @param id - The unique `id` of the field that was blurred * @param data - The data associated with the field that was blurred */ onBlur: (id: string, data: any) => void; /** Callback function to handle when a field on the form is focused. Calls the `onFocus` callback for the `Form` if it * was provided. * * @param id - The unique `id` of the field that was focused * @param data - The data associated with the field that was focused */ onFocus: (id: string, data: any) => void; /** Callback function to handle when the form is submitted. First, it prevents the default event behavior. Nothing * happens if the target and currentTarget of the event are not the same. It will omit any extra data in the * `formData` in the state if `omitExtraData` is true. It will validate the resulting `formData`, reporting errors * via the `onError()` callback unless validation is disabled. Finally, it will add in any `extraErrors` and then call * back the `onSubmit` callback if it was provided. * * @param event - The submit HTML form event */ onSubmit: (event: FormEvent<any>) => void; /** Extracts the `GlobalFormOptions` from the given Form `props` * * @param props - The form props to extract the global form options from * @returns - The `GlobalFormOptions` from the props * @private */ private getGlobalFormOptions; /** Computed the registry for the form using the given `props`, `schema` and `schemaUtils` */ getRegistry(props: FormProps<T, S, F>, schema: S, schemaUtils: SchemaUtilsType<T, S, F>): Registry<T, S, F>; /** Provides a function that can be used to programmatically submit the `Form` */ submit: () => void; /** Attempts to focus on the field associated with the `error`. Uses the `property` field to compute path of the error * field, then, using the `idPrefix` and `idSeparator` converts that path into an id. Then the input element with that * id is attempted to be found using the `formElement` ref. If it is located, then it is focused. * * @param error - The error on which to focus */ focusOnError(error: RJSFValidationError): void; /** Validates the form using the given `formData`. For use on form submission or on programmatic validation. * If `onError` is provided, then it will be called with the list of errors. * * @param formData - The form data to validate * @returns - True if the form is valid, false otherwise. */ validateFormWithFormData: (formData?: T) => boolean; /** Programmatically validate the form. If `omitExtraData` is true, the `formData` will first be filtered to remove * any extra data not in a form field. If `onError` is provided, then it will be called with the list of errors the * same way as would happen on form submission. * * @returns - True if the form is valid, false otherwise. */ validateForm(): boolean; /** Renders the `Form` fields inside the <form> | `tagName` or `_internalFormWrapper`, rendering any errors if * needed along with the submit button or any children of the form. */ render(): import("react/jsx-runtime").JSX.Element; } export {}; //# sourceMappingURL=Form.d.ts.map